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>
9*a7d2cdddSEd Tanous #include "base64.h"
10b98ec66cSLawrence Tang #include "../edk/Cper.h"
11b98ec66cSLawrence Tang #include "../cper-utils.h"
12b98ec66cSLawrence Tang #include "cper-section-cxl-protocol.h"
13b98ec66cSLawrence Tang 
14b98ec66cSLawrence Tang //Converts a single CXL protocol error CPER section into JSON IR.
cper_section_cxl_protocol_to_ir(void * section)15f8fc7052SJohn Chung json_object *cper_section_cxl_protocol_to_ir(void *section)
16b98ec66cSLawrence Tang {
17e407b4c8SLawrence Tang 	EFI_CXL_PROTOCOL_ERROR_DATA *cxl_protocol_error =
18e407b4c8SLawrence Tang 		(EFI_CXL_PROTOCOL_ERROR_DATA *)section;
19b98ec66cSLawrence Tang 	json_object *section_ir = json_object_new_object();
20b98ec66cSLawrence Tang 
21b98ec66cSLawrence Tang 	//Validation bits.
22e407b4c8SLawrence Tang 	json_object *validation =
23e407b4c8SLawrence Tang 		bitfield_to_ir(cxl_protocol_error->ValidBits, 7,
24e407b4c8SLawrence Tang 			       CXL_PROTOCOL_ERROR_VALID_BITFIELD_NAMES);
25b98ec66cSLawrence Tang 	json_object_object_add(section_ir, "validationBits", validation);
26b98ec66cSLawrence Tang 
27b98ec66cSLawrence Tang 	//Type of detecting agent.
28e407b4c8SLawrence Tang 	json_object *agent_type = integer_to_readable_pair(
29e407b4c8SLawrence Tang 		cxl_protocol_error->CxlAgentType, 2,
30b98ec66cSLawrence Tang 		CXL_PROTOCOL_ERROR_AGENT_TYPES_KEYS,
31e407b4c8SLawrence Tang 		CXL_PROTOCOL_ERROR_AGENT_TYPES_VALUES, "Unknown (Reserved)");
32b98ec66cSLawrence Tang 	json_object_object_add(section_ir, "agentType", agent_type);
33b98ec66cSLawrence Tang 
34b98ec66cSLawrence Tang 	//CXL agent address, depending on the agent type.
35cef2a592SLawrence Tang 	json_object *agent_address = json_object_new_object();
36e407b4c8SLawrence Tang 	if (cxl_protocol_error->CxlAgentType ==
37e407b4c8SLawrence Tang 	    CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
38b98ec66cSLawrence Tang 		//Address is a CXL1.1 device agent.
39e407b4c8SLawrence Tang 		json_object_object_add(
40e407b4c8SLawrence Tang 			agent_address, "functionNumber",
41e407b4c8SLawrence Tang 			json_object_new_uint64(
42e407b4c8SLawrence Tang 				cxl_protocol_error->CxlAgentAddress
43e407b4c8SLawrence Tang 					.DeviceAddress.FunctionNumber));
44e407b4c8SLawrence Tang 		json_object_object_add(
45e407b4c8SLawrence Tang 			agent_address, "deviceNumber",
46e407b4c8SLawrence Tang 			json_object_new_uint64(
47e407b4c8SLawrence Tang 				cxl_protocol_error->CxlAgentAddress
48e407b4c8SLawrence Tang 					.DeviceAddress.DeviceNumber));
49e407b4c8SLawrence Tang 		json_object_object_add(
50e407b4c8SLawrence Tang 			agent_address, "busNumber",
51e407b4c8SLawrence Tang 			json_object_new_uint64(
52e407b4c8SLawrence Tang 				cxl_protocol_error->CxlAgentAddress
53e407b4c8SLawrence Tang 					.DeviceAddress.BusNumber));
54e407b4c8SLawrence Tang 		json_object_object_add(
55e407b4c8SLawrence Tang 			agent_address, "segmentNumber",
56e407b4c8SLawrence Tang 			json_object_new_uint64(
57e407b4c8SLawrence Tang 				cxl_protocol_error->CxlAgentAddress
58e407b4c8SLawrence Tang 					.DeviceAddress.SegmentNumber));
59e407b4c8SLawrence Tang 	} else if (cxl_protocol_error->CxlAgentType ==
60e407b4c8SLawrence Tang 		   CXL_PROTOCOL_ERROR_HOST_DOWNSTREAM_PORT_AGENT) {
61b98ec66cSLawrence Tang 		//Address is a CXL port RCRB base address.
62e407b4c8SLawrence Tang 		json_object_object_add(
63e407b4c8SLawrence Tang 			agent_address, "value",
64e407b4c8SLawrence Tang 			json_object_new_uint64(
65e407b4c8SLawrence Tang 				cxl_protocol_error->CxlAgentAddress
66e407b4c8SLawrence Tang 					.PortRcrbBaseAddress));
67b98ec66cSLawrence Tang 	}
68cef2a592SLawrence Tang 	json_object_object_add(section_ir, "cxlAgentAddress", agent_address);
69b98ec66cSLawrence Tang 
70b98ec66cSLawrence Tang 	//Device ID.
71b98ec66cSLawrence Tang 	json_object *device_id = json_object_new_object();
72e407b4c8SLawrence Tang 	json_object_object_add(
73e407b4c8SLawrence Tang 		device_id, "vendorID",
74b98ec66cSLawrence Tang 		json_object_new_uint64(cxl_protocol_error->DeviceId.VendorId));
75e407b4c8SLawrence Tang 	json_object_object_add(
76e407b4c8SLawrence Tang 		device_id, "deviceID",
77b98ec66cSLawrence Tang 		json_object_new_uint64(cxl_protocol_error->DeviceId.DeviceId));
78e407b4c8SLawrence Tang 	json_object_object_add(
79e407b4c8SLawrence Tang 		device_id, "subsystemVendorID",
80e407b4c8SLawrence Tang 		json_object_new_uint64(
81e407b4c8SLawrence Tang 			cxl_protocol_error->DeviceId.SubsystemVendorId));
82e407b4c8SLawrence Tang 	json_object_object_add(
83e407b4c8SLawrence Tang 		device_id, "subsystemDeviceID",
84e407b4c8SLawrence Tang 		json_object_new_uint64(
85e407b4c8SLawrence Tang 			cxl_protocol_error->DeviceId.SubsystemDeviceId));
86e407b4c8SLawrence Tang 	json_object_object_add(
87e407b4c8SLawrence Tang 		device_id, "classCode",
88b98ec66cSLawrence Tang 		json_object_new_uint64(cxl_protocol_error->DeviceId.ClassCode));
89e407b4c8SLawrence Tang 	json_object_object_add(
90e407b4c8SLawrence Tang 		device_id, "slotNumber",
91e407b4c8SLawrence Tang 		json_object_new_uint64(
92e407b4c8SLawrence Tang 			cxl_protocol_error->DeviceId.SlotNumber));
93b98ec66cSLawrence Tang 	json_object_object_add(section_ir, "deviceID", device_id);
94b98ec66cSLawrence Tang 
95*a7d2cdddSEd Tanous 	char *encoded;
96b98ec66cSLawrence Tang 	//Device serial & capability structure (if CXL 1.1 device).
97e407b4c8SLawrence Tang 	if (cxl_protocol_error->CxlAgentType ==
98e407b4c8SLawrence Tang 	    CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
99e407b4c8SLawrence Tang 		json_object_object_add(
100e407b4c8SLawrence Tang 			section_ir, "deviceSerial",
101e407b4c8SLawrence Tang 			json_object_new_uint64(
102e407b4c8SLawrence Tang 				cxl_protocol_error->DeviceSerial));
103368e0b40SLawrence Tang 
104368e0b40SLawrence Tang 		//The PCIe capability structure provided here could either be PCIe 1.1 Capability Structure
105368e0b40SLawrence Tang 		//(36-byte, padded to 60 bytes) or PCIe 2.0 Capability Structure (60-byte). There does not seem
106368e0b40SLawrence Tang 		//to be a way to differentiate these, so this is left as a b64 dump.
107*a7d2cdddSEd Tanous 
108*a7d2cdddSEd Tanous 		int32_t encoded_len = 0;
109*a7d2cdddSEd Tanous 
110*a7d2cdddSEd Tanous 		encoded = base64_encode(
111*a7d2cdddSEd Tanous 			(UINT8 *)cxl_protocol_error->CapabilityStructure.PcieCap,
112*a7d2cdddSEd Tanous 			60, &encoded_len);
113*a7d2cdddSEd Tanous 		if (encoded == NULL) {
114f8fc7052SJohn Chung 			printf("Failed to allocate encode output buffer. \n");
115*a7d2cdddSEd Tanous 			return NULL;
116b98ec66cSLawrence Tang 		}
117*a7d2cdddSEd Tanous 		json_object_object_add(section_ir, "capabilityStructure",
118*a7d2cdddSEd Tanous 				       json_object_new_string_len(encoded,
119*a7d2cdddSEd Tanous 								  encoded_len));
120*a7d2cdddSEd Tanous 		free(encoded);
121f8fc7052SJohn Chung 	}
122b98ec66cSLawrence Tang 
123b98ec66cSLawrence Tang 	//CXL DVSEC & error log length.
124e407b4c8SLawrence Tang 	json_object_object_add(
125e407b4c8SLawrence Tang 		section_ir, "dvsecLength",
126e407b4c8SLawrence Tang 		json_object_new_int(cxl_protocol_error->CxlDvsecLength));
127e407b4c8SLawrence Tang 	json_object_object_add(
128e407b4c8SLawrence Tang 		section_ir, "errorLogLength",
129e407b4c8SLawrence Tang 		json_object_new_int(cxl_protocol_error->CxlErrorLogLength));
130b98ec66cSLawrence Tang 
131b98ec66cSLawrence Tang 	//CXL DVSEC
132368e0b40SLawrence Tang 	//For CXL 1.1 devices, this is the "CXL DVSEC For Flex Bus Device" structure as in CXL 1.1 spec.
133cef2a592SLawrence Tang 	//For CXL 1.1 host downstream ports, this is the "CXL DVSEC For Flex Bus Port" structure as in CXL 1.1 spec.
134f8fc7052SJohn Chung 	const char *cur_pos = (const char *)(cxl_protocol_error + 1);
135*a7d2cdddSEd Tanous 	int32_t encoded_len = 0;
136*a7d2cdddSEd Tanous 
137*a7d2cdddSEd Tanous 	encoded = base64_encode((UINT8 *)cur_pos,
138*a7d2cdddSEd Tanous 				cxl_protocol_error->CxlDvsecLength,
139*a7d2cdddSEd Tanous 				&encoded_len);
140*a7d2cdddSEd Tanous 	if (encoded == NULL) {
141*a7d2cdddSEd Tanous 		return NULL;
142*a7d2cdddSEd Tanous 	}
143e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "cxlDVSEC",
144f8fc7052SJohn Chung 			       json_object_new_string_len(encoded,
145f8fc7052SJohn Chung 							  encoded_len));
146f8fc7052SJohn Chung 
147368e0b40SLawrence Tang 	free(encoded);
148*a7d2cdddSEd Tanous 
149368e0b40SLawrence Tang 	cur_pos += cxl_protocol_error->CxlDvsecLength;
150368e0b40SLawrence Tang 
151b98ec66cSLawrence Tang 	//CXL Error Log
152cef2a592SLawrence Tang 	//This is the "CXL RAS Capability Structure" as in CXL 1.1 spec.
153*a7d2cdddSEd Tanous 
154f8fc7052SJohn Chung 	encoded_len = 0;
155*a7d2cdddSEd Tanous 	encoded = base64_encode((UINT8 *)cur_pos,
156*a7d2cdddSEd Tanous 				cxl_protocol_error->CxlErrorLogLength,
157*a7d2cdddSEd Tanous 				&encoded_len);
158*a7d2cdddSEd Tanous 
159*a7d2cdddSEd Tanous 	if (encoded == NULL) {
160f8fc7052SJohn Chung 		printf("Failed to allocate encode output buffer. \n");
161*a7d2cdddSEd Tanous 		return NULL;
162*a7d2cdddSEd Tanous 	}
163e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "cxlErrorLog",
164f8fc7052SJohn Chung 			       json_object_new_string_len(encoded,
165f8fc7052SJohn Chung 							  encoded_len));
166cef2a592SLawrence Tang 	free(encoded);
167*a7d2cdddSEd Tanous 
168b98ec66cSLawrence Tang 	return section_ir;
169b98ec66cSLawrence Tang }
170aec83900SLawrence Tang 
171aec83900SLawrence Tang //Converts a single CXL protocol CPER-JSON section into CPER binary, outputting to the given stream.
ir_section_cxl_protocol_to_cper(json_object * section,FILE * out)172aec83900SLawrence Tang void ir_section_cxl_protocol_to_cper(json_object *section, FILE *out)
173aec83900SLawrence Tang {
174aec83900SLawrence Tang 	EFI_CXL_PROTOCOL_ERROR_DATA *section_cper =
175e407b4c8SLawrence Tang 		(EFI_CXL_PROTOCOL_ERROR_DATA *)calloc(
176e407b4c8SLawrence Tang 			1, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA));
177aec83900SLawrence Tang 
178aec83900SLawrence Tang 	//Validation bits.
179e407b4c8SLawrence Tang 	section_cper->ValidBits = ir_to_bitfield(
180e407b4c8SLawrence Tang 		json_object_object_get(section, "validationBits"), 7,
181e407b4c8SLawrence Tang 		CXL_PROTOCOL_ERROR_VALID_BITFIELD_NAMES);
182aec83900SLawrence Tang 
183aec83900SLawrence Tang 	//Detecting agent type.
184e407b4c8SLawrence Tang 	section_cper->CxlAgentType = readable_pair_to_integer(
185e407b4c8SLawrence Tang 		json_object_object_get(section, "agentType"));
186aec83900SLawrence Tang 
187aec83900SLawrence Tang 	//Based on the agent type, set the address.
188e407b4c8SLawrence Tang 	json_object *address =
189e407b4c8SLawrence Tang 		json_object_object_get(section, "cxlAgentAddress");
190e407b4c8SLawrence Tang 	if (section_cper->CxlAgentType == CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
191aec83900SLawrence Tang 		//Address is split by function, device, bus & segment.
192e407b4c8SLawrence Tang 		UINT64 function = json_object_get_uint64(
193e407b4c8SLawrence Tang 			json_object_object_get(address, "functionNumber"));
194e407b4c8SLawrence Tang 		UINT64 device = json_object_get_uint64(
195e407b4c8SLawrence Tang 			json_object_object_get(address, "deviceNumber"));
196e407b4c8SLawrence Tang 		UINT64 bus = json_object_get_uint64(
197e407b4c8SLawrence Tang 			json_object_object_get(address, "busNumber"));
198e407b4c8SLawrence Tang 		UINT64 segment = json_object_get_uint64(
199e407b4c8SLawrence Tang 			json_object_object_get(address, "segmentNumber"));
200e407b4c8SLawrence Tang 		section_cper->CxlAgentAddress.DeviceAddress.FunctionNumber =
201e407b4c8SLawrence Tang 			function;
202e407b4c8SLawrence Tang 		section_cper->CxlAgentAddress.DeviceAddress.DeviceNumber =
203e407b4c8SLawrence Tang 			device;
204aec83900SLawrence Tang 		section_cper->CxlAgentAddress.DeviceAddress.BusNumber = bus;
205e407b4c8SLawrence Tang 		section_cper->CxlAgentAddress.DeviceAddress.SegmentNumber =
206e407b4c8SLawrence Tang 			segment;
207e407b4c8SLawrence Tang 	} else if (section_cper->CxlAgentType ==
208e407b4c8SLawrence Tang 		   CXL_PROTOCOL_ERROR_HOST_DOWNSTREAM_PORT_AGENT) {
209aec83900SLawrence Tang 		//Plain RCRB base address.
210aec83900SLawrence Tang 		section_cper->CxlAgentAddress.PortRcrbBaseAddress =
211e407b4c8SLawrence Tang 			json_object_get_uint64(
212e407b4c8SLawrence Tang 				json_object_object_get(address, "value"));
213aec83900SLawrence Tang 	}
214aec83900SLawrence Tang 
215aec83900SLawrence Tang 	//Device ID information.
216aec83900SLawrence Tang 	json_object *device_id = json_object_object_get(section, "deviceID");
217e407b4c8SLawrence Tang 	section_cper->DeviceId.VendorId = json_object_get_uint64(
218e407b4c8SLawrence Tang 		json_object_object_get(device_id, "vendorID"));
219e407b4c8SLawrence Tang 	section_cper->DeviceId.DeviceId = json_object_get_uint64(
220e407b4c8SLawrence Tang 		json_object_object_get(device_id, "deviceID"));
221e407b4c8SLawrence Tang 	section_cper->DeviceId.SubsystemVendorId = json_object_get_uint64(
222e407b4c8SLawrence Tang 		json_object_object_get(device_id, "subsystemVendorID"));
223e407b4c8SLawrence Tang 	section_cper->DeviceId.SubsystemDeviceId = json_object_get_uint64(
224e407b4c8SLawrence Tang 		json_object_object_get(device_id, "subsystemDeviceID"));
225e407b4c8SLawrence Tang 	section_cper->DeviceId.ClassCode = json_object_get_uint64(
226e407b4c8SLawrence Tang 		json_object_object_get(device_id, "classCode"));
227e407b4c8SLawrence Tang 	section_cper->DeviceId.SlotNumber = json_object_get_uint64(
228e407b4c8SLawrence Tang 		json_object_object_get(device_id, "slotNumber"));
229aec83900SLawrence Tang 
230aec83900SLawrence Tang 	//If CXL 1.1 device, the serial number & PCI capability structure.
231*a7d2cdddSEd Tanous 	UINT8 *decoded;
232e407b4c8SLawrence Tang 	if (section_cper->CxlAgentType == CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
233e407b4c8SLawrence Tang 		section_cper->DeviceSerial = json_object_get_uint64(
234e407b4c8SLawrence Tang 			json_object_object_get(section, "deviceSerial"));
235aec83900SLawrence Tang 
236e407b4c8SLawrence Tang 		json_object *encoded =
237e407b4c8SLawrence Tang 			json_object_object_get(section, "capabilityStructure");
238*a7d2cdddSEd Tanous 
239*a7d2cdddSEd Tanous 		int32_t decoded_len = 0;
240*a7d2cdddSEd Tanous 
241*a7d2cdddSEd Tanous 		decoded = base64_decode(json_object_get_string(encoded),
242*a7d2cdddSEd Tanous 					json_object_get_string_len(encoded),
243*a7d2cdddSEd Tanous 					&decoded_len);
244*a7d2cdddSEd Tanous 
245*a7d2cdddSEd Tanous 		if (decoded == NULL) {
246f8fc7052SJohn Chung 			printf("Failed to allocate decode output buffer. \n");
247f8fc7052SJohn Chung 		} else {
248f8fc7052SJohn Chung 			memcpy(section_cper->CapabilityStructure.PcieCap,
249f8fc7052SJohn Chung 			       decoded, decoded_len);
250aec83900SLawrence Tang 			free(decoded);
251aec83900SLawrence Tang 		}
252f8fc7052SJohn Chung 	}
253aec83900SLawrence Tang 
254aec83900SLawrence Tang 	//DVSEC length & error log length.
255e407b4c8SLawrence Tang 	section_cper->CxlDvsecLength = (UINT16)json_object_get_int(
256e407b4c8SLawrence Tang 		json_object_object_get(section, "dvsecLength"));
257e407b4c8SLawrence Tang 	section_cper->CxlErrorLogLength = (UINT16)json_object_get_int(
258e407b4c8SLawrence Tang 		json_object_object_get(section, "errorLogLength"));
259aec83900SLawrence Tang 
260aec83900SLawrence Tang 	//Write header to stream.
2613ab351feSLawrence Tang 	fwrite(section_cper, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA), 1, out);
262aec83900SLawrence Tang 	fflush(out);
263aec83900SLawrence Tang 
264aec83900SLawrence Tang 	//DVSEC out to stream.
265aec83900SLawrence Tang 	json_object *encoded = json_object_object_get(section, "cxlDVSEC");
266*a7d2cdddSEd Tanous 
267*a7d2cdddSEd Tanous 	int32_t decoded_len = 0;
268*a7d2cdddSEd Tanous 
269*a7d2cdddSEd Tanous 	decoded = base64_decode(json_object_get_string(encoded),
270*a7d2cdddSEd Tanous 				json_object_get_string_len(encoded),
271*a7d2cdddSEd Tanous 				&decoded_len);
272*a7d2cdddSEd Tanous 	if (decoded == NULL) {
273f8fc7052SJohn Chung 		printf("Failed to allocate decode output buffer. \n");
274f8fc7052SJohn Chung 	} else {
275f8fc7052SJohn Chung 		fwrite(decoded, decoded_len, 1, out);
276aec83900SLawrence Tang 		fflush(out);
277aec83900SLawrence Tang 		free(decoded);
278f8fc7052SJohn Chung 	}
279aec83900SLawrence Tang 
280aec83900SLawrence Tang 	//Error log out to stream.
281aec83900SLawrence Tang 	encoded = json_object_object_get(section, "cxlErrorLog");
282f8fc7052SJohn Chung 	decoded_len = 0;
283*a7d2cdddSEd Tanous 
284*a7d2cdddSEd Tanous 	decoded = base64_decode(json_object_get_string(encoded),
285*a7d2cdddSEd Tanous 				json_object_get_string_len(encoded),
286*a7d2cdddSEd Tanous 				&decoded_len);
287*a7d2cdddSEd Tanous 	if (decoded == NULL) {
288f8fc7052SJohn Chung 		printf("Failed to allocate decode output buffer. \n");
289f8fc7052SJohn Chung 	} else {
290f8fc7052SJohn Chung 		fwrite(decoded, decoded_len, 1, out);
291aec83900SLawrence Tang 		fflush(out);
292aec83900SLawrence Tang 		free(decoded);
293f8fc7052SJohn Chung 	}
294aec83900SLawrence Tang 
295aec83900SLawrence Tang 	free(section_cper);
296aec83900SLawrence Tang }
297