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