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