blob: 93d63315e6ed35c96d409dceb92dc326fcf6fd9e [file] [log] [blame]
Lawrence Tang4dbe3d72022-07-06 13:51:01 +01001/**
2 * Describes functions for converting PCIe CPER sections from binary and JSON format
3 * into an intermediate format.
Ed Tanousfedd4572024-07-12 13:56:00 -07004 *
Lawrence Tang4dbe3d72022-07-06 13:51:01 +01005 * Author: Lawrence.Tang@arm.com
6 **/
7#include <stdio.h>
Lawrence Tang3b7f45b2022-07-14 14:14:30 +01008#include <string.h>
Lawrence Tang5202bbb2022-08-12 14:54:36 +01009#include <json.h>
Thu Nguyene42fb482024-10-15 14:43:11 +000010#include <libcper/base64.h>
11#include <libcper/Cper.h>
12#include <libcper/cper-utils.h>
13#include <libcper/sections/cper-section-pcie.h>
Lawrence Tang4dbe3d72022-07-06 13:51:01 +010014
Andrew Adriance3cebfc22024-11-20 12:57:04 -080015struct aer_info_registers {
16 UINT32 pcie_capability_header;
17 UINT32 uncorrectable_error_status;
18 UINT32 uncorrectable_error_mask;
19 UINT32 uncorrectable_error_severity;
20 UINT32 correctable_error_status;
21 UINT32 correctable_error_mask;
22 UINT32 aer_capabilites_control;
23 UINT32 tlp_header_log[4];
24};
25
Lawrence Tang4dbe3d72022-07-06 13:51:01 +010026//Converts a single PCIe CPER section into JSON IR.
Ed Tanous12dbd4f2025-03-08 19:05:01 -080027json_object *cper_section_pcie_to_ir(const UINT8 *section, UINT32 size)
Lawrence Tang4dbe3d72022-07-06 13:51:01 +010028{
Ed Tanous12dbd4f2025-03-08 19:05:01 -080029 if (size < sizeof(EFI_PCIE_ERROR_DATA)) {
30 return NULL;
31 }
32
Lawrence Tange407b4c2022-07-21 13:54:01 +010033 EFI_PCIE_ERROR_DATA *pcie_error = (EFI_PCIE_ERROR_DATA *)section;
34 json_object *section_ir = json_object_new_object();
Lawrence Tang4dbe3d72022-07-06 13:51:01 +010035
Lawrence Tange407b4c2022-07-21 13:54:01 +010036 //Validation bits.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080037 ValidationTypes ui64Type = { UINT_64T,
38 .value.ui64 = pcie_error->ValidFields };
Lawrence Tang4dbe3d72022-07-06 13:51:01 +010039
Lawrence Tange407b4c2022-07-21 13:54:01 +010040 //Port type.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080041 if (isvalid_prop_to_ir(&ui64Type, 0)) {
42 json_object *port_type = integer_to_readable_pair(
43 pcie_error->PortType, 9, PCIE_ERROR_PORT_TYPES_KEYS,
44 PCIE_ERROR_PORT_TYPES_VALUES, "Unknown");
45 json_object_object_add(section_ir, "portType", port_type);
46 }
Lawrence Tang4dbe3d72022-07-06 13:51:01 +010047
Lawrence Tange407b4c2022-07-21 13:54:01 +010048 //Version, provided each half in BCD.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080049 if (isvalid_prop_to_ir(&ui64Type, 1)) {
50 json_object *version = json_object_new_object();
51 json_object_object_add(version, "minor",
52 json_object_new_int(bcd_to_int(
53 pcie_error->Version & 0xFF)));
54 json_object_object_add(version, "major",
55 json_object_new_int(bcd_to_int(
56 pcie_error->Version >> 8)));
57 json_object_object_add(section_ir, "version", version);
58 }
Lawrence Tang4dbe3d72022-07-06 13:51:01 +010059
Lawrence Tange407b4c2022-07-21 13:54:01 +010060 //Command & status.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080061 if (isvalid_prop_to_ir(&ui64Type, 2)) {
62 json_object *command_status = json_object_new_object();
63 json_object_object_add(
64 command_status, "commandRegister",
65 json_object_new_uint64(pcie_error->CommandStatus &
66 0xFFFF));
67 json_object_object_add(
68 command_status, "statusRegister",
69 json_object_new_uint64(pcie_error->CommandStatus >>
70 16));
71 json_object_object_add(section_ir, "commandStatus",
72 command_status);
73 }
Lawrence Tang4dbe3d72022-07-06 13:51:01 +010074
Lawrence Tange407b4c2022-07-21 13:54:01 +010075 //PCIe Device ID.
Aushim Nagarkatticc367012024-12-05 18:17:27 -080076 char hexstring_buf[EFI_UINT64_HEX_STRING_LEN];
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080077 if (isvalid_prop_to_ir(&ui64Type, 3)) {
78 json_object *device_id = json_object_new_object();
79 UINT64 class_id = (pcie_error->DevBridge.ClassCode[0] << 16) +
80 (pcie_error->DevBridge.ClassCode[1] << 8) +
81 pcie_error->DevBridge.ClassCode[2];
82 json_object_object_add(
83 device_id, "vendorID",
84 json_object_new_uint64(pcie_error->DevBridge.VendorId));
85 json_object_object_add(
86 device_id, "deviceID",
87 json_object_new_uint64(pcie_error->DevBridge.DeviceId));
Aushim Nagarkatticc367012024-12-05 18:17:27 -080088
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080089 snprintf(hexstring_buf, EFI_UINT64_HEX_STRING_LEN, "0x%0X",
90 pcie_error->DevBridge.DeviceId);
91 json_object_object_add(device_id, "deviceIDHex",
92 json_object_new_string(hexstring_buf));
93
94 json_object_object_add(device_id, "classCode",
95 json_object_new_uint64(class_id));
96 json_object_object_add(
97 device_id, "functionNumber",
98 json_object_new_uint64(pcie_error->DevBridge.Function));
99 json_object_object_add(
100 device_id, "deviceNumber",
101 json_object_new_uint64(pcie_error->DevBridge.Device));
102 json_object_object_add(
103 device_id, "segmentNumber",
104 json_object_new_uint64(pcie_error->DevBridge.Segment));
105 json_object_object_add(
106 device_id, "primaryOrDeviceBusNumber",
107 json_object_new_uint64(
108 pcie_error->DevBridge.PrimaryOrDeviceBus));
109 json_object_object_add(
110 device_id, "secondaryBusNumber",
111 json_object_new_uint64(
112 pcie_error->DevBridge.SecondaryBus));
113 json_object_object_add(
114 device_id, "slotNumber",
115 json_object_new_uint64(
116 pcie_error->DevBridge.Slot.Number));
117 json_object_object_add(section_ir, "deviceID", device_id);
118 }
Lawrence Tang4dbe3d72022-07-06 13:51:01 +0100119
Lawrence Tange407b4c2022-07-21 13:54:01 +0100120 //Device serial number.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800121 if (isvalid_prop_to_ir(&ui64Type, 4)) {
122 json_object_object_add(
123 section_ir, "deviceSerialNumber",
124 json_object_new_uint64(pcie_error->SerialNo));
125 }
Lawrence Tang4dbe3d72022-07-06 13:51:01 +0100126
Lawrence Tange407b4c2022-07-21 13:54:01 +0100127 //Bridge control status.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800128 if (isvalid_prop_to_ir(&ui64Type, 5)) {
129 json_object *bridge_control_status = json_object_new_object();
130 json_object_object_add(
131 bridge_control_status, "secondaryStatusRegister",
132 json_object_new_uint64(pcie_error->BridgeControlStatus &
133 0xFFFF));
134 json_object_object_add(
135 bridge_control_status, "controlRegister",
136 json_object_new_uint64(
137 pcie_error->BridgeControlStatus >> 16));
138 json_object_object_add(section_ir, "bridgeControlStatus",
139 bridge_control_status);
140 }
Lawrence Tang4dbe3d72022-07-06 13:51:01 +0100141
Lawrence Tange407b4c2022-07-21 13:54:01 +0100142 //Capability structure.
143 //The PCIe capability structure provided here could either be PCIe 1.1 Capability Structure
144 //(36-byte, padded to 60 bytes) or PCIe 2.0 Capability Structure (60-byte). There does not seem
145 //to be a way to differentiate these, so this is left as a b64 dump.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700146 int32_t encoded_len = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800147 char *encoded = NULL;
148 if (isvalid_prop_to_ir(&ui64Type, 6)) {
149 char *encoded =
150 base64_encode((UINT8 *)pcie_error->Capability.PcieCap,
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700151 60, &encoded_len);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800152 if (encoded == NULL) {
153 printf("Failed to allocate encode output buffer. \n");
154 } else {
155 json_object *capability = json_object_new_object();
156 json_object_object_add(capability, "data",
157 json_object_new_string_len(
158 encoded, encoded_len));
159 free(encoded);
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700160
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800161 json_object_object_add(
162 section_ir, "capabilityStructure", capability);
163 }
John Chungf8fc7052024-05-03 20:05:29 +0800164 }
Lawrence Tang4dbe3d72022-07-06 13:51:01 +0100165
Lawrence Tange407b4c2022-07-21 13:54:01 +0100166 //AER information.
John Chungf8fc7052024-05-03 20:05:29 +0800167 encoded_len = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800168 encoded = NULL;
169 if (isvalid_prop_to_ir(&ui64Type, 7)) {
170 json_object *aer_capability_ir = json_object_new_object();
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700171
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800172 encoded = base64_encode((UINT8 *)pcie_error->AerInfo.PcieAer,
173 96, &encoded_len);
174 if (encoded == NULL) {
175 printf("Failed to allocate encode output buffer. \n");
176 } else {
177 json_object_object_add(aer_capability_ir, "data",
178 json_object_new_string_len(
179 encoded, encoded_len));
180 free(encoded);
181 }
182
183 struct aer_info_registers *aer_decode;
184 aer_decode = (struct aer_info_registers *)&pcie_error->AerInfo
185 .PcieAer;
186 json_object_object_add(
187 aer_capability_ir, "capability_header",
188 json_object_new_uint64(
189 aer_decode->pcie_capability_header));
190 json_object_object_add(
191 aer_capability_ir, "uncorrectable_error_status",
192 json_object_new_uint64(
193 aer_decode->uncorrectable_error_status));
194
195 snprintf(hexstring_buf, EFI_UINT64_HEX_STRING_LEN,
196 "0x%08" PRIX32,
197 aer_decode->uncorrectable_error_status);
198 json_object_object_add(aer_capability_ir,
199 "uncorrectable_error_status_hex",
200 json_object_new_string(hexstring_buf));
201
202 json_object_object_add(
203 aer_capability_ir, "uncorrectable_error_mask",
204 json_object_new_uint64(
205 aer_decode->uncorrectable_error_mask));
206 json_object_object_add(
207 aer_capability_ir, "uncorrectable_error_severity",
208 json_object_new_uint64(
209 aer_decode->uncorrectable_error_severity));
210 json_object_object_add(
211 aer_capability_ir, "correctable_error_status",
212 json_object_new_uint64(
213 aer_decode->correctable_error_status));
214
215 snprintf(hexstring_buf, EFI_UINT64_HEX_STRING_LEN,
216 "0x%08" PRIX32, aer_decode->correctable_error_status);
217 json_object_object_add(aer_capability_ir,
218 "correctable_error_status_hex",
219 json_object_new_string(hexstring_buf));
220
221 json_object_object_add(
222 aer_capability_ir, "correctable_error_mask",
223 json_object_new_uint64(
224 aer_decode->correctable_error_mask));
225 json_object_object_add(
226 aer_capability_ir, "capabilites_control",
227 json_object_new_uint64(
228 aer_decode->aer_capabilites_control));
229 json_object_object_add(
230 aer_capability_ir, "tlp_header_0",
231 json_object_new_uint64(aer_decode->tlp_header_log[0]));
232 json_object_object_add(
233 aer_capability_ir, "tlp_header_1",
234 json_object_new_uint64(aer_decode->tlp_header_log[1]));
235 json_object_object_add(
236 aer_capability_ir, "tlp_header_2",
237 json_object_new_uint64(aer_decode->tlp_header_log[2]));
238 json_object_object_add(
239 aer_capability_ir, "tlp_header_3",
240 json_object_new_uint64(aer_decode->tlp_header_log[3]));
241 json_object_object_add(section_ir, "aerInfo",
242 aer_capability_ir);
John Chungf8fc7052024-05-03 20:05:29 +0800243 }
Andrew Adriance3cebfc22024-11-20 12:57:04 -0800244
Lawrence Tange407b4c2022-07-21 13:54:01 +0100245 return section_ir;
Lawrence Tang3b7f45b2022-07-14 14:14:30 +0100246}
247
248//Converts a single CPER-JSON PCIe section into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100249void ir_section_pcie_to_cper(json_object *section, FILE *out)
Lawrence Tang3b7f45b2022-07-14 14:14:30 +0100250{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100251 EFI_PCIE_ERROR_DATA *section_cper =
252 (EFI_PCIE_ERROR_DATA *)calloc(1, sizeof(EFI_PCIE_ERROR_DATA));
Lawrence Tang3b7f45b2022-07-14 14:14:30 +0100253
Lawrence Tange407b4c2022-07-21 13:54:01 +0100254 //Validation bits.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800255 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
256 struct json_object *obj = NULL;
Lawrence Tang3b7f45b2022-07-14 14:14:30 +0100257
Lawrence Tange407b4c2022-07-21 13:54:01 +0100258 //Version.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800259 if (json_object_object_get_ex(section, "version", &obj)) {
260 json_object *version = obj;
261 UINT32 minor = int_to_bcd(json_object_get_int(
262 json_object_object_get(version, "minor")));
263 UINT32 major = int_to_bcd(json_object_get_int(
264 json_object_object_get(version, "major")));
265 section_cper->Version = minor + (major << 8);
266 add_to_valid_bitfield(&ui64Type, 1);
John Chungf8fc7052024-05-03 20:05:29 +0800267 }
Lawrence Tang3b7f45b2022-07-14 14:14:30 +0100268
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800269 //Command/status registers.
270 if (json_object_object_get_ex(section, "commandStatus", &obj)) {
271 json_object *command_status = obj;
272 UINT32 command = (UINT16)json_object_get_uint64(
273 json_object_object_get(command_status,
274 "commandRegister"));
275 UINT32 status = (UINT16)json_object_get_uint64(
276 json_object_object_get(command_status,
277 "statusRegister"));
278 section_cper->CommandStatus = command + (status << 16);
279 add_to_valid_bitfield(&ui64Type, 2);
280 }
281
282 //Device ID.
283 if (json_object_object_get_ex(section, "deviceID", &obj)) {
284 json_object *device_id = obj;
285 UINT64 class_id = json_object_get_uint64(
286 json_object_object_get(device_id, "classCode"));
287 section_cper->DevBridge.VendorId =
288 (UINT16)json_object_get_uint64(
289 json_object_object_get(device_id, "vendorID"));
290 section_cper->DevBridge.DeviceId =
291 (UINT16)json_object_get_uint64(
292 json_object_object_get(device_id, "deviceID"));
293 section_cper->DevBridge.ClassCode[0] = class_id >> 16;
294 section_cper->DevBridge.ClassCode[1] = (class_id >> 8) & 0xFF;
295 section_cper->DevBridge.ClassCode[2] = class_id & 0xFF;
296 section_cper->DevBridge.Function =
297 (UINT8)json_object_get_uint64(json_object_object_get(
298 device_id, "functionNumber"));
299 section_cper->DevBridge.Device = (UINT8)json_object_get_uint64(
300 json_object_object_get(device_id, "deviceNumber"));
301 section_cper->DevBridge.Segment =
302 (UINT16)json_object_get_uint64(json_object_object_get(
303 device_id, "segmentNumber"));
304 section_cper->DevBridge.PrimaryOrDeviceBus =
305 (UINT8)json_object_get_uint64(json_object_object_get(
306 device_id, "primaryOrDeviceBusNumber"));
307 section_cper->DevBridge.SecondaryBus =
308 (UINT8)json_object_get_uint64(json_object_object_get(
309 device_id, "secondaryBusNumber"));
310 section_cper->DevBridge.Slot.Number =
311 (UINT16)json_object_get_uint64(json_object_object_get(
312 device_id, "slotNumber"));
313 add_to_valid_bitfield(&ui64Type, 3);
314 }
315
316 //Bridge/control status.
317 if (json_object_object_get_ex(section, "bridgeControlStatus", &obj)) {
318 json_object *bridge_control = obj;
319 UINT32 bridge_status = (UINT16)json_object_get_uint64(
320 json_object_object_get(bridge_control,
321 "secondaryStatusRegister"));
322 UINT32 control_status = (UINT16)json_object_get_uint64(
323 json_object_object_get(bridge_control,
324 "controlRegister"));
325 section_cper->BridgeControlStatus =
326 bridge_status + (control_status << 16);
327 add_to_valid_bitfield(&ui64Type, 5);
328 }
329
330 //Capability structure.
331 int32_t decoded_len = 0;
332 UINT8 *decoded = NULL;
333 json_object *encoded = NULL;
334 if (json_object_object_get_ex(section, "capabilityStructure", &obj)) {
335 json_object *capability = obj;
336 json_object *encoded =
337 json_object_object_get(capability, "data");
338
339 UINT8 *decoded = base64_decode(
340 json_object_get_string(encoded),
341 json_object_get_string_len(encoded), &decoded_len);
342 if (decoded == NULL) {
343 printf("Failed to allocate decode output buffer. \n");
344 } else {
345 memcpy(section_cper->Capability.PcieCap, decoded,
346 decoded_len);
347 free(decoded);
348 }
349 add_to_valid_bitfield(&ui64Type, 6);
350 }
351
352 decoded = NULL;
353 encoded = NULL;
Lawrence Tange407b4c2022-07-21 13:54:01 +0100354 //AER capability structure.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800355 if (json_object_object_get_ex(section, "aerInfo", &obj)) {
356 json_object *aer_info = obj;
357 encoded = json_object_object_get(aer_info, "data");
358 decoded_len = 0;
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700359
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800360 decoded = base64_decode(json_object_get_string(encoded),
361 json_object_get_string_len(encoded),
362 &decoded_len);
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700363
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800364 if (decoded == NULL) {
365 printf("Failed to allocate decode output buffer. \n");
366 } else {
367 memcpy(section_cper->AerInfo.PcieAer, decoded,
368 decoded_len);
369 free(decoded);
370 }
371 add_to_valid_bitfield(&ui64Type, 7);
John Chungf8fc7052024-05-03 20:05:29 +0800372 }
Lawrence Tang3b7f45b2022-07-14 14:14:30 +0100373
Lawrence Tange407b4c2022-07-21 13:54:01 +0100374 //Miscellaneous value fields.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800375 if (json_object_object_get_ex(section, "portType", &obj)) {
376 section_cper->PortType = (UINT32)readable_pair_to_integer(obj);
377 add_to_valid_bitfield(&ui64Type, 0);
378 }
379 if (json_object_object_get_ex(section, "deviceSerialNumber", &obj)) {
380 section_cper->SerialNo = json_object_get_uint64(obj);
381 add_to_valid_bitfield(&ui64Type, 4);
382 }
383
384 section_cper->ValidFields = ui64Type.value.ui64;
Lawrence Tang3b7f45b2022-07-14 14:14:30 +0100385
Lawrence Tange407b4c2022-07-21 13:54:01 +0100386 //Write out to stream, free resources.
387 fwrite(section_cper, sizeof(EFI_PCIE_ERROR_DATA), 1, out);
388 fflush(out);
389 free(section_cper);
John Chungf8fc7052024-05-03 20:05:29 +0800390}