1b98ec66cSLawrence Tang /**
2b98ec66cSLawrence Tang  * Describes functions for converting CXL protocol error CPER sections from binary and JSON format
3b98ec66cSLawrence Tang  * into an intermediate format.
4b98ec66cSLawrence Tang  *
5b98ec66cSLawrence Tang  * Author: Lawrence.Tang@arm.com
6b98ec66cSLawrence Tang  **/
7b98ec66cSLawrence Tang #include <stdio.h>
8aec83900SLawrence Tang #include <string.h>
9b98ec66cSLawrence Tang #include "json.h"
10368e0b40SLawrence Tang #include "b64.h"
11b98ec66cSLawrence Tang #include "../edk/Cper.h"
12b98ec66cSLawrence Tang #include "../cper-utils.h"
13b98ec66cSLawrence Tang #include "cper-section-cxl-protocol.h"
14b98ec66cSLawrence Tang 
15b98ec66cSLawrence Tang //Converts a single CXL protocol error CPER section into JSON IR.
16*e407b4c8SLawrence Tang json_object *
17*e407b4c8SLawrence Tang cper_section_cxl_protocol_to_ir(void *section,
18*e407b4c8SLawrence Tang 				EFI_ERROR_SECTION_DESCRIPTOR *descriptor)
19b98ec66cSLawrence Tang {
20*e407b4c8SLawrence Tang 	EFI_CXL_PROTOCOL_ERROR_DATA *cxl_protocol_error =
21*e407b4c8SLawrence Tang 		(EFI_CXL_PROTOCOL_ERROR_DATA *)section;
22b98ec66cSLawrence Tang 	json_object *section_ir = json_object_new_object();
23b98ec66cSLawrence Tang 
24b98ec66cSLawrence Tang 	//Validation bits.
25*e407b4c8SLawrence Tang 	json_object *validation =
26*e407b4c8SLawrence Tang 		bitfield_to_ir(cxl_protocol_error->ValidBits, 7,
27*e407b4c8SLawrence Tang 			       CXL_PROTOCOL_ERROR_VALID_BITFIELD_NAMES);
28b98ec66cSLawrence Tang 	json_object_object_add(section_ir, "validationBits", validation);
29b98ec66cSLawrence Tang 
30b98ec66cSLawrence Tang 	//Type of detecting agent.
31*e407b4c8SLawrence Tang 	json_object *agent_type = integer_to_readable_pair(
32*e407b4c8SLawrence Tang 		cxl_protocol_error->CxlAgentType, 2,
33b98ec66cSLawrence Tang 		CXL_PROTOCOL_ERROR_AGENT_TYPES_KEYS,
34*e407b4c8SLawrence Tang 		CXL_PROTOCOL_ERROR_AGENT_TYPES_VALUES, "Unknown (Reserved)");
35b98ec66cSLawrence Tang 	json_object_object_add(section_ir, "agentType", agent_type);
36b98ec66cSLawrence Tang 
37b98ec66cSLawrence Tang 	//CXL agent address, depending on the agent type.
38cef2a592SLawrence Tang 	json_object *agent_address = json_object_new_object();
39*e407b4c8SLawrence Tang 	if (cxl_protocol_error->CxlAgentType ==
40*e407b4c8SLawrence Tang 	    CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
41b98ec66cSLawrence Tang 		//Address is a CXL1.1 device agent.
42*e407b4c8SLawrence Tang 		json_object_object_add(
43*e407b4c8SLawrence Tang 			agent_address, "functionNumber",
44*e407b4c8SLawrence Tang 			json_object_new_uint64(
45*e407b4c8SLawrence Tang 				cxl_protocol_error->CxlAgentAddress
46*e407b4c8SLawrence Tang 					.DeviceAddress.FunctionNumber));
47*e407b4c8SLawrence Tang 		json_object_object_add(
48*e407b4c8SLawrence Tang 			agent_address, "deviceNumber",
49*e407b4c8SLawrence Tang 			json_object_new_uint64(
50*e407b4c8SLawrence Tang 				cxl_protocol_error->CxlAgentAddress
51*e407b4c8SLawrence Tang 					.DeviceAddress.DeviceNumber));
52*e407b4c8SLawrence Tang 		json_object_object_add(
53*e407b4c8SLawrence Tang 			agent_address, "busNumber",
54*e407b4c8SLawrence Tang 			json_object_new_uint64(
55*e407b4c8SLawrence Tang 				cxl_protocol_error->CxlAgentAddress
56*e407b4c8SLawrence Tang 					.DeviceAddress.BusNumber));
57*e407b4c8SLawrence Tang 		json_object_object_add(
58*e407b4c8SLawrence Tang 			agent_address, "segmentNumber",
59*e407b4c8SLawrence Tang 			json_object_new_uint64(
60*e407b4c8SLawrence Tang 				cxl_protocol_error->CxlAgentAddress
61*e407b4c8SLawrence Tang 					.DeviceAddress.SegmentNumber));
62*e407b4c8SLawrence Tang 	} else if (cxl_protocol_error->CxlAgentType ==
63*e407b4c8SLawrence Tang 		   CXL_PROTOCOL_ERROR_HOST_DOWNSTREAM_PORT_AGENT) {
64b98ec66cSLawrence Tang 		//Address is a CXL port RCRB base address.
65*e407b4c8SLawrence Tang 		json_object_object_add(
66*e407b4c8SLawrence Tang 			agent_address, "value",
67*e407b4c8SLawrence Tang 			json_object_new_uint64(
68*e407b4c8SLawrence Tang 				cxl_protocol_error->CxlAgentAddress
69*e407b4c8SLawrence Tang 					.PortRcrbBaseAddress));
70b98ec66cSLawrence Tang 	}
71cef2a592SLawrence Tang 	json_object_object_add(section_ir, "cxlAgentAddress", agent_address);
72b98ec66cSLawrence Tang 
73b98ec66cSLawrence Tang 	//Device ID.
74b98ec66cSLawrence Tang 	json_object *device_id = json_object_new_object();
75*e407b4c8SLawrence Tang 	json_object_object_add(
76*e407b4c8SLawrence Tang 		device_id, "vendorID",
77b98ec66cSLawrence Tang 		json_object_new_uint64(cxl_protocol_error->DeviceId.VendorId));
78*e407b4c8SLawrence Tang 	json_object_object_add(
79*e407b4c8SLawrence Tang 		device_id, "deviceID",
80b98ec66cSLawrence Tang 		json_object_new_uint64(cxl_protocol_error->DeviceId.DeviceId));
81*e407b4c8SLawrence Tang 	json_object_object_add(
82*e407b4c8SLawrence Tang 		device_id, "subsystemVendorID",
83*e407b4c8SLawrence Tang 		json_object_new_uint64(
84*e407b4c8SLawrence Tang 			cxl_protocol_error->DeviceId.SubsystemVendorId));
85*e407b4c8SLawrence Tang 	json_object_object_add(
86*e407b4c8SLawrence Tang 		device_id, "subsystemDeviceID",
87*e407b4c8SLawrence Tang 		json_object_new_uint64(
88*e407b4c8SLawrence Tang 			cxl_protocol_error->DeviceId.SubsystemDeviceId));
89*e407b4c8SLawrence Tang 	json_object_object_add(
90*e407b4c8SLawrence Tang 		device_id, "classCode",
91b98ec66cSLawrence Tang 		json_object_new_uint64(cxl_protocol_error->DeviceId.ClassCode));
92*e407b4c8SLawrence Tang 	json_object_object_add(
93*e407b4c8SLawrence Tang 		device_id, "slotNumber",
94*e407b4c8SLawrence Tang 		json_object_new_uint64(
95*e407b4c8SLawrence Tang 			cxl_protocol_error->DeviceId.SlotNumber));
96b98ec66cSLawrence Tang 	json_object_object_add(section_ir, "deviceID", device_id);
97b98ec66cSLawrence Tang 
98b98ec66cSLawrence Tang 	//Device serial & capability structure (if CXL 1.1 device).
99*e407b4c8SLawrence Tang 	if (cxl_protocol_error->CxlAgentType ==
100*e407b4c8SLawrence Tang 	    CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
101*e407b4c8SLawrence Tang 		json_object_object_add(
102*e407b4c8SLawrence Tang 			section_ir, "deviceSerial",
103*e407b4c8SLawrence Tang 			json_object_new_uint64(
104*e407b4c8SLawrence Tang 				cxl_protocol_error->DeviceSerial));
105368e0b40SLawrence Tang 
106368e0b40SLawrence Tang 		//The PCIe capability structure provided here could either be PCIe 1.1 Capability Structure
107368e0b40SLawrence Tang 		//(36-byte, padded to 60 bytes) or PCIe 2.0 Capability Structure (60-byte). There does not seem
108368e0b40SLawrence Tang 		//to be a way to differentiate these, so this is left as a b64 dump.
109*e407b4c8SLawrence Tang 		char *encoded = b64_encode(
110*e407b4c8SLawrence Tang 			cxl_protocol_error->CapabilityStructure.PcieCap, 60);
111*e407b4c8SLawrence Tang 		json_object_object_add(section_ir, "capabilityStructure",
112*e407b4c8SLawrence Tang 				       json_object_new_string(encoded));
113368e0b40SLawrence Tang 		free(encoded);
114b98ec66cSLawrence Tang 	}
115b98ec66cSLawrence Tang 
116b98ec66cSLawrence Tang 	//CXL DVSEC & error log length.
117*e407b4c8SLawrence Tang 	json_object_object_add(
118*e407b4c8SLawrence Tang 		section_ir, "dvsecLength",
119*e407b4c8SLawrence Tang 		json_object_new_int(cxl_protocol_error->CxlDvsecLength));
120*e407b4c8SLawrence Tang 	json_object_object_add(
121*e407b4c8SLawrence Tang 		section_ir, "errorLogLength",
122*e407b4c8SLawrence Tang 		json_object_new_int(cxl_protocol_error->CxlErrorLogLength));
123b98ec66cSLawrence Tang 
124b98ec66cSLawrence Tang 	//CXL DVSEC
125368e0b40SLawrence Tang 	//For CXL 1.1 devices, this is the "CXL DVSEC For Flex Bus Device" structure as in CXL 1.1 spec.
126cef2a592SLawrence Tang 	//For CXL 1.1 host downstream ports, this is the "CXL DVSEC For Flex Bus Port" structure as in CXL 1.1 spec.
127368e0b40SLawrence Tang 	unsigned char *cur_pos = (unsigned char *)(cxl_protocol_error + 1);
128368e0b40SLawrence Tang 	char *encoded = b64_encode(cur_pos, cxl_protocol_error->CxlDvsecLength);
129*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "cxlDVSEC",
130*e407b4c8SLawrence Tang 			       json_object_new_string(encoded));
131368e0b40SLawrence Tang 	free(encoded);
132368e0b40SLawrence Tang 	cur_pos += cxl_protocol_error->CxlDvsecLength;
133368e0b40SLawrence Tang 
134b98ec66cSLawrence Tang 	//CXL Error Log
135cef2a592SLawrence Tang 	//This is the "CXL RAS Capability Structure" as in CXL 1.1 spec.
136cef2a592SLawrence Tang 	encoded = b64_encode(cur_pos, cxl_protocol_error->CxlErrorLogLength);
137*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "cxlErrorLog",
138*e407b4c8SLawrence Tang 			       json_object_new_string(encoded));
139cef2a592SLawrence Tang 	free(encoded);
140b98ec66cSLawrence Tang 
141b98ec66cSLawrence Tang 	return section_ir;
142b98ec66cSLawrence Tang }
143aec83900SLawrence Tang 
144aec83900SLawrence Tang //Converts a single CXL protocol CPER-JSON section into CPER binary, outputting to the given stream.
145aec83900SLawrence Tang void ir_section_cxl_protocol_to_cper(json_object *section, FILE *out)
146aec83900SLawrence Tang {
147aec83900SLawrence Tang 	EFI_CXL_PROTOCOL_ERROR_DATA *section_cper =
148*e407b4c8SLawrence Tang 		(EFI_CXL_PROTOCOL_ERROR_DATA *)calloc(
149*e407b4c8SLawrence Tang 			1, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA));
150aec83900SLawrence Tang 
151aec83900SLawrence Tang 	//Validation bits.
152*e407b4c8SLawrence Tang 	section_cper->ValidBits = ir_to_bitfield(
153*e407b4c8SLawrence Tang 		json_object_object_get(section, "validationBits"), 7,
154*e407b4c8SLawrence Tang 		CXL_PROTOCOL_ERROR_VALID_BITFIELD_NAMES);
155aec83900SLawrence Tang 
156aec83900SLawrence Tang 	//Detecting agent type.
157*e407b4c8SLawrence Tang 	section_cper->CxlAgentType = readable_pair_to_integer(
158*e407b4c8SLawrence Tang 		json_object_object_get(section, "agentType"));
159aec83900SLawrence Tang 
160aec83900SLawrence Tang 	//Based on the agent type, set the address.
161*e407b4c8SLawrence Tang 	json_object *address =
162*e407b4c8SLawrence Tang 		json_object_object_get(section, "cxlAgentAddress");
163*e407b4c8SLawrence Tang 	if (section_cper->CxlAgentType == CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
164aec83900SLawrence Tang 		//Address is split by function, device, bus & segment.
165*e407b4c8SLawrence Tang 		UINT64 function = json_object_get_uint64(
166*e407b4c8SLawrence Tang 			json_object_object_get(address, "functionNumber"));
167*e407b4c8SLawrence Tang 		UINT64 device = json_object_get_uint64(
168*e407b4c8SLawrence Tang 			json_object_object_get(address, "deviceNumber"));
169*e407b4c8SLawrence Tang 		UINT64 bus = json_object_get_uint64(
170*e407b4c8SLawrence Tang 			json_object_object_get(address, "busNumber"));
171*e407b4c8SLawrence Tang 		UINT64 segment = json_object_get_uint64(
172*e407b4c8SLawrence Tang 			json_object_object_get(address, "segmentNumber"));
173*e407b4c8SLawrence Tang 		section_cper->CxlAgentAddress.DeviceAddress.FunctionNumber =
174*e407b4c8SLawrence Tang 			function;
175*e407b4c8SLawrence Tang 		section_cper->CxlAgentAddress.DeviceAddress.DeviceNumber =
176*e407b4c8SLawrence Tang 			device;
177aec83900SLawrence Tang 		section_cper->CxlAgentAddress.DeviceAddress.BusNumber = bus;
178*e407b4c8SLawrence Tang 		section_cper->CxlAgentAddress.DeviceAddress.SegmentNumber =
179*e407b4c8SLawrence Tang 			segment;
180*e407b4c8SLawrence Tang 	} else if (section_cper->CxlAgentType ==
181*e407b4c8SLawrence Tang 		   CXL_PROTOCOL_ERROR_HOST_DOWNSTREAM_PORT_AGENT) {
182aec83900SLawrence Tang 		//Plain RCRB base address.
183aec83900SLawrence Tang 		section_cper->CxlAgentAddress.PortRcrbBaseAddress =
184*e407b4c8SLawrence Tang 			json_object_get_uint64(
185*e407b4c8SLawrence Tang 				json_object_object_get(address, "value"));
186aec83900SLawrence Tang 	}
187aec83900SLawrence Tang 
188aec83900SLawrence Tang 	//Device ID information.
189aec83900SLawrence Tang 	json_object *device_id = json_object_object_get(section, "deviceID");
190*e407b4c8SLawrence Tang 	section_cper->DeviceId.VendorId = json_object_get_uint64(
191*e407b4c8SLawrence Tang 		json_object_object_get(device_id, "vendorID"));
192*e407b4c8SLawrence Tang 	section_cper->DeviceId.DeviceId = json_object_get_uint64(
193*e407b4c8SLawrence Tang 		json_object_object_get(device_id, "deviceID"));
194*e407b4c8SLawrence Tang 	section_cper->DeviceId.SubsystemVendorId = json_object_get_uint64(
195*e407b4c8SLawrence Tang 		json_object_object_get(device_id, "subsystemVendorID"));
196*e407b4c8SLawrence Tang 	section_cper->DeviceId.SubsystemDeviceId = json_object_get_uint64(
197*e407b4c8SLawrence Tang 		json_object_object_get(device_id, "subsystemDeviceID"));
198*e407b4c8SLawrence Tang 	section_cper->DeviceId.ClassCode = json_object_get_uint64(
199*e407b4c8SLawrence Tang 		json_object_object_get(device_id, "classCode"));
200*e407b4c8SLawrence Tang 	section_cper->DeviceId.SlotNumber = json_object_get_uint64(
201*e407b4c8SLawrence Tang 		json_object_object_get(device_id, "slotNumber"));
202aec83900SLawrence Tang 
203aec83900SLawrence Tang 	//If CXL 1.1 device, the serial number & PCI capability structure.
204*e407b4c8SLawrence Tang 	if (section_cper->CxlAgentType == CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
205*e407b4c8SLawrence Tang 		section_cper->DeviceSerial = json_object_get_uint64(
206*e407b4c8SLawrence Tang 			json_object_object_get(section, "deviceSerial"));
207aec83900SLawrence Tang 
208*e407b4c8SLawrence Tang 		json_object *encoded =
209*e407b4c8SLawrence Tang 			json_object_object_get(section, "capabilityStructure");
210*e407b4c8SLawrence Tang 		char *decoded = b64_decode(json_object_get_string(encoded),
211*e407b4c8SLawrence Tang 					   json_object_get_string_len(encoded));
212aec83900SLawrence Tang 		memcpy(section_cper->CapabilityStructure.PcieCap, decoded, 60);
213aec83900SLawrence Tang 		free(decoded);
214aec83900SLawrence Tang 	}
215aec83900SLawrence Tang 
216aec83900SLawrence Tang 	//DVSEC length & error log length.
217*e407b4c8SLawrence Tang 	section_cper->CxlDvsecLength = (UINT16)json_object_get_int(
218*e407b4c8SLawrence Tang 		json_object_object_get(section, "dvsecLength"));
219*e407b4c8SLawrence Tang 	section_cper->CxlErrorLogLength = (UINT16)json_object_get_int(
220*e407b4c8SLawrence Tang 		json_object_object_get(section, "errorLogLength"));
221aec83900SLawrence Tang 
222aec83900SLawrence Tang 	//Write header to stream.
2233ab351feSLawrence Tang 	fwrite(section_cper, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA), 1, out);
224aec83900SLawrence Tang 	fflush(out);
225aec83900SLawrence Tang 
226aec83900SLawrence Tang 	//DVSEC out to stream.
227aec83900SLawrence Tang 	json_object *encoded = json_object_object_get(section, "cxlDVSEC");
228*e407b4c8SLawrence Tang 	char *decoded = b64_decode(json_object_get_string(encoded),
229*e407b4c8SLawrence Tang 				   json_object_get_string_len(encoded));
230aec83900SLawrence Tang 	fwrite(decoded, section_cper->CxlDvsecLength, 1, out);
231aec83900SLawrence Tang 	fflush(out);
232aec83900SLawrence Tang 	free(decoded);
233aec83900SLawrence Tang 
234aec83900SLawrence Tang 	//Error log out to stream.
235aec83900SLawrence Tang 	encoded = json_object_object_get(section, "cxlErrorLog");
236*e407b4c8SLawrence Tang 	decoded = b64_decode(json_object_get_string(encoded),
237*e407b4c8SLawrence Tang 			     json_object_get_string_len(encoded));
238aec83900SLawrence Tang 	fwrite(decoded, section_cper->CxlErrorLogLength, 1, out);
239aec83900SLawrence Tang 	fflush(out);
240aec83900SLawrence Tang 	free(decoded);
241aec83900SLawrence Tang 
242aec83900SLawrence Tang 	free(section_cper);
243aec83900SLawrence Tang }