12800cd8eSLawrence Tang /**
22800cd8eSLawrence Tang  * Describes functions for converting ARM CPER sections from binary and JSON format
32800cd8eSLawrence Tang  * into an intermediate format.
42800cd8eSLawrence Tang  *
52800cd8eSLawrence Tang  * Author: Lawrence.Tang@arm.com
62800cd8eSLawrence Tang  **/
72800cd8eSLawrence Tang 
82800cd8eSLawrence Tang #include <stdio.h>
92800cd8eSLawrence Tang #include "json.h"
10d7e8ca34SLawrence Tang #include "b64.h"
112800cd8eSLawrence Tang #include "../edk/Cper.h"
122800cd8eSLawrence Tang #include "../cper-utils.h"
132800cd8eSLawrence Tang #include "cper-section-arm.h"
142800cd8eSLawrence Tang 
153d0e4f24SLawrence Tang //Private pre-definitions.
16*e407b4c8SLawrence Tang json_object *
17*e407b4c8SLawrence Tang cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info);
18*e407b4c8SLawrence Tang json_object *
19*e407b4c8SLawrence Tang cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
20*e407b4c8SLawrence Tang 				 void **cur_pos);
21*e407b4c8SLawrence Tang json_object *
22*e407b4c8SLawrence Tang cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
23*e407b4c8SLawrence Tang 			       EFI_ARM_ERROR_INFORMATION_ENTRY *error_info);
247f21db6cSLawrence Tang json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error);
25*e407b4c8SLawrence Tang json_object *cper_arm_misc_register_array_to_ir(
26*e407b4c8SLawrence Tang 	EFI_ARM_MISC_CONTEXT_REGISTER *misc_register);
277cd13908SLawrence Tang void ir_arm_error_info_to_cper(json_object *error_info, FILE *out);
287cd13908SLawrence Tang void ir_arm_context_info_to_cper(json_object *context_info, FILE *out);
29*e407b4c8SLawrence Tang void ir_arm_error_cache_tlb_info_to_cper(
30*e407b4c8SLawrence Tang 	json_object *error_information,
31*e407b4c8SLawrence Tang 	EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper);
32*e407b4c8SLawrence Tang void ir_arm_error_bus_info_to_cper(json_object *error_information,
33*e407b4c8SLawrence Tang 				   EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper);
3471570a2aSLawrence Tang void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out);
3571570a2aSLawrence Tang void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out);
3671570a2aSLawrence Tang void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out);
3771570a2aSLawrence Tang void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out);
3871570a2aSLawrence Tang void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out);
3971570a2aSLawrence Tang void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out);
4071570a2aSLawrence Tang void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out);
4171570a2aSLawrence Tang void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out);
4271570a2aSLawrence Tang void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out);
43*e407b4c8SLawrence Tang void ir_arm_unknown_register_to_cper(json_object *registers,
44*e407b4c8SLawrence Tang 				     EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
45*e407b4c8SLawrence Tang 				     FILE *out);
463d0e4f24SLawrence Tang 
472800cd8eSLawrence Tang //Converts the given processor-generic CPER section into JSON IR.
48*e407b4c8SLawrence Tang json_object *cper_section_arm_to_ir(void *section,
49*e407b4c8SLawrence Tang 				    EFI_ERROR_SECTION_DESCRIPTOR *descriptor)
502800cd8eSLawrence Tang {
517f21db6cSLawrence Tang 	EFI_ARM_ERROR_RECORD *record = (EFI_ARM_ERROR_RECORD *)section;
522800cd8eSLawrence Tang 	json_object *section_ir = json_object_new_object();
532800cd8eSLawrence Tang 
542800cd8eSLawrence Tang 	//Validation bits.
55*e407b4c8SLawrence Tang 	json_object *validation = bitfield_to_ir(
56*e407b4c8SLawrence Tang 		record->ValidFields, 4, ARM_ERROR_VALID_BITFIELD_NAMES);
572800cd8eSLawrence Tang 	json_object_object_add(section_ir, "validationBits", validation);
582800cd8eSLawrence Tang 
592800cd8eSLawrence Tang 	//Number of error info and context info structures, and length.
60*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "errorInfoNum",
61*e407b4c8SLawrence Tang 			       json_object_new_int(record->ErrInfoNum));
62*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "contextInfoNum",
63*e407b4c8SLawrence Tang 			       json_object_new_int(record->ContextInfoNum));
64*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "sectionLength",
65*e407b4c8SLawrence Tang 			       json_object_new_uint64(record->SectionLength));
662800cd8eSLawrence Tang 
672800cd8eSLawrence Tang 	//Error affinity.
682800cd8eSLawrence Tang 	json_object *error_affinity = json_object_new_object();
69*e407b4c8SLawrence Tang 	json_object_object_add(error_affinity, "value",
70*e407b4c8SLawrence Tang 			       json_object_new_int(record->ErrorAffinityLevel));
71*e407b4c8SLawrence Tang 	json_object_object_add(
72*e407b4c8SLawrence Tang 		error_affinity, "type",
73*e407b4c8SLawrence Tang 		json_object_new_string(record->ErrorAffinityLevel < 4 ?
74*e407b4c8SLawrence Tang 						     "Vendor Defined" :
75*e407b4c8SLawrence Tang 						     "Reserved"));
762800cd8eSLawrence Tang 	json_object_object_add(section_ir, "errorAffinity", error_affinity);
772800cd8eSLawrence Tang 
782800cd8eSLawrence Tang 	//Processor ID (MPIDR_EL1) and chip ID (MIDR_EL1).
79*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "mpidrEl1",
80*e407b4c8SLawrence Tang 			       json_object_new_uint64(record->MPIDR_EL1));
81*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "midrEl1",
82*e407b4c8SLawrence Tang 			       json_object_new_uint64(record->MIDR_EL1));
832800cd8eSLawrence Tang 
842800cd8eSLawrence Tang 	//Whether the processor is running, and the state of it if so.
85*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "running",
86*e407b4c8SLawrence Tang 			       json_object_new_boolean(record->RunningState &
87*e407b4c8SLawrence Tang 						       0b1));
88*e407b4c8SLawrence Tang 	if (!(record->RunningState >> 31)) {
893d0e4f24SLawrence Tang 		//Bit 32 of running state is on, so PSCI state information is included.
902721739aSLawrence Tang 		//This can't be made human readable, as it is unknown whether this will be the pre-PSCI 1.0 format
912721739aSLawrence Tang 		//or the newer Extended StateID format.
92*e407b4c8SLawrence Tang 		json_object_object_add(
93*e407b4c8SLawrence Tang 			section_ir, "psciState",
94*e407b4c8SLawrence Tang 			json_object_new_uint64(record->PsciState));
952800cd8eSLawrence Tang 	}
962800cd8eSLawrence Tang 
973d0e4f24SLawrence Tang 	//Processor error structures.
983d0e4f24SLawrence Tang 	json_object *error_info_array = json_object_new_array();
99*e407b4c8SLawrence Tang 	EFI_ARM_ERROR_INFORMATION_ENTRY *cur_error =
100*e407b4c8SLawrence Tang 		(EFI_ARM_ERROR_INFORMATION_ENTRY *)(record + 1);
101*e407b4c8SLawrence Tang 	for (int i = 0; i < record->ErrInfoNum; i++) {
102*e407b4c8SLawrence Tang 		json_object_array_add(error_info_array,
103*e407b4c8SLawrence Tang 				      cper_arm_error_info_to_ir(cur_error));
1047f21db6cSLawrence Tang 		cur_error++;
1053d0e4f24SLawrence Tang 	}
1067f21db6cSLawrence Tang 	json_object_object_add(section_ir, "errorInfo", error_info_array);
1077f21db6cSLawrence Tang 
1087f21db6cSLawrence Tang 	//Processor context structures.
1097f21db6cSLawrence Tang 	//The current position is moved within the processing, as it is a dynamic size structure.
1107f21db6cSLawrence Tang 	void *cur_pos = (void *)cur_error;
1113636d3c2SLawrence Tang 	json_object *context_info_array = json_object_new_array();
112*e407b4c8SLawrence Tang 	for (int i = 0; i < record->ContextInfoNum; i++) {
113*e407b4c8SLawrence Tang 		EFI_ARM_CONTEXT_INFORMATION_HEADER *header =
114*e407b4c8SLawrence Tang 			(EFI_ARM_CONTEXT_INFORMATION_HEADER *)cur_pos;
115*e407b4c8SLawrence Tang 		json_object *processor_context =
116*e407b4c8SLawrence Tang 			cper_arm_processor_context_to_ir(header, &cur_pos);
1173636d3c2SLawrence Tang 		json_object_array_add(context_info_array, processor_context);
1183636d3c2SLawrence Tang 	}
1193636d3c2SLawrence Tang 	json_object_object_add(section_ir, "contextInfo", context_info_array);
1207f21db6cSLawrence Tang 
1217f21db6cSLawrence Tang 	//Is there any vendor-specific information following?
122*e407b4c8SLawrence Tang 	if (cur_pos < section + record->SectionLength) {
123d7e8ca34SLawrence Tang 		json_object *vendor_specific = json_object_new_object();
124*e407b4c8SLawrence Tang 		char *encoded =
125*e407b4c8SLawrence Tang 			b64_encode((unsigned char *)cur_pos,
126*e407b4c8SLawrence Tang 				   section + record->SectionLength - cur_pos);
127*e407b4c8SLawrence Tang 		json_object_object_add(vendor_specific, "data",
128*e407b4c8SLawrence Tang 				       json_object_new_string(encoded));
129d7e8ca34SLawrence Tang 		free(encoded);
130d7e8ca34SLawrence Tang 
131*e407b4c8SLawrence Tang 		json_object_object_add(section_ir, "vendorSpecificInfo",
132*e407b4c8SLawrence Tang 				       vendor_specific);
1337f21db6cSLawrence Tang 	}
1347f21db6cSLawrence Tang 
1352800cd8eSLawrence Tang 	return section_ir;
1362800cd8eSLawrence Tang }
1373d0e4f24SLawrence Tang 
1383d0e4f24SLawrence Tang //Converts a single ARM Process Error Information structure into JSON IR.
139*e407b4c8SLawrence Tang json_object *
140*e407b4c8SLawrence Tang cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info)
1413d0e4f24SLawrence Tang {
1423d0e4f24SLawrence Tang 	json_object *error_info_ir = json_object_new_object();
1433d0e4f24SLawrence Tang 
1443d0e4f24SLawrence Tang 	//Version, length.
145*e407b4c8SLawrence Tang 	json_object_object_add(error_info_ir, "version",
146*e407b4c8SLawrence Tang 			       json_object_new_int(error_info->Version));
147*e407b4c8SLawrence Tang 	json_object_object_add(error_info_ir, "length",
148*e407b4c8SLawrence Tang 			       json_object_new_int(error_info->Length));
1493d0e4f24SLawrence Tang 
1503d0e4f24SLawrence Tang 	//Validation bitfield.
151*e407b4c8SLawrence Tang 	json_object *validation =
152*e407b4c8SLawrence Tang 		bitfield_to_ir(error_info->ValidationBits, 5,
153*e407b4c8SLawrence Tang 			       ARM_ERROR_INFO_ENTRY_VALID_BITFIELD_NAMES);
1543d0e4f24SLawrence Tang 	json_object_object_add(error_info_ir, "validationBits", validation);
1553d0e4f24SLawrence Tang 
1563d0e4f24SLawrence Tang 	//The type of error information in this log.
157*e407b4c8SLawrence Tang 	json_object *error_type = integer_to_readable_pair(
158*e407b4c8SLawrence Tang 		error_info->Type, 4, ARM_ERROR_INFO_ENTRY_INFO_TYPES_KEYS,
159*e407b4c8SLawrence Tang 		ARM_ERROR_INFO_ENTRY_INFO_TYPES_VALUES, "Unknown (Reserved)");
1603d0e4f24SLawrence Tang 	json_object_object_add(error_info_ir, "errorType", error_type);
1613d0e4f24SLawrence Tang 
1623d0e4f24SLawrence Tang 	//Multiple error count.
16322a467ceSLawrence Tang 	json_object *multiple_error = json_object_new_object();
164*e407b4c8SLawrence Tang 	json_object_object_add(multiple_error, "value",
165*e407b4c8SLawrence Tang 			       json_object_new_int(error_info->MultipleError));
166*e407b4c8SLawrence Tang 	json_object_object_add(
167*e407b4c8SLawrence Tang 		multiple_error, "type",
168*e407b4c8SLawrence Tang 		json_object_new_string(error_info->MultipleError < 1 ?
169*e407b4c8SLawrence Tang 						     "Single Error" :
170*e407b4c8SLawrence Tang 						     "Multiple Errors"));
1713d0e4f24SLawrence Tang 	json_object_object_add(error_info_ir, "multipleError", multiple_error);
1723d0e4f24SLawrence Tang 
1733d0e4f24SLawrence Tang 	//Flags.
174*e407b4c8SLawrence Tang 	json_object *flags = bitfield_to_ir(error_info->Flags, 4,
175*e407b4c8SLawrence Tang 					    ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
1763d0e4f24SLawrence Tang 	json_object_object_add(error_info_ir, "flags", flags);
1773d0e4f24SLawrence Tang 
1783d0e4f24SLawrence Tang 	//Error information, split by type.
1793d0e4f24SLawrence Tang 	json_object *error_subinfo = NULL;
180*e407b4c8SLawrence Tang 	switch (error_info->Type) {
18171570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_CACHE: //Cache
18271570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_TLB: //TLB
183*e407b4c8SLawrence Tang 		error_subinfo = cper_arm_cache_tlb_error_to_ir(
184*e407b4c8SLawrence Tang 			(EFI_ARM_CACHE_ERROR_STRUCTURE *)&error_info
185*e407b4c8SLawrence Tang 				->ErrorInformation,
186*e407b4c8SLawrence Tang 			error_info);
1873d0e4f24SLawrence Tang 		break;
18871570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_BUS: //Bus
189*e407b4c8SLawrence Tang 		error_subinfo = cper_arm_bus_error_to_ir(
190*e407b4c8SLawrence Tang 			(EFI_ARM_BUS_ERROR_STRUCTURE *)&error_info
191*e407b4c8SLawrence Tang 				->ErrorInformation);
1923d0e4f24SLawrence Tang 		break;
19371570a2aSLawrence Tang 
19471570a2aSLawrence Tang 	default:
19571570a2aSLawrence Tang 		//Unknown/microarch, so can't be made readable. Simply dump as a uint64 data object.
19671570a2aSLawrence Tang 		error_subinfo = json_object_new_object();
197*e407b4c8SLawrence Tang 		json_object_object_add(
198*e407b4c8SLawrence Tang 			error_subinfo, "data",
199*e407b4c8SLawrence Tang 			json_object_new_uint64(
200*e407b4c8SLawrence Tang 				*((UINT64 *)&error_info->ErrorInformation)));
20171570a2aSLawrence Tang 		break;
2023d0e4f24SLawrence Tang 	}
203*e407b4c8SLawrence Tang 	json_object_object_add(error_info_ir, "errorInformation",
204*e407b4c8SLawrence Tang 			       error_subinfo);
2053d0e4f24SLawrence Tang 
206b98ec66cSLawrence Tang 	//Virtual fault address, physical fault address.
207*e407b4c8SLawrence Tang 	json_object_object_add(
208*e407b4c8SLawrence Tang 		error_info_ir, "virtualFaultAddress",
209*e407b4c8SLawrence Tang 		json_object_new_uint64(error_info->VirtualFaultAddress));
210*e407b4c8SLawrence Tang 	json_object_object_add(
211*e407b4c8SLawrence Tang 		error_info_ir, "physicalFaultAddress",
212*e407b4c8SLawrence Tang 		json_object_new_uint64(error_info->PhysicalFaultAddress));
213b98ec66cSLawrence Tang 
2143d0e4f24SLawrence Tang 	return error_info_ir;
2153d0e4f24SLawrence Tang }
2163d0e4f24SLawrence Tang 
2177f21db6cSLawrence Tang //Converts a single ARM cache/TLB error information structure into JSON IR format.
218*e407b4c8SLawrence Tang json_object *
219*e407b4c8SLawrence Tang cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
220*e407b4c8SLawrence Tang 			       EFI_ARM_ERROR_INFORMATION_ENTRY *error_info)
2213d0e4f24SLawrence Tang {
2227f21db6cSLawrence Tang 	json_object *cache_tlb_error_ir = json_object_new_object();
2233d0e4f24SLawrence Tang 
2247f21db6cSLawrence Tang 	//Validation bitfield.
225*e407b4c8SLawrence Tang 	json_object *validation =
226*e407b4c8SLawrence Tang 		bitfield_to_ir(cache_tlb_error->ValidationBits, 7,
227*e407b4c8SLawrence Tang 			       ARM_CACHE_TLB_ERROR_VALID_BITFIELD_NAMES);
228*e407b4c8SLawrence Tang 	json_object_object_add(cache_tlb_error_ir, "validationBits",
229*e407b4c8SLawrence Tang 			       validation);
2307f21db6cSLawrence Tang 
2317f21db6cSLawrence Tang 	//Transaction type.
232*e407b4c8SLawrence Tang 	json_object *transaction_type = integer_to_readable_pair(
233*e407b4c8SLawrence Tang 		cache_tlb_error->TransactionType, 3,
2347f21db6cSLawrence Tang 		ARM_ERROR_TRANSACTION_TYPES_KEYS,
235*e407b4c8SLawrence Tang 		ARM_ERROR_TRANSACTION_TYPES_VALUES, "Unknown (Reserved)");
236*e407b4c8SLawrence Tang 	json_object_object_add(cache_tlb_error_ir, "transactionType",
237*e407b4c8SLawrence Tang 			       transaction_type);
2387f21db6cSLawrence Tang 
2397f21db6cSLawrence Tang 	//Operation.
2407f21db6cSLawrence Tang 	json_object *operation;
241*e407b4c8SLawrence Tang 	if (error_info->Type == 0) {
2427f21db6cSLawrence Tang 		//Cache operation.
243*e407b4c8SLawrence Tang 		operation = integer_to_readable_pair(
244*e407b4c8SLawrence Tang 			cache_tlb_error->Operation, 11,
2457f21db6cSLawrence Tang 			ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
2467f21db6cSLawrence Tang 			ARM_CACHE_BUS_OPERATION_TYPES_VALUES,
2477f21db6cSLawrence Tang 			"Unknown (Reserved)");
248*e407b4c8SLawrence Tang 	} else {
2497f21db6cSLawrence Tang 		//TLB operation.
250*e407b4c8SLawrence Tang 		operation = integer_to_readable_pair(
251*e407b4c8SLawrence Tang 			cache_tlb_error->Operation, 9,
2527f21db6cSLawrence Tang 			ARM_TLB_OPERATION_TYPES_KEYS,
253*e407b4c8SLawrence Tang 			ARM_TLB_OPERATION_TYPES_VALUES, "Unknown (Reserved)");
2547f21db6cSLawrence Tang 	}
2557f21db6cSLawrence Tang 	json_object_object_add(cache_tlb_error_ir, "operation", operation);
2567f21db6cSLawrence Tang 
2577f21db6cSLawrence Tang 	//Miscellaneous remaining fields.
258*e407b4c8SLawrence Tang 	json_object_object_add(cache_tlb_error_ir, "level",
259*e407b4c8SLawrence Tang 			       json_object_new_int(cache_tlb_error->Level));
260*e407b4c8SLawrence Tang 	json_object_object_add(
261*e407b4c8SLawrence Tang 		cache_tlb_error_ir, "processorContextCorrupt",
262*e407b4c8SLawrence Tang 		json_object_new_boolean(
263*e407b4c8SLawrence Tang 			cache_tlb_error->ProcessorContextCorrupt));
264*e407b4c8SLawrence Tang 	json_object_object_add(
265*e407b4c8SLawrence Tang 		cache_tlb_error_ir, "corrected",
266*e407b4c8SLawrence Tang 		json_object_new_boolean(cache_tlb_error->Corrected));
267*e407b4c8SLawrence Tang 	json_object_object_add(
268*e407b4c8SLawrence Tang 		cache_tlb_error_ir, "precisePC",
269*e407b4c8SLawrence Tang 		json_object_new_boolean(cache_tlb_error->PrecisePC));
270*e407b4c8SLawrence Tang 	json_object_object_add(
271*e407b4c8SLawrence Tang 		cache_tlb_error_ir, "restartablePC",
272*e407b4c8SLawrence Tang 		json_object_new_boolean(cache_tlb_error->RestartablePC));
2737f21db6cSLawrence Tang 	return cache_tlb_error_ir;
2743d0e4f24SLawrence Tang }
2753d0e4f24SLawrence Tang 
2763d0e4f24SLawrence Tang //Converts a single ARM bus error information structure into JSON IR format.
2777f21db6cSLawrence Tang json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error)
2783d0e4f24SLawrence Tang {
2797f21db6cSLawrence Tang 	json_object *bus_error_ir = json_object_new_object();
2807f21db6cSLawrence Tang 
2817f21db6cSLawrence Tang 	//Validation bits.
282*e407b4c8SLawrence Tang 	json_object *validation =
283*e407b4c8SLawrence Tang 		bitfield_to_ir(bus_error->ValidationBits, 12,
284*e407b4c8SLawrence Tang 			       ARM_BUS_ERROR_VALID_BITFIELD_NAMES);
2857f21db6cSLawrence Tang 	json_object_object_add(bus_error_ir, "validationBits", validation);
2867f21db6cSLawrence Tang 
2877f21db6cSLawrence Tang 	//Transaction type.
288*e407b4c8SLawrence Tang 	json_object *transaction_type = integer_to_readable_pair(
289*e407b4c8SLawrence Tang 		bus_error->TransactionType, 3, ARM_ERROR_TRANSACTION_TYPES_KEYS,
290*e407b4c8SLawrence Tang 		ARM_ERROR_TRANSACTION_TYPES_VALUES, "Unknown (Reserved)");
291*e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "transactionType",
292*e407b4c8SLawrence Tang 			       transaction_type);
2937f21db6cSLawrence Tang 
2947f21db6cSLawrence Tang 	//Operation.
295*e407b4c8SLawrence Tang 	json_object *operation = integer_to_readable_pair(
296*e407b4c8SLawrence Tang 		bus_error->Operation, 7, ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
297*e407b4c8SLawrence Tang 		ARM_CACHE_BUS_OPERATION_TYPES_VALUES, "Unknown (Reserved)");
2987f21db6cSLawrence Tang 	json_object_object_add(bus_error_ir, "operation", operation);
2997f21db6cSLawrence Tang 
3007f21db6cSLawrence Tang 	//Affinity level of bus error, + miscellaneous fields.
301*e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "level",
302*e407b4c8SLawrence Tang 			       json_object_new_int(bus_error->Level));
303*e407b4c8SLawrence Tang 	json_object_object_add(
304*e407b4c8SLawrence Tang 		bus_error_ir, "processorContextCorrupt",
305*e407b4c8SLawrence Tang 		json_object_new_boolean(bus_error->ProcessorContextCorrupt));
306*e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "corrected",
307*e407b4c8SLawrence Tang 			       json_object_new_boolean(bus_error->Corrected));
308*e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "precisePC",
309*e407b4c8SLawrence Tang 			       json_object_new_boolean(bus_error->PrecisePC));
310*e407b4c8SLawrence Tang 	json_object_object_add(
311*e407b4c8SLawrence Tang 		bus_error_ir, "restartablePC",
312*e407b4c8SLawrence Tang 		json_object_new_boolean(bus_error->RestartablePC));
313*e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "timedOut",
314*e407b4c8SLawrence Tang 			       json_object_new_boolean(bus_error->TimeOut));
3157f21db6cSLawrence Tang 
3167f21db6cSLawrence Tang 	//Participation type.
317*e407b4c8SLawrence Tang 	json_object *participation_type = integer_to_readable_pair(
318*e407b4c8SLawrence Tang 		bus_error->ParticipationType, 4,
3197f21db6cSLawrence Tang 		ARM_BUS_PARTICIPATION_TYPES_KEYS,
320*e407b4c8SLawrence Tang 		ARM_BUS_PARTICIPATION_TYPES_VALUES, "Unknown");
321*e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "participationType",
322*e407b4c8SLawrence Tang 			       participation_type);
3237f21db6cSLawrence Tang 
3247f21db6cSLawrence Tang 	//Address space.
325*e407b4c8SLawrence Tang 	json_object *address_space = integer_to_readable_pair(
326*e407b4c8SLawrence Tang 		bus_error->AddressSpace, 3, ARM_BUS_ADDRESS_SPACE_TYPES_KEYS,
327*e407b4c8SLawrence Tang 		ARM_BUS_ADDRESS_SPACE_TYPES_VALUES, "Unknown");
3287f21db6cSLawrence Tang 	json_object_object_add(bus_error_ir, "addressSpace", address_space);
3297f21db6cSLawrence Tang 
3307f21db6cSLawrence Tang 	//Memory access attributes.
3317f21db6cSLawrence Tang 	//todo: find the specification of these in the ARM ARM
332*e407b4c8SLawrence Tang 	json_object_object_add(
333*e407b4c8SLawrence Tang 		bus_error_ir, "memoryAttributes",
334*e407b4c8SLawrence Tang 		json_object_new_int(bus_error->MemoryAddressAttributes));
3357f21db6cSLawrence Tang 
3367f21db6cSLawrence Tang 	//Access Mode
3377f21db6cSLawrence Tang 	json_object *access_mode = json_object_new_object();
338*e407b4c8SLawrence Tang 	json_object_object_add(access_mode, "value",
339*e407b4c8SLawrence Tang 			       json_object_new_int(bus_error->AccessMode));
340*e407b4c8SLawrence Tang 	json_object_object_add(
341*e407b4c8SLawrence Tang 		access_mode, "name",
342*e407b4c8SLawrence Tang 		json_object_new_string(bus_error->AccessMode == 0 ? "Secure" :
343*e407b4c8SLawrence Tang 									  "Normal"));
3447f21db6cSLawrence Tang 	json_object_object_add(bus_error_ir, "accessMode", access_mode);
3457f21db6cSLawrence Tang 
3467f21db6cSLawrence Tang 	return bus_error_ir;
3477f21db6cSLawrence Tang }
3487f21db6cSLawrence Tang 
3497f21db6cSLawrence Tang //Converts a single ARM processor context block into JSON IR.
350*e407b4c8SLawrence Tang json_object *
351*e407b4c8SLawrence Tang cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
352*e407b4c8SLawrence Tang 				 void **cur_pos)
3537f21db6cSLawrence Tang {
3547f21db6cSLawrence Tang 	json_object *context_ir = json_object_new_object();
3557f21db6cSLawrence Tang 
35671570a2aSLawrence Tang 	//Version.
357*e407b4c8SLawrence Tang 	json_object_object_add(context_ir, "version",
358*e407b4c8SLawrence Tang 			       json_object_new_int(header->Version));
35971570a2aSLawrence Tang 
3607f21db6cSLawrence Tang 	//Add the context type.
361*e407b4c8SLawrence Tang 	json_object *context_type = integer_to_readable_pair(
362*e407b4c8SLawrence Tang 		header->RegisterContextType, 9,
3637f21db6cSLawrence Tang 		ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_KEYS,
3647f21db6cSLawrence Tang 		ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_VALUES,
3657f21db6cSLawrence Tang 		"Unknown (Reserved)");
3667f21db6cSLawrence Tang 	json_object_object_add(context_ir, "registerContextType", context_type);
3677f21db6cSLawrence Tang 
3687f21db6cSLawrence Tang 	//Register array size (bytes).
369*e407b4c8SLawrence Tang 	json_object_object_add(
370*e407b4c8SLawrence Tang 		context_ir, "registerArraySize",
371*e407b4c8SLawrence Tang 		json_object_new_uint64(header->RegisterArraySize));
3727f21db6cSLawrence Tang 
3737f21db6cSLawrence Tang 	//The register array itself.
3747f21db6cSLawrence Tang 	*cur_pos = (void *)(header + 1);
3757f21db6cSLawrence Tang 	json_object *register_array = NULL;
376*e407b4c8SLawrence Tang 	switch (header->RegisterContextType) {
3777f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
378*e407b4c8SLawrence Tang 		register_array = uniform_struct_to_ir(
379*e407b4c8SLawrence Tang 			(UINT32 *)cur_pos,
380*e407b4c8SLawrence Tang 			sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
381*e407b4c8SLawrence Tang 			ARM_AARCH32_GPR_NAMES);
3827f21db6cSLawrence Tang 		break;
3837f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
384*e407b4c8SLawrence Tang 		register_array = uniform_struct_to_ir(
385*e407b4c8SLawrence Tang 			(UINT32 *)cur_pos,
386*e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
387*e407b4c8SLawrence Tang 				sizeof(UINT32),
388*e407b4c8SLawrence Tang 			ARM_AARCH32_EL1_REGISTER_NAMES);
3897f21db6cSLawrence Tang 		break;
3907f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
391*e407b4c8SLawrence Tang 		register_array = uniform_struct_to_ir(
392*e407b4c8SLawrence Tang 			(UINT32 *)cur_pos,
393*e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
394*e407b4c8SLawrence Tang 				sizeof(UINT32),
395*e407b4c8SLawrence Tang 			ARM_AARCH32_EL2_REGISTER_NAMES);
3967f21db6cSLawrence Tang 		break;
3977f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
398*e407b4c8SLawrence Tang 		register_array = uniform_struct_to_ir(
399*e407b4c8SLawrence Tang 			(UINT32 *)cur_pos,
400*e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
401*e407b4c8SLawrence Tang 				sizeof(UINT32),
402*e407b4c8SLawrence Tang 			ARM_AARCH32_SECURE_REGISTER_NAMES);
4037f21db6cSLawrence Tang 		break;
4047f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
405*e407b4c8SLawrence Tang 		register_array = uniform_struct64_to_ir(
406*e407b4c8SLawrence Tang 			(UINT64 *)cur_pos,
407*e407b4c8SLawrence Tang 			sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
408*e407b4c8SLawrence Tang 			ARM_AARCH64_GPR_NAMES);
4097f21db6cSLawrence Tang 		break;
4107f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
411*e407b4c8SLawrence Tang 		register_array = uniform_struct64_to_ir(
412*e407b4c8SLawrence Tang 			(UINT64 *)cur_pos,
413*e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
414*e407b4c8SLawrence Tang 				sizeof(UINT64),
415*e407b4c8SLawrence Tang 			ARM_AARCH64_EL1_REGISTER_NAMES);
4167f21db6cSLawrence Tang 		break;
4177f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
418*e407b4c8SLawrence Tang 		register_array = uniform_struct64_to_ir(
419*e407b4c8SLawrence Tang 			(UINT64 *)cur_pos,
420*e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
421*e407b4c8SLawrence Tang 				sizeof(UINT64),
422*e407b4c8SLawrence Tang 			ARM_AARCH64_EL2_REGISTER_NAMES);
4237f21db6cSLawrence Tang 		break;
4247f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
425*e407b4c8SLawrence Tang 		register_array = uniform_struct64_to_ir(
426*e407b4c8SLawrence Tang 			(UINT64 *)cur_pos,
427*e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
428*e407b4c8SLawrence Tang 				sizeof(UINT64),
429*e407b4c8SLawrence Tang 			ARM_AARCH64_EL3_REGISTER_NAMES);
4307f21db6cSLawrence Tang 		break;
4317f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_MISC:
432*e407b4c8SLawrence Tang 		register_array = cper_arm_misc_register_array_to_ir(
433*e407b4c8SLawrence Tang 			(EFI_ARM_MISC_CONTEXT_REGISTER *)cur_pos);
4347f21db6cSLawrence Tang 		break;
4357f21db6cSLawrence Tang 	default:
436d7e8ca34SLawrence Tang 		//Unknown register array type, add as base64 data instead.
4377f21db6cSLawrence Tang 		register_array = json_object_new_object();
438*e407b4c8SLawrence Tang 		char *encoded = b64_encode((unsigned char *)cur_pos,
439*e407b4c8SLawrence Tang 					   header->RegisterArraySize);
440*e407b4c8SLawrence Tang 		json_object_object_add(register_array, "data",
441*e407b4c8SLawrence Tang 				       json_object_new_string(encoded));
442d7e8ca34SLawrence Tang 		free(encoded);
4437f21db6cSLawrence Tang 		break;
4447f21db6cSLawrence Tang 	}
4453636d3c2SLawrence Tang 	json_object_object_add(context_ir, "registerArray", register_array);
4467f21db6cSLawrence Tang 
4477f21db6cSLawrence Tang 	//Set the current position to after the processor context structure.
4487f21db6cSLawrence Tang 	*cur_pos = (UINT8 *)(*cur_pos) + header->RegisterArraySize;
4497f21db6cSLawrence Tang 
4507f21db6cSLawrence Tang 	return context_ir;
4517f21db6cSLawrence Tang }
4527f21db6cSLawrence Tang 
4537f21db6cSLawrence Tang //Converts a single CPER ARM miscellaneous register array to JSON IR format.
454*e407b4c8SLawrence Tang json_object *
455*e407b4c8SLawrence Tang cper_arm_misc_register_array_to_ir(EFI_ARM_MISC_CONTEXT_REGISTER *misc_register)
4567f21db6cSLawrence Tang {
4577f21db6cSLawrence Tang 	json_object *register_array = json_object_new_object();
4587f21db6cSLawrence Tang 	json_object *mrs_encoding = json_object_new_object();
459*e407b4c8SLawrence Tang 	json_object_object_add(mrs_encoding, "op2",
460*e407b4c8SLawrence Tang 			       json_object_new_uint64(misc_register->MrsOp2));
461*e407b4c8SLawrence Tang 	json_object_object_add(mrs_encoding, "crm",
462*e407b4c8SLawrence Tang 			       json_object_new_uint64(misc_register->MrsCrm));
463*e407b4c8SLawrence Tang 	json_object_object_add(mrs_encoding, "crn",
464*e407b4c8SLawrence Tang 			       json_object_new_uint64(misc_register->MrsCrn));
465*e407b4c8SLawrence Tang 	json_object_object_add(mrs_encoding, "op1",
466*e407b4c8SLawrence Tang 			       json_object_new_uint64(misc_register->MrsOp1));
467*e407b4c8SLawrence Tang 	json_object_object_add(mrs_encoding, "o0",
468*e407b4c8SLawrence Tang 			       json_object_new_uint64(misc_register->MrsO0));
4697f21db6cSLawrence Tang 	json_object_object_add(register_array, "mrsEncoding", mrs_encoding);
470*e407b4c8SLawrence Tang 	json_object_object_add(register_array, "value",
471*e407b4c8SLawrence Tang 			       json_object_new_uint64(misc_register->Value));
4727f21db6cSLawrence Tang 
4737f21db6cSLawrence Tang 	return register_array;
4743d0e4f24SLawrence Tang }
4757cd13908SLawrence Tang 
4767cd13908SLawrence Tang //Converts a single CPER-JSON ARM error section into CPER binary, outputting to the given stream.
4777cd13908SLawrence Tang void ir_section_arm_to_cper(json_object *section, FILE *out)
4787cd13908SLawrence Tang {
479*e407b4c8SLawrence Tang 	EFI_ARM_ERROR_RECORD *section_cper =
480*e407b4c8SLawrence Tang 		(EFI_ARM_ERROR_RECORD *)calloc(1, sizeof(EFI_ARM_ERROR_RECORD));
48101e3a44dSLawrence Tang 	long starting_stream_pos = ftell(out);
4827cd13908SLawrence Tang 
4837cd13908SLawrence Tang 	//Validation bits.
484*e407b4c8SLawrence Tang 	section_cper->ValidFields = ir_to_bitfield(
485*e407b4c8SLawrence Tang 		json_object_object_get(section, "validationBits"), 4,
486*e407b4c8SLawrence Tang 		ARM_ERROR_VALID_BITFIELD_NAMES);
4877cd13908SLawrence Tang 
4887cd13908SLawrence Tang 	//Count of error/context info structures.
489*e407b4c8SLawrence Tang 	section_cper->ErrInfoNum = json_object_get_int(
490*e407b4c8SLawrence Tang 		json_object_object_get(section, "errorInfoNum"));
491*e407b4c8SLawrence Tang 	section_cper->ContextInfoNum = json_object_get_int(
492*e407b4c8SLawrence Tang 		json_object_object_get(section, "contextInfoNum"));
4937cd13908SLawrence Tang 
4947cd13908SLawrence Tang 	//Miscellaneous raw value fields.
495*e407b4c8SLawrence Tang 	section_cper->SectionLength = json_object_get_uint64(
496*e407b4c8SLawrence Tang 		json_object_object_get(section, "sectionLength"));
497*e407b4c8SLawrence Tang 	section_cper->ErrorAffinityLevel = readable_pair_to_integer(
498*e407b4c8SLawrence Tang 		json_object_object_get(section, "errorAffinity"));
499*e407b4c8SLawrence Tang 	section_cper->MPIDR_EL1 = json_object_get_uint64(
500*e407b4c8SLawrence Tang 		json_object_object_get(section, "mpidrEl1"));
501*e407b4c8SLawrence Tang 	section_cper->MIDR_EL1 = json_object_get_uint64(
502*e407b4c8SLawrence Tang 		json_object_object_get(section, "midrEl1"));
503*e407b4c8SLawrence Tang 	section_cper->RunningState = json_object_get_boolean(
504*e407b4c8SLawrence Tang 		json_object_object_get(section, "running"));
5057cd13908SLawrence Tang 
5067cd13908SLawrence Tang 	//Optional PSCI state.
5077cd13908SLawrence Tang 	json_object *psci_state = json_object_object_get(section, "psciState");
5087cd13908SLawrence Tang 	if (psci_state != NULL)
5097cd13908SLawrence Tang 		section_cper->PsciState = json_object_get_uint64(psci_state);
5107cd13908SLawrence Tang 
5117cd13908SLawrence Tang 	//Flush header to stream.
5127cd13908SLawrence Tang 	fwrite(section_cper, sizeof(EFI_ARM_ERROR_RECORD), 1, out);
5137cd13908SLawrence Tang 	fflush(out);
5147cd13908SLawrence Tang 
5157cd13908SLawrence Tang 	//Error info structure array.
5167cd13908SLawrence Tang 	json_object *error_info = json_object_object_get(section, "errorInfo");
5177cd13908SLawrence Tang 	for (int i = 0; i < section_cper->ErrInfoNum; i++)
518*e407b4c8SLawrence Tang 		ir_arm_error_info_to_cper(
519*e407b4c8SLawrence Tang 			json_object_array_get_idx(error_info, i), out);
5207cd13908SLawrence Tang 
5217cd13908SLawrence Tang 	//Context info structure array.
522*e407b4c8SLawrence Tang 	json_object *context_info =
523*e407b4c8SLawrence Tang 		json_object_object_get(section, "contextInfo");
5247cd13908SLawrence Tang 	for (int i = 0; i < section_cper->ContextInfoNum; i++)
525*e407b4c8SLawrence Tang 		ir_arm_context_info_to_cper(
526*e407b4c8SLawrence Tang 			json_object_array_get_idx(context_info, i), out);
5277cd13908SLawrence Tang 
5287cd13908SLawrence Tang 	//Vendor specific error info.
529*e407b4c8SLawrence Tang 	json_object *vendor_specific_info =
530*e407b4c8SLawrence Tang 		json_object_object_get(section, "vendorSpecificInfo");
531*e407b4c8SLawrence Tang 	if (vendor_specific_info != NULL) {
532*e407b4c8SLawrence Tang 		json_object *vendor_info_string =
533*e407b4c8SLawrence Tang 			json_object_object_get(vendor_specific_info, "data");
534*e407b4c8SLawrence Tang 		int vendor_specific_len =
535*e407b4c8SLawrence Tang 			json_object_get_string_len(vendor_info_string);
536*e407b4c8SLawrence Tang 		UINT8 *decoded =
537*e407b4c8SLawrence Tang 			b64_decode(json_object_get_string(vendor_info_string),
538*e407b4c8SLawrence Tang 				   vendor_specific_len);
53901e3a44dSLawrence Tang 
54001e3a44dSLawrence Tang 		//Write out to file.
54101e3a44dSLawrence Tang 		long cur_stream_pos = ftell(out);
542*e407b4c8SLawrence Tang 		fwrite(decoded,
543*e407b4c8SLawrence Tang 		       starting_stream_pos + section_cper->SectionLength -
544*e407b4c8SLawrence Tang 			       cur_stream_pos,
545*e407b4c8SLawrence Tang 		       1, out);
5467cd13908SLawrence Tang 		fflush(out);
5477cd13908SLawrence Tang 		free(decoded);
5487cd13908SLawrence Tang 	}
5497cd13908SLawrence Tang 
5507cd13908SLawrence Tang 	//Free remaining resources.
5517cd13908SLawrence Tang 	free(section_cper);
5527cd13908SLawrence Tang }
5537cd13908SLawrence Tang 
5547cd13908SLawrence Tang //Converts a single ARM error information structure into CPER binary, outputting to the given stream.
5557cd13908SLawrence Tang void ir_arm_error_info_to_cper(json_object *error_info, FILE *out)
5567cd13908SLawrence Tang {
5577cd13908SLawrence Tang 	EFI_ARM_ERROR_INFORMATION_ENTRY error_info_cper;
5587cd13908SLawrence Tang 
5597cd13908SLawrence Tang 	//Version, length.
560*e407b4c8SLawrence Tang 	error_info_cper.Version = json_object_get_int(
561*e407b4c8SLawrence Tang 		json_object_object_get(error_info, "version"));
562*e407b4c8SLawrence Tang 	error_info_cper.Length = json_object_get_int(
563*e407b4c8SLawrence Tang 		json_object_object_get(error_info, "length"));
5647cd13908SLawrence Tang 
5657cd13908SLawrence Tang 	//Validation bits.
566*e407b4c8SLawrence Tang 	error_info_cper.ValidationBits = ir_to_bitfield(
567*e407b4c8SLawrence Tang 		json_object_object_get(error_info, "validationBits"), 5,
568*e407b4c8SLawrence Tang 		ARM_ERROR_INFO_ENTRY_VALID_BITFIELD_NAMES);
5697cd13908SLawrence Tang 
5707cd13908SLawrence Tang 	//Type, multiple error.
571*e407b4c8SLawrence Tang 	error_info_cper.Type = (UINT8)readable_pair_to_integer(
572*e407b4c8SLawrence Tang 		json_object_object_get(error_info, "type"));
573*e407b4c8SLawrence Tang 	error_info_cper.MultipleError = (UINT16)readable_pair_to_integer(
574*e407b4c8SLawrence Tang 		json_object_object_get(error_info, "multipleError"));
5757cd13908SLawrence Tang 
5767cd13908SLawrence Tang 	//Flags object.
577*e407b4c8SLawrence Tang 	error_info_cper.Flags = (UINT8)ir_to_bitfield(
578*e407b4c8SLawrence Tang 		json_object_object_get(error_info, "flags"), 4,
579*e407b4c8SLawrence Tang 		ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
5807cd13908SLawrence Tang 
5817cd13908SLawrence Tang 	//Error information.
582*e407b4c8SLawrence Tang 	json_object *error_info_information =
583*e407b4c8SLawrence Tang 		json_object_object_get(error_info, "errorInformation");
584*e407b4c8SLawrence Tang 	switch (error_info_cper.Type) {
58571570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_CACHE:
58671570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_TLB:
587*e407b4c8SLawrence Tang 		ir_arm_error_cache_tlb_info_to_cper(
588*e407b4c8SLawrence Tang 			error_info_information,
589*e407b4c8SLawrence Tang 			&error_info_cper.ErrorInformation.CacheError);
59071570a2aSLawrence Tang 		break;
59171570a2aSLawrence Tang 
59271570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_BUS:
593*e407b4c8SLawrence Tang 		ir_arm_error_bus_info_to_cper(
594*e407b4c8SLawrence Tang 			error_info_information,
595*e407b4c8SLawrence Tang 			&error_info_cper.ErrorInformation.BusError);
59671570a2aSLawrence Tang 		break;
59771570a2aSLawrence Tang 
59871570a2aSLawrence Tang 	default:
59971570a2aSLawrence Tang 		//Unknown error information type.
60071570a2aSLawrence Tang 		*((UINT64 *)&error_info_cper.ErrorInformation) =
601*e407b4c8SLawrence Tang 			json_object_get_uint64(json_object_object_get(
602*e407b4c8SLawrence Tang 				error_info_information, "data"));
60371570a2aSLawrence Tang 		break;
60471570a2aSLawrence Tang 	}
6057cd13908SLawrence Tang 
6067cd13908SLawrence Tang 	//Virtual/physical fault address.
607*e407b4c8SLawrence Tang 	error_info_cper.VirtualFaultAddress = json_object_get_uint64(
608*e407b4c8SLawrence Tang 		json_object_object_get(error_info, "virtualFaultAddress"));
609*e407b4c8SLawrence Tang 	error_info_cper.PhysicalFaultAddress = json_object_get_uint64(
610*e407b4c8SLawrence Tang 		json_object_object_get(error_info, "physicalFaultAddress"));
6117cd13908SLawrence Tang 
6127cd13908SLawrence Tang 	//Write out to stream.
613*e407b4c8SLawrence Tang 	fwrite(&error_info_cper, sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY), 1,
614*e407b4c8SLawrence Tang 	       out);
6157cd13908SLawrence Tang 	fflush(out);
6167cd13908SLawrence Tang }
6177cd13908SLawrence Tang 
61871570a2aSLawrence Tang //Converts a single ARM cache/TLB error information structure into a CPER structure.
619*e407b4c8SLawrence Tang void ir_arm_error_cache_tlb_info_to_cper(
620*e407b4c8SLawrence Tang 	json_object *error_information,
621*e407b4c8SLawrence Tang 	EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper)
62271570a2aSLawrence Tang {
62371570a2aSLawrence Tang 	//Validation bits.
624*e407b4c8SLawrence Tang 	error_info_cper->ValidationBits = ir_to_bitfield(
625*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "validationBits"), 7,
626*e407b4c8SLawrence Tang 		ARM_CACHE_TLB_ERROR_VALID_BITFIELD_NAMES);
62771570a2aSLawrence Tang 
62871570a2aSLawrence Tang 	//Miscellaneous value fields.
629*e407b4c8SLawrence Tang 	error_info_cper->TransactionType = readable_pair_to_integer(
630*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "transactionType"));
631*e407b4c8SLawrence Tang 	error_info_cper->Operation = readable_pair_to_integer(
632*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "operation"));
633*e407b4c8SLawrence Tang 	error_info_cper->Level = json_object_get_uint64(
634*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "level"));
635*e407b4c8SLawrence Tang 	error_info_cper->ProcessorContextCorrupt = json_object_get_boolean(
636*e407b4c8SLawrence Tang 		json_object_object_get(error_information,
637*e407b4c8SLawrence Tang 				       "processorContextCorrupt"));
638*e407b4c8SLawrence Tang 	error_info_cper->Corrected = json_object_get_boolean(
639*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "corrected"));
640*e407b4c8SLawrence Tang 	error_info_cper->PrecisePC = json_object_get_boolean(
641*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "precisePC"));
642*e407b4c8SLawrence Tang 	error_info_cper->RestartablePC = json_object_get_boolean(
643*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "restartablePC"));
64471570a2aSLawrence Tang 	error_info_cper->Reserved = 0;
64571570a2aSLawrence Tang }
64671570a2aSLawrence Tang 
64771570a2aSLawrence Tang //Converts a single ARM bus error information structure into a CPER structure.
648*e407b4c8SLawrence Tang void ir_arm_error_bus_info_to_cper(json_object *error_information,
649*e407b4c8SLawrence Tang 				   EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper)
65071570a2aSLawrence Tang {
65171570a2aSLawrence Tang 	//Validation bits.
652*e407b4c8SLawrence Tang 	error_info_cper->ValidationBits = ir_to_bitfield(
653*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "validationBits"), 7,
654*e407b4c8SLawrence Tang 		ARM_BUS_ERROR_VALID_BITFIELD_NAMES);
65571570a2aSLawrence Tang 
65671570a2aSLawrence Tang 	//Miscellaneous value fields.
657*e407b4c8SLawrence Tang 	error_info_cper->TransactionType = readable_pair_to_integer(
658*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "transactionType"));
659*e407b4c8SLawrence Tang 	error_info_cper->Operation = readable_pair_to_integer(
660*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "operation"));
661*e407b4c8SLawrence Tang 	error_info_cper->Level = json_object_get_uint64(
662*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "level"));
663*e407b4c8SLawrence Tang 	error_info_cper->ProcessorContextCorrupt = json_object_get_boolean(
664*e407b4c8SLawrence Tang 		json_object_object_get(error_information,
665*e407b4c8SLawrence Tang 				       "processorContextCorrupt"));
666*e407b4c8SLawrence Tang 	error_info_cper->Corrected = json_object_get_boolean(
667*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "corrected"));
668*e407b4c8SLawrence Tang 	error_info_cper->PrecisePC = json_object_get_boolean(
669*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "precisePC"));
670*e407b4c8SLawrence Tang 	error_info_cper->RestartablePC = json_object_get_boolean(
671*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "restartablePC"));
672*e407b4c8SLawrence Tang 	error_info_cper->ParticipationType = readable_pair_to_integer(
673*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "participationType"));
674*e407b4c8SLawrence Tang 	error_info_cper->AddressSpace = readable_pair_to_integer(
675*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "addressSpace"));
676*e407b4c8SLawrence Tang 	error_info_cper->AccessMode = readable_pair_to_integer(
677*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "accessMode"));
678*e407b4c8SLawrence Tang 	error_info_cper->MemoryAddressAttributes = json_object_get_uint64(
679*e407b4c8SLawrence Tang 		json_object_object_get(error_information, "memoryAttributes"));
68071570a2aSLawrence Tang 	error_info_cper->Reserved = 0;
68171570a2aSLawrence Tang }
68271570a2aSLawrence Tang 
6837cd13908SLawrence Tang //Converts a single ARM context information structure into CPER binary, outputting to the given stream.
6847cd13908SLawrence Tang void ir_arm_context_info_to_cper(json_object *context_info, FILE *out)
6857cd13908SLawrence Tang {
68671570a2aSLawrence Tang 	EFI_ARM_CONTEXT_INFORMATION_HEADER info_header;
6877cd13908SLawrence Tang 
68871570a2aSLawrence Tang 	//Version, array size, context type.
689*e407b4c8SLawrence Tang 	info_header.Version = json_object_get_int(
690*e407b4c8SLawrence Tang 		json_object_object_get(context_info, "version"));
691*e407b4c8SLawrence Tang 	info_header.RegisterArraySize = json_object_get_int(
692*e407b4c8SLawrence Tang 		json_object_object_get(context_info, "registerArraySize"));
693*e407b4c8SLawrence Tang 	info_header.RegisterContextType = readable_pair_to_integer(
694*e407b4c8SLawrence Tang 		json_object_object_get(context_info, "registerContextType"));
69571570a2aSLawrence Tang 
69671570a2aSLawrence Tang 	//Flush to stream, write the register array itself.
697*e407b4c8SLawrence Tang 	fwrite(&info_header, sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER), 1,
698*e407b4c8SLawrence Tang 	       out);
69971570a2aSLawrence Tang 	fflush(out);
70071570a2aSLawrence Tang 
701*e407b4c8SLawrence Tang 	json_object *register_array =
702*e407b4c8SLawrence Tang 		json_object_object_get(context_info, "registerArray");
703*e407b4c8SLawrence Tang 	switch (info_header.RegisterContextType) {
70471570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
70571570a2aSLawrence Tang 		ir_arm_aarch32_gpr_to_cper(register_array, out);
70671570a2aSLawrence Tang 		break;
70771570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
70871570a2aSLawrence Tang 		ir_arm_aarch32_el1_to_cper(register_array, out);
70971570a2aSLawrence Tang 		break;
71071570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
71171570a2aSLawrence Tang 		ir_arm_aarch32_el2_to_cper(register_array, out);
71271570a2aSLawrence Tang 		break;
71371570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
71471570a2aSLawrence Tang 		ir_arm_aarch32_secure_to_cper(register_array, out);
71571570a2aSLawrence Tang 		break;
71671570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
71771570a2aSLawrence Tang 		ir_arm_aarch64_gpr_to_cper(register_array, out);
71871570a2aSLawrence Tang 		break;
71971570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
72071570a2aSLawrence Tang 		ir_arm_aarch64_el1_to_cper(register_array, out);
72171570a2aSLawrence Tang 		break;
72271570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
72371570a2aSLawrence Tang 		ir_arm_aarch64_el2_to_cper(register_array, out);
72471570a2aSLawrence Tang 		break;
72571570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
72671570a2aSLawrence Tang 		ir_arm_aarch64_el3_to_cper(register_array, out);
72771570a2aSLawrence Tang 		break;
72871570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_MISC:
72971570a2aSLawrence Tang 		ir_arm_misc_registers_to_cper(register_array, out);
73071570a2aSLawrence Tang 		break;
73171570a2aSLawrence Tang 	default:
73271570a2aSLawrence Tang 		//Unknown register structure.
733*e407b4c8SLawrence Tang 		ir_arm_unknown_register_to_cper(register_array, &info_header,
734*e407b4c8SLawrence Tang 						out);
73571570a2aSLawrence Tang 		break;
73671570a2aSLawrence Tang 	}
73771570a2aSLawrence Tang }
73871570a2aSLawrence Tang 
73971570a2aSLawrence Tang //Converts a single AARCH32 GPR CPER-JSON object to CPER binary, outputting to the given stream.
74071570a2aSLawrence Tang void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out)
74171570a2aSLawrence Tang {
74271570a2aSLawrence Tang 	//Get uniform register array.
74371570a2aSLawrence Tang 	EFI_ARM_V8_AARCH32_GPR reg_array;
74471570a2aSLawrence Tang 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
745*e407b4c8SLawrence Tang 			     sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
746*e407b4c8SLawrence Tang 			     ARM_AARCH32_GPR_NAMES);
74771570a2aSLawrence Tang 
74871570a2aSLawrence Tang 	//Flush to stream.
74971570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
75071570a2aSLawrence Tang 	fflush(out);
75171570a2aSLawrence Tang }
75271570a2aSLawrence Tang 
75371570a2aSLawrence Tang //Converts a single AARCH32 EL1 register set CPER-JSON object to CPER binary, outputting to the given stream.
75471570a2aSLawrence Tang void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out)
75571570a2aSLawrence Tang {
75671570a2aSLawrence Tang 	//Get uniform register array.
75771570a2aSLawrence Tang 	EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS reg_array;
75871570a2aSLawrence Tang 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
759*e407b4c8SLawrence Tang 			     sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
760*e407b4c8SLawrence Tang 				     sizeof(UINT32),
761*e407b4c8SLawrence Tang 			     ARM_AARCH32_EL1_REGISTER_NAMES);
76271570a2aSLawrence Tang 
76371570a2aSLawrence Tang 	//Flush to stream.
76471570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
76571570a2aSLawrence Tang 	fflush(out);
76671570a2aSLawrence Tang }
76771570a2aSLawrence Tang 
76871570a2aSLawrence Tang //Converts a single AARCH32 EL2 register set CPER-JSON object to CPER binary, outputting to the given stream.
76971570a2aSLawrence Tang void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out)
77071570a2aSLawrence Tang {
77171570a2aSLawrence Tang 	//Get uniform register array.
77271570a2aSLawrence Tang 	EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS reg_array;
77371570a2aSLawrence Tang 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
774*e407b4c8SLawrence Tang 			     sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
775*e407b4c8SLawrence Tang 				     sizeof(UINT32),
776*e407b4c8SLawrence Tang 			     ARM_AARCH32_EL2_REGISTER_NAMES);
77771570a2aSLawrence Tang 
77871570a2aSLawrence Tang 	//Flush to stream.
77971570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
78071570a2aSLawrence Tang 	fflush(out);
78171570a2aSLawrence Tang }
78271570a2aSLawrence Tang 
78371570a2aSLawrence Tang //Converts a single AARCH32 secure register set CPER-JSON object to CPER binary, outputting to the given stream.
78471570a2aSLawrence Tang void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out)
78571570a2aSLawrence Tang {
78671570a2aSLawrence Tang 	//Get uniform register array.
78771570a2aSLawrence Tang 	EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS reg_array;
78871570a2aSLawrence Tang 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
789*e407b4c8SLawrence Tang 			     sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
790*e407b4c8SLawrence Tang 				     sizeof(UINT32),
791*e407b4c8SLawrence Tang 			     ARM_AARCH32_SECURE_REGISTER_NAMES);
79271570a2aSLawrence Tang 
79371570a2aSLawrence Tang 	//Flush to stream.
79471570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
79571570a2aSLawrence Tang 	fflush(out);
79671570a2aSLawrence Tang }
79771570a2aSLawrence Tang 
79871570a2aSLawrence Tang //Converts a single AARCH64 GPR CPER-JSON object to CPER binary, outputting to the given stream.
79971570a2aSLawrence Tang void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out)
80071570a2aSLawrence Tang {
80171570a2aSLawrence Tang 	//Get uniform register array.
80271570a2aSLawrence Tang 	EFI_ARM_V8_AARCH64_GPR reg_array;
80371570a2aSLawrence Tang 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
804*e407b4c8SLawrence Tang 			       sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
805*e407b4c8SLawrence Tang 			       ARM_AARCH64_GPR_NAMES);
80671570a2aSLawrence Tang 
80771570a2aSLawrence Tang 	//Flush to stream.
80871570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
80971570a2aSLawrence Tang 	fflush(out);
81071570a2aSLawrence Tang }
81171570a2aSLawrence Tang 
81271570a2aSLawrence Tang //Converts a single AARCH64 EL1 register set CPER-JSON object to CPER binary, outputting to the given stream.
81371570a2aSLawrence Tang void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out)
81471570a2aSLawrence Tang {
81571570a2aSLawrence Tang 	//Get uniform register array.
81671570a2aSLawrence Tang 	EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS reg_array;
81771570a2aSLawrence Tang 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
818*e407b4c8SLawrence Tang 			       sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
819*e407b4c8SLawrence Tang 				       sizeof(UINT64),
820*e407b4c8SLawrence Tang 			       ARM_AARCH64_EL1_REGISTER_NAMES);
82171570a2aSLawrence Tang 
82271570a2aSLawrence Tang 	//Flush to stream.
82371570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
82471570a2aSLawrence Tang 	fflush(out);
82571570a2aSLawrence Tang }
82671570a2aSLawrence Tang 
82771570a2aSLawrence Tang //Converts a single AARCH64 EL2 register set CPER-JSON object to CPER binary, outputting to the given stream.
82871570a2aSLawrence Tang void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out)
82971570a2aSLawrence Tang {
83071570a2aSLawrence Tang 	//Get uniform register array.
83171570a2aSLawrence Tang 	EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS reg_array;
83271570a2aSLawrence Tang 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
833*e407b4c8SLawrence Tang 			       sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
834*e407b4c8SLawrence Tang 				       sizeof(UINT64),
835*e407b4c8SLawrence Tang 			       ARM_AARCH64_EL2_REGISTER_NAMES);
83671570a2aSLawrence Tang 
83771570a2aSLawrence Tang 	//Flush to stream.
83871570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
83971570a2aSLawrence Tang 	fflush(out);
84071570a2aSLawrence Tang }
84171570a2aSLawrence Tang 
84271570a2aSLawrence Tang //Converts a single AARCH64 EL3 register set CPER-JSON object to CPER binary, outputting to the given stream.
84371570a2aSLawrence Tang void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out)
84471570a2aSLawrence Tang {
84571570a2aSLawrence Tang 	//Get uniform register array.
84671570a2aSLawrence Tang 	EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS reg_array;
84771570a2aSLawrence Tang 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
848*e407b4c8SLawrence Tang 			       sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
849*e407b4c8SLawrence Tang 				       sizeof(UINT64),
850*e407b4c8SLawrence Tang 			       ARM_AARCH64_EL3_REGISTER_NAMES);
85171570a2aSLawrence Tang 
85271570a2aSLawrence Tang 	//Flush to stream.
85371570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
85471570a2aSLawrence Tang 	fflush(out);
85571570a2aSLawrence Tang }
85671570a2aSLawrence Tang 
85771570a2aSLawrence Tang //Converts a single ARM miscellaneous register set CPER-JSON object to CPER binary, outputting to the given stream.
85871570a2aSLawrence Tang void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out)
85971570a2aSLawrence Tang {
86071570a2aSLawrence Tang 	EFI_ARM_MISC_CONTEXT_REGISTER reg_array;
86171570a2aSLawrence Tang 
86271570a2aSLawrence Tang 	//MRS encoding information.
863*e407b4c8SLawrence Tang 	json_object *mrs_encoding =
864*e407b4c8SLawrence Tang 		json_object_object_get(registers, "mrsEncoding");
865*e407b4c8SLawrence Tang 	reg_array.MrsOp2 = json_object_get_uint64(
866*e407b4c8SLawrence Tang 		json_object_object_get(mrs_encoding, "op2"));
867*e407b4c8SLawrence Tang 	reg_array.MrsCrm = json_object_get_uint64(
868*e407b4c8SLawrence Tang 		json_object_object_get(mrs_encoding, "crm"));
869*e407b4c8SLawrence Tang 	reg_array.MrsCrn = json_object_get_uint64(
870*e407b4c8SLawrence Tang 		json_object_object_get(mrs_encoding, "crn"));
871*e407b4c8SLawrence Tang 	reg_array.MrsOp1 = json_object_get_uint64(
872*e407b4c8SLawrence Tang 		json_object_object_get(mrs_encoding, "op1"));
873*e407b4c8SLawrence Tang 	reg_array.MrsO0 = json_object_get_uint64(
874*e407b4c8SLawrence Tang 		json_object_object_get(mrs_encoding, "o0"));
87571570a2aSLawrence Tang 
87671570a2aSLawrence Tang 	//Actual register value.
877*e407b4c8SLawrence Tang 	reg_array.Value = json_object_get_uint64(
878*e407b4c8SLawrence Tang 		json_object_object_get(registers, "value"));
87971570a2aSLawrence Tang 
88071570a2aSLawrence Tang 	//Flush to stream.
88171570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
88271570a2aSLawrence Tang 	fflush(out);
88371570a2aSLawrence Tang }
88471570a2aSLawrence Tang 
88571570a2aSLawrence Tang //Converts a single ARM unknown register CPER-JSON object to CPER binary, outputting to the given stream.
886*e407b4c8SLawrence Tang void ir_arm_unknown_register_to_cper(json_object *registers,
887*e407b4c8SLawrence Tang 				     EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
888*e407b4c8SLawrence Tang 				     FILE *out)
88971570a2aSLawrence Tang {
89071570a2aSLawrence Tang 	//Get base64 represented data.
89171570a2aSLawrence Tang 	json_object *encoded = json_object_object_get(registers, "data");
892*e407b4c8SLawrence Tang 	UINT8 *decoded = b64_decode(json_object_get_string(encoded),
893*e407b4c8SLawrence Tang 				    json_object_get_string_len(encoded));
89471570a2aSLawrence Tang 
89571570a2aSLawrence Tang 	//Flush out to stream.
89671570a2aSLawrence Tang 	fwrite(&decoded, header->RegisterArraySize, 1, out);
89771570a2aSLawrence Tang 	fflush(out);
89871570a2aSLawrence Tang 	free(decoded);
8997cd13908SLawrence Tang }