blob: 6ae53254b89240c6f05a6640d39057bfdc899e7f [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>
Ed Tanous50b966f2025-03-11 09:06:19 -070013#include <libcper/log.h>
Lawrence Tangb98ec662022-07-06 16:50:21 +010014
15//Converts a single CXL protocol error CPER section into JSON IR.
Ed Tanous12dbd4f2025-03-08 19:05:01 -080016json_object *cper_section_cxl_protocol_to_ir(const UINT8 *section, UINT32 size)
Lawrence Tangb98ec662022-07-06 16:50:21 +010017{
Ed Tanous12dbd4f2025-03-08 19:05:01 -080018 if (size < sizeof(EFI_CXL_PROTOCOL_ERROR_DATA)) {
19 return NULL;
20 }
21
Lawrence Tange407b4c2022-07-21 13:54:01 +010022 EFI_CXL_PROTOCOL_ERROR_DATA *cxl_protocol_error =
23 (EFI_CXL_PROTOCOL_ERROR_DATA *)section;
Ed Tanous12dbd4f2025-03-08 19:05:01 -080024
25 if (size < sizeof(EFI_CXL_PROTOCOL_ERROR_DATA) +
26 cxl_protocol_error->CxlDvsecLength +
27 cxl_protocol_error->CxlErrorLogLength) {
28 return NULL;
29 }
30
Lawrence Tange407b4c2022-07-21 13:54:01 +010031 json_object *section_ir = json_object_new_object();
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080032 ValidationTypes ui64Type = {
33 UINT_64T, .value.ui64 = cxl_protocol_error->ValidBits
34 };
Lawrence Tangb98ec662022-07-06 16:50:21 +010035
Lawrence Tange407b4c2022-07-21 13:54:01 +010036 //Type of detecting agent.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080037 if (isvalid_prop_to_ir(&ui64Type, 0)) {
38 json_object *agent_type = integer_to_readable_pair(
39 cxl_protocol_error->CxlAgentType, 2,
40 CXL_PROTOCOL_ERROR_AGENT_TYPES_KEYS,
41 CXL_PROTOCOL_ERROR_AGENT_TYPES_VALUES,
42 "Unknown (Reserved)");
43 json_object_object_add(section_ir, "agentType", agent_type);
44 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080045 if (isvalid_prop_to_ir(&ui64Type, 1)) {
Ed Tanousd6b62632025-03-14 15:30:07 -070046 //CXL agent address, depending on the agent type.
47 json_object *agent_address = NULL;
48 if (cxl_protocol_error->CxlAgentType ==
49 CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
50 agent_address = json_object_new_object();
51 //Address is a CXL1.1 device agent.
52 json_object_object_add(
53 agent_address, "functionNumber",
54 json_object_new_uint64(
55 cxl_protocol_error->CxlAgentAddress
56 .DeviceAddress.FunctionNumber));
57 json_object_object_add(
58 agent_address, "deviceNumber",
59 json_object_new_uint64(
60 cxl_protocol_error->CxlAgentAddress
61 .DeviceAddress.DeviceNumber));
62 json_object_object_add(
63 agent_address, "busNumber",
64 json_object_new_uint64(
65 cxl_protocol_error->CxlAgentAddress
66 .DeviceAddress.BusNumber));
67 json_object_object_add(
68 agent_address, "segmentNumber",
69 json_object_new_uint64(
70 cxl_protocol_error->CxlAgentAddress
71 .DeviceAddress.SegmentNumber));
72 } else if (cxl_protocol_error->CxlAgentType ==
73 CXL_PROTOCOL_ERROR_HOST_DOWNSTREAM_PORT_AGENT) {
74 agent_address = json_object_new_object();
75 //Address is a CXL port RCRB base address.
76 json_object_object_add(
77 agent_address, "value",
78 json_object_new_uint64(
79 cxl_protocol_error->CxlAgentAddress
80 .PortRcrbBaseAddress));
81 }
82 if (agent_address != NULL) {
83 json_object_object_add(section_ir, "cxlAgentAddress",
84 agent_address);
85 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080086 }
Lawrence Tangb98ec662022-07-06 16:50:21 +010087
Lawrence Tange407b4c2022-07-21 13:54:01 +010088 json_object *device_id = json_object_new_object();
89 json_object_object_add(
90 device_id, "vendorID",
91 json_object_new_uint64(cxl_protocol_error->DeviceId.VendorId));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080092
93 //Device ID.
94 if (isvalid_prop_to_ir(&ui64Type, 2)) {
95 json_object_object_add(
96 device_id, "deviceID",
97 json_object_new_uint64(
98 cxl_protocol_error->DeviceId.DeviceId));
99 json_object_object_add(
100 device_id, "subsystemVendorID",
101 json_object_new_uint64(
102 cxl_protocol_error->DeviceId.SubsystemVendorId));
103 json_object_object_add(
104 device_id, "subsystemDeviceID",
105 json_object_new_uint64(
106 cxl_protocol_error->DeviceId.SubsystemDeviceId));
107 json_object_object_add(
108 device_id, "classCode",
109 json_object_new_uint64(
110 cxl_protocol_error->DeviceId.ClassCode));
111 json_object_object_add(
112 device_id, "slotNumber",
113 json_object_new_uint64(
114 cxl_protocol_error->DeviceId.SlotNumber));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800115 }
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800116 json_object_object_add(section_ir, "deviceID", device_id);
Lawrence Tang368e0b42022-07-07 14:31:06 +0100117
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800118 if (isvalid_prop_to_ir(&ui64Type, 3)) {
119 //Device serial & capability structure (if CXL 1.1 device).
120 if (cxl_protocol_error->CxlAgentType ==
121 CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
122 json_object_object_add(
123 section_ir, "deviceSerial",
124 json_object_new_uint64(
125 cxl_protocol_error->DeviceSerial));
126 }
127 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700128
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800129 char *encoded;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800130 int32_t encoded_len = 0;
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700131
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800132 //The PCIe capability structure provided here could either be PCIe 1.1 Capability Structure
133 //(36-byte, padded to 60 bytes) or PCIe 2.0 Capability Structure (60-byte). There does not seem
134 //to be a way to differentiate these, so this is left as a b64 dump.
135 if (isvalid_prop_to_ir(&ui64Type, 4)) {
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700136 encoded = base64_encode(
137 (UINT8 *)cxl_protocol_error->CapabilityStructure.PcieCap,
138 60, &encoded_len);
139 if (encoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700140 cper_print_log(
141 "Failed to allocate encode output buffer. \n");
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800142 json_object_put(section_ir);
143
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700144 return NULL;
John Chungf8fc7052024-05-03 20:05:29 +0800145 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700146 json_object_object_add(section_ir, "capabilityStructure",
147 json_object_new_string_len(encoded,
148 encoded_len));
149 free(encoded);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100150 }
Lawrence Tangb98ec662022-07-06 16:50:21 +0100151
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800152 const UINT8 *cur_pos = (const UINT8 *)(cxl_protocol_error + 1);
John Chungf8fc7052024-05-03 20:05:29 +0800153
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800154 if (isvalid_prop_to_ir(&ui64Type, 5)) {
155 //CXL DVSEC & error log length.
156 json_object_object_add(
157 section_ir, "dvsecLength",
158 json_object_new_int(
159 cxl_protocol_error->CxlDvsecLength));
160 //CXL DVSEC
161 //For CXL 1.1 devices, this is the "CXL DVSEC For Flex Bus Device" structure as in CXL 1.1 spec.
162 //For CXL 1.1 host downstream ports, this is the "CXL DVSEC For Flex Bus Port" structure as in CXL 1.1 spec.
163 int32_t encoded_len = 0;
164
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800165 encoded = base64_encode(cur_pos,
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800166 cxl_protocol_error->CxlDvsecLength,
167 &encoded_len);
168 if (encoded == NULL) {
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800169 json_object_put(section_ir);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800170 return NULL;
171 }
172 json_object_object_add(section_ir, "cxlDVSEC",
173 json_object_new_string_len(encoded,
174 encoded_len));
175
176 free(encoded);
John Chungf8fc7052024-05-03 20:05:29 +0800177 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700178
Lawrence Tange407b4c2022-07-21 13:54:01 +0100179 cur_pos += cxl_protocol_error->CxlDvsecLength;
Lawrence Tang368e0b42022-07-07 14:31:06 +0100180
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800181 if (isvalid_prop_to_ir(&ui64Type, 6)) {
182 json_object_object_add(
183 section_ir, "errorLogLength",
184 json_object_new_int(
185 cxl_protocol_error->CxlErrorLogLength));
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700186
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800187 //CXL Error Log
188 //This is the "CXL RAS Capability Structure" as in CXL 1.1 spec.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700189
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800190 encoded_len = 0;
191 encoded = base64_encode((UINT8 *)cur_pos,
192 cxl_protocol_error->CxlErrorLogLength,
193 &encoded_len);
194
195 if (encoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700196 cper_print_log(
197 "Failed to allocate encode output buffer. \n");
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800198 json_object_put(section_ir);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800199 return NULL;
200 }
201 json_object_object_add(section_ir, "cxlErrorLog",
202 json_object_new_string_len(encoded,
203 encoded_len));
204 free(encoded);
John Chungf8fc7052024-05-03 20:05:29 +0800205 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700206
Lawrence Tange407b4c2022-07-21 13:54:01 +0100207 return section_ir;
Lawrence Tangaec83902022-07-18 09:41:08 +0100208}
209
210//Converts a single CXL protocol CPER-JSON section into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100211void ir_section_cxl_protocol_to_cper(json_object *section, FILE *out)
Lawrence Tangaec83902022-07-18 09:41:08 +0100212{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100213 EFI_CXL_PROTOCOL_ERROR_DATA *section_cper =
214 (EFI_CXL_PROTOCOL_ERROR_DATA *)calloc(
215 1, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800216 struct json_object *obj = NULL;
Lawrence Tangaec83902022-07-18 09:41:08 +0100217
Lawrence Tange407b4c2022-07-21 13:54:01 +0100218 //Validation bits.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800219 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
Lawrence Tangaec83902022-07-18 09:41:08 +0100220
Lawrence Tange407b4c2022-07-21 13:54:01 +0100221 //Detecting agent type.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800222 if (json_object_object_get_ex(section, "agentType", &obj)) {
223 section_cper->CxlAgentType = readable_pair_to_integer(obj);
224 add_to_valid_bitfield(&ui64Type, 0);
225 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100226
Lawrence Tange407b4c2022-07-21 13:54:01 +0100227 //Based on the agent type, set the address.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800228 if (json_object_object_get_ex(section, "cxlAgentAddress", &obj)) {
229 json_object *address = obj;
230 if (section_cper->CxlAgentType ==
231 CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
232 //Address is split by function, device, bus & segment.
233 UINT64 function = json_object_get_uint64(
234 json_object_object_get(address,
235 "functionNumber"));
236 UINT64 device = json_object_get_uint64(
237 json_object_object_get(address,
238 "deviceNumber"));
239 UINT64 bus = json_object_get_uint64(
240 json_object_object_get(address, "busNumber"));
241 UINT64 segment = json_object_get_uint64(
242 json_object_object_get(address,
243 "segmentNumber"));
244 section_cper->CxlAgentAddress.DeviceAddress
245 .FunctionNumber = function;
246 section_cper->CxlAgentAddress.DeviceAddress
247 .DeviceNumber = device;
248 section_cper->CxlAgentAddress.DeviceAddress.BusNumber =
249 bus;
250 section_cper->CxlAgentAddress.DeviceAddress
251 .SegmentNumber = segment;
252 } else if (section_cper->CxlAgentType ==
253 CXL_PROTOCOL_ERROR_HOST_DOWNSTREAM_PORT_AGENT) {
254 //Plain RCRB base address.
255 section_cper->CxlAgentAddress.PortRcrbBaseAddress =
256 json_object_get_uint64(json_object_object_get(
257 address, "value"));
258 }
259 add_to_valid_bitfield(&ui64Type, 1);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100260 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100261
Lawrence Tange407b4c2022-07-21 13:54:01 +0100262 //Device ID information.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800263 if (json_object_object_get_ex(section, "deviceID", &obj)) {
264 json_object *device_id = obj;
265 section_cper->DeviceId.VendorId = json_object_get_uint64(
266 json_object_object_get(device_id, "vendorID"));
267 section_cper->DeviceId.DeviceId = json_object_get_uint64(
268 json_object_object_get(device_id, "deviceID"));
269 section_cper->DeviceId.SubsystemVendorId =
270 json_object_get_uint64(json_object_object_get(
271 device_id, "subsystemVendorID"));
272 section_cper->DeviceId.SubsystemDeviceId =
273 json_object_get_uint64(json_object_object_get(
274 device_id, "subsystemDeviceID"));
275 section_cper->DeviceId.ClassCode = json_object_get_uint64(
276 json_object_object_get(device_id, "classCode"));
277 section_cper->DeviceId.SlotNumber = json_object_get_uint64(
278 json_object_object_get(device_id, "slotNumber"));
279 add_to_valid_bitfield(&ui64Type, 2);
280 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100281
Lawrence Tange407b4c2022-07-21 13:54:01 +0100282 //If CXL 1.1 device, the serial number & PCI capability structure.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700283 UINT8 *decoded;
Lawrence Tange407b4c2022-07-21 13:54:01 +0100284 if (section_cper->CxlAgentType == CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800285 if (json_object_object_get_ex(section, "deviceSerial", &obj)) {
286 section_cper->DeviceSerial =
287 json_object_get_uint64(obj);
288 add_to_valid_bitfield(&ui64Type, 3);
289 }
290 if (json_object_object_get_ex(section, "capabilityStructure",
291 &obj)) {
292 json_object *encoded = obj;
Lawrence Tangaec83902022-07-18 09:41:08 +0100293
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800294 int32_t decoded_len = 0;
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700295
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800296 decoded = base64_decode(
297 json_object_get_string(encoded),
298 json_object_get_string_len(encoded),
299 &decoded_len);
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700300
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800301 if (decoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700302 cper_print_log(
303 "Failed to allocate decode output buffer. \n");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800304 } else {
305 memcpy(section_cper->CapabilityStructure.PcieCap,
306 decoded, decoded_len);
307 free(decoded);
308 add_to_valid_bitfield(&ui64Type, 4);
309 }
John Chungf8fc7052024-05-03 20:05:29 +0800310 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100311 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100312
Lawrence Tange407b4c2022-07-21 13:54:01 +0100313 //DVSEC length & error log length.
314 section_cper->CxlDvsecLength = (UINT16)json_object_get_int(
315 json_object_object_get(section, "dvsecLength"));
316 section_cper->CxlErrorLogLength = (UINT16)json_object_get_int(
317 json_object_object_get(section, "errorLogLength"));
Lawrence Tangaec83902022-07-18 09:41:08 +0100318
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800319 json_object *encodedsrc = NULL;
320 json_object *encodederr = NULL;
321
322 //DVSEC out: write valid bits
323 if (json_object_object_get_ex(section, "cxlDVSEC", &obj)) {
324 add_to_valid_bitfield(&ui64Type, 5);
325 encodedsrc = obj;
326 }
327
328 //Error log: write valid bits
329 if (json_object_object_get_ex(section, "cxlErrorLog", &obj)) {
330 add_to_valid_bitfield(&ui64Type, 6);
331 encodederr = obj;
332 }
333 section_cper->ValidBits = ui64Type.value.ui64;
334
Lawrence Tange407b4c2022-07-21 13:54:01 +0100335 //Write header to stream.
336 fwrite(section_cper, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA), 1, out);
337 fflush(out);
Lawrence Tangaec83902022-07-18 09:41:08 +0100338
Lawrence Tange407b4c2022-07-21 13:54:01 +0100339 //DVSEC out to stream.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700340 int32_t decoded_len = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800341 if (encodedsrc != NULL) {
342 decoded = base64_decode(json_object_get_string(encodedsrc),
343 json_object_get_string_len(encodedsrc),
344 &decoded_len);
345 if (decoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700346 cper_print_log(
347 "Failed to allocate decode output buffer. \n");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800348 } else {
349 fwrite(decoded, decoded_len, 1, out);
350 fflush(out);
351 free(decoded);
352 }
John Chungf8fc7052024-05-03 20:05:29 +0800353 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100354
Lawrence Tange407b4c2022-07-21 13:54:01 +0100355 //Error log out to stream.
John Chungf8fc7052024-05-03 20:05:29 +0800356 decoded_len = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800357 if (encodederr != NULL) {
358 decoded = base64_decode(json_object_get_string(encodederr),
359 json_object_get_string_len(encodederr),
360 &decoded_len);
361 if (decoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700362 cper_print_log(
363 "Failed to allocate decode output buffer. \n");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800364 } else {
365 fwrite(decoded, decoded_len, 1, out);
366 fflush(out);
367 free(decoded);
368 }
John Chungf8fc7052024-05-03 20:05:29 +0800369 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100370
371 free(section_cper);
John Chungf8fc7052024-05-03 20:05:29 +0800372}