1 /**
2 * Describes functions for converting ARM CPER sections from binary and JSON format
3 * into an intermediate format.
4 *
5 * Author: Lawrence.Tang@arm.com
6 **/
7
8 #include <stdio.h>
9 #include <json.h>
10 #include "base64.h"
11 #include "../edk/Cper.h"
12 #include "../cper-utils.h"
13 #include "cper-section-arm.h"
14
15 //Private pre-definitions.
16 json_object *
17 cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info);
18 json_object *
19 cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
20 void **cur_pos);
21 json_object *
22 cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
23 EFI_ARM_ERROR_INFORMATION_ENTRY *error_info);
24 json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error);
25 json_object *cper_arm_misc_register_array_to_ir(
26 EFI_ARM_MISC_CONTEXT_REGISTER *misc_register);
27 void ir_arm_error_info_to_cper(json_object *error_info, FILE *out);
28 void ir_arm_context_info_to_cper(json_object *context_info, FILE *out);
29 void ir_arm_error_cache_tlb_info_to_cper(
30 json_object *error_information,
31 EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper);
32 void ir_arm_error_bus_info_to_cper(json_object *error_information,
33 EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper);
34 void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out);
35 void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out);
36 void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out);
37 void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out);
38 void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out);
39 void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out);
40 void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out);
41 void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out);
42 void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out);
43 void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out);
44
45 //Converts the given processor-generic CPER section into JSON IR.
cper_section_arm_to_ir(void * section)46 json_object *cper_section_arm_to_ir(void *section)
47 {
48 EFI_ARM_ERROR_RECORD *record = (EFI_ARM_ERROR_RECORD *)section;
49 json_object *section_ir = json_object_new_object();
50
51 //Validation bits.
52 json_object *validation = bitfield_to_ir(
53 record->ValidFields, 4, ARM_ERROR_VALID_BITFIELD_NAMES);
54 json_object_object_add(section_ir, "validationBits", validation);
55
56 //Number of error info and context info structures, and length.
57 json_object_object_add(section_ir, "errorInfoNum",
58 json_object_new_int(record->ErrInfoNum));
59 json_object_object_add(section_ir, "contextInfoNum",
60 json_object_new_int(record->ContextInfoNum));
61 json_object_object_add(section_ir, "sectionLength",
62 json_object_new_uint64(record->SectionLength));
63
64 //Error affinity.
65 json_object *error_affinity = json_object_new_object();
66 json_object_object_add(error_affinity, "value",
67 json_object_new_int(record->ErrorAffinityLevel));
68 json_object_object_add(
69 error_affinity, "type",
70 json_object_new_string(record->ErrorAffinityLevel < 4 ?
71 "Vendor Defined" :
72 "Reserved"));
73 json_object_object_add(section_ir, "errorAffinity", error_affinity);
74
75 //Processor ID (MPIDR_EL1) and chip ID (MIDR_EL1).
76 json_object_object_add(section_ir, "mpidrEl1",
77 json_object_new_uint64(record->MPIDR_EL1));
78 json_object_object_add(section_ir, "midrEl1",
79 json_object_new_uint64(record->MIDR_EL1));
80
81 //Whether the processor is running, and the state of it if so.
82 json_object_object_add(section_ir, "running",
83 json_object_new_boolean(record->RunningState &
84 0x1));
85 if (!(record->RunningState >> 31)) {
86 //Bit 32 of running state is on, so PSCI state information is included.
87 //This can't be made human readable, as it is unknown whether this will be the pre-PSCI 1.0 format
88 //or the newer Extended StateID format.
89 json_object_object_add(
90 section_ir, "psciState",
91 json_object_new_uint64(record->PsciState));
92 }
93
94 //Processor error structures.
95 json_object *error_info_array = json_object_new_array();
96 EFI_ARM_ERROR_INFORMATION_ENTRY *cur_error =
97 (EFI_ARM_ERROR_INFORMATION_ENTRY *)(record + 1);
98 for (int i = 0; i < record->ErrInfoNum; i++) {
99 json_object_array_add(error_info_array,
100 cper_arm_error_info_to_ir(cur_error));
101 cur_error++;
102 }
103 json_object_object_add(section_ir, "errorInfo", error_info_array);
104
105 //Processor context structures.
106 //The current position is moved within the processing, as it is a dynamic size structure.
107 uint8_t *cur_pos = (uint8_t *)cur_error;
108 json_object *context_info_array = json_object_new_array();
109 for (int i = 0; i < record->ContextInfoNum; i++) {
110 EFI_ARM_CONTEXT_INFORMATION_HEADER *header =
111 (EFI_ARM_CONTEXT_INFORMATION_HEADER *)cur_pos;
112 json_object *processor_context =
113 cper_arm_processor_context_to_ir(header,
114 (void **)&cur_pos);
115 json_object_array_add(context_info_array, processor_context);
116 }
117 json_object_object_add(section_ir, "contextInfo", context_info_array);
118
119 //Is there any vendor-specific information following?
120 if (cur_pos < (uint8_t *)section + record->SectionLength) {
121 json_object *vendor_specific = json_object_new_object();
122 size_t input_size =
123 (uint8_t *)section + record->SectionLength - cur_pos;
124 int32_t encoded_len = 0;
125 char *encoded =
126 base64_encode(cur_pos, input_size, &encoded_len);
127 if (encoded == NULL) {
128 return NULL;
129 }
130 json_object_object_add(vendor_specific, "data",
131 json_object_new_string_len(encoded,
132 encoded_len));
133 free(encoded);
134
135 json_object_object_add(section_ir, "vendorSpecificInfo",
136 vendor_specific);
137 }
138
139 return section_ir;
140 }
141
142 //Converts a single ARM Process Error Information structure into JSON IR.
143 json_object *
cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY * error_info)144 cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info)
145 {
146 json_object *error_info_ir = json_object_new_object();
147
148 //Version, length.
149 json_object_object_add(error_info_ir, "version",
150 json_object_new_int(error_info->Version));
151 json_object_object_add(error_info_ir, "length",
152 json_object_new_int(error_info->Length));
153
154 //Validation bitfield.
155 json_object *validation =
156 bitfield_to_ir(error_info->ValidationBits, 5,
157 ARM_ERROR_INFO_ENTRY_VALID_BITFIELD_NAMES);
158 json_object_object_add(error_info_ir, "validationBits", validation);
159
160 //The type of error information in this log.
161 json_object *error_type = integer_to_readable_pair(
162 error_info->Type, 4, ARM_ERROR_INFO_ENTRY_INFO_TYPES_KEYS,
163 ARM_ERROR_INFO_ENTRY_INFO_TYPES_VALUES, "Unknown (Reserved)");
164 json_object_object_add(error_info_ir, "errorType", error_type);
165
166 //Multiple error count.
167 json_object *multiple_error = json_object_new_object();
168 json_object_object_add(multiple_error, "value",
169 json_object_new_int(error_info->MultipleError));
170 json_object_object_add(
171 multiple_error, "type",
172 json_object_new_string(error_info->MultipleError < 1 ?
173 "Single Error" :
174 "Multiple Errors"));
175 json_object_object_add(error_info_ir, "multipleError", multiple_error);
176
177 //Flags.
178 json_object *flags = bitfield_to_ir(error_info->Flags, 4,
179 ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
180 json_object_object_add(error_info_ir, "flags", flags);
181
182 //Error information, split by type.
183 json_object *error_subinfo = NULL;
184 switch (error_info->Type) {
185 case ARM_ERROR_INFORMATION_TYPE_CACHE: //Cache
186 case ARM_ERROR_INFORMATION_TYPE_TLB: //TLB
187 error_subinfo = cper_arm_cache_tlb_error_to_ir(
188 (EFI_ARM_CACHE_ERROR_STRUCTURE *)&error_info
189 ->ErrorInformation,
190 error_info);
191 break;
192 case ARM_ERROR_INFORMATION_TYPE_BUS: //Bus
193 error_subinfo = cper_arm_bus_error_to_ir(
194 (EFI_ARM_BUS_ERROR_STRUCTURE *)&error_info
195 ->ErrorInformation);
196 break;
197
198 default:
199 //Unknown/microarch, so can't be made readable. Simply dump as a uint64 data object.
200 error_subinfo = json_object_new_object();
201 json_object_object_add(
202 error_subinfo, "data",
203 json_object_new_uint64(
204 error_info->ErrorInformation.Value));
205 break;
206 }
207 json_object_object_add(error_info_ir, "errorInformation",
208 error_subinfo);
209
210 //Virtual fault address, physical fault address.
211 json_object_object_add(
212 error_info_ir, "virtualFaultAddress",
213 json_object_new_uint64(error_info->VirtualFaultAddress));
214 json_object_object_add(
215 error_info_ir, "physicalFaultAddress",
216 json_object_new_uint64(error_info->PhysicalFaultAddress));
217
218 return error_info_ir;
219 }
220
221 //Converts a single ARM cache/TLB error information structure into JSON IR format.
222 json_object *
cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE * cache_tlb_error,EFI_ARM_ERROR_INFORMATION_ENTRY * error_info)223 cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
224 EFI_ARM_ERROR_INFORMATION_ENTRY *error_info)
225 {
226 json_object *cache_tlb_error_ir = json_object_new_object();
227
228 //Validation bitfield.
229 json_object *validation =
230 bitfield_to_ir(cache_tlb_error->ValidationBits, 7,
231 ARM_CACHE_TLB_ERROR_VALID_BITFIELD_NAMES);
232 json_object_object_add(cache_tlb_error_ir, "validationBits",
233 validation);
234
235 //Transaction type.
236 json_object *transaction_type = integer_to_readable_pair(
237 cache_tlb_error->TransactionType, 3,
238 ARM_ERROR_TRANSACTION_TYPES_KEYS,
239 ARM_ERROR_TRANSACTION_TYPES_VALUES, "Unknown (Reserved)");
240 json_object_object_add(cache_tlb_error_ir, "transactionType",
241 transaction_type);
242
243 //Operation.
244 json_object *operation;
245 if (error_info->Type == 0) {
246 //Cache operation.
247 operation = integer_to_readable_pair(
248 cache_tlb_error->Operation, 11,
249 ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
250 ARM_CACHE_BUS_OPERATION_TYPES_VALUES,
251 "Unknown (Reserved)");
252 } else {
253 //TLB operation.
254 operation = integer_to_readable_pair(
255 cache_tlb_error->Operation, 9,
256 ARM_TLB_OPERATION_TYPES_KEYS,
257 ARM_TLB_OPERATION_TYPES_VALUES, "Unknown (Reserved)");
258 }
259 json_object_object_add(cache_tlb_error_ir, "operation", operation);
260
261 //Miscellaneous remaining fields.
262 json_object_object_add(cache_tlb_error_ir, "level",
263 json_object_new_int(cache_tlb_error->Level));
264 json_object_object_add(
265 cache_tlb_error_ir, "processorContextCorrupt",
266 json_object_new_boolean(
267 cache_tlb_error->ProcessorContextCorrupt));
268 json_object_object_add(
269 cache_tlb_error_ir, "corrected",
270 json_object_new_boolean(cache_tlb_error->Corrected));
271 json_object_object_add(
272 cache_tlb_error_ir, "precisePC",
273 json_object_new_boolean(cache_tlb_error->PrecisePC));
274 json_object_object_add(
275 cache_tlb_error_ir, "restartablePC",
276 json_object_new_boolean(cache_tlb_error->RestartablePC));
277 return cache_tlb_error_ir;
278 }
279
280 //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)281 json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error)
282 {
283 json_object *bus_error_ir = json_object_new_object();
284
285 //Validation bits.
286 json_object *validation =
287 bitfield_to_ir(bus_error->ValidationBits, 12,
288 ARM_BUS_ERROR_VALID_BITFIELD_NAMES);
289 json_object_object_add(bus_error_ir, "validationBits", validation);
290
291 //Transaction type.
292 json_object *transaction_type = integer_to_readable_pair(
293 bus_error->TransactionType, 3, ARM_ERROR_TRANSACTION_TYPES_KEYS,
294 ARM_ERROR_TRANSACTION_TYPES_VALUES, "Unknown (Reserved)");
295 json_object_object_add(bus_error_ir, "transactionType",
296 transaction_type);
297
298 //Operation.
299 json_object *operation = integer_to_readable_pair(
300 bus_error->Operation, 7, ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
301 ARM_CACHE_BUS_OPERATION_TYPES_VALUES, "Unknown (Reserved)");
302 json_object_object_add(bus_error_ir, "operation", operation);
303
304 //Affinity level of bus error, + miscellaneous fields.
305 json_object_object_add(bus_error_ir, "level",
306 json_object_new_int(bus_error->Level));
307 json_object_object_add(
308 bus_error_ir, "processorContextCorrupt",
309 json_object_new_boolean(bus_error->ProcessorContextCorrupt));
310 json_object_object_add(bus_error_ir, "corrected",
311 json_object_new_boolean(bus_error->Corrected));
312 json_object_object_add(bus_error_ir, "precisePC",
313 json_object_new_boolean(bus_error->PrecisePC));
314 json_object_object_add(
315 bus_error_ir, "restartablePC",
316 json_object_new_boolean(bus_error->RestartablePC));
317 json_object_object_add(bus_error_ir, "timedOut",
318 json_object_new_boolean(bus_error->TimeOut));
319
320 //Participation type.
321 json_object *participation_type = integer_to_readable_pair(
322 bus_error->ParticipationType, 4,
323 ARM_BUS_PARTICIPATION_TYPES_KEYS,
324 ARM_BUS_PARTICIPATION_TYPES_VALUES, "Unknown");
325 json_object_object_add(bus_error_ir, "participationType",
326 participation_type);
327
328 //Address space.
329 json_object *address_space = integer_to_readable_pair(
330 bus_error->AddressSpace, 3, ARM_BUS_ADDRESS_SPACE_TYPES_KEYS,
331 ARM_BUS_ADDRESS_SPACE_TYPES_VALUES, "Unknown");
332 json_object_object_add(bus_error_ir, "addressSpace", address_space);
333
334 //Memory access attributes.
335 //todo: find the specification of these in the ARM ARM
336 json_object_object_add(
337 bus_error_ir, "memoryAttributes",
338 json_object_new_int(bus_error->MemoryAddressAttributes));
339
340 //Access Mode
341 json_object *access_mode = json_object_new_object();
342 json_object_object_add(access_mode, "value",
343 json_object_new_int(bus_error->AccessMode));
344 json_object_object_add(
345 access_mode, "name",
346 json_object_new_string(bus_error->AccessMode == 0 ? "Secure" :
347 "Normal"));
348 json_object_object_add(bus_error_ir, "accessMode", access_mode);
349
350 return bus_error_ir;
351 }
352
353 //Converts a single ARM processor context block into JSON IR.
354 json_object *
cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER * header,void ** cur_pos)355 cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
356 void **cur_pos)
357 {
358 json_object *context_ir = json_object_new_object();
359
360 //Version.
361 json_object_object_add(context_ir, "version",
362 json_object_new_int(header->Version));
363
364 //Add the context type.
365 json_object *context_type = integer_to_readable_pair(
366 header->RegisterContextType, 9,
367 ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_KEYS,
368 ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_VALUES,
369 "Unknown (Reserved)");
370 json_object_object_add(context_ir, "registerContextType", context_type);
371
372 //Register array size (bytes).
373 json_object_object_add(
374 context_ir, "registerArraySize",
375 json_object_new_uint64(header->RegisterArraySize));
376
377 //The register array itself.
378 *cur_pos = (void *)(header + 1);
379 json_object *register_array = NULL;
380 switch (header->RegisterContextType) {
381 case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
382 register_array = uniform_struct_to_ir(
383 (UINT32 *)cur_pos,
384 sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
385 ARM_AARCH32_GPR_NAMES);
386 break;
387 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
388 register_array = uniform_struct_to_ir(
389 (UINT32 *)cur_pos,
390 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
391 sizeof(UINT32),
392 ARM_AARCH32_EL1_REGISTER_NAMES);
393 break;
394 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
395 register_array = uniform_struct_to_ir(
396 (UINT32 *)cur_pos,
397 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
398 sizeof(UINT32),
399 ARM_AARCH32_EL2_REGISTER_NAMES);
400 break;
401 case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
402 register_array = uniform_struct_to_ir(
403 (UINT32 *)cur_pos,
404 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
405 sizeof(UINT32),
406 ARM_AARCH32_SECURE_REGISTER_NAMES);
407 break;
408 case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
409 register_array = uniform_struct64_to_ir(
410 (UINT64 *)cur_pos,
411 sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
412 ARM_AARCH64_GPR_NAMES);
413 break;
414 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
415 register_array = uniform_struct64_to_ir(
416 (UINT64 *)cur_pos,
417 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
418 sizeof(UINT64),
419 ARM_AARCH64_EL1_REGISTER_NAMES);
420 break;
421 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
422 register_array = uniform_struct64_to_ir(
423 (UINT64 *)cur_pos,
424 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
425 sizeof(UINT64),
426 ARM_AARCH64_EL2_REGISTER_NAMES);
427 break;
428 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
429 register_array = uniform_struct64_to_ir(
430 (UINT64 *)cur_pos,
431 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
432 sizeof(UINT64),
433 ARM_AARCH64_EL3_REGISTER_NAMES);
434 break;
435 case EFI_ARM_CONTEXT_TYPE_MISC:
436 register_array = cper_arm_misc_register_array_to_ir(
437 (EFI_ARM_MISC_CONTEXT_REGISTER *)cur_pos);
438 break;
439 default:
440 //Unknown register array type, add as base64 data instead.
441 register_array = json_object_new_object();
442 int32_t encoded_len = 0;
443 char *encoded = base64_encode((UINT8 *)cur_pos,
444 header->RegisterArraySize,
445 &encoded_len);
446 if (encoded == NULL) {
447 printf("Failed to allocate encode output buffer. \n");
448 return NULL;
449 }
450 json_object_object_add(register_array, "data",
451 json_object_new_string_len(encoded,
452 encoded_len));
453 free(encoded);
454
455 break;
456 }
457 json_object_object_add(context_ir, "registerArray", register_array);
458
459 //Set the current position to after the processor context structure.
460 *cur_pos = (UINT8 *)(*cur_pos) + header->RegisterArraySize;
461
462 return context_ir;
463 }
464
465 //Converts a single CPER ARM miscellaneous register array to JSON IR format.
466 json_object *
cper_arm_misc_register_array_to_ir(EFI_ARM_MISC_CONTEXT_REGISTER * misc_register)467 cper_arm_misc_register_array_to_ir(EFI_ARM_MISC_CONTEXT_REGISTER *misc_register)
468 {
469 json_object *register_array = json_object_new_object();
470 json_object *mrs_encoding = json_object_new_object();
471 json_object_object_add(mrs_encoding, "op2",
472 json_object_new_uint64(misc_register->MrsOp2));
473 json_object_object_add(mrs_encoding, "crm",
474 json_object_new_uint64(misc_register->MrsCrm));
475 json_object_object_add(mrs_encoding, "crn",
476 json_object_new_uint64(misc_register->MrsCrn));
477 json_object_object_add(mrs_encoding, "op1",
478 json_object_new_uint64(misc_register->MrsOp1));
479 json_object_object_add(mrs_encoding, "o0",
480 json_object_new_uint64(misc_register->MrsO0));
481 json_object_object_add(register_array, "mrsEncoding", mrs_encoding);
482 json_object_object_add(register_array, "value",
483 json_object_new_uint64(misc_register->Value));
484
485 return register_array;
486 }
487
488 //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)489 void ir_section_arm_to_cper(json_object *section, FILE *out)
490 {
491 EFI_ARM_ERROR_RECORD *section_cper =
492 (EFI_ARM_ERROR_RECORD *)calloc(1, sizeof(EFI_ARM_ERROR_RECORD));
493
494 //Validation bits.
495 section_cper->ValidFields = ir_to_bitfield(
496 json_object_object_get(section, "validationBits"), 4,
497 ARM_ERROR_VALID_BITFIELD_NAMES);
498
499 //Count of error/context info structures.
500 section_cper->ErrInfoNum = json_object_get_int(
501 json_object_object_get(section, "errorInfoNum"));
502 section_cper->ContextInfoNum = json_object_get_int(
503 json_object_object_get(section, "contextInfoNum"));
504
505 //Miscellaneous raw value fields.
506 section_cper->SectionLength = json_object_get_uint64(
507 json_object_object_get(section, "sectionLength"));
508 section_cper->ErrorAffinityLevel = readable_pair_to_integer(
509 json_object_object_get(section, "errorAffinity"));
510 section_cper->MPIDR_EL1 = json_object_get_uint64(
511 json_object_object_get(section, "mpidrEl1"));
512 section_cper->MIDR_EL1 = json_object_get_uint64(
513 json_object_object_get(section, "midrEl1"));
514 section_cper->RunningState = json_object_get_boolean(
515 json_object_object_get(section, "running"));
516
517 //Optional PSCI state.
518 json_object *psci_state = json_object_object_get(section, "psciState");
519 if (psci_state != NULL) {
520 section_cper->PsciState = json_object_get_uint64(psci_state);
521 }
522
523 //Flush header to stream.
524 fwrite(section_cper, sizeof(EFI_ARM_ERROR_RECORD), 1, out);
525 fflush(out);
526
527 //Error info structure array.
528 json_object *error_info = json_object_object_get(section, "errorInfo");
529 for (int i = 0; i < section_cper->ErrInfoNum; i++) {
530 ir_arm_error_info_to_cper(
531 json_object_array_get_idx(error_info, i), out);
532 }
533
534 //Context info structure array.
535 json_object *context_info =
536 json_object_object_get(section, "contextInfo");
537 for (int i = 0; i < section_cper->ContextInfoNum; i++) {
538 ir_arm_context_info_to_cper(
539 json_object_array_get_idx(context_info, i), out);
540 }
541
542 //Vendor specific error info.
543 json_object *vendor_specific_info =
544 json_object_object_get(section, "vendorSpecificInfo");
545 if (vendor_specific_info != NULL) {
546 json_object *vendor_info_string =
547 json_object_object_get(vendor_specific_info, "data");
548 int vendor_specific_len =
549 json_object_get_string_len(vendor_info_string);
550
551 int32_t decoded_len = 0;
552
553 UINT8 *decoded = base64_decode(
554 json_object_get_string(vendor_info_string),
555 vendor_specific_len, &decoded_len);
556
557 //Write out to file.
558 fwrite(decoded, decoded_len, 1, out);
559 fflush(out);
560 free(decoded);
561 }
562
563 //Free remaining resources.
564 free(section_cper);
565 }
566
567 //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)568 void ir_arm_error_info_to_cper(json_object *error_info, FILE *out)
569 {
570 EFI_ARM_ERROR_INFORMATION_ENTRY error_info_cper;
571
572 //Version, length.
573 error_info_cper.Version = json_object_get_int(
574 json_object_object_get(error_info, "version"));
575 error_info_cper.Length = json_object_get_int(
576 json_object_object_get(error_info, "length"));
577
578 //Validation bits.
579 error_info_cper.ValidationBits = ir_to_bitfield(
580 json_object_object_get(error_info, "validationBits"), 5,
581 ARM_ERROR_INFO_ENTRY_VALID_BITFIELD_NAMES);
582
583 //Type, multiple error.
584 error_info_cper.Type = (UINT8)readable_pair_to_integer(
585 json_object_object_get(error_info, "type"));
586 error_info_cper.MultipleError = (UINT16)readable_pair_to_integer(
587 json_object_object_get(error_info, "multipleError"));
588
589 //Flags object.
590 error_info_cper.Flags = (UINT8)ir_to_bitfield(
591 json_object_object_get(error_info, "flags"), 4,
592 ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
593
594 //Error information.
595 json_object *error_info_information =
596 json_object_object_get(error_info, "errorInformation");
597 switch (error_info_cper.Type) {
598 case ARM_ERROR_INFORMATION_TYPE_CACHE:
599 case ARM_ERROR_INFORMATION_TYPE_TLB:
600 ir_arm_error_cache_tlb_info_to_cper(
601 error_info_information,
602 &error_info_cper.ErrorInformation.CacheError);
603 break;
604
605 case ARM_ERROR_INFORMATION_TYPE_BUS:
606 ir_arm_error_bus_info_to_cper(
607 error_info_information,
608 &error_info_cper.ErrorInformation.BusError);
609 break;
610
611 default:
612 //Unknown error information type.
613 error_info_cper.ErrorInformation.Value = json_object_get_uint64(
614 json_object_object_get(error_info_information, "data"));
615 break;
616 }
617
618 //Virtual/physical fault address.
619 error_info_cper.VirtualFaultAddress = json_object_get_uint64(
620 json_object_object_get(error_info, "virtualFaultAddress"));
621 error_info_cper.PhysicalFaultAddress = json_object_get_uint64(
622 json_object_object_get(error_info, "physicalFaultAddress"));
623
624 //Write out to stream.
625 fwrite(&error_info_cper, sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY), 1,
626 out);
627 fflush(out);
628 }
629
630 //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)631 void ir_arm_error_cache_tlb_info_to_cper(
632 json_object *error_information,
633 EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper)
634 {
635 //Validation bits.
636 error_info_cper->ValidationBits = ir_to_bitfield(
637 json_object_object_get(error_information, "validationBits"), 7,
638 ARM_CACHE_TLB_ERROR_VALID_BITFIELD_NAMES);
639
640 //Miscellaneous value fields.
641 error_info_cper->TransactionType = readable_pair_to_integer(
642 json_object_object_get(error_information, "transactionType"));
643 error_info_cper->Operation = readable_pair_to_integer(
644 json_object_object_get(error_information, "operation"));
645 error_info_cper->Level = json_object_get_uint64(
646 json_object_object_get(error_information, "level"));
647 error_info_cper->ProcessorContextCorrupt = json_object_get_boolean(
648 json_object_object_get(error_information,
649 "processorContextCorrupt"));
650 error_info_cper->Corrected = json_object_get_boolean(
651 json_object_object_get(error_information, "corrected"));
652 error_info_cper->PrecisePC = json_object_get_boolean(
653 json_object_object_get(error_information, "precisePC"));
654 error_info_cper->RestartablePC = json_object_get_boolean(
655 json_object_object_get(error_information, "restartablePC"));
656 error_info_cper->Reserved = 0;
657 }
658
659 //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)660 void ir_arm_error_bus_info_to_cper(json_object *error_information,
661 EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper)
662 {
663 //Validation bits.
664 error_info_cper->ValidationBits = ir_to_bitfield(
665 json_object_object_get(error_information, "validationBits"), 7,
666 ARM_BUS_ERROR_VALID_BITFIELD_NAMES);
667
668 //Miscellaneous value fields.
669 error_info_cper->TransactionType = readable_pair_to_integer(
670 json_object_object_get(error_information, "transactionType"));
671 error_info_cper->Operation = readable_pair_to_integer(
672 json_object_object_get(error_information, "operation"));
673 error_info_cper->Level = json_object_get_uint64(
674 json_object_object_get(error_information, "level"));
675 error_info_cper->ProcessorContextCorrupt = json_object_get_boolean(
676 json_object_object_get(error_information,
677 "processorContextCorrupt"));
678 error_info_cper->Corrected = json_object_get_boolean(
679 json_object_object_get(error_information, "corrected"));
680 error_info_cper->PrecisePC = json_object_get_boolean(
681 json_object_object_get(error_information, "precisePC"));
682 error_info_cper->RestartablePC = json_object_get_boolean(
683 json_object_object_get(error_information, "restartablePC"));
684 error_info_cper->ParticipationType = readable_pair_to_integer(
685 json_object_object_get(error_information, "participationType"));
686 error_info_cper->AddressSpace = readable_pair_to_integer(
687 json_object_object_get(error_information, "addressSpace"));
688 error_info_cper->AccessMode = readable_pair_to_integer(
689 json_object_object_get(error_information, "accessMode"));
690 error_info_cper->MemoryAddressAttributes = json_object_get_uint64(
691 json_object_object_get(error_information, "memoryAttributes"));
692 error_info_cper->Reserved = 0;
693 }
694
695 //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)696 void ir_arm_context_info_to_cper(json_object *context_info, FILE *out)
697 {
698 EFI_ARM_CONTEXT_INFORMATION_HEADER info_header;
699
700 //Version, array size, context type.
701 info_header.Version = json_object_get_int(
702 json_object_object_get(context_info, "version"));
703 info_header.RegisterArraySize = json_object_get_int(
704 json_object_object_get(context_info, "registerArraySize"));
705 info_header.RegisterContextType = readable_pair_to_integer(
706 json_object_object_get(context_info, "registerContextType"));
707
708 //Flush to stream, write the register array itself.
709 fwrite(&info_header, sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER), 1,
710 out);
711 fflush(out);
712
713 json_object *register_array =
714 json_object_object_get(context_info, "registerArray");
715 switch (info_header.RegisterContextType) {
716 case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
717 ir_arm_aarch32_gpr_to_cper(register_array, out);
718 break;
719 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
720 ir_arm_aarch32_el1_to_cper(register_array, out);
721 break;
722 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
723 ir_arm_aarch32_el2_to_cper(register_array, out);
724 break;
725 case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
726 ir_arm_aarch32_secure_to_cper(register_array, out);
727 break;
728 case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
729 ir_arm_aarch64_gpr_to_cper(register_array, out);
730 break;
731 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
732 ir_arm_aarch64_el1_to_cper(register_array, out);
733 break;
734 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
735 ir_arm_aarch64_el2_to_cper(register_array, out);
736 break;
737 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
738 ir_arm_aarch64_el3_to_cper(register_array, out);
739 break;
740 case EFI_ARM_CONTEXT_TYPE_MISC:
741 ir_arm_misc_registers_to_cper(register_array, out);
742 break;
743 default:
744 //Unknown register structure.
745 ir_arm_unknown_register_to_cper(register_array, out);
746 break;
747 }
748 }
749
750 //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)751 void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out)
752 {
753 //Get uniform register array.
754 EFI_ARM_V8_AARCH32_GPR reg_array;
755 ir_to_uniform_struct(registers, (UINT32 *)®_array,
756 sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
757 ARM_AARCH32_GPR_NAMES);
758
759 //Flush to stream.
760 fwrite(®_array, sizeof(reg_array), 1, out);
761 fflush(out);
762 }
763
764 //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)765 void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out)
766 {
767 //Get uniform register array.
768 EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS reg_array;
769 ir_to_uniform_struct(registers, (UINT32 *)®_array,
770 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
771 sizeof(UINT32),
772 ARM_AARCH32_EL1_REGISTER_NAMES);
773
774 //Flush to stream.
775 fwrite(®_array, sizeof(reg_array), 1, out);
776 fflush(out);
777 }
778
779 //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)780 void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out)
781 {
782 //Get uniform register array.
783 EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS reg_array;
784 ir_to_uniform_struct(registers, (UINT32 *)®_array,
785 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
786 sizeof(UINT32),
787 ARM_AARCH32_EL2_REGISTER_NAMES);
788
789 //Flush to stream.
790 fwrite(®_array, sizeof(reg_array), 1, out);
791 fflush(out);
792 }
793
794 //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)795 void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out)
796 {
797 //Get uniform register array.
798 EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS reg_array;
799 ir_to_uniform_struct(registers, (UINT32 *)®_array,
800 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
801 sizeof(UINT32),
802 ARM_AARCH32_SECURE_REGISTER_NAMES);
803
804 //Flush to stream.
805 fwrite(®_array, sizeof(reg_array), 1, out);
806 fflush(out);
807 }
808
809 //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)810 void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out)
811 {
812 //Get uniform register array.
813 EFI_ARM_V8_AARCH64_GPR reg_array;
814 ir_to_uniform_struct64(registers, (UINT64 *)®_array,
815 sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
816 ARM_AARCH64_GPR_NAMES);
817
818 //Flush to stream.
819 fwrite(®_array, sizeof(reg_array), 1, out);
820 fflush(out);
821 }
822
823 //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)824 void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out)
825 {
826 //Get uniform register array.
827 EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS reg_array;
828 ir_to_uniform_struct64(registers, (UINT64 *)®_array,
829 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
830 sizeof(UINT64),
831 ARM_AARCH64_EL1_REGISTER_NAMES);
832
833 //Flush to stream.
834 fwrite(®_array, sizeof(reg_array), 1, out);
835 fflush(out);
836 }
837
838 //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)839 void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out)
840 {
841 //Get uniform register array.
842 EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS reg_array;
843 ir_to_uniform_struct64(registers, (UINT64 *)®_array,
844 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
845 sizeof(UINT64),
846 ARM_AARCH64_EL2_REGISTER_NAMES);
847
848 //Flush to stream.
849 fwrite(®_array, sizeof(reg_array), 1, out);
850 fflush(out);
851 }
852
853 //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)854 void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out)
855 {
856 //Get uniform register array.
857 EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS reg_array;
858 ir_to_uniform_struct64(registers, (UINT64 *)®_array,
859 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
860 sizeof(UINT64),
861 ARM_AARCH64_EL3_REGISTER_NAMES);
862
863 //Flush to stream.
864 fwrite(®_array, sizeof(reg_array), 1, out);
865 fflush(out);
866 }
867
868 //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)869 void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out)
870 {
871 EFI_ARM_MISC_CONTEXT_REGISTER reg_array;
872
873 //MRS encoding information.
874 json_object *mrs_encoding =
875 json_object_object_get(registers, "mrsEncoding");
876 reg_array.MrsOp2 = json_object_get_uint64(
877 json_object_object_get(mrs_encoding, "op2"));
878 reg_array.MrsCrm = json_object_get_uint64(
879 json_object_object_get(mrs_encoding, "crm"));
880 reg_array.MrsCrn = json_object_get_uint64(
881 json_object_object_get(mrs_encoding, "crn"));
882 reg_array.MrsOp1 = json_object_get_uint64(
883 json_object_object_get(mrs_encoding, "op1"));
884 reg_array.MrsO0 = json_object_get_uint64(
885 json_object_object_get(mrs_encoding, "o0"));
886
887 //Actual register value.
888 reg_array.Value = json_object_get_uint64(
889 json_object_object_get(registers, "value"));
890
891 //Flush to stream.
892 fwrite(®_array, sizeof(reg_array), 1, out);
893 fflush(out);
894 }
895
896 //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)897 void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out)
898 {
899 //Get base64 represented data.
900 json_object *encoded = json_object_object_get(registers, "data");
901
902 int32_t decoded_len = 0;
903
904 UINT8 *decoded = base64_decode(json_object_get_string(encoded),
905 json_object_get_string_len(encoded),
906 &decoded_len);
907
908 if (decoded == NULL) {
909 printf("Failed to allocate decode output buffer. \n");
910 } else {
911 //Flush out to stream.
912 fwrite(&decoded, decoded_len, 1, out);
913 fflush(out);
914 free(decoded);
915 }
916 }
917