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