blob: 151943fc95757c482fb42a5cf327997996ab56b0 [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.
John Chungf8fc7052024-05-03 20:05:29 +080015json_object *cper_section_cxl_protocol_to_ir(void *section)
Lawrence Tangb98ec662022-07-06 16:50:21 +010016{
Lawrence Tange407b4c2022-07-21 13:54:01 +010017 EFI_CXL_PROTOCOL_ERROR_DATA *cxl_protocol_error =
18 (EFI_CXL_PROTOCOL_ERROR_DATA *)section;
19 json_object *section_ir = json_object_new_object();
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080020 ValidationTypes ui64Type = {
21 UINT_64T, .value.ui64 = cxl_protocol_error->ValidBits
22 };
Lawrence Tangb98ec662022-07-06 16:50:21 +010023
Lawrence Tange407b4c2022-07-21 13:54:01 +010024 //Type of detecting agent.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080025 if (isvalid_prop_to_ir(&ui64Type, 0)) {
26 json_object *agent_type = integer_to_readable_pair(
27 cxl_protocol_error->CxlAgentType, 2,
28 CXL_PROTOCOL_ERROR_AGENT_TYPES_KEYS,
29 CXL_PROTOCOL_ERROR_AGENT_TYPES_VALUES,
30 "Unknown (Reserved)");
31 json_object_object_add(section_ir, "agentType", agent_type);
32 }
Lawrence Tangb98ec662022-07-06 16:50:21 +010033
Lawrence Tange407b4c2022-07-21 13:54:01 +010034 //CXL agent address, depending on the agent type.
35 json_object *agent_address = json_object_new_object();
36 if (cxl_protocol_error->CxlAgentType ==
37 CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
38 //Address is a CXL1.1 device agent.
39 json_object_object_add(
40 agent_address, "functionNumber",
41 json_object_new_uint64(
42 cxl_protocol_error->CxlAgentAddress
43 .DeviceAddress.FunctionNumber));
44 json_object_object_add(
45 agent_address, "deviceNumber",
46 json_object_new_uint64(
47 cxl_protocol_error->CxlAgentAddress
48 .DeviceAddress.DeviceNumber));
49 json_object_object_add(
50 agent_address, "busNumber",
51 json_object_new_uint64(
52 cxl_protocol_error->CxlAgentAddress
53 .DeviceAddress.BusNumber));
54 json_object_object_add(
55 agent_address, "segmentNumber",
56 json_object_new_uint64(
57 cxl_protocol_error->CxlAgentAddress
58 .DeviceAddress.SegmentNumber));
59 } else if (cxl_protocol_error->CxlAgentType ==
60 CXL_PROTOCOL_ERROR_HOST_DOWNSTREAM_PORT_AGENT) {
61 //Address is a CXL port RCRB base address.
62 json_object_object_add(
63 agent_address, "value",
64 json_object_new_uint64(
65 cxl_protocol_error->CxlAgentAddress
66 .PortRcrbBaseAddress));
67 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080068 if (isvalid_prop_to_ir(&ui64Type, 1)) {
69 json_object_object_add(section_ir, "cxlAgentAddress",
70 agent_address);
71 } else {
72 json_object_put(agent_address);
73 }
Lawrence Tangb98ec662022-07-06 16:50:21 +010074
Lawrence Tange407b4c2022-07-21 13:54:01 +010075 json_object *device_id = json_object_new_object();
76 json_object_object_add(
77 device_id, "vendorID",
78 json_object_new_uint64(cxl_protocol_error->DeviceId.VendorId));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080079
80 //Device ID.
81 if (isvalid_prop_to_ir(&ui64Type, 2)) {
82 json_object_object_add(
83 device_id, "deviceID",
84 json_object_new_uint64(
85 cxl_protocol_error->DeviceId.DeviceId));
86 json_object_object_add(
87 device_id, "subsystemVendorID",
88 json_object_new_uint64(
89 cxl_protocol_error->DeviceId.SubsystemVendorId));
90 json_object_object_add(
91 device_id, "subsystemDeviceID",
92 json_object_new_uint64(
93 cxl_protocol_error->DeviceId.SubsystemDeviceId));
94 json_object_object_add(
95 device_id, "classCode",
96 json_object_new_uint64(
97 cxl_protocol_error->DeviceId.ClassCode));
98 json_object_object_add(
99 device_id, "slotNumber",
100 json_object_new_uint64(
101 cxl_protocol_error->DeviceId.SlotNumber));
102 json_object_object_add(section_ir, "deviceID", device_id);
103 }
Lawrence Tangb98ec662022-07-06 16:50:21 +0100104
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700105 char *encoded;
Lawrence Tang368e0b42022-07-07 14:31:06 +0100106
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800107 if (isvalid_prop_to_ir(&ui64Type, 3)) {
108 //Device serial & capability structure (if CXL 1.1 device).
109 if (cxl_protocol_error->CxlAgentType ==
110 CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
111 json_object_object_add(
112 section_ir, "deviceSerial",
113 json_object_new_uint64(
114 cxl_protocol_error->DeviceSerial));
115 }
116 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700117
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800118 int32_t encoded_len = 0;
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700119
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800120 //The PCIe capability structure provided here could either be PCIe 1.1 Capability Structure
121 //(36-byte, padded to 60 bytes) or PCIe 2.0 Capability Structure (60-byte). There does not seem
122 //to be a way to differentiate these, so this is left as a b64 dump.
123 if (isvalid_prop_to_ir(&ui64Type, 4)) {
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700124 encoded = base64_encode(
125 (UINT8 *)cxl_protocol_error->CapabilityStructure.PcieCap,
126 60, &encoded_len);
127 if (encoded == NULL) {
John Chungf8fc7052024-05-03 20:05:29 +0800128 printf("Failed to allocate encode output buffer. \n");
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700129 return NULL;
John Chungf8fc7052024-05-03 20:05:29 +0800130 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700131 json_object_object_add(section_ir, "capabilityStructure",
132 json_object_new_string_len(encoded,
133 encoded_len));
134 free(encoded);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100135 }
Lawrence Tangb98ec662022-07-06 16:50:21 +0100136
John Chungf8fc7052024-05-03 20:05:29 +0800137 const char *cur_pos = (const char *)(cxl_protocol_error + 1);
John Chungf8fc7052024-05-03 20:05:29 +0800138
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800139 if (isvalid_prop_to_ir(&ui64Type, 5)) {
140 //CXL DVSEC & error log length.
141 json_object_object_add(
142 section_ir, "dvsecLength",
143 json_object_new_int(
144 cxl_protocol_error->CxlDvsecLength));
145 //CXL DVSEC
146 //For CXL 1.1 devices, this is the "CXL DVSEC For Flex Bus Device" structure as in CXL 1.1 spec.
147 //For CXL 1.1 host downstream ports, this is the "CXL DVSEC For Flex Bus Port" structure as in CXL 1.1 spec.
148 int32_t encoded_len = 0;
149
150 encoded = base64_encode((UINT8 *)cur_pos,
151 cxl_protocol_error->CxlDvsecLength,
152 &encoded_len);
153 if (encoded == NULL) {
154 return NULL;
155 }
156 json_object_object_add(section_ir, "cxlDVSEC",
157 json_object_new_string_len(encoded,
158 encoded_len));
159
160 free(encoded);
John Chungf8fc7052024-05-03 20:05:29 +0800161 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700162
Lawrence Tange407b4c2022-07-21 13:54:01 +0100163 cur_pos += cxl_protocol_error->CxlDvsecLength;
Lawrence Tang368e0b42022-07-07 14:31:06 +0100164
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800165 if (isvalid_prop_to_ir(&ui64Type, 6)) {
166 json_object_object_add(
167 section_ir, "errorLogLength",
168 json_object_new_int(
169 cxl_protocol_error->CxlErrorLogLength));
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700170
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800171 //CXL Error Log
172 //This is the "CXL RAS Capability Structure" as in CXL 1.1 spec.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700173
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800174 encoded_len = 0;
175 encoded = base64_encode((UINT8 *)cur_pos,
176 cxl_protocol_error->CxlErrorLogLength,
177 &encoded_len);
178
179 if (encoded == NULL) {
180 printf("Failed to allocate encode output buffer. \n");
181 return NULL;
182 }
183 json_object_object_add(section_ir, "cxlErrorLog",
184 json_object_new_string_len(encoded,
185 encoded_len));
186 free(encoded);
John Chungf8fc7052024-05-03 20:05:29 +0800187 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700188
Lawrence Tange407b4c2022-07-21 13:54:01 +0100189 return section_ir;
Lawrence Tangaec83902022-07-18 09:41:08 +0100190}
191
192//Converts a single CXL protocol CPER-JSON section into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100193void ir_section_cxl_protocol_to_cper(json_object *section, FILE *out)
Lawrence Tangaec83902022-07-18 09:41:08 +0100194{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100195 EFI_CXL_PROTOCOL_ERROR_DATA *section_cper =
196 (EFI_CXL_PROTOCOL_ERROR_DATA *)calloc(
197 1, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800198 struct json_object *obj = NULL;
Lawrence Tangaec83902022-07-18 09:41:08 +0100199
Lawrence Tange407b4c2022-07-21 13:54:01 +0100200 //Validation bits.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800201 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
Lawrence Tangaec83902022-07-18 09:41:08 +0100202
Lawrence Tange407b4c2022-07-21 13:54:01 +0100203 //Detecting agent type.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800204 if (json_object_object_get_ex(section, "agentType", &obj)) {
205 section_cper->CxlAgentType = readable_pair_to_integer(obj);
206 add_to_valid_bitfield(&ui64Type, 0);
207 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100208
Lawrence Tange407b4c2022-07-21 13:54:01 +0100209 //Based on the agent type, set the address.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800210 if (json_object_object_get_ex(section, "cxlAgentAddress", &obj)) {
211 json_object *address = obj;
212 if (section_cper->CxlAgentType ==
213 CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
214 //Address is split by function, device, bus & segment.
215 UINT64 function = json_object_get_uint64(
216 json_object_object_get(address,
217 "functionNumber"));
218 UINT64 device = json_object_get_uint64(
219 json_object_object_get(address,
220 "deviceNumber"));
221 UINT64 bus = json_object_get_uint64(
222 json_object_object_get(address, "busNumber"));
223 UINT64 segment = json_object_get_uint64(
224 json_object_object_get(address,
225 "segmentNumber"));
226 section_cper->CxlAgentAddress.DeviceAddress
227 .FunctionNumber = function;
228 section_cper->CxlAgentAddress.DeviceAddress
229 .DeviceNumber = device;
230 section_cper->CxlAgentAddress.DeviceAddress.BusNumber =
231 bus;
232 section_cper->CxlAgentAddress.DeviceAddress
233 .SegmentNumber = segment;
234 } else if (section_cper->CxlAgentType ==
235 CXL_PROTOCOL_ERROR_HOST_DOWNSTREAM_PORT_AGENT) {
236 //Plain RCRB base address.
237 section_cper->CxlAgentAddress.PortRcrbBaseAddress =
238 json_object_get_uint64(json_object_object_get(
239 address, "value"));
240 }
241 add_to_valid_bitfield(&ui64Type, 1);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100242 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100243
Lawrence Tange407b4c2022-07-21 13:54:01 +0100244 //Device ID information.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800245 if (json_object_object_get_ex(section, "deviceID", &obj)) {
246 json_object *device_id = obj;
247 section_cper->DeviceId.VendorId = json_object_get_uint64(
248 json_object_object_get(device_id, "vendorID"));
249 section_cper->DeviceId.DeviceId = json_object_get_uint64(
250 json_object_object_get(device_id, "deviceID"));
251 section_cper->DeviceId.SubsystemVendorId =
252 json_object_get_uint64(json_object_object_get(
253 device_id, "subsystemVendorID"));
254 section_cper->DeviceId.SubsystemDeviceId =
255 json_object_get_uint64(json_object_object_get(
256 device_id, "subsystemDeviceID"));
257 section_cper->DeviceId.ClassCode = json_object_get_uint64(
258 json_object_object_get(device_id, "classCode"));
259 section_cper->DeviceId.SlotNumber = json_object_get_uint64(
260 json_object_object_get(device_id, "slotNumber"));
261 add_to_valid_bitfield(&ui64Type, 2);
262 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100263
Lawrence Tange407b4c2022-07-21 13:54:01 +0100264 //If CXL 1.1 device, the serial number & PCI capability structure.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700265 UINT8 *decoded;
Lawrence Tange407b4c2022-07-21 13:54:01 +0100266 if (section_cper->CxlAgentType == CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800267 if (json_object_object_get_ex(section, "deviceSerial", &obj)) {
268 section_cper->DeviceSerial =
269 json_object_get_uint64(obj);
270 add_to_valid_bitfield(&ui64Type, 3);
271 }
272 if (json_object_object_get_ex(section, "capabilityStructure",
273 &obj)) {
274 json_object *encoded = obj;
Lawrence Tangaec83902022-07-18 09:41:08 +0100275
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800276 int32_t decoded_len = 0;
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700277
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800278 decoded = base64_decode(
279 json_object_get_string(encoded),
280 json_object_get_string_len(encoded),
281 &decoded_len);
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700282
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800283 if (decoded == NULL) {
284 printf("Failed to allocate decode output buffer. \n");
285 } else {
286 memcpy(section_cper->CapabilityStructure.PcieCap,
287 decoded, decoded_len);
288 free(decoded);
289 add_to_valid_bitfield(&ui64Type, 4);
290 }
John Chungf8fc7052024-05-03 20:05:29 +0800291 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100292 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100293
Lawrence Tange407b4c2022-07-21 13:54:01 +0100294 //DVSEC length & error log length.
295 section_cper->CxlDvsecLength = (UINT16)json_object_get_int(
296 json_object_object_get(section, "dvsecLength"));
297 section_cper->CxlErrorLogLength = (UINT16)json_object_get_int(
298 json_object_object_get(section, "errorLogLength"));
Lawrence Tangaec83902022-07-18 09:41:08 +0100299
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800300 json_object *encodedsrc = NULL;
301 json_object *encodederr = NULL;
302
303 //DVSEC out: write valid bits
304 if (json_object_object_get_ex(section, "cxlDVSEC", &obj)) {
305 add_to_valid_bitfield(&ui64Type, 5);
306 encodedsrc = obj;
307 }
308
309 //Error log: write valid bits
310 if (json_object_object_get_ex(section, "cxlErrorLog", &obj)) {
311 add_to_valid_bitfield(&ui64Type, 6);
312 encodederr = obj;
313 }
314 section_cper->ValidBits = ui64Type.value.ui64;
315
Lawrence Tange407b4c2022-07-21 13:54:01 +0100316 //Write header to stream.
317 fwrite(section_cper, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA), 1, out);
318 fflush(out);
Lawrence Tangaec83902022-07-18 09:41:08 +0100319
Lawrence Tange407b4c2022-07-21 13:54:01 +0100320 //DVSEC out to stream.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700321 int32_t decoded_len = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800322 if (encodedsrc != NULL) {
323 decoded = base64_decode(json_object_get_string(encodedsrc),
324 json_object_get_string_len(encodedsrc),
325 &decoded_len);
326 if (decoded == NULL) {
327 printf("Failed to allocate decode output buffer. \n");
328 } else {
329 fwrite(decoded, decoded_len, 1, out);
330 fflush(out);
331 free(decoded);
332 }
John Chungf8fc7052024-05-03 20:05:29 +0800333 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100334
Lawrence Tange407b4c2022-07-21 13:54:01 +0100335 //Error log out to stream.
John Chungf8fc7052024-05-03 20:05:29 +0800336 decoded_len = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800337 if (encodederr != NULL) {
338 decoded = base64_decode(json_object_get_string(encodederr),
339 json_object_get_string_len(encodederr),
340 &decoded_len);
341 if (decoded == NULL) {
342 printf("Failed to allocate decode output buffer. \n");
343 } else {
344 fwrite(decoded, decoded_len, 1, out);
345 fflush(out);
346 free(decoded);
347 }
John Chungf8fc7052024-05-03 20:05:29 +0800348 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100349
350 free(section_cper);
John Chungf8fc7052024-05-03 20:05:29 +0800351}