1 /**
2 * Describes functions for converting PCIe CPER sections from binary and JSON format
3 * into an intermediate format.
4 *
5 * Author: Lawrence.Tang@arm.com
6 **/
7 #include <stdio.h>
8 #include <string.h>
9 #include <json.h>
10 #include <libcper/base64.h>
11 #include <libcper/Cper.h>
12 #include <libcper/cper-utils.h>
13 #include <libcper/sections/cper-section-pcie.h>
14
15 struct 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
26 //Converts a single PCIe CPER section into JSON IR.
cper_section_pcie_to_ir(void * section)27 json_object *cper_section_pcie_to_ir(void *section)
28 {
29 EFI_PCIE_ERROR_DATA *pcie_error = (EFI_PCIE_ERROR_DATA *)section;
30 json_object *section_ir = json_object_new_object();
31
32 //Validation bits.
33 ValidationTypes ui64Type = { UINT_64T,
34 .value.ui64 = pcie_error->ValidFields };
35
36 //Port type.
37 if (isvalid_prop_to_ir(&ui64Type, 0)) {
38 json_object *port_type = integer_to_readable_pair(
39 pcie_error->PortType, 9, PCIE_ERROR_PORT_TYPES_KEYS,
40 PCIE_ERROR_PORT_TYPES_VALUES, "Unknown");
41 json_object_object_add(section_ir, "portType", port_type);
42 }
43
44 //Version, provided each half in BCD.
45 if (isvalid_prop_to_ir(&ui64Type, 1)) {
46 json_object *version = json_object_new_object();
47 json_object_object_add(version, "minor",
48 json_object_new_int(bcd_to_int(
49 pcie_error->Version & 0xFF)));
50 json_object_object_add(version, "major",
51 json_object_new_int(bcd_to_int(
52 pcie_error->Version >> 8)));
53 json_object_object_add(section_ir, "version", version);
54 }
55
56 //Command & status.
57 if (isvalid_prop_to_ir(&ui64Type, 2)) {
58 json_object *command_status = json_object_new_object();
59 json_object_object_add(
60 command_status, "commandRegister",
61 json_object_new_uint64(pcie_error->CommandStatus &
62 0xFFFF));
63 json_object_object_add(
64 command_status, "statusRegister",
65 json_object_new_uint64(pcie_error->CommandStatus >>
66 16));
67 json_object_object_add(section_ir, "commandStatus",
68 command_status);
69 }
70
71 //PCIe Device ID.
72 char hexstring_buf[EFI_UINT64_HEX_STRING_LEN];
73 if (isvalid_prop_to_ir(&ui64Type, 3)) {
74 json_object *device_id = json_object_new_object();
75 UINT64 class_id = (pcie_error->DevBridge.ClassCode[0] << 16) +
76 (pcie_error->DevBridge.ClassCode[1] << 8) +
77 pcie_error->DevBridge.ClassCode[2];
78 json_object_object_add(
79 device_id, "vendorID",
80 json_object_new_uint64(pcie_error->DevBridge.VendorId));
81 json_object_object_add(
82 device_id, "deviceID",
83 json_object_new_uint64(pcie_error->DevBridge.DeviceId));
84
85 snprintf(hexstring_buf, EFI_UINT64_HEX_STRING_LEN, "0x%0X",
86 pcie_error->DevBridge.DeviceId);
87 json_object_object_add(device_id, "deviceIDHex",
88 json_object_new_string(hexstring_buf));
89
90 json_object_object_add(device_id, "classCode",
91 json_object_new_uint64(class_id));
92 json_object_object_add(
93 device_id, "functionNumber",
94 json_object_new_uint64(pcie_error->DevBridge.Function));
95 json_object_object_add(
96 device_id, "deviceNumber",
97 json_object_new_uint64(pcie_error->DevBridge.Device));
98 json_object_object_add(
99 device_id, "segmentNumber",
100 json_object_new_uint64(pcie_error->DevBridge.Segment));
101 json_object_object_add(
102 device_id, "primaryOrDeviceBusNumber",
103 json_object_new_uint64(
104 pcie_error->DevBridge.PrimaryOrDeviceBus));
105 json_object_object_add(
106 device_id, "secondaryBusNumber",
107 json_object_new_uint64(
108 pcie_error->DevBridge.SecondaryBus));
109 json_object_object_add(
110 device_id, "slotNumber",
111 json_object_new_uint64(
112 pcie_error->DevBridge.Slot.Number));
113 json_object_object_add(section_ir, "deviceID", device_id);
114 }
115
116 //Device serial number.
117 if (isvalid_prop_to_ir(&ui64Type, 4)) {
118 json_object_object_add(
119 section_ir, "deviceSerialNumber",
120 json_object_new_uint64(pcie_error->SerialNo));
121 }
122
123 //Bridge control status.
124 if (isvalid_prop_to_ir(&ui64Type, 5)) {
125 json_object *bridge_control_status = json_object_new_object();
126 json_object_object_add(
127 bridge_control_status, "secondaryStatusRegister",
128 json_object_new_uint64(pcie_error->BridgeControlStatus &
129 0xFFFF));
130 json_object_object_add(
131 bridge_control_status, "controlRegister",
132 json_object_new_uint64(
133 pcie_error->BridgeControlStatus >> 16));
134 json_object_object_add(section_ir, "bridgeControlStatus",
135 bridge_control_status);
136 }
137
138 //Capability structure.
139 //The PCIe capability structure provided here could either be PCIe 1.1 Capability Structure
140 //(36-byte, padded to 60 bytes) or PCIe 2.0 Capability Structure (60-byte). There does not seem
141 //to be a way to differentiate these, so this is left as a b64 dump.
142 int32_t encoded_len = 0;
143 char *encoded = NULL;
144 if (isvalid_prop_to_ir(&ui64Type, 6)) {
145 char *encoded =
146 base64_encode((UINT8 *)pcie_error->Capability.PcieCap,
147 60, &encoded_len);
148 if (encoded == NULL) {
149 printf("Failed to allocate encode output buffer. \n");
150 } else {
151 json_object *capability = json_object_new_object();
152 json_object_object_add(capability, "data",
153 json_object_new_string_len(
154 encoded, encoded_len));
155 free(encoded);
156
157 json_object_object_add(
158 section_ir, "capabilityStructure", capability);
159 }
160 }
161
162 //AER information.
163 encoded_len = 0;
164 encoded = NULL;
165 if (isvalid_prop_to_ir(&ui64Type, 7)) {
166 json_object *aer_capability_ir = json_object_new_object();
167
168 encoded = base64_encode((UINT8 *)pcie_error->AerInfo.PcieAer,
169 96, &encoded_len);
170 if (encoded == NULL) {
171 printf("Failed to allocate encode output buffer. \n");
172 } else {
173 json_object_object_add(aer_capability_ir, "data",
174 json_object_new_string_len(
175 encoded, encoded_len));
176 free(encoded);
177 }
178
179 struct aer_info_registers *aer_decode;
180 aer_decode = (struct aer_info_registers *)&pcie_error->AerInfo
181 .PcieAer;
182 json_object_object_add(
183 aer_capability_ir, "capability_header",
184 json_object_new_uint64(
185 aer_decode->pcie_capability_header));
186 json_object_object_add(
187 aer_capability_ir, "uncorrectable_error_status",
188 json_object_new_uint64(
189 aer_decode->uncorrectable_error_status));
190
191 snprintf(hexstring_buf, EFI_UINT64_HEX_STRING_LEN,
192 "0x%08" PRIX32,
193 aer_decode->uncorrectable_error_status);
194 json_object_object_add(aer_capability_ir,
195 "uncorrectable_error_status_hex",
196 json_object_new_string(hexstring_buf));
197
198 json_object_object_add(
199 aer_capability_ir, "uncorrectable_error_mask",
200 json_object_new_uint64(
201 aer_decode->uncorrectable_error_mask));
202 json_object_object_add(
203 aer_capability_ir, "uncorrectable_error_severity",
204 json_object_new_uint64(
205 aer_decode->uncorrectable_error_severity));
206 json_object_object_add(
207 aer_capability_ir, "correctable_error_status",
208 json_object_new_uint64(
209 aer_decode->correctable_error_status));
210
211 snprintf(hexstring_buf, EFI_UINT64_HEX_STRING_LEN,
212 "0x%08" PRIX32, aer_decode->correctable_error_status);
213 json_object_object_add(aer_capability_ir,
214 "correctable_error_status_hex",
215 json_object_new_string(hexstring_buf));
216
217 json_object_object_add(
218 aer_capability_ir, "correctable_error_mask",
219 json_object_new_uint64(
220 aer_decode->correctable_error_mask));
221 json_object_object_add(
222 aer_capability_ir, "capabilites_control",
223 json_object_new_uint64(
224 aer_decode->aer_capabilites_control));
225 json_object_object_add(
226 aer_capability_ir, "tlp_header_0",
227 json_object_new_uint64(aer_decode->tlp_header_log[0]));
228 json_object_object_add(
229 aer_capability_ir, "tlp_header_1",
230 json_object_new_uint64(aer_decode->tlp_header_log[1]));
231 json_object_object_add(
232 aer_capability_ir, "tlp_header_2",
233 json_object_new_uint64(aer_decode->tlp_header_log[2]));
234 json_object_object_add(
235 aer_capability_ir, "tlp_header_3",
236 json_object_new_uint64(aer_decode->tlp_header_log[3]));
237 json_object_object_add(section_ir, "aerInfo",
238 aer_capability_ir);
239 }
240
241 return section_ir;
242 }
243
244 //Converts a single CPER-JSON PCIe section into CPER binary, outputting to the given stream.
ir_section_pcie_to_cper(json_object * section,FILE * out)245 void ir_section_pcie_to_cper(json_object *section, FILE *out)
246 {
247 EFI_PCIE_ERROR_DATA *section_cper =
248 (EFI_PCIE_ERROR_DATA *)calloc(1, sizeof(EFI_PCIE_ERROR_DATA));
249
250 //Validation bits.
251 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
252 struct json_object *obj = NULL;
253
254 //Version.
255 if (json_object_object_get_ex(section, "version", &obj)) {
256 json_object *version = obj;
257 UINT32 minor = int_to_bcd(json_object_get_int(
258 json_object_object_get(version, "minor")));
259 UINT32 major = int_to_bcd(json_object_get_int(
260 json_object_object_get(version, "major")));
261 section_cper->Version = minor + (major << 8);
262 add_to_valid_bitfield(&ui64Type, 1);
263 }
264
265 //Command/status registers.
266 if (json_object_object_get_ex(section, "commandStatus", &obj)) {
267 json_object *command_status = obj;
268 UINT32 command = (UINT16)json_object_get_uint64(
269 json_object_object_get(command_status,
270 "commandRegister"));
271 UINT32 status = (UINT16)json_object_get_uint64(
272 json_object_object_get(command_status,
273 "statusRegister"));
274 section_cper->CommandStatus = command + (status << 16);
275 add_to_valid_bitfield(&ui64Type, 2);
276 }
277
278 //Device ID.
279 if (json_object_object_get_ex(section, "deviceID", &obj)) {
280 json_object *device_id = obj;
281 UINT64 class_id = json_object_get_uint64(
282 json_object_object_get(device_id, "classCode"));
283 section_cper->DevBridge.VendorId =
284 (UINT16)json_object_get_uint64(
285 json_object_object_get(device_id, "vendorID"));
286 section_cper->DevBridge.DeviceId =
287 (UINT16)json_object_get_uint64(
288 json_object_object_get(device_id, "deviceID"));
289 section_cper->DevBridge.ClassCode[0] = class_id >> 16;
290 section_cper->DevBridge.ClassCode[1] = (class_id >> 8) & 0xFF;
291 section_cper->DevBridge.ClassCode[2] = class_id & 0xFF;
292 section_cper->DevBridge.Function =
293 (UINT8)json_object_get_uint64(json_object_object_get(
294 device_id, "functionNumber"));
295 section_cper->DevBridge.Device = (UINT8)json_object_get_uint64(
296 json_object_object_get(device_id, "deviceNumber"));
297 section_cper->DevBridge.Segment =
298 (UINT16)json_object_get_uint64(json_object_object_get(
299 device_id, "segmentNumber"));
300 section_cper->DevBridge.PrimaryOrDeviceBus =
301 (UINT8)json_object_get_uint64(json_object_object_get(
302 device_id, "primaryOrDeviceBusNumber"));
303 section_cper->DevBridge.SecondaryBus =
304 (UINT8)json_object_get_uint64(json_object_object_get(
305 device_id, "secondaryBusNumber"));
306 section_cper->DevBridge.Slot.Number =
307 (UINT16)json_object_get_uint64(json_object_object_get(
308 device_id, "slotNumber"));
309 add_to_valid_bitfield(&ui64Type, 3);
310 }
311
312 //Bridge/control status.
313 if (json_object_object_get_ex(section, "bridgeControlStatus", &obj)) {
314 json_object *bridge_control = obj;
315 UINT32 bridge_status = (UINT16)json_object_get_uint64(
316 json_object_object_get(bridge_control,
317 "secondaryStatusRegister"));
318 UINT32 control_status = (UINT16)json_object_get_uint64(
319 json_object_object_get(bridge_control,
320 "controlRegister"));
321 section_cper->BridgeControlStatus =
322 bridge_status + (control_status << 16);
323 add_to_valid_bitfield(&ui64Type, 5);
324 }
325
326 //Capability structure.
327 int32_t decoded_len = 0;
328 UINT8 *decoded = NULL;
329 json_object *encoded = NULL;
330 if (json_object_object_get_ex(section, "capabilityStructure", &obj)) {
331 json_object *capability = obj;
332 json_object *encoded =
333 json_object_object_get(capability, "data");
334
335 UINT8 *decoded = base64_decode(
336 json_object_get_string(encoded),
337 json_object_get_string_len(encoded), &decoded_len);
338 if (decoded == NULL) {
339 printf("Failed to allocate decode output buffer. \n");
340 } else {
341 memcpy(section_cper->Capability.PcieCap, decoded,
342 decoded_len);
343 free(decoded);
344 }
345 add_to_valid_bitfield(&ui64Type, 6);
346 }
347
348 decoded = NULL;
349 encoded = NULL;
350 //AER capability structure.
351 if (json_object_object_get_ex(section, "aerInfo", &obj)) {
352 json_object *aer_info = obj;
353 encoded = json_object_object_get(aer_info, "data");
354 decoded_len = 0;
355
356 decoded = base64_decode(json_object_get_string(encoded),
357 json_object_get_string_len(encoded),
358 &decoded_len);
359
360 if (decoded == NULL) {
361 printf("Failed to allocate decode output buffer. \n");
362 } else {
363 memcpy(section_cper->AerInfo.PcieAer, decoded,
364 decoded_len);
365 free(decoded);
366 }
367 add_to_valid_bitfield(&ui64Type, 7);
368 }
369
370 //Miscellaneous value fields.
371 if (json_object_object_get_ex(section, "portType", &obj)) {
372 section_cper->PortType = (UINT32)readable_pair_to_integer(obj);
373 add_to_valid_bitfield(&ui64Type, 0);
374 }
375 if (json_object_object_get_ex(section, "deviceSerialNumber", &obj)) {
376 section_cper->SerialNo = json_object_get_uint64(obj);
377 add_to_valid_bitfield(&ui64Type, 4);
378 }
379
380 section_cper->ValidFields = ui64Type.value.ui64;
381
382 //Write out to stream, free resources.
383 fwrite(section_cper, sizeof(EFI_PCIE_ERROR_DATA), 1, out);
384 fflush(out);
385 free(section_cper);
386 }
387