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 == ARM_ERROR_INFORMATION_TYPE_CACHE) {
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
1051 if (json_object_object_get_ex(error_info, "errorType", &obj)) {
1052 error_info_cper.Type = readable_pair_to_integer(obj);
1053 } else {
1054 error_info_cper.Type = 0;
1055 }
1056
1057 //multiple error.
1058 if (json_object_object_get_ex(error_info, "multipleError", &obj)) {
1059 error_info_cper.MultipleError =
1060 (UINT16)readable_pair_to_integer(obj);
1061 add_to_valid_bitfield(&ui16Type, 0);
1062 } else {
1063 error_info_cper.MultipleError = 0;
1064 }
1065
1066 //Flags object.
1067 if (json_object_object_get_ex(error_info, "flags", &obj)) {
1068 error_info_cper.Flags = (UINT8)ir_to_bitfield(
1069 obj, 4, ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
1070 add_to_valid_bitfield(&ui16Type, 1);
1071 } else {
1072 error_info_cper.Flags = 0;
1073 }
1074
1075 //Error information.
1076 if (json_object_object_get_ex(error_info, "errorInformation", &obj)) {
1077 json_object *error_info_information = obj;
1078 json_object *error_info_prop = NULL;
1079 switch (error_info_cper.Type) {
1080 case ARM_ERROR_INFORMATION_TYPE_CACHE:
1081 error_info_cper.ErrorInformation.Value = 0;
1082 error_info_prop = json_object_object_get(
1083 error_info_information, "cacheError");
1084 ir_arm_error_cache_tlb_info_to_cper(
1085 error_info_prop,
1086 &error_info_cper.ErrorInformation.CacheError);
1087 break;
1088 case ARM_ERROR_INFORMATION_TYPE_TLB:
1089 error_info_cper.ErrorInformation.Value = 0;
1090 error_info_prop = json_object_object_get(
1091 error_info_information, "tlbError");
1092 ir_arm_error_cache_tlb_info_to_cper(
1093 error_info_prop,
1094 &error_info_cper.ErrorInformation.CacheError);
1095 break;
1096
1097 case ARM_ERROR_INFORMATION_TYPE_BUS:
1098 error_info_cper.ErrorInformation.Value = 0;
1099 error_info_prop = json_object_object_get(
1100 error_info_information, "busError");
1101 ir_arm_error_bus_info_to_cper(
1102 error_info_prop,
1103 &error_info_cper.ErrorInformation.BusError);
1104 break;
1105
1106 default:
1107 //Unknown error information type.
1108 break;
1109 }
1110 add_to_valid_bitfield(&ui16Type, 2);
1111 }
1112
1113 //Virtual/physical fault address.
1114 if (json_object_object_get_ex(error_info, "virtualFaultAddress",
1115 &obj)) {
1116 error_info_cper.VirtualFaultAddress =
1117 json_object_get_uint64(obj);
1118 add_to_valid_bitfield(&ui16Type, 3);
1119 } else {
1120 error_info_cper.VirtualFaultAddress = 0;
1121 }
1122
1123 if (json_object_object_get_ex(error_info, "physicalFaultAddress",
1124 &obj)) {
1125 error_info_cper.PhysicalFaultAddress =
1126 json_object_get_uint64(obj);
1127 add_to_valid_bitfield(&ui16Type, 4);
1128 } else {
1129 error_info_cper.PhysicalFaultAddress = 0;
1130 }
1131 error_info_cper.ValidationBits = ui16Type.value.ui16;
1132
1133 //Write out to stream.
1134 fwrite(&error_info_cper, sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY), 1,
1135 out);
1136 }
1137
1138 //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)1139 void ir_arm_error_cache_tlb_info_to_cper(
1140 json_object *error_information,
1141 EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper)
1142 {
1143 // //Validation bits.
1144 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
1145 struct json_object *obj = NULL;
1146
1147 //Miscellaneous value fields.
1148 if (json_object_object_get_ex(error_information, "transactionType",
1149 &obj)) {
1150 error_info_cper->TransactionType =
1151 readable_pair_to_integer(obj);
1152 add_to_valid_bitfield(&ui64Type, 0);
1153 }
1154 if (json_object_object_get_ex(error_information, "operation", &obj)) {
1155 error_info_cper->Operation = readable_pair_to_integer(obj);
1156 add_to_valid_bitfield(&ui64Type, 1);
1157 }
1158 if (json_object_object_get_ex(error_information, "level", &obj)) {
1159 error_info_cper->Level = json_object_get_uint64(obj);
1160 add_to_valid_bitfield(&ui64Type, 2);
1161 }
1162 if (json_object_object_get_ex(error_information,
1163 "processorContextCorrupt", &obj)) {
1164 error_info_cper->ProcessorContextCorrupt =
1165 json_object_get_boolean(obj);
1166 add_to_valid_bitfield(&ui64Type, 3);
1167 }
1168 if (json_object_object_get_ex(error_information, "corrected", &obj)) {
1169 error_info_cper->Corrected = json_object_get_boolean(obj);
1170 add_to_valid_bitfield(&ui64Type, 4);
1171 }
1172 if (json_object_object_get_ex(error_information, "precisePC", &obj)) {
1173 error_info_cper->PrecisePC = json_object_get_boolean(obj);
1174 add_to_valid_bitfield(&ui64Type, 5);
1175 }
1176 if (json_object_object_get_ex(error_information, "restartablePC",
1177 &obj)) {
1178 error_info_cper->RestartablePC = json_object_get_boolean(obj);
1179 add_to_valid_bitfield(&ui64Type, 6);
1180 }
1181 error_info_cper->Reserved = 0;
1182 error_info_cper->ValidationBits = ui64Type.value.ui64;
1183 }
1184
1185 //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)1186 void ir_arm_error_bus_info_to_cper(json_object *error_information,
1187 EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper)
1188 {
1189 //Validation bits.
1190 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
1191 struct json_object *obj = NULL;
1192
1193 //Miscellaneous value fields.
1194 if (json_object_object_get_ex(error_information, "transactionType",
1195 &obj)) {
1196 error_info_cper->TransactionType =
1197 readable_pair_to_integer(obj);
1198 add_to_valid_bitfield(&ui64Type, 0);
1199 } else {
1200 error_info_cper->TransactionType = 0;
1201 }
1202 if (json_object_object_get_ex(error_information, "operation", &obj)) {
1203 error_info_cper->Operation = readable_pair_to_integer(obj);
1204 add_to_valid_bitfield(&ui64Type, 1);
1205 } else {
1206 error_info_cper->Operation = 0;
1207 }
1208 if (json_object_object_get_ex(error_information, "level", &obj)) {
1209 error_info_cper->Level = json_object_get_uint64(obj);
1210 add_to_valid_bitfield(&ui64Type, 2);
1211 } else {
1212 error_info_cper->Level = 0;
1213 }
1214 if (json_object_object_get_ex(error_information,
1215 "processorContextCorrupt", &obj)) {
1216 error_info_cper->ProcessorContextCorrupt =
1217 json_object_get_boolean(obj);
1218 add_to_valid_bitfield(&ui64Type, 3);
1219 } else {
1220 error_info_cper->ProcessorContextCorrupt = 0;
1221 }
1222 if (json_object_object_get_ex(error_information, "corrected", &obj)) {
1223 error_info_cper->Corrected = json_object_get_boolean(obj);
1224 add_to_valid_bitfield(&ui64Type, 4);
1225 } else {
1226 error_info_cper->Corrected = 0;
1227 }
1228 if (json_object_object_get_ex(error_information, "precisePC", &obj)) {
1229 error_info_cper->PrecisePC = json_object_get_boolean(obj);
1230 add_to_valid_bitfield(&ui64Type, 5);
1231 } else {
1232 error_info_cper->PrecisePC = 0;
1233 }
1234 if (json_object_object_get_ex(error_information, "restartablePC",
1235 &obj)) {
1236 error_info_cper->RestartablePC = json_object_get_boolean(obj);
1237 add_to_valid_bitfield(&ui64Type, 6);
1238 } else {
1239 error_info_cper->RestartablePC = 0;
1240 }
1241 if (json_object_object_get_ex(error_information, "participationType",
1242 &obj)) {
1243 error_info_cper->ParticipationType =
1244 readable_pair_to_integer(obj);
1245 add_to_valid_bitfield(&ui64Type, 7);
1246 } else {
1247 error_info_cper->ParticipationType = 0;
1248 }
1249 if (json_object_object_get_ex(error_information, "timedOut", &obj)) {
1250 error_info_cper->TimeOut = json_object_get_boolean(obj);
1251 add_to_valid_bitfield(&ui64Type, 8);
1252 } else {
1253 error_info_cper->TimeOut = 0;
1254 }
1255 if (json_object_object_get_ex(error_information, "addressSpace",
1256 &obj)) {
1257 error_info_cper->AddressSpace = readable_pair_to_integer(obj);
1258 add_to_valid_bitfield(&ui64Type, 9);
1259 } else {
1260 error_info_cper->AddressSpace = 0;
1261 }
1262 if (json_object_object_get_ex(error_information, "accessMode", &obj)) {
1263 error_info_cper->AccessMode = readable_pair_to_integer(obj);
1264 add_to_valid_bitfield(&ui64Type, 11);
1265 } else {
1266 error_info_cper->AccessMode = 0;
1267 }
1268 if (json_object_object_get_ex(error_information, "memoryAttributes",
1269 &obj)) {
1270 error_info_cper->MemoryAddressAttributes =
1271 json_object_get_uint64(obj);
1272 add_to_valid_bitfield(&ui64Type, 10);
1273 } else {
1274 error_info_cper->MemoryAddressAttributes = 0;
1275 }
1276 error_info_cper->Reserved = 0;
1277 error_info_cper->ValidationBits = ui64Type.value.ui64;
1278 }
1279
1280 //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)1281 void ir_arm_context_info_to_cper(json_object *context_info, FILE *out)
1282 {
1283 EFI_ARM_CONTEXT_INFORMATION_HEADER info_header;
1284
1285 //Version, array size, context type.
1286 info_header.Version = json_object_get_int(
1287 json_object_object_get(context_info, "version"));
1288 info_header.RegisterArraySize = json_object_get_int(
1289 json_object_object_get(context_info, "registerArraySize"));
1290 info_header.RegisterContextType = readable_pair_to_integer(
1291 json_object_object_get(context_info, "registerContextType"));
1292
1293 //Flush to stream, write the register array itself.
1294 fwrite(&info_header, sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER), 1,
1295 out);
1296 fflush(out);
1297
1298 json_object *register_array =
1299 json_object_object_get(context_info, "registerArray");
1300 switch (info_header.RegisterContextType) {
1301 case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
1302 ir_arm_aarch32_gpr_to_cper(register_array, out);
1303 break;
1304 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
1305 ir_arm_aarch32_el1_to_cper(register_array, out);
1306 break;
1307 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
1308 ir_arm_aarch32_el2_to_cper(register_array, out);
1309 break;
1310 case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
1311 ir_arm_aarch32_secure_to_cper(register_array, out);
1312 break;
1313 case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
1314 ir_arm_aarch64_gpr_to_cper(register_array, out);
1315 break;
1316 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
1317 ir_arm_aarch64_el1_to_cper(register_array, out);
1318 break;
1319 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
1320 ir_arm_aarch64_el2_to_cper(register_array, out);
1321 break;
1322 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
1323 ir_arm_aarch64_el3_to_cper(register_array, out);
1324 break;
1325 case EFI_ARM_CONTEXT_TYPE_MISC:
1326 ir_arm_misc_registers_to_cper(register_array, out);
1327 break;
1328 default:
1329 //Unknown register structure.
1330 ir_arm_unknown_register_to_cper(register_array, out);
1331 break;
1332 }
1333 }
1334
1335 //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)1336 void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out)
1337 {
1338 //Get uniform register array.
1339 EFI_ARM_V8_AARCH32_GPR reg_array;
1340 ir_to_uniform_struct(registers, (UINT32 *)®_array,
1341 sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
1342 ARM_AARCH32_GPR_NAMES);
1343
1344 //Flush to stream.
1345 fwrite(®_array, sizeof(reg_array), 1, out);
1346 fflush(out);
1347 }
1348
1349 //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)1350 void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out)
1351 {
1352 //Get uniform register array.
1353 EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS reg_array;
1354 ir_to_uniform_struct(registers, (UINT32 *)®_array,
1355 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
1356 sizeof(UINT32),
1357 ARM_AARCH32_EL1_REGISTER_NAMES);
1358
1359 //Flush to stream.
1360 fwrite(®_array, sizeof(reg_array), 1, out);
1361 fflush(out);
1362 }
1363
1364 //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)1365 void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out)
1366 {
1367 //Get uniform register array.
1368 EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS reg_array;
1369 ir_to_uniform_struct(registers, (UINT32 *)®_array,
1370 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
1371 sizeof(UINT32),
1372 ARM_AARCH32_EL2_REGISTER_NAMES);
1373
1374 //Flush to stream.
1375 fwrite(®_array, sizeof(reg_array), 1, out);
1376 fflush(out);
1377 }
1378
1379 //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)1380 void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out)
1381 {
1382 //Get uniform register array.
1383 EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS reg_array;
1384 ir_to_uniform_struct(registers, (UINT32 *)®_array,
1385 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
1386 sizeof(UINT32),
1387 ARM_AARCH32_SECURE_REGISTER_NAMES);
1388
1389 //Flush to stream.
1390 fwrite(®_array, sizeof(reg_array), 1, out);
1391 fflush(out);
1392 }
1393
1394 //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)1395 void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out)
1396 {
1397 //Get uniform register array.
1398 EFI_ARM_V8_AARCH64_GPR reg_array;
1399 ir_to_uniform_struct64(registers, (UINT64 *)®_array,
1400 sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
1401 ARM_AARCH64_GPR_NAMES);
1402
1403 //Flush to stream.
1404 fwrite(®_array, sizeof(reg_array), 1, out);
1405 fflush(out);
1406 }
1407
1408 //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)1409 void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out)
1410 {
1411 //Get uniform register array.
1412 EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS reg_array;
1413 ir_to_uniform_struct64(registers, (UINT64 *)®_array,
1414 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
1415 sizeof(UINT64),
1416 ARM_AARCH64_EL1_REGISTER_NAMES);
1417
1418 //Flush to stream.
1419 fwrite(®_array, sizeof(reg_array), 1, out);
1420 fflush(out);
1421 }
1422
1423 //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)1424 void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out)
1425 {
1426 //Get uniform register array.
1427 EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS reg_array;
1428 ir_to_uniform_struct64(registers, (UINT64 *)®_array,
1429 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
1430 sizeof(UINT64),
1431 ARM_AARCH64_EL2_REGISTER_NAMES);
1432
1433 //Flush to stream.
1434 fwrite(®_array, sizeof(reg_array), 1, out);
1435 fflush(out);
1436 }
1437
1438 //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)1439 void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out)
1440 {
1441 //Get uniform register array.
1442 EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS reg_array;
1443 ir_to_uniform_struct64(registers, (UINT64 *)®_array,
1444 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
1445 sizeof(UINT64),
1446 ARM_AARCH64_EL3_REGISTER_NAMES);
1447
1448 //Flush to stream.
1449 fwrite(®_array, sizeof(reg_array), 1, out);
1450 fflush(out);
1451 }
1452
1453 //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)1454 void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out)
1455 {
1456 EFI_ARM_MISC_CONTEXT_REGISTER reg_array;
1457
1458 //MRS encoding information.
1459 json_object *mrs_encoding =
1460 json_object_object_get(registers, "mrsEncoding");
1461 reg_array.MrsOp2 = json_object_get_uint64(
1462 json_object_object_get(mrs_encoding, "op2"));
1463 reg_array.MrsCrm = json_object_get_uint64(
1464 json_object_object_get(mrs_encoding, "crm"));
1465 reg_array.MrsCrn = json_object_get_uint64(
1466 json_object_object_get(mrs_encoding, "crn"));
1467 reg_array.MrsOp1 = json_object_get_uint64(
1468 json_object_object_get(mrs_encoding, "op1"));
1469 reg_array.MrsO0 = json_object_get_uint64(
1470 json_object_object_get(mrs_encoding, "o0"));
1471
1472 //Actual register value.
1473 reg_array.Value = json_object_get_uint64(
1474 json_object_object_get(registers, "value"));
1475
1476 //Flush to stream.
1477 fwrite(®_array, sizeof(reg_array), 1, out);
1478 fflush(out);
1479 }
1480
1481 //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)1482 void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out)
1483 {
1484 //Get base64 represented data.
1485 json_object *encoded = json_object_object_get(registers, "data");
1486
1487 int32_t decoded_len = 0;
1488
1489 UINT8 *decoded = base64_decode(json_object_get_string(encoded),
1490 json_object_get_string_len(encoded),
1491 &decoded_len);
1492
1493 if (decoded == NULL) {
1494 cper_print_log("Failed to allocate decode output buffer. \n");
1495 } else {
1496 //Flush out to stream.
1497 fwrite(&decoded, decoded_len, 1, out);
1498 fflush(out);
1499 free(decoded);
1500 }
1501 }
1502