1 /**
2 * Describes functions for converting ARM CPER sections from binary and JSON format
3 * into an intermediate format.
4 *
5 * Author: Lawrence.Tang@arm.com
6 **/
7
8 #include <stdio.h>
9 #include <string.h>
10 #include <json.h>
11 #include <inttypes.h>
12 #include <libcper/base64.h>
13 #include <libcper/Cper.h>
14 #include <libcper/cper-utils.h>
15 #include <libcper/sections/cper-section-arm.h>
16 #include <libcper/log.h>
17 #include <string.h>
18
19 //Private pre-definitions.
20 json_object *
21 cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info,
22 char **err_info_desc_i);
23 json_object *
24 cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
25 const UINT8 **cur_pos, UINT32 *remaining_size);
26 json_object *
27 cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
28 EFI_ARM_ERROR_INFORMATION_ENTRY *error_info);
29 json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error);
30 json_object *cper_arm_misc_register_array_to_ir(
31 EFI_ARM_MISC_CONTEXT_REGISTER *misc_register);
32 void ir_arm_error_info_to_cper(json_object *error_info, FILE *out);
33 void ir_arm_context_info_to_cper(json_object *context_info, FILE *out);
34 void ir_arm_error_cache_tlb_info_to_cper(
35 json_object *error_information,
36 EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper);
37 void ir_arm_error_bus_info_to_cper(json_object *error_information,
38 EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper);
39 void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out);
40 void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out);
41 void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out);
42 void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out);
43 void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out);
44 void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out);
45 void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out);
46 void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out);
47 void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out);
48 void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out);
49
50 //Converts the given processor-generic CPER section into JSON IR.
cper_section_arm_to_ir(const UINT8 * section,UINT32 size,char ** desc_string)51 json_object *cper_section_arm_to_ir(const UINT8 *section, UINT32 size,
52 char **desc_string)
53 {
54 *desc_string = malloc(SECTION_DESC_STRING_SIZE);
55 int outstr_len = 0;
56 outstr_len = snprintf(*desc_string, SECTION_DESC_STRING_SIZE,
57 "An ARM Processor Error occurred");
58 if (outstr_len < 0) {
59 cper_print_log(
60 "Error: Could not write to ARM description string\n");
61 } else if (outstr_len > SECTION_DESC_STRING_SIZE) {
62 cper_print_log("Error: ARM description string truncated: %s\n",
63 *desc_string);
64 }
65
66 const UINT8 *cur_pos = section;
67 UINT32 remaining_size = size;
68
69 if (remaining_size < sizeof(EFI_ARM_ERROR_RECORD)) {
70 return NULL;
71 }
72 EFI_ARM_ERROR_RECORD *record = (EFI_ARM_ERROR_RECORD *)cur_pos;
73 cur_pos += sizeof(EFI_ARM_ERROR_RECORD);
74 remaining_size -= sizeof(EFI_ARM_ERROR_RECORD);
75 json_object *section_ir = json_object_new_object();
76
77 //Length of ValidationBits from spec
78 ValidationTypes ui64Type = { UINT_64T,
79 .value.ui64 = record->ValidFields };
80
81 //Number of error info and context info structures, and length.
82 json_object_object_add(section_ir, "errorInfoNum",
83 json_object_new_int(record->ErrInfoNum));
84 json_object_object_add(section_ir, "contextInfoNum",
85 json_object_new_int(record->ContextInfoNum));
86 json_object_object_add(section_ir, "sectionLength",
87 json_object_new_uint64(record->SectionLength));
88
89 //Error affinity.
90 if (isvalid_prop_to_ir(&ui64Type, 1)) {
91 json_object *error_affinity = json_object_new_object();
92 json_object_object_add(
93 error_affinity, "value",
94 json_object_new_int(record->ErrorAffinityLevel));
95 json_object_object_add(
96 error_affinity, "type",
97 json_object_new_string(record->ErrorAffinityLevel < 4 ?
98 "Vendor Defined" :
99 "Reserved"));
100 json_object_object_add(section_ir, "errorAffinity",
101 error_affinity);
102 }
103
104 //Processor ID (MPIDR_EL1) and chip ID (MIDR_EL1).
105 if (isvalid_prop_to_ir(&ui64Type, 0)) {
106 uint64_t mpidr_eli1 = record->MPIDR_EL1;
107 uint64_t sock;
108 json_object_object_add(section_ir, "mpidrEl1",
109 json_object_new_uint64(mpidr_eli1));
110
111 //Arm Processor socket info dependes on mpidr_eli1
112 sock = (mpidr_eli1 & ARM_SOCK_MASK) >> 32;
113 json_object_object_add(section_ir, "affinity3",
114 json_object_new_uint64(sock));
115 char *node_desc_str = malloc(EFI_ERROR_DESCRIPTION_STRING_LEN);
116 outstr_len = snprintf(node_desc_str,
117 EFI_ERROR_DESCRIPTION_STRING_LEN,
118 " on CPU %" PRIu64, sock);
119 if (outstr_len < 0) {
120 cper_print_log(
121 "Error: Could not write to node description string\n");
122 } else if (outstr_len > EFI_ERROR_DESCRIPTION_STRING_LEN) {
123 cper_print_log(
124 "Error: Node description string truncated: %s\n",
125 node_desc_str);
126 } else {
127 if (strlen(node_desc_str) + strlen(*desc_string) <
128 SECTION_DESC_STRING_SIZE) {
129 strncat(*desc_string, node_desc_str,
130 outstr_len);
131 } else {
132 cper_print_log(
133 "Error: Node description string too long, not added to description string: %s\n",
134 node_desc_str);
135 }
136 }
137 free(node_desc_str);
138 }
139
140 json_object_object_add(section_ir, "midrEl1",
141 json_object_new_uint64(record->MIDR_EL1));
142
143 if (isvalid_prop_to_ir(&ui64Type, 2)) {
144 //Whether the processor is running, and the state of it if so.
145 json_object_object_add(
146 section_ir, "running",
147 json_object_new_boolean(record->RunningState & 0x1));
148 }
149 if (!(record->RunningState >> 31)) {
150 //Bit 32 of running state is on, so PSCI state information is included.
151 //This can't be made human readable, as it is unknown whether this will be the pre-PSCI 1.0 format
152 //or the newer Extended StateID format.
153 json_object_object_add(
154 section_ir, "psciState",
155 json_object_new_uint64(record->PsciState));
156 }
157
158 //Processor error structures.
159 json_object *error_info_array = json_object_new_array();
160 EFI_ARM_ERROR_INFORMATION_ENTRY *cur_error =
161 (EFI_ARM_ERROR_INFORMATION_ENTRY *)(record + 1);
162 if (remaining_size <
163 (record->ErrInfoNum * sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY))) {
164 json_object_put(error_info_array);
165 json_object_put(section_ir);
166 cper_print_log(
167 "Invalid CPER file: Invalid processor error info num.\n");
168 return NULL;
169 }
170 strncat(*desc_string, "; Error Type(s): {",
171 EFI_ERROR_DESCRIPTION_STRING_LEN);
172 char *err_info_desc_i =
173 malloc(EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN);
174 size_t err_info_desc_i_len = 0;
175 for (int i = 0; i < record->ErrInfoNum; i++) {
176 json_object_array_add(
177 error_info_array,
178 cper_arm_error_info_to_ir(cur_error, &err_info_desc_i));
179 err_info_desc_i_len = strlen(err_info_desc_i);
180 if (err_info_desc_i_len > 0 &&
181 strlen(*desc_string) + err_info_desc_i_len <
182 SECTION_DESC_STRING_SIZE) {
183 strncat(*desc_string, err_info_desc_i,
184 SECTION_DESC_STRING_SIZE -
185 strlen(*desc_string) - 1);
186 } else {
187 cper_print_log(
188 "Error: Error info description string too long, not added to description string: %s\n",
189 err_info_desc_i);
190 }
191 cur_error++;
192 if (i == record->ErrInfoNum - 1) {
193 if (strlen(*desc_string) + 2 <
194 SECTION_DESC_STRING_SIZE) {
195 strncat(*desc_string, "}", 2);
196 } else {
197 cper_print_log(
198 "Error: Description string too long, not added '}'to description string: %s\n",
199 *desc_string);
200 }
201 break;
202 }
203 if (strlen(*desc_string) + 3 < SECTION_DESC_STRING_SIZE) {
204 strncat(*desc_string, ", ", 3);
205 } else {
206 cper_print_log(
207 "Error: Description string too long, not added ',' to description string: %s\n",
208 *desc_string);
209 }
210 }
211 free(err_info_desc_i);
212
213 cur_pos += (UINT32)(record->ErrInfoNum *
214 sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY));
215 remaining_size -= (UINT32)(record->ErrInfoNum *
216 sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY));
217
218 json_object_object_add(section_ir, "errorInfo", error_info_array);
219
220 //Processor context structures.
221 //The current position is moved within the processing, as it is a dynamic size structure.
222 json_object *context_info_array = json_object_new_array();
223 for (int i = 0; i < record->ContextInfoNum; i++) {
224 if (remaining_size <
225 sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER)) {
226 json_object_put(context_info_array);
227 json_object_put(section_ir);
228 cper_print_log(
229 "Invalid CPER file: Invalid processor context info num.\n");
230 return NULL;
231 }
232 EFI_ARM_CONTEXT_INFORMATION_HEADER *header =
233 (EFI_ARM_CONTEXT_INFORMATION_HEADER *)cur_pos;
234
235 cur_pos += sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER);
236 remaining_size -= sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER);
237 json_object *processor_context =
238 cper_arm_processor_context_to_ir(header, &cur_pos,
239 &remaining_size);
240 if (processor_context == NULL) {
241 json_object_put(context_info_array);
242 json_object_put(section_ir);
243 cper_print_log(
244 "Invalid CPER file: Invalid processor context info num.\n");
245 return NULL;
246 }
247 json_object_array_add(context_info_array, processor_context);
248 }
249 json_object_object_add(section_ir, "contextInfo", context_info_array);
250
251 //Is there any vendor-specific information following?
252 if (isvalid_prop_to_ir(&ui64Type, 3)) {
253 if (cur_pos < (uint8_t *)section + record->SectionLength) {
254 json_object *vendor_specific = json_object_new_object();
255 size_t input_size = (uint8_t *)section +
256 record->SectionLength - cur_pos;
257 if (remaining_size < input_size) {
258 json_object_put(vendor_specific);
259 json_object_put(section_ir);
260 cper_print_log(
261 "Invalid CPER file: Invalid vendor-specific info length.\n");
262 return NULL;
263 }
264 int32_t encoded_len = 0;
265 char *encoded = base64_encode(cur_pos, input_size,
266 &encoded_len);
267 if (encoded == NULL) {
268 json_object_put(vendor_specific);
269 json_object_put(section_ir);
270 cper_print_log(
271 "base64 encode of vendorSpecificInfo failed\n");
272 return NULL;
273 }
274 json_object_object_add(vendor_specific, "data",
275 json_object_new_string_len(
276 encoded, encoded_len));
277 free(encoded);
278
279 json_object_object_add(section_ir, "vendorSpecificInfo",
280 vendor_specific);
281 } else {
282 cper_print_log(
283 "vendorSpecificInfo is marked valid but not present in binary\n");
284 }
285 }
286
287 return section_ir;
288 }
289
290 //Converts a single ARM Process Error Information structure into JSON IR.
291 json_object *
cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY * error_info,char ** err_info_desc_i)292 cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info,
293 char **err_info_desc_i)
294 {
295 json_object *error_info_ir = json_object_new_object();
296 int outstr_len = 0;
297
298 //Version, length.
299 json_object_object_add(error_info_ir, "version",
300 json_object_new_int(error_info->Version));
301 json_object_object_add(error_info_ir, "length",
302 json_object_new_int(error_info->Length));
303
304 //Validation bitfield.
305 ValidationTypes ui16Type = { UINT_16T,
306 .value.ui16 = error_info->ValidationBits };
307
308 //The type of error information in this log.
309 json_object *error_type = integer_to_readable_pair(
310 error_info->Type, 4, ARM_ERROR_INFO_ENTRY_INFO_TYPES_KEYS,
311 ARM_ERROR_INFO_ENTRY_INFO_TYPES_VALUES, "Unknown (Reserved)");
312 json_object_object_add(error_info_ir, "errorType", error_type);
313
314 //Multiple error count.
315 if (isvalid_prop_to_ir(&ui16Type, 0)) {
316 json_object *multiple_error = json_object_new_object();
317 json_object_object_add(
318 multiple_error, "value",
319 json_object_new_int(error_info->MultipleError));
320 json_object_object_add(
321 multiple_error, "type",
322 json_object_new_string(error_info->MultipleError < 1 ?
323 "Single Error" :
324 "Multiple Errors"));
325 json_object_object_add(error_info_ir, "multipleError",
326 multiple_error);
327 }
328
329 //Flags.
330 if (isvalid_prop_to_ir(&ui16Type, 1)) {
331 json_object *flags = bitfield_to_ir(
332 error_info->Flags, 4, ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
333 json_object_object_add(error_info_ir, "flags", flags);
334 }
335
336 //Error information, split by type.
337 if (isvalid_prop_to_ir(&ui16Type, 2)) {
338 json_object *error_subinfo = NULL;
339 switch (error_info->Type) {
340 case ARM_ERROR_INFORMATION_TYPE_CACHE: //Cache
341 error_subinfo = cper_arm_cache_tlb_error_to_ir(
342 (EFI_ARM_CACHE_ERROR_STRUCTURE *)&error_info
343 ->ErrorInformation,
344 error_info);
345 const char *cache_error_desc = "Cache Error";
346 if (strlen(cache_error_desc) >=
347 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
348 cper_print_log(
349 "Error: Cache Error Description too long %s\n",
350 cache_error_desc);
351 } else {
352 strncpy(*err_info_desc_i, cache_error_desc,
353 strlen(cache_error_desc) + 1);
354 }
355 break;
356 case ARM_ERROR_INFORMATION_TYPE_TLB: //TLB
357 error_subinfo = cper_arm_cache_tlb_error_to_ir(
358 (EFI_ARM_CACHE_ERROR_STRUCTURE *)&error_info
359 ->ErrorInformation,
360 error_info);
361 const char *tlb_error_desc = "TLB Error";
362 if (strlen(tlb_error_desc) >=
363 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
364 cper_print_log(
365 "Error: TLB Error Description too long %s\n",
366 tlb_error_desc);
367 } else {
368 strncpy(*err_info_desc_i, tlb_error_desc,
369 strlen(tlb_error_desc) + 1);
370 }
371 break;
372 case ARM_ERROR_INFORMATION_TYPE_BUS: //Bus
373 error_subinfo = cper_arm_bus_error_to_ir(
374 (EFI_ARM_BUS_ERROR_STRUCTURE *)&error_info
375 ->ErrorInformation);
376 const char *bus_error_desc = "Bus Error";
377 if (strlen(bus_error_desc) >=
378 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
379 cper_print_log(
380 "Error: Bus Error Description too long %s\n",
381 bus_error_desc);
382 } else {
383 strncpy(*err_info_desc_i, bus_error_desc,
384 strlen(bus_error_desc) + 1);
385 }
386 break;
387
388 default:
389 //Unknown/microarch, will not support.
390 break;
391 }
392 if (error_subinfo != NULL) {
393 json_object_object_add(error_info_ir,
394 "errorInformation",
395 error_subinfo);
396 }
397 }
398
399 //Virtual fault address, physical fault address.
400 char *fault_address_desc = malloc(EFI_ERROR_DESCRIPTION_STRING_LEN);
401 if (isvalid_prop_to_ir(&ui16Type, 3)) {
402 outstr_len = snprintf(fault_address_desc,
403 EFI_ERROR_DESCRIPTION_STRING_LEN,
404 " at Virtual Addr=0x%llX",
405 error_info->VirtualFaultAddress);
406 if (outstr_len < 0) {
407 cper_print_log(
408 "Error: Could not write to fault address description string\n");
409 } else if (outstr_len > EFI_ERROR_DESCRIPTION_STRING_LEN) {
410 cper_print_log(
411 "Error: Virtual fault address description string truncated: %s\n",
412 fault_address_desc);
413 } else {
414 if (strlen(fault_address_desc) +
415 strlen(*err_info_desc_i) <
416 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
417 strncat(*err_info_desc_i, fault_address_desc,
418 outstr_len);
419 } else {
420 cper_print_log(
421 "Error: Virtual fault address description string too long, not added to description string: %s\n",
422 fault_address_desc);
423 }
424 }
425 json_object_object_add(
426 error_info_ir, "virtualFaultAddress",
427 json_object_new_uint64(
428 error_info->VirtualFaultAddress));
429 }
430 if (isvalid_prop_to_ir(&ui16Type, 4)) {
431 outstr_len = snprintf(fault_address_desc,
432 EFI_ERROR_DESCRIPTION_STRING_LEN,
433 " Physical Addr=0x%llX",
434 error_info->PhysicalFaultAddress);
435 if (outstr_len < 0) {
436 cper_print_log(
437 "Error: Could not write to physical fault address description string\n");
438 } else if (outstr_len > EFI_ERROR_DESCRIPTION_STRING_LEN) {
439 cper_print_log(
440 "Error: Physical fault address description string truncated: %s\n",
441 fault_address_desc);
442 } else {
443 if (strlen(fault_address_desc) +
444 strlen(*err_info_desc_i) <
445 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
446 strncat(*err_info_desc_i, fault_address_desc,
447 outstr_len);
448 } else {
449 cper_print_log(
450 "Error:Physical fault address description string too long, not added to description string: %s\n",
451 fault_address_desc);
452 }
453 }
454 json_object_object_add(
455 error_info_ir, "physicalFaultAddress",
456 json_object_new_uint64(
457 error_info->PhysicalFaultAddress));
458 }
459
460 free(fault_address_desc);
461
462 return error_info_ir;
463 }
464
465 //Converts a single ARM cache/TLB error information structure into JSON IR format.
466 json_object *
cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE * cache_tlb_error,EFI_ARM_ERROR_INFORMATION_ENTRY * error_info)467 cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
468 EFI_ARM_ERROR_INFORMATION_ENTRY *error_info)
469 {
470 json_object *cache_tlb_error_ir = json_object_new_object();
471 json_object *cache_tlb_prop = json_object_new_object();
472 char *cache_tlb_propname;
473
474 //Validation bitfield.
475 ValidationTypes ui64Type = {
476 UINT_64T, .value.ui64 = cache_tlb_error->ValidationBits
477 };
478
479 //Transaction type.
480 if (isvalid_prop_to_ir(&ui64Type, 0)) {
481 json_object *transaction_type = integer_to_readable_pair(
482 cache_tlb_error->TransactionType, 3,
483 ARM_ERROR_TRANSACTION_TYPES_KEYS,
484 ARM_ERROR_TRANSACTION_TYPES_VALUES,
485 "Unknown (Reserved)");
486 json_object_object_add(cache_tlb_error_ir, "transactionType",
487 transaction_type);
488 }
489
490 //Operation.
491 bool cacheErrorFlag = 1;
492 if (error_info->Type == 0) {
493 cache_tlb_propname = "cacheError";
494 } else {
495 //TLB operation.
496 cache_tlb_propname = "tlbError";
497 cacheErrorFlag = 0;
498 }
499
500 if (isvalid_prop_to_ir(&ui64Type, 1)) {
501 json_object *operation;
502
503 if (cacheErrorFlag) {
504 //Cache operation.
505 operation = integer_to_readable_pair(
506 cache_tlb_error->Operation, 11,
507 ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
508 ARM_CACHE_BUS_OPERATION_TYPES_VALUES,
509 "Unknown (Reserved)");
510 } else {
511 operation = integer_to_readable_pair(
512 cache_tlb_error->Operation, 9,
513 ARM_TLB_OPERATION_TYPES_KEYS,
514 ARM_TLB_OPERATION_TYPES_VALUES,
515 "Unknown (Reserved)");
516 }
517 json_object_object_add(cache_tlb_error_ir, "operation",
518 operation);
519 }
520
521 //Miscellaneous remaining fields.
522 if (isvalid_prop_to_ir(&ui64Type, 2)) {
523 json_object_object_add(
524 cache_tlb_error_ir, "level",
525 json_object_new_int(cache_tlb_error->Level));
526 }
527 if (isvalid_prop_to_ir(&ui64Type, 3)) {
528 json_object_object_add(
529 cache_tlb_error_ir, "processorContextCorrupt",
530 json_object_new_boolean(
531 cache_tlb_error->ProcessorContextCorrupt));
532 }
533 if (isvalid_prop_to_ir(&ui64Type, 4)) {
534 json_object_object_add(
535 cache_tlb_error_ir, "corrected",
536 json_object_new_boolean(cache_tlb_error->Corrected));
537 }
538 if (isvalid_prop_to_ir(&ui64Type, 5)) {
539 json_object_object_add(
540 cache_tlb_error_ir, "precisePC",
541 json_object_new_boolean(cache_tlb_error->PrecisePC));
542 }
543 if (isvalid_prop_to_ir(&ui64Type, 6)) {
544 json_object_object_add(cache_tlb_error_ir, "restartablePC",
545 json_object_new_boolean(
546 cache_tlb_error->RestartablePC));
547 }
548
549 json_object_object_add(cache_tlb_prop, cache_tlb_propname,
550 cache_tlb_error_ir);
551
552 return cache_tlb_prop;
553 }
554
555 //Converts a single ARM bus error information structure into JSON IR format.
cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE * bus_error)556 json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error)
557 {
558 json_object *bus_error_ir = json_object_new_object();
559 json_object *bus_prop = json_object_new_object();
560 char *bus_propname = "busError";
561
562 //Validation bits.
563 ValidationTypes ui64Type = { UINT_64T,
564 .value.ui64 = bus_error->ValidationBits };
565
566 //Transaction type.
567 if (isvalid_prop_to_ir(&ui64Type, 0)) {
568 json_object *transaction_type = integer_to_readable_pair(
569 bus_error->TransactionType, 3,
570 ARM_ERROR_TRANSACTION_TYPES_KEYS,
571 ARM_ERROR_TRANSACTION_TYPES_VALUES,
572 "Unknown (Reserved)");
573 json_object_object_add(bus_error_ir, "transactionType",
574 transaction_type);
575 }
576
577 //Operation.
578 if (isvalid_prop_to_ir(&ui64Type, 1)) {
579 json_object *operation = integer_to_readable_pair(
580 bus_error->Operation, 7,
581 ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
582 ARM_CACHE_BUS_OPERATION_TYPES_VALUES,
583 "Unknown (Reserved)");
584 json_object_object_add(bus_error_ir, "operation", operation);
585 }
586
587 if (isvalid_prop_to_ir(&ui64Type, 2)) {
588 //Affinity level of bus error, + miscellaneous fields.
589 json_object_object_add(bus_error_ir, "level",
590 json_object_new_int(bus_error->Level));
591 }
592 if (isvalid_prop_to_ir(&ui64Type, 3)) {
593 json_object_object_add(
594 bus_error_ir, "processorContextCorrupt",
595 json_object_new_boolean(
596 bus_error->ProcessorContextCorrupt));
597 }
598 if (isvalid_prop_to_ir(&ui64Type, 4)) {
599 json_object_object_add(
600 bus_error_ir, "corrected",
601 json_object_new_boolean(bus_error->Corrected));
602 }
603 if (isvalid_prop_to_ir(&ui64Type, 5)) {
604 json_object_object_add(
605 bus_error_ir, "precisePC",
606 json_object_new_boolean(bus_error->PrecisePC));
607 }
608 if (isvalid_prop_to_ir(&ui64Type, 6)) {
609 json_object_object_add(
610 bus_error_ir, "restartablePC",
611 json_object_new_boolean(bus_error->RestartablePC));
612 }
613
614 //Participation type.
615 if (isvalid_prop_to_ir(&ui64Type, 7)) {
616 json_object *participation_type = integer_to_readable_pair(
617 bus_error->ParticipationType, 4,
618 ARM_BUS_PARTICIPATION_TYPES_KEYS,
619 ARM_BUS_PARTICIPATION_TYPES_VALUES, "Unknown");
620 json_object_object_add(bus_error_ir, "participationType",
621 participation_type);
622 }
623 if (isvalid_prop_to_ir(&ui64Type, 8)) {
624 json_object_object_add(
625 bus_error_ir, "timedOut",
626 json_object_new_boolean(bus_error->TimeOut));
627 }
628
629 //Address space.
630 if (isvalid_prop_to_ir(&ui64Type, 9)) {
631 json_object *address_space = integer_to_readable_pair(
632 bus_error->AddressSpace, 3,
633 ARM_BUS_ADDRESS_SPACE_TYPES_KEYS,
634 ARM_BUS_ADDRESS_SPACE_TYPES_VALUES, "Unknown");
635 json_object_object_add(bus_error_ir, "addressSpace",
636 address_space);
637 }
638
639 //Memory access attributes.
640 //todo: find the specification of these in the ARM ARM
641 if (isvalid_prop_to_ir(&ui64Type, 10)) {
642 json_object_object_add(
643 bus_error_ir, "memoryAttributes",
644 json_object_new_int(
645 bus_error->MemoryAddressAttributes));
646 }
647
648 //Access Mode
649 if (isvalid_prop_to_ir(&ui64Type, 8)) {
650 json_object *access_mode = json_object_new_object();
651 json_object_object_add(
652 access_mode, "value",
653 json_object_new_int(bus_error->AccessMode));
654 json_object_object_add(
655 access_mode, "name",
656 json_object_new_string(bus_error->AccessMode == 0 ?
657 "Secure" :
658 "Normal"));
659 json_object_object_add(bus_error_ir, "accessMode", access_mode);
660 }
661 json_object_object_add(bus_prop, bus_propname, bus_error_ir);
662
663 return bus_prop;
664 }
665
666 //Converts a single ARM processor context block into JSON IR.
667 json_object *
cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER * header,const UINT8 ** cur_pos,UINT32 * remaining_size)668 cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
669 const UINT8 **cur_pos, UINT32 *remaining_size)
670 {
671 if (header->RegisterArraySize > *remaining_size) {
672 cper_print_log(
673 "Invalid CPER file: Invalid processor context info num.\n");
674 return NULL;
675 }
676
677 json_object *context_ir = json_object_new_object();
678
679 //Version.
680 json_object_object_add(context_ir, "version",
681 json_object_new_int(header->Version));
682
683 //Add the context type.
684 json_object *context_type = integer_to_readable_pair(
685 header->RegisterContextType,
686 ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_COUNT,
687 ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_KEYS,
688 ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_VALUES,
689 "Unknown (Reserved)");
690 json_object_object_add(context_ir, "registerContextType", context_type);
691
692 //Register array size (bytes).
693 json_object_object_add(
694 context_ir, "registerArraySize",
695 json_object_new_uint64(header->RegisterArraySize));
696
697 //The register array itself.
698 json_object *register_array = NULL;
699 switch (header->RegisterContextType) {
700 case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
701 if (*remaining_size < sizeof(EFI_ARM_V8_AARCH32_GPR)) {
702 cper_print_log(
703 "Invalid CPER file: Invalid processor context info num.\n");
704 goto fail;
705 }
706 if (header->RegisterArraySize <
707 sizeof(EFI_ARM_V8_AARCH32_GPR)) {
708 cper_print_log(
709 "Invalid CPER file: Not enough bytes for aarch32 gpr\n");
710 goto fail;
711 }
712 register_array = uniform_struct_to_ir(
713 (UINT32 *)*cur_pos,
714 sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
715 ARM_AARCH32_GPR_NAMES);
716 break;
717 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
718 if (*remaining_size <
719 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS)) {
720 cper_print_log(
721 "Invalid CPER file: Invalid processor context info num.\n");
722 goto fail;
723 }
724 if (header->RegisterArraySize <
725 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS)) {
726 cper_print_log(
727 "Invalid CPER file: Not enough bytes for aarch32 el1\n");
728 goto fail;
729 }
730 register_array = uniform_struct_to_ir(
731 (UINT32 *)*cur_pos,
732 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
733 sizeof(UINT32),
734 ARM_AARCH32_EL1_REGISTER_NAMES);
735 break;
736 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
737 if (*remaining_size <
738 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS)) {
739 cper_print_log(
740 "Invalid CPER file: Invalid processor context info num.\n");
741 goto fail;
742 }
743 if (header->RegisterArraySize <
744 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS)) {
745 cper_print_log(
746 "Invalid CPER file: Not enough bytes for aarch32 el2\n");
747 goto fail;
748 }
749 register_array = uniform_struct_to_ir(
750 (UINT32 *)*cur_pos,
751 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
752 sizeof(UINT32),
753 ARM_AARCH32_EL2_REGISTER_NAMES);
754
755 break;
756 case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
757 if (*remaining_size <
758 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS)) {
759 json_object_put(context_ir);
760 cper_print_log(
761 "Invalid CPER file: Invalid processor context info num.\n");
762 return NULL;
763 }
764 if (header->RegisterArraySize <
765 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS)) {
766 cper_print_log(
767 "Invalid CPER file: Not enough bytes for aarch32 secure\n");
768 goto fail;
769 }
770 register_array = uniform_struct_to_ir(
771 (UINT32 *)*cur_pos,
772 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
773 sizeof(UINT32),
774 ARM_AARCH32_SECURE_REGISTER_NAMES);
775 break;
776 case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
777 if (*remaining_size < sizeof(EFI_ARM_V8_AARCH64_GPR)) {
778 cper_print_log(
779 "Invalid CPER file: Invalid processor context info num.\n");
780 goto fail;
781 }
782 if (header->RegisterArraySize <
783 sizeof(EFI_ARM_V8_AARCH64_GPR)) {
784 cper_print_log(
785 "Invalid CPER file: Not enough bytes for aarch64 gpr\n");
786 goto fail;
787 }
788 register_array = uniform_struct64_to_ir(
789 (UINT64 *)*cur_pos,
790 sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
791 ARM_AARCH64_GPR_NAMES);
792 break;
793 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
794 if (*remaining_size <
795 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS)) {
796 cper_print_log(
797 "Invalid CPER file: Invalid processor context info num.\n");
798 goto fail;
799 }
800 if (header->RegisterArraySize <
801 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS)) {
802 cper_print_log(
803 "Invalid CPER file: Not enough bytes for aarch64 el1\n");
804 goto fail;
805 }
806 register_array = uniform_struct64_to_ir(
807 (UINT64 *)*cur_pos,
808 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
809 sizeof(UINT64),
810 ARM_AARCH64_EL1_REGISTER_NAMES);
811 break;
812 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
813 if (*remaining_size <
814 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS)) {
815 cper_print_log(
816 "Invalid CPER file: Invalid processor context info num.\n");
817 goto fail;
818 }
819 if (header->RegisterArraySize <
820 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS)) {
821 cper_print_log(
822 "Invalid CPER file: Not enough bytes for aarch64 el2\n");
823 goto fail;
824 }
825 register_array = uniform_struct64_to_ir(
826 (UINT64 *)*cur_pos,
827 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
828 sizeof(UINT64),
829 ARM_AARCH64_EL2_REGISTER_NAMES);
830 break;
831 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
832 if (*remaining_size <
833 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS)) {
834 cper_print_log(
835 "Invalid CPER file: Invalid processor context info num.\n");
836 goto fail;
837 }
838 if (header->RegisterArraySize <
839 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS)) {
840 cper_print_log(
841 "Invalid CPER file: Not enough bytes for aarch64 el3\n");
842 goto fail;
843 }
844 register_array = uniform_struct64_to_ir(
845 (UINT64 *)*cur_pos,
846 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
847 sizeof(UINT64),
848 ARM_AARCH64_EL3_REGISTER_NAMES);
849 break;
850 case EFI_ARM_CONTEXT_TYPE_MISC:
851 if (*remaining_size < sizeof(EFI_ARM_MISC_CONTEXT_REGISTER)) {
852 cper_print_log(
853 "Invalid CPER file: Invalid processor context info num.\n");
854 goto fail;
855 }
856 if (header->RegisterArraySize <
857 sizeof(EFI_ARM_MISC_CONTEXT_REGISTER)) {
858 cper_print_log(
859 "Invalid CPER file: Not enough bytes for misc\n");
860 goto fail;
861 }
862 register_array = cper_arm_misc_register_array_to_ir(
863 (EFI_ARM_MISC_CONTEXT_REGISTER *)*cur_pos);
864 break;
865 default:
866 if (*remaining_size < header->RegisterArraySize) {
867 cper_print_log(
868 "Invalid CPER file: Invalid processor context info num.\n");
869 goto fail;
870 }
871 //Unknown register array type, add as base64 data instead.
872 int32_t encoded_len = 0;
873 char *encoded = base64_encode((UINT8 *)*cur_pos,
874 header->RegisterArraySize,
875 &encoded_len);
876 if (encoded == NULL) {
877 goto fail;
878 }
879 register_array = json_object_new_object();
880 json_object_object_add(register_array, "data",
881 json_object_new_string_len(encoded,
882 encoded_len));
883 free(encoded);
884
885 break;
886 }
887 json_object_object_add(context_ir, "registerArray", register_array);
888
889 //Set the current position to after the processor context structure.
890 *cur_pos = (UINT8 *)(*cur_pos) + header->RegisterArraySize;
891 *remaining_size -= header->RegisterArraySize;
892
893 return context_ir;
894
895 fail:
896 json_object_put(context_ir);
897 return NULL;
898 }
899
900 //Converts a single CPER ARM miscellaneous register array to JSON IR format.
901 json_object *
cper_arm_misc_register_array_to_ir(EFI_ARM_MISC_CONTEXT_REGISTER * misc_register)902 cper_arm_misc_register_array_to_ir(EFI_ARM_MISC_CONTEXT_REGISTER *misc_register)
903 {
904 json_object *register_array = json_object_new_object();
905 json_object *mrs_encoding = json_object_new_object();
906 json_object_object_add(mrs_encoding, "op2",
907 json_object_new_uint64(misc_register->MrsOp2));
908 json_object_object_add(mrs_encoding, "crm",
909 json_object_new_uint64(misc_register->MrsCrm));
910 json_object_object_add(mrs_encoding, "crn",
911 json_object_new_uint64(misc_register->MrsCrn));
912 json_object_object_add(mrs_encoding, "op1",
913 json_object_new_uint64(misc_register->MrsOp1));
914 json_object_object_add(mrs_encoding, "o0",
915 json_object_new_uint64(misc_register->MrsO0));
916 json_object_object_add(register_array, "mrsEncoding", mrs_encoding);
917 json_object_object_add(register_array, "value",
918 json_object_new_uint64(misc_register->Value));
919
920 return register_array;
921 }
922
923 //Converts a single CPER-JSON ARM error section into CPER binary, outputting to the given stream.
ir_section_arm_to_cper(json_object * section,FILE * out)924 void ir_section_arm_to_cper(json_object *section, FILE *out)
925 {
926 EFI_ARM_ERROR_RECORD section_cper;
927 memset(§ion_cper, 0, sizeof(section_cper));
928
929 //Validation bits.
930 struct json_object *obj = NULL;
931 ValidationTypes u32Type = { UINT_32T, .value.ui32 = 0 };
932
933 //Count of error/context info structures.
934 section_cper.ErrInfoNum = json_object_get_int(
935 json_object_object_get(section, "errorInfoNum"));
936 section_cper.ContextInfoNum = json_object_get_int(
937 json_object_object_get(section, "contextInfoNum"));
938
939 //Miscellaneous raw value fields.
940 section_cper.SectionLength = json_object_get_uint64(
941 json_object_object_get(section, "sectionLength"));
942 if (json_object_object_get_ex(section, "mpidrEl1", &obj)) {
943 section_cper.MPIDR_EL1 = json_object_get_uint64(obj);
944 add_to_valid_bitfield(&u32Type, 0);
945 }
946 if (json_object_object_get_ex(section, "errorAffinity", &obj)) {
947 section_cper.ErrorAffinityLevel = readable_pair_to_integer(obj);
948 add_to_valid_bitfield(&u32Type, 1);
949 }
950 section_cper.MIDR_EL1 = json_object_get_uint64(
951 json_object_object_get(section, "midrEl1"));
952 if (json_object_object_get_ex(section, "running", &obj)) {
953 section_cper.RunningState = json_object_get_boolean(obj);
954 add_to_valid_bitfield(&u32Type, 2);
955 }
956
957 //Optional PSCI state.
958 json_object *psci_state = json_object_object_get(section, "psciState");
959 if (psci_state != NULL) {
960 section_cper.PsciState = json_object_get_uint64(psci_state);
961 }
962
963 //Validationbits for EFI_ARM_ERROR_RECORD should also consider vendorSpecificInfo
964 bool vendorSpecificPresent =
965 json_object_object_get_ex(section, "vendorSpecificInfo", &obj);
966 json_object *vendor_specific_info = obj;
967 if (vendorSpecificPresent) {
968 add_to_valid_bitfield(&u32Type, 3);
969 }
970
971 section_cper.ValidFields = u32Type.value.ui32;
972
973 //Flush header to stream.
974 fwrite(§ion_cper, sizeof(section_cper), 1, out);
975
976 //Error info structure array.
977
978 json_object *error_info = json_object_object_get(section, "errorInfo");
979 for (int i = 0; i < section_cper.ErrInfoNum; i++) {
980 ir_arm_error_info_to_cper(
981 json_object_array_get_idx(error_info, i), out);
982 }
983
984 //Context info structure array.
985 json_object *context_info =
986 json_object_object_get(section, "contextInfo");
987 for (int i = 0; i < section_cper.ContextInfoNum; i++) {
988 ir_arm_context_info_to_cper(
989 json_object_array_get_idx(context_info, i), out);
990 }
991
992 //Vendor specific error info.
993 if (vendorSpecificPresent) {
994 json_object *vendor_info_string =
995 json_object_object_get(vendor_specific_info, "data");
996 int vendor_specific_len =
997 json_object_get_string_len(vendor_info_string);
998
999 int32_t decoded_len = 0;
1000
1001 UINT8 *decoded = base64_decode(
1002 json_object_get_string(vendor_info_string),
1003 vendor_specific_len, &decoded_len);
1004
1005 //Write out to file.
1006 fwrite(decoded, decoded_len, 1, out);
1007 free(decoded);
1008 }
1009
1010 fflush(out);
1011 }
1012
1013 //Converts a single ARM error information structure into CPER binary, outputting to the given stream.
ir_arm_error_info_to_cper(json_object * error_info,FILE * out)1014 void ir_arm_error_info_to_cper(json_object *error_info, FILE *out)
1015 {
1016 EFI_ARM_ERROR_INFORMATION_ENTRY error_info_cper;
1017 memset(&error_info_cper, 0, sizeof(error_info_cper));
1018 struct json_object *obj = NULL;
1019 ValidationTypes ui16Type = { UINT_16T, .value.ui16 = 0 };
1020
1021 //Version, length.
1022 error_info_cper.Version = json_object_get_int(
1023 json_object_object_get(error_info, "version"));
1024 error_info_cper.Length = json_object_get_int(
1025 json_object_object_get(error_info, "length"));
1026
1027 //Type, multiple error.
1028 error_info_cper.Type = (UINT8)readable_pair_to_integer(
1029 json_object_object_get(error_info, "errorType"));
1030
1031 if (json_object_object_get_ex(error_info, "multipleError", &obj)) {
1032 error_info_cper.MultipleError =
1033 (UINT16)readable_pair_to_integer(obj);
1034 add_to_valid_bitfield(&ui16Type, 0);
1035 } else {
1036 error_info_cper.MultipleError = 0;
1037 }
1038
1039 //Flags object.
1040 if (json_object_object_get_ex(error_info, "flags", &obj)) {
1041 error_info_cper.Flags = (UINT8)ir_to_bitfield(
1042 obj, 4, ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
1043 add_to_valid_bitfield(&ui16Type, 1);
1044 } else {
1045 error_info_cper.Flags = 0;
1046 }
1047
1048 //Error information.
1049 if (json_object_object_get_ex(error_info, "errorInformation", &obj)) {
1050 json_object *error_info_information = obj;
1051 json_object *error_info_prop = NULL;
1052 switch (error_info_cper.Type) {
1053 case ARM_ERROR_INFORMATION_TYPE_CACHE:
1054 error_info_cper.ErrorInformation.Value = 0;
1055 error_info_prop = json_object_object_get(
1056 error_info_information, "cacheError");
1057 ir_arm_error_cache_tlb_info_to_cper(
1058 error_info_prop,
1059 &error_info_cper.ErrorInformation.CacheError);
1060 break;
1061 case ARM_ERROR_INFORMATION_TYPE_TLB:
1062 error_info_cper.ErrorInformation.Value = 0;
1063 error_info_prop = json_object_object_get(
1064 error_info_information, "tlbError");
1065 ir_arm_error_cache_tlb_info_to_cper(
1066 error_info_prop,
1067 &error_info_cper.ErrorInformation.CacheError);
1068 break;
1069
1070 case ARM_ERROR_INFORMATION_TYPE_BUS:
1071 error_info_cper.ErrorInformation.Value = 0;
1072 error_info_prop = json_object_object_get(
1073 error_info_information, "busError");
1074 ir_arm_error_bus_info_to_cper(
1075 error_info_prop,
1076 &error_info_cper.ErrorInformation.BusError);
1077 break;
1078
1079 default:
1080 //Unknown error information type.
1081 break;
1082 }
1083 add_to_valid_bitfield(&ui16Type, 2);
1084 }
1085
1086 //Virtual/physical fault address.
1087 if (json_object_object_get_ex(error_info, "virtualFaultAddress",
1088 &obj)) {
1089 error_info_cper.VirtualFaultAddress =
1090 json_object_get_uint64(obj);
1091 add_to_valid_bitfield(&ui16Type, 3);
1092 } else {
1093 error_info_cper.VirtualFaultAddress = 0;
1094 }
1095
1096 if (json_object_object_get_ex(error_info, "physicalFaultAddress",
1097 &obj)) {
1098 error_info_cper.PhysicalFaultAddress =
1099 json_object_get_uint64(obj);
1100 add_to_valid_bitfield(&ui16Type, 4);
1101 } else {
1102 error_info_cper.PhysicalFaultAddress = 0;
1103 }
1104 error_info_cper.ValidationBits = ui16Type.value.ui16;
1105
1106 //Write out to stream.
1107 fwrite(&error_info_cper, sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY), 1,
1108 out);
1109 }
1110
1111 //Converts a single ARM cache/TLB error information structure into a CPER structure.
ir_arm_error_cache_tlb_info_to_cper(json_object * error_information,EFI_ARM_CACHE_ERROR_STRUCTURE * error_info_cper)1112 void ir_arm_error_cache_tlb_info_to_cper(
1113 json_object *error_information,
1114 EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper)
1115 {
1116 // //Validation bits.
1117 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
1118 struct json_object *obj = NULL;
1119
1120 //Miscellaneous value fields.
1121 if (json_object_object_get_ex(error_information, "transactionType",
1122 &obj)) {
1123 error_info_cper->TransactionType =
1124 readable_pair_to_integer(obj);
1125 add_to_valid_bitfield(&ui64Type, 0);
1126 }
1127 if (json_object_object_get_ex(error_information, "operation", &obj)) {
1128 error_info_cper->Operation = readable_pair_to_integer(obj);
1129 add_to_valid_bitfield(&ui64Type, 1);
1130 }
1131 if (json_object_object_get_ex(error_information, "level", &obj)) {
1132 error_info_cper->Level = json_object_get_uint64(obj);
1133 add_to_valid_bitfield(&ui64Type, 2);
1134 }
1135 if (json_object_object_get_ex(error_information,
1136 "processorContextCorrupt", &obj)) {
1137 error_info_cper->ProcessorContextCorrupt =
1138 json_object_get_boolean(obj);
1139 add_to_valid_bitfield(&ui64Type, 3);
1140 }
1141 if (json_object_object_get_ex(error_information, "corrected", &obj)) {
1142 error_info_cper->Corrected = json_object_get_boolean(obj);
1143 add_to_valid_bitfield(&ui64Type, 4);
1144 }
1145 if (json_object_object_get_ex(error_information, "precisePC", &obj)) {
1146 error_info_cper->PrecisePC = json_object_get_boolean(obj);
1147 add_to_valid_bitfield(&ui64Type, 5);
1148 }
1149 if (json_object_object_get_ex(error_information, "restartablePC",
1150 &obj)) {
1151 error_info_cper->RestartablePC = json_object_get_boolean(obj);
1152 add_to_valid_bitfield(&ui64Type, 6);
1153 }
1154 error_info_cper->Reserved = 0;
1155 error_info_cper->ValidationBits = ui64Type.value.ui64;
1156 }
1157
1158 //Converts a single ARM bus error information structure into a CPER structure.
ir_arm_error_bus_info_to_cper(json_object * error_information,EFI_ARM_BUS_ERROR_STRUCTURE * error_info_cper)1159 void ir_arm_error_bus_info_to_cper(json_object *error_information,
1160 EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper)
1161 {
1162 //Validation bits.
1163 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
1164 struct json_object *obj = NULL;
1165
1166 memset(error_info_cper, 0, sizeof(EFI_ARM_BUS_ERROR_STRUCTURE));
1167
1168 //Miscellaneous value fields.
1169 if (json_object_object_get_ex(error_information, "transactionType",
1170 &obj)) {
1171 error_info_cper->TransactionType =
1172 readable_pair_to_integer(obj);
1173 add_to_valid_bitfield(&ui64Type, 0);
1174 } else {
1175 error_info_cper->TransactionType = 0;
1176 }
1177 if (json_object_object_get_ex(error_information, "operation", &obj)) {
1178 error_info_cper->Operation = readable_pair_to_integer(obj);
1179 add_to_valid_bitfield(&ui64Type, 1);
1180 } else {
1181 error_info_cper->Operation = 0;
1182 }
1183 if (json_object_object_get_ex(error_information, "level", &obj)) {
1184 error_info_cper->Level = json_object_get_uint64(obj);
1185 add_to_valid_bitfield(&ui64Type, 2);
1186 } else {
1187 error_info_cper->Level = 0;
1188 }
1189 if (json_object_object_get_ex(error_information,
1190 "processorContextCorrupt", &obj)) {
1191 error_info_cper->ProcessorContextCorrupt =
1192 json_object_get_boolean(obj);
1193 add_to_valid_bitfield(&ui64Type, 3);
1194 } else {
1195 error_info_cper->ProcessorContextCorrupt = 0;
1196 }
1197 if (json_object_object_get_ex(error_information, "corrected", &obj)) {
1198 error_info_cper->Corrected = json_object_get_boolean(obj);
1199 add_to_valid_bitfield(&ui64Type, 4);
1200 } else {
1201 error_info_cper->Corrected = 0;
1202 }
1203 if (json_object_object_get_ex(error_information, "precisePC", &obj)) {
1204 error_info_cper->PrecisePC = json_object_get_boolean(obj);
1205 add_to_valid_bitfield(&ui64Type, 5);
1206 } else {
1207 error_info_cper->PrecisePC = 0;
1208 }
1209 if (json_object_object_get_ex(error_information, "restartablePC",
1210 &obj)) {
1211 error_info_cper->RestartablePC = json_object_get_boolean(obj);
1212 add_to_valid_bitfield(&ui64Type, 6);
1213 } else {
1214 error_info_cper->RestartablePC = 0;
1215 }
1216 if (json_object_object_get_ex(error_information, "participationType",
1217 &obj)) {
1218 error_info_cper->ParticipationType =
1219 readable_pair_to_integer(obj);
1220 add_to_valid_bitfield(&ui64Type, 7);
1221 } else {
1222 error_info_cper->ParticipationType = 0;
1223 }
1224 if (json_object_object_get_ex(error_information, "timedOut", &obj)) {
1225 error_info_cper->TimeOut = json_object_get_boolean(obj);
1226 add_to_valid_bitfield(&ui64Type, 8);
1227 } else {
1228 error_info_cper->TimeOut = 0;
1229 }
1230 if (json_object_object_get_ex(error_information, "addressSpace",
1231 &obj)) {
1232 error_info_cper->AddressSpace = readable_pair_to_integer(obj);
1233 add_to_valid_bitfield(&ui64Type, 9);
1234 } else {
1235 error_info_cper->AddressSpace = 0;
1236 }
1237 if (json_object_object_get_ex(error_information, "accessMode", &obj)) {
1238 error_info_cper->AccessMode = readable_pair_to_integer(obj);
1239 add_to_valid_bitfield(&ui64Type, 11);
1240 } else {
1241 error_info_cper->AccessMode = 0;
1242 }
1243 if (json_object_object_get_ex(error_information, "memoryAttributes",
1244 &obj)) {
1245 error_info_cper->MemoryAddressAttributes =
1246 json_object_get_uint64(obj);
1247 add_to_valid_bitfield(&ui64Type, 10);
1248 } else {
1249 error_info_cper->MemoryAddressAttributes = 0;
1250 }
1251 error_info_cper->Reserved = 0;
1252 error_info_cper->ValidationBits = ui64Type.value.ui64;
1253 }
1254
1255 //Converts a single ARM context information structure into CPER binary, outputting to the given stream.
ir_arm_context_info_to_cper(json_object * context_info,FILE * out)1256 void ir_arm_context_info_to_cper(json_object *context_info, FILE *out)
1257 {
1258 EFI_ARM_CONTEXT_INFORMATION_HEADER info_header;
1259
1260 //Version, array size, context type.
1261 info_header.Version = json_object_get_int(
1262 json_object_object_get(context_info, "version"));
1263 info_header.RegisterArraySize = json_object_get_int(
1264 json_object_object_get(context_info, "registerArraySize"));
1265 info_header.RegisterContextType = readable_pair_to_integer(
1266 json_object_object_get(context_info, "registerContextType"));
1267
1268 //Flush to stream, write the register array itself.
1269 fwrite(&info_header, sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER), 1,
1270 out);
1271 fflush(out);
1272
1273 json_object *register_array =
1274 json_object_object_get(context_info, "registerArray");
1275 switch (info_header.RegisterContextType) {
1276 case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
1277 ir_arm_aarch32_gpr_to_cper(register_array, out);
1278 break;
1279 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
1280 ir_arm_aarch32_el1_to_cper(register_array, out);
1281 break;
1282 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
1283 ir_arm_aarch32_el2_to_cper(register_array, out);
1284 break;
1285 case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
1286 ir_arm_aarch32_secure_to_cper(register_array, out);
1287 break;
1288 case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
1289 ir_arm_aarch64_gpr_to_cper(register_array, out);
1290 break;
1291 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
1292 ir_arm_aarch64_el1_to_cper(register_array, out);
1293 break;
1294 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
1295 ir_arm_aarch64_el2_to_cper(register_array, out);
1296 break;
1297 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
1298 ir_arm_aarch64_el3_to_cper(register_array, out);
1299 break;
1300 case EFI_ARM_CONTEXT_TYPE_MISC:
1301 ir_arm_misc_registers_to_cper(register_array, out);
1302 break;
1303 default:
1304 //Unknown register structure.
1305 ir_arm_unknown_register_to_cper(register_array, out);
1306 break;
1307 }
1308 }
1309
1310 //Converts a single AARCH32 GPR CPER-JSON object to CPER binary, outputting to the given stream.
ir_arm_aarch32_gpr_to_cper(json_object * registers,FILE * out)1311 void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out)
1312 {
1313 //Get uniform register array.
1314 EFI_ARM_V8_AARCH32_GPR reg_array;
1315 ir_to_uniform_struct(registers, (UINT32 *)®_array,
1316 sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
1317 ARM_AARCH32_GPR_NAMES);
1318
1319 //Flush to stream.
1320 fwrite(®_array, sizeof(reg_array), 1, out);
1321 fflush(out);
1322 }
1323
1324 //Converts a single AARCH32 EL1 register set CPER-JSON object to CPER binary, outputting to the given stream.
ir_arm_aarch32_el1_to_cper(json_object * registers,FILE * out)1325 void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out)
1326 {
1327 //Get uniform register array.
1328 EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS reg_array;
1329 ir_to_uniform_struct(registers, (UINT32 *)®_array,
1330 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
1331 sizeof(UINT32),
1332 ARM_AARCH32_EL1_REGISTER_NAMES);
1333
1334 //Flush to stream.
1335 fwrite(®_array, sizeof(reg_array), 1, out);
1336 fflush(out);
1337 }
1338
1339 //Converts a single AARCH32 EL2 register set CPER-JSON object to CPER binary, outputting to the given stream.
ir_arm_aarch32_el2_to_cper(json_object * registers,FILE * out)1340 void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out)
1341 {
1342 //Get uniform register array.
1343 EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS reg_array;
1344 ir_to_uniform_struct(registers, (UINT32 *)®_array,
1345 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
1346 sizeof(UINT32),
1347 ARM_AARCH32_EL2_REGISTER_NAMES);
1348
1349 //Flush to stream.
1350 fwrite(®_array, sizeof(reg_array), 1, out);
1351 fflush(out);
1352 }
1353
1354 //Converts a single AARCH32 secure register set CPER-JSON object to CPER binary, outputting to the given stream.
ir_arm_aarch32_secure_to_cper(json_object * registers,FILE * out)1355 void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out)
1356 {
1357 //Get uniform register array.
1358 EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS reg_array;
1359 ir_to_uniform_struct(registers, (UINT32 *)®_array,
1360 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
1361 sizeof(UINT32),
1362 ARM_AARCH32_SECURE_REGISTER_NAMES);
1363
1364 //Flush to stream.
1365 fwrite(®_array, sizeof(reg_array), 1, out);
1366 fflush(out);
1367 }
1368
1369 //Converts a single AARCH64 GPR CPER-JSON object to CPER binary, outputting to the given stream.
ir_arm_aarch64_gpr_to_cper(json_object * registers,FILE * out)1370 void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out)
1371 {
1372 //Get uniform register array.
1373 EFI_ARM_V8_AARCH64_GPR reg_array;
1374 ir_to_uniform_struct64(registers, (UINT64 *)®_array,
1375 sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
1376 ARM_AARCH64_GPR_NAMES);
1377
1378 //Flush to stream.
1379 fwrite(®_array, sizeof(reg_array), 1, out);
1380 fflush(out);
1381 }
1382
1383 //Converts a single AARCH64 EL1 register set CPER-JSON object to CPER binary, outputting to the given stream.
ir_arm_aarch64_el1_to_cper(json_object * registers,FILE * out)1384 void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out)
1385 {
1386 //Get uniform register array.
1387 EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS reg_array;
1388 ir_to_uniform_struct64(registers, (UINT64 *)®_array,
1389 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
1390 sizeof(UINT64),
1391 ARM_AARCH64_EL1_REGISTER_NAMES);
1392
1393 //Flush to stream.
1394 fwrite(®_array, sizeof(reg_array), 1, out);
1395 fflush(out);
1396 }
1397
1398 //Converts a single AARCH64 EL2 register set CPER-JSON object to CPER binary, outputting to the given stream.
ir_arm_aarch64_el2_to_cper(json_object * registers,FILE * out)1399 void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out)
1400 {
1401 //Get uniform register array.
1402 EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS reg_array;
1403 ir_to_uniform_struct64(registers, (UINT64 *)®_array,
1404 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
1405 sizeof(UINT64),
1406 ARM_AARCH64_EL2_REGISTER_NAMES);
1407
1408 //Flush to stream.
1409 fwrite(®_array, sizeof(reg_array), 1, out);
1410 fflush(out);
1411 }
1412
1413 //Converts a single AARCH64 EL3 register set CPER-JSON object to CPER binary, outputting to the given stream.
ir_arm_aarch64_el3_to_cper(json_object * registers,FILE * out)1414 void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out)
1415 {
1416 //Get uniform register array.
1417 EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS reg_array;
1418 ir_to_uniform_struct64(registers, (UINT64 *)®_array,
1419 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
1420 sizeof(UINT64),
1421 ARM_AARCH64_EL3_REGISTER_NAMES);
1422
1423 //Flush to stream.
1424 fwrite(®_array, sizeof(reg_array), 1, out);
1425 fflush(out);
1426 }
1427
1428 //Converts a single ARM miscellaneous register set CPER-JSON object to CPER binary, outputting to the given stream.
ir_arm_misc_registers_to_cper(json_object * registers,FILE * out)1429 void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out)
1430 {
1431 EFI_ARM_MISC_CONTEXT_REGISTER reg_array;
1432
1433 //MRS encoding information.
1434 json_object *mrs_encoding =
1435 json_object_object_get(registers, "mrsEncoding");
1436 reg_array.MrsOp2 = json_object_get_uint64(
1437 json_object_object_get(mrs_encoding, "op2"));
1438 reg_array.MrsCrm = json_object_get_uint64(
1439 json_object_object_get(mrs_encoding, "crm"));
1440 reg_array.MrsCrn = json_object_get_uint64(
1441 json_object_object_get(mrs_encoding, "crn"));
1442 reg_array.MrsOp1 = json_object_get_uint64(
1443 json_object_object_get(mrs_encoding, "op1"));
1444 reg_array.MrsO0 = json_object_get_uint64(
1445 json_object_object_get(mrs_encoding, "o0"));
1446
1447 //Actual register value.
1448 reg_array.Value = json_object_get_uint64(
1449 json_object_object_get(registers, "value"));
1450
1451 //Flush to stream.
1452 fwrite(®_array, sizeof(reg_array), 1, out);
1453 fflush(out);
1454 }
1455
1456 //Converts a single ARM unknown register CPER-JSON object to CPER binary, outputting to the given stream.
ir_arm_unknown_register_to_cper(json_object * registers,FILE * out)1457 void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out)
1458 {
1459 //Get base64 represented data.
1460 json_object *encoded = json_object_object_get(registers, "data");
1461
1462 int32_t decoded_len = 0;
1463
1464 UINT8 *decoded = base64_decode(json_object_get_string(encoded),
1465 json_object_get_string_len(encoded),
1466 &decoded_len);
1467
1468 if (decoded == NULL) {
1469 cper_print_log("Failed to allocate decode output buffer. \n");
1470 } else {
1471 //Flush out to stream.
1472 fwrite(&decoded, decoded_len, 1, out);
1473 fflush(out);
1474 free(decoded);
1475 }
1476 }
1477