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 				*((UINT64 *)&error_info->ErrorInformation)));
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 		*((UINT64 *)&error_info_cper.ErrorInformation) =
619 			json_object_get_uint64(json_object_object_get(
620 				error_info_information, "data"));
621 		break;
622 	}
623 
624 	//Virtual/physical fault address.
625 	error_info_cper.VirtualFaultAddress = json_object_get_uint64(
626 		json_object_object_get(error_info, "virtualFaultAddress"));
627 	error_info_cper.PhysicalFaultAddress = json_object_get_uint64(
628 		json_object_object_get(error_info, "physicalFaultAddress"));
629 
630 	//Write out to stream.
631 	fwrite(&error_info_cper, sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY), 1,
632 	       out);
633 	fflush(out);
634 }
635 
636 //Converts a single ARM cache/TLB error information structure into a CPER structure.
637 void ir_arm_error_cache_tlb_info_to_cper(
638 	json_object *error_information,
639 	EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper)
640 {
641 	//Validation bits.
642 	error_info_cper->ValidationBits = ir_to_bitfield(
643 		json_object_object_get(error_information, "validationBits"), 7,
644 		ARM_CACHE_TLB_ERROR_VALID_BITFIELD_NAMES);
645 
646 	//Miscellaneous value fields.
647 	error_info_cper->TransactionType = readable_pair_to_integer(
648 		json_object_object_get(error_information, "transactionType"));
649 	error_info_cper->Operation = readable_pair_to_integer(
650 		json_object_object_get(error_information, "operation"));
651 	error_info_cper->Level = json_object_get_uint64(
652 		json_object_object_get(error_information, "level"));
653 	error_info_cper->ProcessorContextCorrupt = json_object_get_boolean(
654 		json_object_object_get(error_information,
655 				       "processorContextCorrupt"));
656 	error_info_cper->Corrected = json_object_get_boolean(
657 		json_object_object_get(error_information, "corrected"));
658 	error_info_cper->PrecisePC = json_object_get_boolean(
659 		json_object_object_get(error_information, "precisePC"));
660 	error_info_cper->RestartablePC = json_object_get_boolean(
661 		json_object_object_get(error_information, "restartablePC"));
662 	error_info_cper->Reserved = 0;
663 }
664 
665 //Converts a single ARM bus error information structure into a CPER structure.
666 void ir_arm_error_bus_info_to_cper(json_object *error_information,
667 				   EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper)
668 {
669 	//Validation bits.
670 	error_info_cper->ValidationBits = ir_to_bitfield(
671 		json_object_object_get(error_information, "validationBits"), 7,
672 		ARM_BUS_ERROR_VALID_BITFIELD_NAMES);
673 
674 	//Miscellaneous value fields.
675 	error_info_cper->TransactionType = readable_pair_to_integer(
676 		json_object_object_get(error_information, "transactionType"));
677 	error_info_cper->Operation = readable_pair_to_integer(
678 		json_object_object_get(error_information, "operation"));
679 	error_info_cper->Level = json_object_get_uint64(
680 		json_object_object_get(error_information, "level"));
681 	error_info_cper->ProcessorContextCorrupt = json_object_get_boolean(
682 		json_object_object_get(error_information,
683 				       "processorContextCorrupt"));
684 	error_info_cper->Corrected = json_object_get_boolean(
685 		json_object_object_get(error_information, "corrected"));
686 	error_info_cper->PrecisePC = json_object_get_boolean(
687 		json_object_object_get(error_information, "precisePC"));
688 	error_info_cper->RestartablePC = json_object_get_boolean(
689 		json_object_object_get(error_information, "restartablePC"));
690 	error_info_cper->ParticipationType = readable_pair_to_integer(
691 		json_object_object_get(error_information, "participationType"));
692 	error_info_cper->AddressSpace = readable_pair_to_integer(
693 		json_object_object_get(error_information, "addressSpace"));
694 	error_info_cper->AccessMode = readable_pair_to_integer(
695 		json_object_object_get(error_information, "accessMode"));
696 	error_info_cper->MemoryAddressAttributes = json_object_get_uint64(
697 		json_object_object_get(error_information, "memoryAttributes"));
698 	error_info_cper->Reserved = 0;
699 }
700 
701 //Converts a single ARM context information structure into CPER binary, outputting to the given stream.
702 void ir_arm_context_info_to_cper(json_object *context_info, FILE *out)
703 {
704 	EFI_ARM_CONTEXT_INFORMATION_HEADER info_header;
705 
706 	//Version, array size, context type.
707 	info_header.Version = json_object_get_int(
708 		json_object_object_get(context_info, "version"));
709 	info_header.RegisterArraySize = json_object_get_int(
710 		json_object_object_get(context_info, "registerArraySize"));
711 	info_header.RegisterContextType = readable_pair_to_integer(
712 		json_object_object_get(context_info, "registerContextType"));
713 
714 	//Flush to stream, write the register array itself.
715 	fwrite(&info_header, sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER), 1,
716 	       out);
717 	fflush(out);
718 
719 	json_object *register_array =
720 		json_object_object_get(context_info, "registerArray");
721 	switch (info_header.RegisterContextType) {
722 	case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
723 		ir_arm_aarch32_gpr_to_cper(register_array, out);
724 		break;
725 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
726 		ir_arm_aarch32_el1_to_cper(register_array, out);
727 		break;
728 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
729 		ir_arm_aarch32_el2_to_cper(register_array, out);
730 		break;
731 	case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
732 		ir_arm_aarch32_secure_to_cper(register_array, out);
733 		break;
734 	case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
735 		ir_arm_aarch64_gpr_to_cper(register_array, out);
736 		break;
737 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
738 		ir_arm_aarch64_el1_to_cper(register_array, out);
739 		break;
740 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
741 		ir_arm_aarch64_el2_to_cper(register_array, out);
742 		break;
743 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
744 		ir_arm_aarch64_el3_to_cper(register_array, out);
745 		break;
746 	case EFI_ARM_CONTEXT_TYPE_MISC:
747 		ir_arm_misc_registers_to_cper(register_array, out);
748 		break;
749 	default:
750 		//Unknown register structure.
751 		ir_arm_unknown_register_to_cper(register_array, out);
752 		break;
753 	}
754 }
755 
756 //Converts a single AARCH32 GPR CPER-JSON object to CPER binary, outputting to the given stream.
757 void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out)
758 {
759 	//Get uniform register array.
760 	EFI_ARM_V8_AARCH32_GPR reg_array;
761 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
762 			     sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
763 			     ARM_AARCH32_GPR_NAMES);
764 
765 	//Flush to stream.
766 	fwrite(&reg_array, sizeof(reg_array), 1, out);
767 	fflush(out);
768 }
769 
770 //Converts a single AARCH32 EL1 register set CPER-JSON object to CPER binary, outputting to the given stream.
771 void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out)
772 {
773 	//Get uniform register array.
774 	EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS reg_array;
775 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
776 			     sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
777 				     sizeof(UINT32),
778 			     ARM_AARCH32_EL1_REGISTER_NAMES);
779 
780 	//Flush to stream.
781 	fwrite(&reg_array, sizeof(reg_array), 1, out);
782 	fflush(out);
783 }
784 
785 //Converts a single AARCH32 EL2 register set CPER-JSON object to CPER binary, outputting to the given stream.
786 void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out)
787 {
788 	//Get uniform register array.
789 	EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS reg_array;
790 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
791 			     sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
792 				     sizeof(UINT32),
793 			     ARM_AARCH32_EL2_REGISTER_NAMES);
794 
795 	//Flush to stream.
796 	fwrite(&reg_array, sizeof(reg_array), 1, out);
797 	fflush(out);
798 }
799 
800 //Converts a single AARCH32 secure register set CPER-JSON object to CPER binary, outputting to the given stream.
801 void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out)
802 {
803 	//Get uniform register array.
804 	EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS reg_array;
805 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
806 			     sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
807 				     sizeof(UINT32),
808 			     ARM_AARCH32_SECURE_REGISTER_NAMES);
809 
810 	//Flush to stream.
811 	fwrite(&reg_array, sizeof(reg_array), 1, out);
812 	fflush(out);
813 }
814 
815 //Converts a single AARCH64 GPR CPER-JSON object to CPER binary, outputting to the given stream.
816 void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out)
817 {
818 	//Get uniform register array.
819 	EFI_ARM_V8_AARCH64_GPR reg_array;
820 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
821 			       sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
822 			       ARM_AARCH64_GPR_NAMES);
823 
824 	//Flush to stream.
825 	fwrite(&reg_array, sizeof(reg_array), 1, out);
826 	fflush(out);
827 }
828 
829 //Converts a single AARCH64 EL1 register set CPER-JSON object to CPER binary, outputting to the given stream.
830 void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out)
831 {
832 	//Get uniform register array.
833 	EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS reg_array;
834 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
835 			       sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
836 				       sizeof(UINT64),
837 			       ARM_AARCH64_EL1_REGISTER_NAMES);
838 
839 	//Flush to stream.
840 	fwrite(&reg_array, sizeof(reg_array), 1, out);
841 	fflush(out);
842 }
843 
844 //Converts a single AARCH64 EL2 register set CPER-JSON object to CPER binary, outputting to the given stream.
845 void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out)
846 {
847 	//Get uniform register array.
848 	EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS reg_array;
849 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
850 			       sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
851 				       sizeof(UINT64),
852 			       ARM_AARCH64_EL2_REGISTER_NAMES);
853 
854 	//Flush to stream.
855 	fwrite(&reg_array, sizeof(reg_array), 1, out);
856 	fflush(out);
857 }
858 
859 //Converts a single AARCH64 EL3 register set CPER-JSON object to CPER binary, outputting to the given stream.
860 void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out)
861 {
862 	//Get uniform register array.
863 	EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS reg_array;
864 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
865 			       sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
866 				       sizeof(UINT64),
867 			       ARM_AARCH64_EL3_REGISTER_NAMES);
868 
869 	//Flush to stream.
870 	fwrite(&reg_array, sizeof(reg_array), 1, out);
871 	fflush(out);
872 }
873 
874 //Converts a single ARM miscellaneous register set CPER-JSON object to CPER binary, outputting to the given stream.
875 void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out)
876 {
877 	EFI_ARM_MISC_CONTEXT_REGISTER reg_array;
878 
879 	//MRS encoding information.
880 	json_object *mrs_encoding =
881 		json_object_object_get(registers, "mrsEncoding");
882 	reg_array.MrsOp2 = json_object_get_uint64(
883 		json_object_object_get(mrs_encoding, "op2"));
884 	reg_array.MrsCrm = json_object_get_uint64(
885 		json_object_object_get(mrs_encoding, "crm"));
886 	reg_array.MrsCrn = json_object_get_uint64(
887 		json_object_object_get(mrs_encoding, "crn"));
888 	reg_array.MrsOp1 = json_object_get_uint64(
889 		json_object_object_get(mrs_encoding, "op1"));
890 	reg_array.MrsO0 = json_object_get_uint64(
891 		json_object_object_get(mrs_encoding, "o0"));
892 
893 	//Actual register value.
894 	reg_array.Value = json_object_get_uint64(
895 		json_object_object_get(registers, "value"));
896 
897 	//Flush to stream.
898 	fwrite(&reg_array, sizeof(reg_array), 1, out);
899 	fflush(out);
900 }
901 
902 //Converts a single ARM unknown register CPER-JSON object to CPER binary, outputting to the given stream.
903 void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out)
904 {
905 	//Get base64 represented data.
906 	json_object *encoded = json_object_object_get(registers, "data");
907 	char *decoded = malloc(json_object_get_string_len(encoded));
908 	size_t decoded_len = 0;
909 	if (!decoded) {
910 		printf("Failed to allocate decode output buffer. \n");
911 	} else {
912 		base64_decode(json_object_get_string(encoded),
913 			      json_object_get_string_len(encoded), decoded,
914 			      &decoded_len, 0);
915 
916 		//Flush out to stream.
917 		fwrite(&decoded, decoded_len, 1, out);
918 		fflush(out);
919 		free(decoded);
920 	}
921 }
922