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