blob: 1a9b33bbba64e0c384a5cd62435c1c8ff5ca39eb [file] [log] [blame]
Lawrence Tangb98ec662022-07-06 16:50:21 +01001/**
2 * Describes functions for converting CXL protocol error CPER sections from binary and JSON format
3 * into an intermediate format.
Ed Tanousfedd4572024-07-12 13:56:00 -07004 *
Lawrence Tangb98ec662022-07-06 16:50:21 +01005 * Author: Lawrence.Tang@arm.com
6 **/
7#include <stdio.h>
Lawrence Tangaec83902022-07-18 09:41:08 +01008#include <string.h>
Thu Nguyene42fb482024-10-15 14:43:11 +00009#include <libcper/base64.h>
10#include <libcper/Cper.h>
11#include <libcper/cper-utils.h>
12#include <libcper/sections/cper-section-cxl-protocol.h>
Lawrence Tangb98ec662022-07-06 16:50:21 +010013
14//Converts a single CXL protocol error CPER section into JSON IR.
Ed Tanous12dbd4f2025-03-08 19:05:01 -080015json_object *cper_section_cxl_protocol_to_ir(const UINT8 *section, UINT32 size)
Lawrence Tangb98ec662022-07-06 16:50:21 +010016{
Ed Tanous12dbd4f2025-03-08 19:05:01 -080017 if (size < sizeof(EFI_CXL_PROTOCOL_ERROR_DATA)) {
18 return NULL;
19 }
20
Lawrence Tange407b4c2022-07-21 13:54:01 +010021 EFI_CXL_PROTOCOL_ERROR_DATA *cxl_protocol_error =
22 (EFI_CXL_PROTOCOL_ERROR_DATA *)section;
Ed Tanous12dbd4f2025-03-08 19:05:01 -080023
24 if (size < sizeof(EFI_CXL_PROTOCOL_ERROR_DATA) +
25 cxl_protocol_error->CxlDvsecLength +
26 cxl_protocol_error->CxlErrorLogLength) {
27 return NULL;
28 }
29
Lawrence Tange407b4c2022-07-21 13:54:01 +010030 json_object *section_ir = json_object_new_object();
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080031 ValidationTypes ui64Type = {
32 UINT_64T, .value.ui64 = cxl_protocol_error->ValidBits
33 };
Lawrence Tangb98ec662022-07-06 16:50:21 +010034
Lawrence Tange407b4c2022-07-21 13:54:01 +010035 //Type of detecting agent.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080036 if (isvalid_prop_to_ir(&ui64Type, 0)) {
37 json_object *agent_type = integer_to_readable_pair(
38 cxl_protocol_error->CxlAgentType, 2,
39 CXL_PROTOCOL_ERROR_AGENT_TYPES_KEYS,
40 CXL_PROTOCOL_ERROR_AGENT_TYPES_VALUES,
41 "Unknown (Reserved)");
42 json_object_object_add(section_ir, "agentType", agent_type);
43 }
Lawrence Tangb98ec662022-07-06 16:50:21 +010044
Lawrence Tange407b4c2022-07-21 13:54:01 +010045 //CXL agent address, depending on the agent type.
46 json_object *agent_address = json_object_new_object();
47 if (cxl_protocol_error->CxlAgentType ==
48 CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
49 //Address is a CXL1.1 device agent.
50 json_object_object_add(
51 agent_address, "functionNumber",
52 json_object_new_uint64(
53 cxl_protocol_error->CxlAgentAddress
54 .DeviceAddress.FunctionNumber));
55 json_object_object_add(
56 agent_address, "deviceNumber",
57 json_object_new_uint64(
58 cxl_protocol_error->CxlAgentAddress
59 .DeviceAddress.DeviceNumber));
60 json_object_object_add(
61 agent_address, "busNumber",
62 json_object_new_uint64(
63 cxl_protocol_error->CxlAgentAddress
64 .DeviceAddress.BusNumber));
65 json_object_object_add(
66 agent_address, "segmentNumber",
67 json_object_new_uint64(
68 cxl_protocol_error->CxlAgentAddress
69 .DeviceAddress.SegmentNumber));
70 } else if (cxl_protocol_error->CxlAgentType ==
71 CXL_PROTOCOL_ERROR_HOST_DOWNSTREAM_PORT_AGENT) {
72 //Address is a CXL port RCRB base address.
73 json_object_object_add(
74 agent_address, "value",
75 json_object_new_uint64(
76 cxl_protocol_error->CxlAgentAddress
77 .PortRcrbBaseAddress));
78 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080079 if (isvalid_prop_to_ir(&ui64Type, 1)) {
80 json_object_object_add(section_ir, "cxlAgentAddress",
81 agent_address);
82 } else {
83 json_object_put(agent_address);
84 }
Lawrence Tangb98ec662022-07-06 16:50:21 +010085
Lawrence Tange407b4c2022-07-21 13:54:01 +010086 json_object *device_id = json_object_new_object();
87 json_object_object_add(
88 device_id, "vendorID",
89 json_object_new_uint64(cxl_protocol_error->DeviceId.VendorId));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080090
91 //Device ID.
92 if (isvalid_prop_to_ir(&ui64Type, 2)) {
93 json_object_object_add(
94 device_id, "deviceID",
95 json_object_new_uint64(
96 cxl_protocol_error->DeviceId.DeviceId));
97 json_object_object_add(
98 device_id, "subsystemVendorID",
99 json_object_new_uint64(
100 cxl_protocol_error->DeviceId.SubsystemVendorId));
101 json_object_object_add(
102 device_id, "subsystemDeviceID",
103 json_object_new_uint64(
104 cxl_protocol_error->DeviceId.SubsystemDeviceId));
105 json_object_object_add(
106 device_id, "classCode",
107 json_object_new_uint64(
108 cxl_protocol_error->DeviceId.ClassCode));
109 json_object_object_add(
110 device_id, "slotNumber",
111 json_object_new_uint64(
112 cxl_protocol_error->DeviceId.SlotNumber));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800113 }
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800114 json_object_object_add(section_ir, "deviceID", device_id);
Lawrence Tang368e0b42022-07-07 14:31:06 +0100115
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800116 if (isvalid_prop_to_ir(&ui64Type, 3)) {
117 //Device serial & capability structure (if CXL 1.1 device).
118 if (cxl_protocol_error->CxlAgentType ==
119 CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
120 json_object_object_add(
121 section_ir, "deviceSerial",
122 json_object_new_uint64(
123 cxl_protocol_error->DeviceSerial));
124 }
125 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700126
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800127 char *encoded;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800128 int32_t encoded_len = 0;
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700129
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800130 //The PCIe capability structure provided here could either be PCIe 1.1 Capability Structure
131 //(36-byte, padded to 60 bytes) or PCIe 2.0 Capability Structure (60-byte). There does not seem
132 //to be a way to differentiate these, so this is left as a b64 dump.
133 if (isvalid_prop_to_ir(&ui64Type, 4)) {
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700134 encoded = base64_encode(
135 (UINT8 *)cxl_protocol_error->CapabilityStructure.PcieCap,
136 60, &encoded_len);
137 if (encoded == NULL) {
John Chungf8fc7052024-05-03 20:05:29 +0800138 printf("Failed to allocate encode output buffer. \n");
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800139 json_object_put(section_ir);
140
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700141 return NULL;
John Chungf8fc7052024-05-03 20:05:29 +0800142 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700143 json_object_object_add(section_ir, "capabilityStructure",
144 json_object_new_string_len(encoded,
145 encoded_len));
146 free(encoded);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100147 }
Lawrence Tangb98ec662022-07-06 16:50:21 +0100148
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800149 const UINT8 *cur_pos = (const UINT8 *)(cxl_protocol_error + 1);
John Chungf8fc7052024-05-03 20:05:29 +0800150
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800151 if (isvalid_prop_to_ir(&ui64Type, 5)) {
152 //CXL DVSEC & error log length.
153 json_object_object_add(
154 section_ir, "dvsecLength",
155 json_object_new_int(
156 cxl_protocol_error->CxlDvsecLength));
157 //CXL DVSEC
158 //For CXL 1.1 devices, this is the "CXL DVSEC For Flex Bus Device" structure as in CXL 1.1 spec.
159 //For CXL 1.1 host downstream ports, this is the "CXL DVSEC For Flex Bus Port" structure as in CXL 1.1 spec.
160 int32_t encoded_len = 0;
161
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800162 encoded = base64_encode(cur_pos,
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800163 cxl_protocol_error->CxlDvsecLength,
164 &encoded_len);
165 if (encoded == NULL) {
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800166 json_object_put(section_ir);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800167 return NULL;
168 }
169 json_object_object_add(section_ir, "cxlDVSEC",
170 json_object_new_string_len(encoded,
171 encoded_len));
172
173 free(encoded);
John Chungf8fc7052024-05-03 20:05:29 +0800174 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700175
Lawrence Tange407b4c2022-07-21 13:54:01 +0100176 cur_pos += cxl_protocol_error->CxlDvsecLength;
Lawrence Tang368e0b42022-07-07 14:31:06 +0100177
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800178 if (isvalid_prop_to_ir(&ui64Type, 6)) {
179 json_object_object_add(
180 section_ir, "errorLogLength",
181 json_object_new_int(
182 cxl_protocol_error->CxlErrorLogLength));
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700183
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800184 //CXL Error Log
185 //This is the "CXL RAS Capability Structure" as in CXL 1.1 spec.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700186
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800187 encoded_len = 0;
188 encoded = base64_encode((UINT8 *)cur_pos,
189 cxl_protocol_error->CxlErrorLogLength,
190 &encoded_len);
191
192 if (encoded == NULL) {
193 printf("Failed to allocate encode output buffer. \n");
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800194 json_object_put(section_ir);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800195 return NULL;
196 }
197 json_object_object_add(section_ir, "cxlErrorLog",
198 json_object_new_string_len(encoded,
199 encoded_len));
200 free(encoded);
John Chungf8fc7052024-05-03 20:05:29 +0800201 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700202
Lawrence Tange407b4c2022-07-21 13:54:01 +0100203 return section_ir;
Lawrence Tangaec83902022-07-18 09:41:08 +0100204}
205
206//Converts a single CXL protocol CPER-JSON section into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100207void ir_section_cxl_protocol_to_cper(json_object *section, FILE *out)
Lawrence Tangaec83902022-07-18 09:41:08 +0100208{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100209 EFI_CXL_PROTOCOL_ERROR_DATA *section_cper =
210 (EFI_CXL_PROTOCOL_ERROR_DATA *)calloc(
211 1, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800212 struct json_object *obj = NULL;
Lawrence Tangaec83902022-07-18 09:41:08 +0100213
Lawrence Tange407b4c2022-07-21 13:54:01 +0100214 //Validation bits.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800215 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
Lawrence Tangaec83902022-07-18 09:41:08 +0100216
Lawrence Tange407b4c2022-07-21 13:54:01 +0100217 //Detecting agent type.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800218 if (json_object_object_get_ex(section, "agentType", &obj)) {
219 section_cper->CxlAgentType = readable_pair_to_integer(obj);
220 add_to_valid_bitfield(&ui64Type, 0);
221 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100222
Lawrence Tange407b4c2022-07-21 13:54:01 +0100223 //Based on the agent type, set the address.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800224 if (json_object_object_get_ex(section, "cxlAgentAddress", &obj)) {
225 json_object *address = obj;
226 if (section_cper->CxlAgentType ==
227 CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
228 //Address is split by function, device, bus & segment.
229 UINT64 function = json_object_get_uint64(
230 json_object_object_get(address,
231 "functionNumber"));
232 UINT64 device = json_object_get_uint64(
233 json_object_object_get(address,
234 "deviceNumber"));
235 UINT64 bus = json_object_get_uint64(
236 json_object_object_get(address, "busNumber"));
237 UINT64 segment = json_object_get_uint64(
238 json_object_object_get(address,
239 "segmentNumber"));
240 section_cper->CxlAgentAddress.DeviceAddress
241 .FunctionNumber = function;
242 section_cper->CxlAgentAddress.DeviceAddress
243 .DeviceNumber = device;
244 section_cper->CxlAgentAddress.DeviceAddress.BusNumber =
245 bus;
246 section_cper->CxlAgentAddress.DeviceAddress
247 .SegmentNumber = segment;
248 } else if (section_cper->CxlAgentType ==
249 CXL_PROTOCOL_ERROR_HOST_DOWNSTREAM_PORT_AGENT) {
250 //Plain RCRB base address.
251 section_cper->CxlAgentAddress.PortRcrbBaseAddress =
252 json_object_get_uint64(json_object_object_get(
253 address, "value"));
254 }
255 add_to_valid_bitfield(&ui64Type, 1);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100256 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100257
Lawrence Tange407b4c2022-07-21 13:54:01 +0100258 //Device ID information.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800259 if (json_object_object_get_ex(section, "deviceID", &obj)) {
260 json_object *device_id = obj;
261 section_cper->DeviceId.VendorId = json_object_get_uint64(
262 json_object_object_get(device_id, "vendorID"));
263 section_cper->DeviceId.DeviceId = json_object_get_uint64(
264 json_object_object_get(device_id, "deviceID"));
265 section_cper->DeviceId.SubsystemVendorId =
266 json_object_get_uint64(json_object_object_get(
267 device_id, "subsystemVendorID"));
268 section_cper->DeviceId.SubsystemDeviceId =
269 json_object_get_uint64(json_object_object_get(
270 device_id, "subsystemDeviceID"));
271 section_cper->DeviceId.ClassCode = json_object_get_uint64(
272 json_object_object_get(device_id, "classCode"));
273 section_cper->DeviceId.SlotNumber = json_object_get_uint64(
274 json_object_object_get(device_id, "slotNumber"));
275 add_to_valid_bitfield(&ui64Type, 2);
276 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100277
Lawrence Tange407b4c2022-07-21 13:54:01 +0100278 //If CXL 1.1 device, the serial number & PCI capability structure.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700279 UINT8 *decoded;
Lawrence Tange407b4c2022-07-21 13:54:01 +0100280 if (section_cper->CxlAgentType == CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800281 if (json_object_object_get_ex(section, "deviceSerial", &obj)) {
282 section_cper->DeviceSerial =
283 json_object_get_uint64(obj);
284 add_to_valid_bitfield(&ui64Type, 3);
285 }
286 if (json_object_object_get_ex(section, "capabilityStructure",
287 &obj)) {
288 json_object *encoded = obj;
Lawrence Tangaec83902022-07-18 09:41:08 +0100289
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800290 int32_t decoded_len = 0;
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700291
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800292 decoded = base64_decode(
293 json_object_get_string(encoded),
294 json_object_get_string_len(encoded),
295 &decoded_len);
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700296
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800297 if (decoded == NULL) {
298 printf("Failed to allocate decode output buffer. \n");
299 } else {
300 memcpy(section_cper->CapabilityStructure.PcieCap,
301 decoded, decoded_len);
302 free(decoded);
303 add_to_valid_bitfield(&ui64Type, 4);
304 }
John Chungf8fc7052024-05-03 20:05:29 +0800305 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100306 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100307
Lawrence Tange407b4c2022-07-21 13:54:01 +0100308 //DVSEC length & error log length.
309 section_cper->CxlDvsecLength = (UINT16)json_object_get_int(
310 json_object_object_get(section, "dvsecLength"));
311 section_cper->CxlErrorLogLength = (UINT16)json_object_get_int(
312 json_object_object_get(section, "errorLogLength"));
Lawrence Tangaec83902022-07-18 09:41:08 +0100313
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800314 json_object *encodedsrc = NULL;
315 json_object *encodederr = NULL;
316
317 //DVSEC out: write valid bits
318 if (json_object_object_get_ex(section, "cxlDVSEC", &obj)) {
319 add_to_valid_bitfield(&ui64Type, 5);
320 encodedsrc = obj;
321 }
322
323 //Error log: write valid bits
324 if (json_object_object_get_ex(section, "cxlErrorLog", &obj)) {
325 add_to_valid_bitfield(&ui64Type, 6);
326 encodederr = obj;
327 }
328 section_cper->ValidBits = ui64Type.value.ui64;
329
Lawrence Tange407b4c2022-07-21 13:54:01 +0100330 //Write header to stream.
331 fwrite(section_cper, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA), 1, out);
332 fflush(out);
Lawrence Tangaec83902022-07-18 09:41:08 +0100333
Lawrence Tange407b4c2022-07-21 13:54:01 +0100334 //DVSEC out to stream.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700335 int32_t decoded_len = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800336 if (encodedsrc != NULL) {
337 decoded = base64_decode(json_object_get_string(encodedsrc),
338 json_object_get_string_len(encodedsrc),
339 &decoded_len);
340 if (decoded == NULL) {
341 printf("Failed to allocate decode output buffer. \n");
342 } else {
343 fwrite(decoded, decoded_len, 1, out);
344 fflush(out);
345 free(decoded);
346 }
John Chungf8fc7052024-05-03 20:05:29 +0800347 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100348
Lawrence Tange407b4c2022-07-21 13:54:01 +0100349 //Error log out to stream.
John Chungf8fc7052024-05-03 20:05:29 +0800350 decoded_len = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800351 if (encodederr != NULL) {
352 decoded = base64_decode(json_object_get_string(encodederr),
353 json_object_get_string_len(encodederr),
354 &decoded_len);
355 if (decoded == NULL) {
356 printf("Failed to allocate decode output buffer. \n");
357 } else {
358 fwrite(decoded, decoded_len, 1, out);
359 fflush(out);
360 free(decoded);
361 }
John Chungf8fc7052024-05-03 20:05:29 +0800362 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100363
364 free(section_cper);
John Chungf8fc7052024-05-03 20:05:29 +0800365}