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>
9*5202bbb4SLawrence 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.
16e407b4c8SLawrence Tang json_object *
17e407b4c8SLawrence Tang cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info);
18e407b4c8SLawrence Tang json_object *
19e407b4c8SLawrence Tang cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
20e407b4c8SLawrence Tang 				 void **cur_pos);
21e407b4c8SLawrence Tang json_object *
22e407b4c8SLawrence Tang cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
23e407b4c8SLawrence 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);
25e407b4c8SLawrence Tang json_object *cper_arm_misc_register_array_to_ir(
26e407b4c8SLawrence 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);
29e407b4c8SLawrence Tang void ir_arm_error_cache_tlb_info_to_cper(
30e407b4c8SLawrence Tang 	json_object *error_information,
31e407b4c8SLawrence Tang 	EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper);
32e407b4c8SLawrence Tang void ir_arm_error_bus_info_to_cper(json_object *error_information,
33e407b4c8SLawrence 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);
43e407b4c8SLawrence Tang void ir_arm_unknown_register_to_cper(json_object *registers,
44e407b4c8SLawrence Tang 				     EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
45e407b4c8SLawrence Tang 				     FILE *out);
463d0e4f24SLawrence Tang 
472800cd8eSLawrence Tang //Converts the given processor-generic CPER section into JSON IR.
48e407b4c8SLawrence Tang json_object *cper_section_arm_to_ir(void *section,
49e407b4c8SLawrence 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.
55e407b4c8SLawrence Tang 	json_object *validation = bitfield_to_ir(
56e407b4c8SLawrence 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.
60e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "errorInfoNum",
61e407b4c8SLawrence Tang 			       json_object_new_int(record->ErrInfoNum));
62e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "contextInfoNum",
63e407b4c8SLawrence Tang 			       json_object_new_int(record->ContextInfoNum));
64e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "sectionLength",
65e407b4c8SLawrence Tang 			       json_object_new_uint64(record->SectionLength));
662800cd8eSLawrence Tang 
672800cd8eSLawrence Tang 	//Error affinity.
682800cd8eSLawrence Tang 	json_object *error_affinity = json_object_new_object();
69e407b4c8SLawrence Tang 	json_object_object_add(error_affinity, "value",
70e407b4c8SLawrence Tang 			       json_object_new_int(record->ErrorAffinityLevel));
71e407b4c8SLawrence Tang 	json_object_object_add(
72e407b4c8SLawrence Tang 		error_affinity, "type",
73e407b4c8SLawrence Tang 		json_object_new_string(record->ErrorAffinityLevel < 4 ?
74e407b4c8SLawrence Tang 						     "Vendor Defined" :
75e407b4c8SLawrence 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).
79e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "mpidrEl1",
80e407b4c8SLawrence Tang 			       json_object_new_uint64(record->MPIDR_EL1));
81e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "midrEl1",
82e407b4c8SLawrence Tang 			       json_object_new_uint64(record->MIDR_EL1));
832800cd8eSLawrence Tang 
842800cd8eSLawrence Tang 	//Whether the processor is running, and the state of it if so.
85e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "running",
86e407b4c8SLawrence Tang 			       json_object_new_boolean(record->RunningState &
87e407b4c8SLawrence Tang 						       0b1));
88e407b4c8SLawrence 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.
92e407b4c8SLawrence Tang 		json_object_object_add(
93e407b4c8SLawrence Tang 			section_ir, "psciState",
94e407b4c8SLawrence 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();
99e407b4c8SLawrence Tang 	EFI_ARM_ERROR_INFORMATION_ENTRY *cur_error =
100e407b4c8SLawrence Tang 		(EFI_ARM_ERROR_INFORMATION_ENTRY *)(record + 1);
101e407b4c8SLawrence Tang 	for (int i = 0; i < record->ErrInfoNum; i++) {
102e407b4c8SLawrence Tang 		json_object_array_add(error_info_array,
103e407b4c8SLawrence 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();
112e407b4c8SLawrence Tang 	for (int i = 0; i < record->ContextInfoNum; i++) {
113e407b4c8SLawrence Tang 		EFI_ARM_CONTEXT_INFORMATION_HEADER *header =
114e407b4c8SLawrence Tang 			(EFI_ARM_CONTEXT_INFORMATION_HEADER *)cur_pos;
115e407b4c8SLawrence Tang 		json_object *processor_context =
116e407b4c8SLawrence 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?
122e407b4c8SLawrence Tang 	if (cur_pos < section + record->SectionLength) {
123d7e8ca34SLawrence Tang 		json_object *vendor_specific = json_object_new_object();
124e407b4c8SLawrence Tang 		char *encoded =
125e407b4c8SLawrence Tang 			b64_encode((unsigned char *)cur_pos,
126e407b4c8SLawrence Tang 				   section + record->SectionLength - cur_pos);
127e407b4c8SLawrence Tang 		json_object_object_add(vendor_specific, "data",
128e407b4c8SLawrence Tang 				       json_object_new_string(encoded));
129d7e8ca34SLawrence Tang 		free(encoded);
130d7e8ca34SLawrence Tang 
131e407b4c8SLawrence Tang 		json_object_object_add(section_ir, "vendorSpecificInfo",
132e407b4c8SLawrence 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.
139e407b4c8SLawrence Tang json_object *
140e407b4c8SLawrence 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.
145e407b4c8SLawrence Tang 	json_object_object_add(error_info_ir, "version",
146e407b4c8SLawrence Tang 			       json_object_new_int(error_info->Version));
147e407b4c8SLawrence Tang 	json_object_object_add(error_info_ir, "length",
148e407b4c8SLawrence Tang 			       json_object_new_int(error_info->Length));
1493d0e4f24SLawrence Tang 
1503d0e4f24SLawrence Tang 	//Validation bitfield.
151e407b4c8SLawrence Tang 	json_object *validation =
152e407b4c8SLawrence Tang 		bitfield_to_ir(error_info->ValidationBits, 5,
153e407b4c8SLawrence 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.
157e407b4c8SLawrence Tang 	json_object *error_type = integer_to_readable_pair(
158e407b4c8SLawrence Tang 		error_info->Type, 4, ARM_ERROR_INFO_ENTRY_INFO_TYPES_KEYS,
159e407b4c8SLawrence 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();
164e407b4c8SLawrence Tang 	json_object_object_add(multiple_error, "value",
165e407b4c8SLawrence Tang 			       json_object_new_int(error_info->MultipleError));
166e407b4c8SLawrence Tang 	json_object_object_add(
167e407b4c8SLawrence Tang 		multiple_error, "type",
168e407b4c8SLawrence Tang 		json_object_new_string(error_info->MultipleError < 1 ?
169e407b4c8SLawrence Tang 						     "Single Error" :
170e407b4c8SLawrence Tang 						     "Multiple Errors"));
1713d0e4f24SLawrence Tang 	json_object_object_add(error_info_ir, "multipleError", multiple_error);
1723d0e4f24SLawrence Tang 
1733d0e4f24SLawrence Tang 	//Flags.
174e407b4c8SLawrence Tang 	json_object *flags = bitfield_to_ir(error_info->Flags, 4,
175e407b4c8SLawrence 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;
180e407b4c8SLawrence Tang 	switch (error_info->Type) {
18171570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_CACHE: //Cache
18271570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_TLB: //TLB
183e407b4c8SLawrence Tang 		error_subinfo = cper_arm_cache_tlb_error_to_ir(
184e407b4c8SLawrence Tang 			(EFI_ARM_CACHE_ERROR_STRUCTURE *)&error_info
185e407b4c8SLawrence Tang 				->ErrorInformation,
186e407b4c8SLawrence Tang 			error_info);
1873d0e4f24SLawrence Tang 		break;
18871570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_BUS: //Bus
189e407b4c8SLawrence Tang 		error_subinfo = cper_arm_bus_error_to_ir(
190e407b4c8SLawrence Tang 			(EFI_ARM_BUS_ERROR_STRUCTURE *)&error_info
191e407b4c8SLawrence 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();
197e407b4c8SLawrence Tang 		json_object_object_add(
198e407b4c8SLawrence Tang 			error_subinfo, "data",
199e407b4c8SLawrence Tang 			json_object_new_uint64(
200e407b4c8SLawrence Tang 				*((UINT64 *)&error_info->ErrorInformation)));
20171570a2aSLawrence Tang 		break;
2023d0e4f24SLawrence Tang 	}
203e407b4c8SLawrence Tang 	json_object_object_add(error_info_ir, "errorInformation",
204e407b4c8SLawrence Tang 			       error_subinfo);
2053d0e4f24SLawrence Tang 
206b98ec66cSLawrence Tang 	//Virtual fault address, physical fault address.
207e407b4c8SLawrence Tang 	json_object_object_add(
208e407b4c8SLawrence Tang 		error_info_ir, "virtualFaultAddress",
209e407b4c8SLawrence Tang 		json_object_new_uint64(error_info->VirtualFaultAddress));
210e407b4c8SLawrence Tang 	json_object_object_add(
211e407b4c8SLawrence Tang 		error_info_ir, "physicalFaultAddress",
212e407b4c8SLawrence 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.
218e407b4c8SLawrence Tang json_object *
219e407b4c8SLawrence Tang cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
220e407b4c8SLawrence 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.
225e407b4c8SLawrence Tang 	json_object *validation =
226e407b4c8SLawrence Tang 		bitfield_to_ir(cache_tlb_error->ValidationBits, 7,
227e407b4c8SLawrence Tang 			       ARM_CACHE_TLB_ERROR_VALID_BITFIELD_NAMES);
228e407b4c8SLawrence Tang 	json_object_object_add(cache_tlb_error_ir, "validationBits",
229e407b4c8SLawrence Tang 			       validation);
2307f21db6cSLawrence Tang 
2317f21db6cSLawrence Tang 	//Transaction type.
232e407b4c8SLawrence Tang 	json_object *transaction_type = integer_to_readable_pair(
233e407b4c8SLawrence Tang 		cache_tlb_error->TransactionType, 3,
2347f21db6cSLawrence Tang 		ARM_ERROR_TRANSACTION_TYPES_KEYS,
235e407b4c8SLawrence Tang 		ARM_ERROR_TRANSACTION_TYPES_VALUES, "Unknown (Reserved)");
236e407b4c8SLawrence Tang 	json_object_object_add(cache_tlb_error_ir, "transactionType",
237e407b4c8SLawrence Tang 			       transaction_type);
2387f21db6cSLawrence Tang 
2397f21db6cSLawrence Tang 	//Operation.
2407f21db6cSLawrence Tang 	json_object *operation;
241e407b4c8SLawrence Tang 	if (error_info->Type == 0) {
2427f21db6cSLawrence Tang 		//Cache operation.
243e407b4c8SLawrence Tang 		operation = integer_to_readable_pair(
244e407b4c8SLawrence 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)");
248e407b4c8SLawrence Tang 	} else {
2497f21db6cSLawrence Tang 		//TLB operation.
250e407b4c8SLawrence Tang 		operation = integer_to_readable_pair(
251e407b4c8SLawrence Tang 			cache_tlb_error->Operation, 9,
2527f21db6cSLawrence Tang 			ARM_TLB_OPERATION_TYPES_KEYS,
253e407b4c8SLawrence 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.
258e407b4c8SLawrence Tang 	json_object_object_add(cache_tlb_error_ir, "level",
259e407b4c8SLawrence Tang 			       json_object_new_int(cache_tlb_error->Level));
260e407b4c8SLawrence Tang 	json_object_object_add(
261e407b4c8SLawrence Tang 		cache_tlb_error_ir, "processorContextCorrupt",
262e407b4c8SLawrence Tang 		json_object_new_boolean(
263e407b4c8SLawrence Tang 			cache_tlb_error->ProcessorContextCorrupt));
264e407b4c8SLawrence Tang 	json_object_object_add(
265e407b4c8SLawrence Tang 		cache_tlb_error_ir, "corrected",
266e407b4c8SLawrence Tang 		json_object_new_boolean(cache_tlb_error->Corrected));
267e407b4c8SLawrence Tang 	json_object_object_add(
268e407b4c8SLawrence Tang 		cache_tlb_error_ir, "precisePC",
269e407b4c8SLawrence Tang 		json_object_new_boolean(cache_tlb_error->PrecisePC));
270e407b4c8SLawrence Tang 	json_object_object_add(
271e407b4c8SLawrence Tang 		cache_tlb_error_ir, "restartablePC",
272e407b4c8SLawrence 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.
282e407b4c8SLawrence Tang 	json_object *validation =
283e407b4c8SLawrence Tang 		bitfield_to_ir(bus_error->ValidationBits, 12,
284e407b4c8SLawrence Tang 			       ARM_BUS_ERROR_VALID_BITFIELD_NAMES);
2857f21db6cSLawrence Tang 	json_object_object_add(bus_error_ir, "validationBits", validation);
2867f21db6cSLawrence Tang 
2877f21db6cSLawrence Tang 	//Transaction type.
288e407b4c8SLawrence Tang 	json_object *transaction_type = integer_to_readable_pair(
289e407b4c8SLawrence Tang 		bus_error->TransactionType, 3, ARM_ERROR_TRANSACTION_TYPES_KEYS,
290e407b4c8SLawrence Tang 		ARM_ERROR_TRANSACTION_TYPES_VALUES, "Unknown (Reserved)");
291e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "transactionType",
292e407b4c8SLawrence Tang 			       transaction_type);
2937f21db6cSLawrence Tang 
2947f21db6cSLawrence Tang 	//Operation.
295e407b4c8SLawrence Tang 	json_object *operation = integer_to_readable_pair(
296e407b4c8SLawrence Tang 		bus_error->Operation, 7, ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
297e407b4c8SLawrence 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.
301e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "level",
302e407b4c8SLawrence Tang 			       json_object_new_int(bus_error->Level));
303e407b4c8SLawrence Tang 	json_object_object_add(
304e407b4c8SLawrence Tang 		bus_error_ir, "processorContextCorrupt",
305e407b4c8SLawrence Tang 		json_object_new_boolean(bus_error->ProcessorContextCorrupt));
306e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "corrected",
307e407b4c8SLawrence Tang 			       json_object_new_boolean(bus_error->Corrected));
308e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "precisePC",
309e407b4c8SLawrence Tang 			       json_object_new_boolean(bus_error->PrecisePC));
310e407b4c8SLawrence Tang 	json_object_object_add(
311e407b4c8SLawrence Tang 		bus_error_ir, "restartablePC",
312e407b4c8SLawrence Tang 		json_object_new_boolean(bus_error->RestartablePC));
313e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "timedOut",
314e407b4c8SLawrence Tang 			       json_object_new_boolean(bus_error->TimeOut));
3157f21db6cSLawrence Tang 
3167f21db6cSLawrence Tang 	//Participation type.
317e407b4c8SLawrence Tang 	json_object *participation_type = integer_to_readable_pair(
318e407b4c8SLawrence Tang 		bus_error->ParticipationType, 4,
3197f21db6cSLawrence Tang 		ARM_BUS_PARTICIPATION_TYPES_KEYS,
320e407b4c8SLawrence Tang 		ARM_BUS_PARTICIPATION_TYPES_VALUES, "Unknown");
321e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "participationType",
322e407b4c8SLawrence Tang 			       participation_type);
3237f21db6cSLawrence Tang 
3247f21db6cSLawrence Tang 	//Address space.
325e407b4c8SLawrence Tang 	json_object *address_space = integer_to_readable_pair(
326e407b4c8SLawrence Tang 		bus_error->AddressSpace, 3, ARM_BUS_ADDRESS_SPACE_TYPES_KEYS,
327e407b4c8SLawrence 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
332e407b4c8SLawrence Tang 	json_object_object_add(
333e407b4c8SLawrence Tang 		bus_error_ir, "memoryAttributes",
334e407b4c8SLawrence Tang 		json_object_new_int(bus_error->MemoryAddressAttributes));
3357f21db6cSLawrence Tang 
3367f21db6cSLawrence Tang 	//Access Mode
3377f21db6cSLawrence Tang 	json_object *access_mode = json_object_new_object();
338e407b4c8SLawrence Tang 	json_object_object_add(access_mode, "value",
339e407b4c8SLawrence Tang 			       json_object_new_int(bus_error->AccessMode));
340e407b4c8SLawrence Tang 	json_object_object_add(
341e407b4c8SLawrence Tang 		access_mode, "name",
342e407b4c8SLawrence Tang 		json_object_new_string(bus_error->AccessMode == 0 ? "Secure" :
343e407b4c8SLawrence 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.
350e407b4c8SLawrence Tang json_object *
351e407b4c8SLawrence Tang cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
352e407b4c8SLawrence Tang 				 void **cur_pos)
3537f21db6cSLawrence Tang {
3547f21db6cSLawrence Tang 	json_object *context_ir = json_object_new_object();
3557f21db6cSLawrence Tang 
35671570a2aSLawrence Tang 	//Version.
357e407b4c8SLawrence Tang 	json_object_object_add(context_ir, "version",
358e407b4c8SLawrence Tang 			       json_object_new_int(header->Version));
35971570a2aSLawrence Tang 
3607f21db6cSLawrence Tang 	//Add the context type.
361e407b4c8SLawrence Tang 	json_object *context_type = integer_to_readable_pair(
362e407b4c8SLawrence 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).
369e407b4c8SLawrence Tang 	json_object_object_add(
370e407b4c8SLawrence Tang 		context_ir, "registerArraySize",
371e407b4c8SLawrence 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;
376e407b4c8SLawrence Tang 	switch (header->RegisterContextType) {
3777f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
378e407b4c8SLawrence Tang 		register_array = uniform_struct_to_ir(
379e407b4c8SLawrence Tang 			(UINT32 *)cur_pos,
380e407b4c8SLawrence Tang 			sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
381e407b4c8SLawrence Tang 			ARM_AARCH32_GPR_NAMES);
3827f21db6cSLawrence Tang 		break;
3837f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
384e407b4c8SLawrence Tang 		register_array = uniform_struct_to_ir(
385e407b4c8SLawrence Tang 			(UINT32 *)cur_pos,
386e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
387e407b4c8SLawrence Tang 				sizeof(UINT32),
388e407b4c8SLawrence Tang 			ARM_AARCH32_EL1_REGISTER_NAMES);
3897f21db6cSLawrence Tang 		break;
3907f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
391e407b4c8SLawrence Tang 		register_array = uniform_struct_to_ir(
392e407b4c8SLawrence Tang 			(UINT32 *)cur_pos,
393e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
394e407b4c8SLawrence Tang 				sizeof(UINT32),
395e407b4c8SLawrence Tang 			ARM_AARCH32_EL2_REGISTER_NAMES);
3967f21db6cSLawrence Tang 		break;
3977f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
398e407b4c8SLawrence Tang 		register_array = uniform_struct_to_ir(
399e407b4c8SLawrence Tang 			(UINT32 *)cur_pos,
400e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
401e407b4c8SLawrence Tang 				sizeof(UINT32),
402e407b4c8SLawrence Tang 			ARM_AARCH32_SECURE_REGISTER_NAMES);
4037f21db6cSLawrence Tang 		break;
4047f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
405e407b4c8SLawrence Tang 		register_array = uniform_struct64_to_ir(
406e407b4c8SLawrence Tang 			(UINT64 *)cur_pos,
407e407b4c8SLawrence Tang 			sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
408e407b4c8SLawrence Tang 			ARM_AARCH64_GPR_NAMES);
4097f21db6cSLawrence Tang 		break;
4107f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
411e407b4c8SLawrence Tang 		register_array = uniform_struct64_to_ir(
412e407b4c8SLawrence Tang 			(UINT64 *)cur_pos,
413e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
414e407b4c8SLawrence Tang 				sizeof(UINT64),
415e407b4c8SLawrence Tang 			ARM_AARCH64_EL1_REGISTER_NAMES);
4167f21db6cSLawrence Tang 		break;
4177f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
418e407b4c8SLawrence Tang 		register_array = uniform_struct64_to_ir(
419e407b4c8SLawrence Tang 			(UINT64 *)cur_pos,
420e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
421e407b4c8SLawrence Tang 				sizeof(UINT64),
422e407b4c8SLawrence Tang 			ARM_AARCH64_EL2_REGISTER_NAMES);
4237f21db6cSLawrence Tang 		break;
4247f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
425e407b4c8SLawrence Tang 		register_array = uniform_struct64_to_ir(
426e407b4c8SLawrence Tang 			(UINT64 *)cur_pos,
427e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
428e407b4c8SLawrence Tang 				sizeof(UINT64),
429e407b4c8SLawrence Tang 			ARM_AARCH64_EL3_REGISTER_NAMES);
4307f21db6cSLawrence Tang 		break;
4317f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_MISC:
432e407b4c8SLawrence Tang 		register_array = cper_arm_misc_register_array_to_ir(
433e407b4c8SLawrence 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();
438e407b4c8SLawrence Tang 		char *encoded = b64_encode((unsigned char *)cur_pos,
439e407b4c8SLawrence Tang 					   header->RegisterArraySize);
440e407b4c8SLawrence Tang 		json_object_object_add(register_array, "data",
441e407b4c8SLawrence 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.
454e407b4c8SLawrence Tang json_object *
455e407b4c8SLawrence 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();
459e407b4c8SLawrence Tang 	json_object_object_add(mrs_encoding, "op2",
460e407b4c8SLawrence Tang 			       json_object_new_uint64(misc_register->MrsOp2));
461e407b4c8SLawrence Tang 	json_object_object_add(mrs_encoding, "crm",
462e407b4c8SLawrence Tang 			       json_object_new_uint64(misc_register->MrsCrm));
463e407b4c8SLawrence Tang 	json_object_object_add(mrs_encoding, "crn",
464e407b4c8SLawrence Tang 			       json_object_new_uint64(misc_register->MrsCrn));
465e407b4c8SLawrence Tang 	json_object_object_add(mrs_encoding, "op1",
466e407b4c8SLawrence Tang 			       json_object_new_uint64(misc_register->MrsOp1));
467e407b4c8SLawrence Tang 	json_object_object_add(mrs_encoding, "o0",
468e407b4c8SLawrence Tang 			       json_object_new_uint64(misc_register->MrsO0));
4697f21db6cSLawrence Tang 	json_object_object_add(register_array, "mrsEncoding", mrs_encoding);
470e407b4c8SLawrence Tang 	json_object_object_add(register_array, "value",
471e407b4c8SLawrence 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 {
479e407b4c8SLawrence Tang 	EFI_ARM_ERROR_RECORD *section_cper =
480e407b4c8SLawrence 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.
484e407b4c8SLawrence Tang 	section_cper->ValidFields = ir_to_bitfield(
485e407b4c8SLawrence Tang 		json_object_object_get(section, "validationBits"), 4,
486e407b4c8SLawrence Tang 		ARM_ERROR_VALID_BITFIELD_NAMES);
4877cd13908SLawrence Tang 
4887cd13908SLawrence Tang 	//Count of error/context info structures.
489e407b4c8SLawrence Tang 	section_cper->ErrInfoNum = json_object_get_int(
490e407b4c8SLawrence Tang 		json_object_object_get(section, "errorInfoNum"));
491e407b4c8SLawrence Tang 	section_cper->ContextInfoNum = json_object_get_int(
492e407b4c8SLawrence Tang 		json_object_object_get(section, "contextInfoNum"));
4937cd13908SLawrence Tang 
4947cd13908SLawrence Tang 	//Miscellaneous raw value fields.
495e407b4c8SLawrence Tang 	section_cper->SectionLength = json_object_get_uint64(
496e407b4c8SLawrence Tang 		json_object_object_get(section, "sectionLength"));
497e407b4c8SLawrence Tang 	section_cper->ErrorAffinityLevel = readable_pair_to_integer(
498e407b4c8SLawrence Tang 		json_object_object_get(section, "errorAffinity"));
499e407b4c8SLawrence Tang 	section_cper->MPIDR_EL1 = json_object_get_uint64(
500e407b4c8SLawrence Tang 		json_object_object_get(section, "mpidrEl1"));
501e407b4c8SLawrence Tang 	section_cper->MIDR_EL1 = json_object_get_uint64(
502e407b4c8SLawrence Tang 		json_object_object_get(section, "midrEl1"));
503e407b4c8SLawrence Tang 	section_cper->RunningState = json_object_get_boolean(
504e407b4c8SLawrence 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++)
518e407b4c8SLawrence Tang 		ir_arm_error_info_to_cper(
519e407b4c8SLawrence Tang 			json_object_array_get_idx(error_info, i), out);
5207cd13908SLawrence Tang 
5217cd13908SLawrence Tang 	//Context info structure array.
522e407b4c8SLawrence Tang 	json_object *context_info =
523e407b4c8SLawrence Tang 		json_object_object_get(section, "contextInfo");
5247cd13908SLawrence Tang 	for (int i = 0; i < section_cper->ContextInfoNum; i++)
525e407b4c8SLawrence Tang 		ir_arm_context_info_to_cper(
526e407b4c8SLawrence Tang 			json_object_array_get_idx(context_info, i), out);
5277cd13908SLawrence Tang 
5287cd13908SLawrence Tang 	//Vendor specific error info.
529e407b4c8SLawrence Tang 	json_object *vendor_specific_info =
530e407b4c8SLawrence Tang 		json_object_object_get(section, "vendorSpecificInfo");
531e407b4c8SLawrence Tang 	if (vendor_specific_info != NULL) {
532e407b4c8SLawrence Tang 		json_object *vendor_info_string =
533e407b4c8SLawrence Tang 			json_object_object_get(vendor_specific_info, "data");
534e407b4c8SLawrence Tang 		int vendor_specific_len =
535e407b4c8SLawrence Tang 			json_object_get_string_len(vendor_info_string);
536e407b4c8SLawrence Tang 		UINT8 *decoded =
537e407b4c8SLawrence Tang 			b64_decode(json_object_get_string(vendor_info_string),
538e407b4c8SLawrence Tang 				   vendor_specific_len);
53901e3a44dSLawrence Tang 
54001e3a44dSLawrence Tang 		//Write out to file.
54101e3a44dSLawrence Tang 		long cur_stream_pos = ftell(out);
542e407b4c8SLawrence Tang 		fwrite(decoded,
543e407b4c8SLawrence Tang 		       starting_stream_pos + section_cper->SectionLength -
544e407b4c8SLawrence Tang 			       cur_stream_pos,
545e407b4c8SLawrence 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.
560e407b4c8SLawrence Tang 	error_info_cper.Version = json_object_get_int(
561e407b4c8SLawrence Tang 		json_object_object_get(error_info, "version"));
562e407b4c8SLawrence Tang 	error_info_cper.Length = json_object_get_int(
563e407b4c8SLawrence Tang 		json_object_object_get(error_info, "length"));
5647cd13908SLawrence Tang 
5657cd13908SLawrence Tang 	//Validation bits.
566e407b4c8SLawrence Tang 	error_info_cper.ValidationBits = ir_to_bitfield(
567e407b4c8SLawrence Tang 		json_object_object_get(error_info, "validationBits"), 5,
568e407b4c8SLawrence Tang 		ARM_ERROR_INFO_ENTRY_VALID_BITFIELD_NAMES);
5697cd13908SLawrence Tang 
5707cd13908SLawrence Tang 	//Type, multiple error.
571e407b4c8SLawrence Tang 	error_info_cper.Type = (UINT8)readable_pair_to_integer(
572e407b4c8SLawrence Tang 		json_object_object_get(error_info, "type"));
573e407b4c8SLawrence Tang 	error_info_cper.MultipleError = (UINT16)readable_pair_to_integer(
574e407b4c8SLawrence Tang 		json_object_object_get(error_info, "multipleError"));
5757cd13908SLawrence Tang 
5767cd13908SLawrence Tang 	//Flags object.
577e407b4c8SLawrence Tang 	error_info_cper.Flags = (UINT8)ir_to_bitfield(
578e407b4c8SLawrence Tang 		json_object_object_get(error_info, "flags"), 4,
579e407b4c8SLawrence Tang 		ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
5807cd13908SLawrence Tang 
5817cd13908SLawrence Tang 	//Error information.
582e407b4c8SLawrence Tang 	json_object *error_info_information =
583e407b4c8SLawrence Tang 		json_object_object_get(error_info, "errorInformation");
584e407b4c8SLawrence Tang 	switch (error_info_cper.Type) {
58571570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_CACHE:
58671570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_TLB:
587e407b4c8SLawrence Tang 		ir_arm_error_cache_tlb_info_to_cper(
588e407b4c8SLawrence Tang 			error_info_information,
589e407b4c8SLawrence Tang 			&error_info_cper.ErrorInformation.CacheError);
59071570a2aSLawrence Tang 		break;
59171570a2aSLawrence Tang 
59271570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_BUS:
593e407b4c8SLawrence Tang 		ir_arm_error_bus_info_to_cper(
594e407b4c8SLawrence Tang 			error_info_information,
595e407b4c8SLawrence 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) =
601e407b4c8SLawrence Tang 			json_object_get_uint64(json_object_object_get(
602e407b4c8SLawrence Tang 				error_info_information, "data"));
60371570a2aSLawrence Tang 		break;
60471570a2aSLawrence Tang 	}
6057cd13908SLawrence Tang 
6067cd13908SLawrence Tang 	//Virtual/physical fault address.
607e407b4c8SLawrence Tang 	error_info_cper.VirtualFaultAddress = json_object_get_uint64(
608e407b4c8SLawrence Tang 		json_object_object_get(error_info, "virtualFaultAddress"));
609e407b4c8SLawrence Tang 	error_info_cper.PhysicalFaultAddress = json_object_get_uint64(
610e407b4c8SLawrence Tang 		json_object_object_get(error_info, "physicalFaultAddress"));
6117cd13908SLawrence Tang 
6127cd13908SLawrence Tang 	//Write out to stream.
613e407b4c8SLawrence Tang 	fwrite(&error_info_cper, sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY), 1,
614e407b4c8SLawrence 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.
619e407b4c8SLawrence Tang void ir_arm_error_cache_tlb_info_to_cper(
620e407b4c8SLawrence Tang 	json_object *error_information,
621e407b4c8SLawrence Tang 	EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper)
62271570a2aSLawrence Tang {
62371570a2aSLawrence Tang 	//Validation bits.
624e407b4c8SLawrence Tang 	error_info_cper->ValidationBits = ir_to_bitfield(
625e407b4c8SLawrence Tang 		json_object_object_get(error_information, "validationBits"), 7,
626e407b4c8SLawrence Tang 		ARM_CACHE_TLB_ERROR_VALID_BITFIELD_NAMES);
62771570a2aSLawrence Tang 
62871570a2aSLawrence Tang 	//Miscellaneous value fields.
629e407b4c8SLawrence Tang 	error_info_cper->TransactionType = readable_pair_to_integer(
630e407b4c8SLawrence Tang 		json_object_object_get(error_information, "transactionType"));
631e407b4c8SLawrence Tang 	error_info_cper->Operation = readable_pair_to_integer(
632e407b4c8SLawrence Tang 		json_object_object_get(error_information, "operation"));
633e407b4c8SLawrence Tang 	error_info_cper->Level = json_object_get_uint64(
634e407b4c8SLawrence Tang 		json_object_object_get(error_information, "level"));
635e407b4c8SLawrence Tang 	error_info_cper->ProcessorContextCorrupt = json_object_get_boolean(
636e407b4c8SLawrence Tang 		json_object_object_get(error_information,
637e407b4c8SLawrence Tang 				       "processorContextCorrupt"));
638e407b4c8SLawrence Tang 	error_info_cper->Corrected = json_object_get_boolean(
639e407b4c8SLawrence Tang 		json_object_object_get(error_information, "corrected"));
640e407b4c8SLawrence Tang 	error_info_cper->PrecisePC = json_object_get_boolean(
641e407b4c8SLawrence Tang 		json_object_object_get(error_information, "precisePC"));
642e407b4c8SLawrence Tang 	error_info_cper->RestartablePC = json_object_get_boolean(
643e407b4c8SLawrence 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.
648e407b4c8SLawrence Tang void ir_arm_error_bus_info_to_cper(json_object *error_information,
649e407b4c8SLawrence Tang 				   EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper)
65071570a2aSLawrence Tang {
65171570a2aSLawrence Tang 	//Validation bits.
652e407b4c8SLawrence Tang 	error_info_cper->ValidationBits = ir_to_bitfield(
653e407b4c8SLawrence Tang 		json_object_object_get(error_information, "validationBits"), 7,
654e407b4c8SLawrence Tang 		ARM_BUS_ERROR_VALID_BITFIELD_NAMES);
65571570a2aSLawrence Tang 
65671570a2aSLawrence Tang 	//Miscellaneous value fields.
657e407b4c8SLawrence Tang 	error_info_cper->TransactionType = readable_pair_to_integer(
658e407b4c8SLawrence Tang 		json_object_object_get(error_information, "transactionType"));
659e407b4c8SLawrence Tang 	error_info_cper->Operation = readable_pair_to_integer(
660e407b4c8SLawrence Tang 		json_object_object_get(error_information, "operation"));
661e407b4c8SLawrence Tang 	error_info_cper->Level = json_object_get_uint64(
662e407b4c8SLawrence Tang 		json_object_object_get(error_information, "level"));
663e407b4c8SLawrence Tang 	error_info_cper->ProcessorContextCorrupt = json_object_get_boolean(
664e407b4c8SLawrence Tang 		json_object_object_get(error_information,
665e407b4c8SLawrence Tang 				       "processorContextCorrupt"));
666e407b4c8SLawrence Tang 	error_info_cper->Corrected = json_object_get_boolean(
667e407b4c8SLawrence Tang 		json_object_object_get(error_information, "corrected"));
668e407b4c8SLawrence Tang 	error_info_cper->PrecisePC = json_object_get_boolean(
669e407b4c8SLawrence Tang 		json_object_object_get(error_information, "precisePC"));
670e407b4c8SLawrence Tang 	error_info_cper->RestartablePC = json_object_get_boolean(
671e407b4c8SLawrence Tang 		json_object_object_get(error_information, "restartablePC"));
672e407b4c8SLawrence Tang 	error_info_cper->ParticipationType = readable_pair_to_integer(
673e407b4c8SLawrence Tang 		json_object_object_get(error_information, "participationType"));
674e407b4c8SLawrence Tang 	error_info_cper->AddressSpace = readable_pair_to_integer(
675e407b4c8SLawrence Tang 		json_object_object_get(error_information, "addressSpace"));
676e407b4c8SLawrence Tang 	error_info_cper->AccessMode = readable_pair_to_integer(
677e407b4c8SLawrence Tang 		json_object_object_get(error_information, "accessMode"));
678e407b4c8SLawrence Tang 	error_info_cper->MemoryAddressAttributes = json_object_get_uint64(
679e407b4c8SLawrence 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.
689e407b4c8SLawrence Tang 	info_header.Version = json_object_get_int(
690e407b4c8SLawrence Tang 		json_object_object_get(context_info, "version"));
691e407b4c8SLawrence Tang 	info_header.RegisterArraySize = json_object_get_int(
692e407b4c8SLawrence Tang 		json_object_object_get(context_info, "registerArraySize"));
693e407b4c8SLawrence Tang 	info_header.RegisterContextType = readable_pair_to_integer(
694e407b4c8SLawrence Tang 		json_object_object_get(context_info, "registerContextType"));
69571570a2aSLawrence Tang 
69671570a2aSLawrence Tang 	//Flush to stream, write the register array itself.
697e407b4c8SLawrence Tang 	fwrite(&info_header, sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER), 1,
698e407b4c8SLawrence Tang 	       out);
69971570a2aSLawrence Tang 	fflush(out);
70071570a2aSLawrence Tang 
701e407b4c8SLawrence Tang 	json_object *register_array =
702e407b4c8SLawrence Tang 		json_object_object_get(context_info, "registerArray");
703e407b4c8SLawrence 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.
733e407b4c8SLawrence Tang 		ir_arm_unknown_register_to_cper(register_array, &info_header,
734e407b4c8SLawrence 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,
745e407b4c8SLawrence Tang 			     sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
746e407b4c8SLawrence 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,
759e407b4c8SLawrence Tang 			     sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
760e407b4c8SLawrence Tang 				     sizeof(UINT32),
761e407b4c8SLawrence 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,
774e407b4c8SLawrence Tang 			     sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
775e407b4c8SLawrence Tang 				     sizeof(UINT32),
776e407b4c8SLawrence 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,
789e407b4c8SLawrence Tang 			     sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
790e407b4c8SLawrence Tang 				     sizeof(UINT32),
791e407b4c8SLawrence 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,
804e407b4c8SLawrence Tang 			       sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
805e407b4c8SLawrence 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,
818e407b4c8SLawrence Tang 			       sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
819e407b4c8SLawrence Tang 				       sizeof(UINT64),
820e407b4c8SLawrence 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,
833e407b4c8SLawrence Tang 			       sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
834e407b4c8SLawrence Tang 				       sizeof(UINT64),
835e407b4c8SLawrence 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,
848e407b4c8SLawrence Tang 			       sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
849e407b4c8SLawrence Tang 				       sizeof(UINT64),
850e407b4c8SLawrence 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.
863e407b4c8SLawrence Tang 	json_object *mrs_encoding =
864e407b4c8SLawrence Tang 		json_object_object_get(registers, "mrsEncoding");
865e407b4c8SLawrence Tang 	reg_array.MrsOp2 = json_object_get_uint64(
866e407b4c8SLawrence Tang 		json_object_object_get(mrs_encoding, "op2"));
867e407b4c8SLawrence Tang 	reg_array.MrsCrm = json_object_get_uint64(
868e407b4c8SLawrence Tang 		json_object_object_get(mrs_encoding, "crm"));
869e407b4c8SLawrence Tang 	reg_array.MrsCrn = json_object_get_uint64(
870e407b4c8SLawrence Tang 		json_object_object_get(mrs_encoding, "crn"));
871e407b4c8SLawrence Tang 	reg_array.MrsOp1 = json_object_get_uint64(
872e407b4c8SLawrence Tang 		json_object_object_get(mrs_encoding, "op1"));
873e407b4c8SLawrence Tang 	reg_array.MrsO0 = json_object_get_uint64(
874e407b4c8SLawrence Tang 		json_object_object_get(mrs_encoding, "o0"));
87571570a2aSLawrence Tang 
87671570a2aSLawrence Tang 	//Actual register value.
877e407b4c8SLawrence Tang 	reg_array.Value = json_object_get_uint64(
878e407b4c8SLawrence 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.
886e407b4c8SLawrence Tang void ir_arm_unknown_register_to_cper(json_object *registers,
887e407b4c8SLawrence Tang 				     EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
888e407b4c8SLawrence Tang 				     FILE *out)
88971570a2aSLawrence Tang {
89071570a2aSLawrence Tang 	//Get base64 represented data.
89171570a2aSLawrence Tang 	json_object *encoded = json_object_object_get(registers, "data");
892e407b4c8SLawrence Tang 	UINT8 *decoded = b64_decode(json_object_get_string(encoded),
893e407b4c8SLawrence 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 }