blob: 6e6915330baf0e61943c9b631361ccc10200b7fc [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>
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070014#include <string.h>
Lawrence Tangb98ec662022-07-06 16:50:21 +010015
16//Converts a single CXL protocol error CPER section into JSON IR.
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070017json_object *cper_section_cxl_protocol_to_ir(const UINT8 *section, UINT32 size,
18 char **desc_string)
Lawrence Tangb98ec662022-07-06 16:50:21 +010019{
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070020 int outstr_len = 0;
21 *desc_string = malloc(SECTION_DESC_STRING_SIZE);
22 outstr_len = snprintf(*desc_string, SECTION_DESC_STRING_SIZE,
23 "A CXL Protocol Error occurred");
24 if (outstr_len < 0) {
25 cper_print_log(
26 "Error: Could not write to CXL protocol description string\n");
27 } else if (outstr_len > SECTION_DESC_STRING_SIZE) {
28 cper_print_log(
29 "Error: CXL protocol description string truncated\n");
30 }
31
Ed Tanous12dbd4f2025-03-08 19:05:01 -080032 if (size < sizeof(EFI_CXL_PROTOCOL_ERROR_DATA)) {
33 return NULL;
34 }
35
Lawrence Tange407b4c2022-07-21 13:54:01 +010036 EFI_CXL_PROTOCOL_ERROR_DATA *cxl_protocol_error =
37 (EFI_CXL_PROTOCOL_ERROR_DATA *)section;
Ed Tanous12dbd4f2025-03-08 19:05:01 -080038
39 if (size < sizeof(EFI_CXL_PROTOCOL_ERROR_DATA) +
40 cxl_protocol_error->CxlDvsecLength +
41 cxl_protocol_error->CxlErrorLogLength) {
42 return NULL;
43 }
44
Lawrence Tange407b4c2022-07-21 13:54:01 +010045 json_object *section_ir = json_object_new_object();
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080046 ValidationTypes ui64Type = {
47 UINT_64T, .value.ui64 = cxl_protocol_error->ValidBits
48 };
Lawrence Tangb98ec662022-07-06 16:50:21 +010049
Lawrence Tange407b4c2022-07-21 13:54:01 +010050 //Type of detecting agent.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080051 if (isvalid_prop_to_ir(&ui64Type, 0)) {
52 json_object *agent_type = integer_to_readable_pair(
53 cxl_protocol_error->CxlAgentType, 2,
54 CXL_PROTOCOL_ERROR_AGENT_TYPES_KEYS,
55 CXL_PROTOCOL_ERROR_AGENT_TYPES_VALUES,
56 "Unknown (Reserved)");
57 json_object_object_add(section_ir, "agentType", agent_type);
58 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080059 if (isvalid_prop_to_ir(&ui64Type, 1)) {
Ed Tanousd6b62632025-03-14 15:30:07 -070060 //CXL agent address, depending on the agent type.
61 json_object *agent_address = NULL;
62 if (cxl_protocol_error->CxlAgentType ==
63 CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
64 agent_address = json_object_new_object();
65 //Address is a CXL1.1 device agent.
66 json_object_object_add(
67 agent_address, "functionNumber",
68 json_object_new_uint64(
69 cxl_protocol_error->CxlAgentAddress
70 .DeviceAddress.FunctionNumber));
71 json_object_object_add(
72 agent_address, "deviceNumber",
73 json_object_new_uint64(
74 cxl_protocol_error->CxlAgentAddress
75 .DeviceAddress.DeviceNumber));
76 json_object_object_add(
77 agent_address, "busNumber",
78 json_object_new_uint64(
79 cxl_protocol_error->CxlAgentAddress
80 .DeviceAddress.BusNumber));
81 json_object_object_add(
82 agent_address, "segmentNumber",
83 json_object_new_uint64(
84 cxl_protocol_error->CxlAgentAddress
85 .DeviceAddress.SegmentNumber));
86 } else if (cxl_protocol_error->CxlAgentType ==
87 CXL_PROTOCOL_ERROR_HOST_DOWNSTREAM_PORT_AGENT) {
88 agent_address = json_object_new_object();
89 //Address is a CXL port RCRB base address.
90 json_object_object_add(
91 agent_address, "value",
92 json_object_new_uint64(
93 cxl_protocol_error->CxlAgentAddress
94 .PortRcrbBaseAddress));
95 }
96 if (agent_address != NULL) {
97 json_object_object_add(section_ir, "cxlAgentAddress",
98 agent_address);
99 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800100 }
Lawrence Tangb98ec662022-07-06 16:50:21 +0100101
Lawrence Tange407b4c2022-07-21 13:54:01 +0100102 json_object *device_id = json_object_new_object();
103 json_object_object_add(
104 device_id, "vendorID",
105 json_object_new_uint64(cxl_protocol_error->DeviceId.VendorId));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800106
107 //Device ID.
108 if (isvalid_prop_to_ir(&ui64Type, 2)) {
109 json_object_object_add(
110 device_id, "deviceID",
111 json_object_new_uint64(
112 cxl_protocol_error->DeviceId.DeviceId));
113 json_object_object_add(
114 device_id, "subsystemVendorID",
115 json_object_new_uint64(
116 cxl_protocol_error->DeviceId.SubsystemVendorId));
117 json_object_object_add(
118 device_id, "subsystemDeviceID",
119 json_object_new_uint64(
120 cxl_protocol_error->DeviceId.SubsystemDeviceId));
121 json_object_object_add(
122 device_id, "classCode",
123 json_object_new_uint64(
124 cxl_protocol_error->DeviceId.ClassCode));
125 json_object_object_add(
126 device_id, "slotNumber",
127 json_object_new_uint64(
128 cxl_protocol_error->DeviceId.SlotNumber));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800129 }
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800130 json_object_object_add(section_ir, "deviceID", device_id);
Lawrence Tang368e0b42022-07-07 14:31:06 +0100131
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800132 if (isvalid_prop_to_ir(&ui64Type, 3)) {
133 //Device serial & capability structure (if CXL 1.1 device).
134 if (cxl_protocol_error->CxlAgentType ==
135 CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
136 json_object_object_add(
137 section_ir, "deviceSerial",
138 json_object_new_uint64(
139 cxl_protocol_error->DeviceSerial));
140 }
141 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700142
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800143 char *encoded;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800144 int32_t encoded_len = 0;
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700145
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800146 //The PCIe capability structure provided here could either be PCIe 1.1 Capability Structure
147 //(36-byte, padded to 60 bytes) or PCIe 2.0 Capability Structure (60-byte). There does not seem
148 //to be a way to differentiate these, so this is left as a b64 dump.
149 if (isvalid_prop_to_ir(&ui64Type, 4)) {
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700150 encoded = base64_encode(
151 (UINT8 *)cxl_protocol_error->CapabilityStructure.PcieCap,
152 60, &encoded_len);
153 if (encoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700154 cper_print_log(
155 "Failed to allocate encode output buffer. \n");
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800156 json_object_put(section_ir);
157
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700158 return NULL;
John Chungf8fc7052024-05-03 20:05:29 +0800159 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700160 json_object_object_add(section_ir, "capabilityStructure",
161 json_object_new_string_len(encoded,
162 encoded_len));
163 free(encoded);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100164 }
Lawrence Tangb98ec662022-07-06 16:50:21 +0100165
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800166 const UINT8 *cur_pos = (const UINT8 *)(cxl_protocol_error + 1);
John Chungf8fc7052024-05-03 20:05:29 +0800167
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800168 if (isvalid_prop_to_ir(&ui64Type, 5)) {
169 //CXL DVSEC & error log length.
170 json_object_object_add(
171 section_ir, "dvsecLength",
172 json_object_new_int(
173 cxl_protocol_error->CxlDvsecLength));
174 //CXL DVSEC
175 //For CXL 1.1 devices, this is the "CXL DVSEC For Flex Bus Device" structure as in CXL 1.1 spec.
176 //For CXL 1.1 host downstream ports, this is the "CXL DVSEC For Flex Bus Port" structure as in CXL 1.1 spec.
177 int32_t encoded_len = 0;
178
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800179 encoded = base64_encode(cur_pos,
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800180 cxl_protocol_error->CxlDvsecLength,
181 &encoded_len);
182 if (encoded == NULL) {
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800183 json_object_put(section_ir);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800184 return NULL;
185 }
186 json_object_object_add(section_ir, "cxlDVSEC",
187 json_object_new_string_len(encoded,
188 encoded_len));
189
190 free(encoded);
John Chungf8fc7052024-05-03 20:05:29 +0800191 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700192
Lawrence Tange407b4c2022-07-21 13:54:01 +0100193 cur_pos += cxl_protocol_error->CxlDvsecLength;
Lawrence Tang368e0b42022-07-07 14:31:06 +0100194
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800195 if (isvalid_prop_to_ir(&ui64Type, 6)) {
196 json_object_object_add(
197 section_ir, "errorLogLength",
198 json_object_new_int(
199 cxl_protocol_error->CxlErrorLogLength));
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700200
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800201 //CXL Error Log
202 //This is the "CXL RAS Capability Structure" as in CXL 1.1 spec.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700203
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800204 encoded_len = 0;
205 encoded = base64_encode((UINT8 *)cur_pos,
206 cxl_protocol_error->CxlErrorLogLength,
207 &encoded_len);
208
209 if (encoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700210 cper_print_log(
211 "Failed to allocate encode output buffer. \n");
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800212 json_object_put(section_ir);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800213 return NULL;
214 }
215 json_object_object_add(section_ir, "cxlErrorLog",
216 json_object_new_string_len(encoded,
217 encoded_len));
218 free(encoded);
John Chungf8fc7052024-05-03 20:05:29 +0800219 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700220
Lawrence Tange407b4c2022-07-21 13:54:01 +0100221 return section_ir;
Lawrence Tangaec83902022-07-18 09:41:08 +0100222}
223
224//Converts a single CXL protocol CPER-JSON section into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100225void ir_section_cxl_protocol_to_cper(json_object *section, FILE *out)
Lawrence Tangaec83902022-07-18 09:41:08 +0100226{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100227 EFI_CXL_PROTOCOL_ERROR_DATA *section_cper =
228 (EFI_CXL_PROTOCOL_ERROR_DATA *)calloc(
229 1, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800230 struct json_object *obj = NULL;
Lawrence Tangaec83902022-07-18 09:41:08 +0100231
Lawrence Tange407b4c2022-07-21 13:54:01 +0100232 //Validation bits.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800233 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
Lawrence Tangaec83902022-07-18 09:41:08 +0100234
Lawrence Tange407b4c2022-07-21 13:54:01 +0100235 //Detecting agent type.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800236 if (json_object_object_get_ex(section, "agentType", &obj)) {
237 section_cper->CxlAgentType = readable_pair_to_integer(obj);
238 add_to_valid_bitfield(&ui64Type, 0);
239 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100240
Lawrence Tange407b4c2022-07-21 13:54:01 +0100241 //Based on the agent type, set the address.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800242 if (json_object_object_get_ex(section, "cxlAgentAddress", &obj)) {
243 json_object *address = obj;
244 if (section_cper->CxlAgentType ==
245 CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
246 //Address is split by function, device, bus & segment.
247 UINT64 function = json_object_get_uint64(
248 json_object_object_get(address,
249 "functionNumber"));
250 UINT64 device = json_object_get_uint64(
251 json_object_object_get(address,
252 "deviceNumber"));
253 UINT64 bus = json_object_get_uint64(
254 json_object_object_get(address, "busNumber"));
255 UINT64 segment = json_object_get_uint64(
256 json_object_object_get(address,
257 "segmentNumber"));
258 section_cper->CxlAgentAddress.DeviceAddress
259 .FunctionNumber = function;
260 section_cper->CxlAgentAddress.DeviceAddress
261 .DeviceNumber = device;
262 section_cper->CxlAgentAddress.DeviceAddress.BusNumber =
263 bus;
264 section_cper->CxlAgentAddress.DeviceAddress
265 .SegmentNumber = segment;
266 } else if (section_cper->CxlAgentType ==
267 CXL_PROTOCOL_ERROR_HOST_DOWNSTREAM_PORT_AGENT) {
268 //Plain RCRB base address.
269 section_cper->CxlAgentAddress.PortRcrbBaseAddress =
270 json_object_get_uint64(json_object_object_get(
271 address, "value"));
272 }
273 add_to_valid_bitfield(&ui64Type, 1);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100274 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100275
Lawrence Tange407b4c2022-07-21 13:54:01 +0100276 //Device ID information.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800277 if (json_object_object_get_ex(section, "deviceID", &obj)) {
278 json_object *device_id = obj;
279 section_cper->DeviceId.VendorId = json_object_get_uint64(
280 json_object_object_get(device_id, "vendorID"));
281 section_cper->DeviceId.DeviceId = json_object_get_uint64(
282 json_object_object_get(device_id, "deviceID"));
283 section_cper->DeviceId.SubsystemVendorId =
284 json_object_get_uint64(json_object_object_get(
285 device_id, "subsystemVendorID"));
286 section_cper->DeviceId.SubsystemDeviceId =
287 json_object_get_uint64(json_object_object_get(
288 device_id, "subsystemDeviceID"));
289 section_cper->DeviceId.ClassCode = json_object_get_uint64(
290 json_object_object_get(device_id, "classCode"));
291 section_cper->DeviceId.SlotNumber = json_object_get_uint64(
292 json_object_object_get(device_id, "slotNumber"));
293 add_to_valid_bitfield(&ui64Type, 2);
294 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100295
Lawrence Tange407b4c2022-07-21 13:54:01 +0100296 //If CXL 1.1 device, the serial number & PCI capability structure.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700297 UINT8 *decoded;
Lawrence Tange407b4c2022-07-21 13:54:01 +0100298 if (section_cper->CxlAgentType == CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800299 if (json_object_object_get_ex(section, "deviceSerial", &obj)) {
300 section_cper->DeviceSerial =
301 json_object_get_uint64(obj);
302 add_to_valid_bitfield(&ui64Type, 3);
303 }
304 if (json_object_object_get_ex(section, "capabilityStructure",
305 &obj)) {
306 json_object *encoded = obj;
Lawrence Tangaec83902022-07-18 09:41:08 +0100307
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800308 int32_t decoded_len = 0;
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700309
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800310 decoded = base64_decode(
311 json_object_get_string(encoded),
312 json_object_get_string_len(encoded),
313 &decoded_len);
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700314
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800315 if (decoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700316 cper_print_log(
317 "Failed to allocate decode output buffer. \n");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800318 } else {
319 memcpy(section_cper->CapabilityStructure.PcieCap,
320 decoded, decoded_len);
321 free(decoded);
322 add_to_valid_bitfield(&ui64Type, 4);
323 }
John Chungf8fc7052024-05-03 20:05:29 +0800324 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100325 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100326
Lawrence Tange407b4c2022-07-21 13:54:01 +0100327 //DVSEC length & error log length.
328 section_cper->CxlDvsecLength = (UINT16)json_object_get_int(
329 json_object_object_get(section, "dvsecLength"));
330 section_cper->CxlErrorLogLength = (UINT16)json_object_get_int(
331 json_object_object_get(section, "errorLogLength"));
Lawrence Tangaec83902022-07-18 09:41:08 +0100332
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800333 json_object *encodedsrc = NULL;
334 json_object *encodederr = NULL;
335
336 //DVSEC out: write valid bits
337 if (json_object_object_get_ex(section, "cxlDVSEC", &obj)) {
338 add_to_valid_bitfield(&ui64Type, 5);
339 encodedsrc = obj;
340 }
341
342 //Error log: write valid bits
343 if (json_object_object_get_ex(section, "cxlErrorLog", &obj)) {
344 add_to_valid_bitfield(&ui64Type, 6);
345 encodederr = obj;
346 }
347 section_cper->ValidBits = ui64Type.value.ui64;
348
Lawrence Tange407b4c2022-07-21 13:54:01 +0100349 //Write header to stream.
350 fwrite(section_cper, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA), 1, out);
351 fflush(out);
Lawrence Tangaec83902022-07-18 09:41:08 +0100352
Lawrence Tange407b4c2022-07-21 13:54:01 +0100353 //DVSEC out to stream.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700354 int32_t decoded_len = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800355 if (encodedsrc != NULL) {
356 decoded = base64_decode(json_object_get_string(encodedsrc),
357 json_object_get_string_len(encodedsrc),
358 &decoded_len);
359 if (decoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700360 cper_print_log(
361 "Failed to allocate decode output buffer. \n");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800362 } else {
363 fwrite(decoded, decoded_len, 1, out);
364 fflush(out);
365 free(decoded);
366 }
John Chungf8fc7052024-05-03 20:05:29 +0800367 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100368
Lawrence Tange407b4c2022-07-21 13:54:01 +0100369 //Error log out to stream.
John Chungf8fc7052024-05-03 20:05:29 +0800370 decoded_len = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800371 if (encodederr != NULL) {
372 decoded = base64_decode(json_object_get_string(encodederr),
373 json_object_get_string_len(encodederr),
374 &decoded_len);
375 if (decoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700376 cper_print_log(
377 "Failed to allocate decode output buffer. \n");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800378 } else {
379 fwrite(decoded, decoded_len, 1, out);
380 fflush(out);
381 free(decoded);
382 }
John Chungf8fc7052024-05-03 20:05:29 +0800383 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100384
385 free(section_cper);
John Chungf8fc7052024-05-03 20:05:29 +0800386}