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>
95202bbb4SLawrence Tang #include <json.h>
10*f8fc7052SJohn Chung #include "libbase64.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);
43*f8fc7052SJohn Chung void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out);
443d0e4f24SLawrence Tang 
452800cd8eSLawrence Tang //Converts the given processor-generic CPER section into JSON IR.
46*f8fc7052SJohn Chung json_object *cper_section_arm_to_ir(void *section)
472800cd8eSLawrence Tang {
487f21db6cSLawrence Tang 	EFI_ARM_ERROR_RECORD *record = (EFI_ARM_ERROR_RECORD *)section;
492800cd8eSLawrence Tang 	json_object *section_ir = json_object_new_object();
502800cd8eSLawrence Tang 
512800cd8eSLawrence Tang 	//Validation bits.
52e407b4c8SLawrence Tang 	json_object *validation = bitfield_to_ir(
53e407b4c8SLawrence Tang 		record->ValidFields, 4, ARM_ERROR_VALID_BITFIELD_NAMES);
542800cd8eSLawrence Tang 	json_object_object_add(section_ir, "validationBits", validation);
552800cd8eSLawrence Tang 
562800cd8eSLawrence Tang 	//Number of error info and context info structures, and length.
57e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "errorInfoNum",
58e407b4c8SLawrence Tang 			       json_object_new_int(record->ErrInfoNum));
59e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "contextInfoNum",
60e407b4c8SLawrence Tang 			       json_object_new_int(record->ContextInfoNum));
61e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "sectionLength",
62e407b4c8SLawrence Tang 			       json_object_new_uint64(record->SectionLength));
632800cd8eSLawrence Tang 
642800cd8eSLawrence Tang 	//Error affinity.
652800cd8eSLawrence Tang 	json_object *error_affinity = json_object_new_object();
66e407b4c8SLawrence Tang 	json_object_object_add(error_affinity, "value",
67e407b4c8SLawrence Tang 			       json_object_new_int(record->ErrorAffinityLevel));
68e407b4c8SLawrence Tang 	json_object_object_add(
69e407b4c8SLawrence Tang 		error_affinity, "type",
70e407b4c8SLawrence Tang 		json_object_new_string(record->ErrorAffinityLevel < 4 ?
71e407b4c8SLawrence Tang 					       "Vendor Defined" :
72e407b4c8SLawrence Tang 					       "Reserved"));
732800cd8eSLawrence Tang 	json_object_object_add(section_ir, "errorAffinity", error_affinity);
742800cd8eSLawrence Tang 
752800cd8eSLawrence Tang 	//Processor ID (MPIDR_EL1) and chip ID (MIDR_EL1).
76e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "mpidrEl1",
77e407b4c8SLawrence Tang 			       json_object_new_uint64(record->MPIDR_EL1));
78e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "midrEl1",
79e407b4c8SLawrence Tang 			       json_object_new_uint64(record->MIDR_EL1));
802800cd8eSLawrence Tang 
812800cd8eSLawrence Tang 	//Whether the processor is running, and the state of it if so.
82e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "running",
83e407b4c8SLawrence Tang 			       json_object_new_boolean(record->RunningState &
84*f8fc7052SJohn Chung 						       0x1));
85e407b4c8SLawrence Tang 	if (!(record->RunningState >> 31)) {
863d0e4f24SLawrence Tang 		//Bit 32 of running state is on, so PSCI state information is included.
872721739aSLawrence Tang 		//This can't be made human readable, as it is unknown whether this will be the pre-PSCI 1.0 format
882721739aSLawrence Tang 		//or the newer Extended StateID format.
89e407b4c8SLawrence Tang 		json_object_object_add(
90e407b4c8SLawrence Tang 			section_ir, "psciState",
91e407b4c8SLawrence Tang 			json_object_new_uint64(record->PsciState));
922800cd8eSLawrence Tang 	}
932800cd8eSLawrence Tang 
943d0e4f24SLawrence Tang 	//Processor error structures.
953d0e4f24SLawrence Tang 	json_object *error_info_array = json_object_new_array();
96e407b4c8SLawrence Tang 	EFI_ARM_ERROR_INFORMATION_ENTRY *cur_error =
97e407b4c8SLawrence Tang 		(EFI_ARM_ERROR_INFORMATION_ENTRY *)(record + 1);
98e407b4c8SLawrence Tang 	for (int i = 0; i < record->ErrInfoNum; i++) {
99e407b4c8SLawrence Tang 		json_object_array_add(error_info_array,
100e407b4c8SLawrence Tang 				      cper_arm_error_info_to_ir(cur_error));
1017f21db6cSLawrence Tang 		cur_error++;
1023d0e4f24SLawrence Tang 	}
1037f21db6cSLawrence Tang 	json_object_object_add(section_ir, "errorInfo", error_info_array);
1047f21db6cSLawrence Tang 
1057f21db6cSLawrence Tang 	//Processor context structures.
1067f21db6cSLawrence Tang 	//The current position is moved within the processing, as it is a dynamic size structure.
107*f8fc7052SJohn Chung 	uint8_t *cur_pos = (uint8_t *)cur_error;
1083636d3c2SLawrence Tang 	json_object *context_info_array = json_object_new_array();
109e407b4c8SLawrence Tang 	for (int i = 0; i < record->ContextInfoNum; i++) {
110e407b4c8SLawrence Tang 		EFI_ARM_CONTEXT_INFORMATION_HEADER *header =
111e407b4c8SLawrence Tang 			(EFI_ARM_CONTEXT_INFORMATION_HEADER *)cur_pos;
112e407b4c8SLawrence Tang 		json_object *processor_context =
113*f8fc7052SJohn Chung 			cper_arm_processor_context_to_ir(header,
114*f8fc7052SJohn Chung 							 (void **)&cur_pos);
1153636d3c2SLawrence Tang 		json_object_array_add(context_info_array, processor_context);
1163636d3c2SLawrence Tang 	}
1173636d3c2SLawrence Tang 	json_object_object_add(section_ir, "contextInfo", context_info_array);
1187f21db6cSLawrence Tang 
1197f21db6cSLawrence Tang 	//Is there any vendor-specific information following?
120*f8fc7052SJohn Chung 	if (cur_pos < (uint8_t *)section + record->SectionLength) {
121d7e8ca34SLawrence Tang 		json_object *vendor_specific = json_object_new_object();
122*f8fc7052SJohn Chung 		size_t input_size =
123*f8fc7052SJohn Chung 			(uint8_t *)section + record->SectionLength - cur_pos;
124*f8fc7052SJohn Chung 		char *encoded = malloc(2 * input_size);
125*f8fc7052SJohn Chung 		size_t encoded_len = 0;
126*f8fc7052SJohn Chung 		if (!encoded) {
127*f8fc7052SJohn Chung 			printf("Failed to allocate encode output buffer. \n");
128*f8fc7052SJohn Chung 		} else {
129*f8fc7052SJohn Chung 			base64_encode((const char *)cur_pos, input_size,
130*f8fc7052SJohn Chung 				      encoded, &encoded_len, 0);
131e407b4c8SLawrence Tang 			json_object_object_add(vendor_specific, "data",
132*f8fc7052SJohn Chung 					       json_object_new_string_len(
133*f8fc7052SJohn Chung 						       encoded, encoded_len));
134d7e8ca34SLawrence Tang 			free(encoded);
135d7e8ca34SLawrence Tang 
136e407b4c8SLawrence Tang 			json_object_object_add(section_ir, "vendorSpecificInfo",
137e407b4c8SLawrence Tang 					       vendor_specific);
1387f21db6cSLawrence Tang 		}
139*f8fc7052SJohn Chung 	}
1407f21db6cSLawrence Tang 
1412800cd8eSLawrence Tang 	return section_ir;
1422800cd8eSLawrence Tang }
1433d0e4f24SLawrence Tang 
1443d0e4f24SLawrence Tang //Converts a single ARM Process Error Information structure into JSON IR.
145e407b4c8SLawrence Tang json_object *
146e407b4c8SLawrence Tang cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info)
1473d0e4f24SLawrence Tang {
1483d0e4f24SLawrence Tang 	json_object *error_info_ir = json_object_new_object();
1493d0e4f24SLawrence Tang 
1503d0e4f24SLawrence Tang 	//Version, length.
151e407b4c8SLawrence Tang 	json_object_object_add(error_info_ir, "version",
152e407b4c8SLawrence Tang 			       json_object_new_int(error_info->Version));
153e407b4c8SLawrence Tang 	json_object_object_add(error_info_ir, "length",
154e407b4c8SLawrence Tang 			       json_object_new_int(error_info->Length));
1553d0e4f24SLawrence Tang 
1563d0e4f24SLawrence Tang 	//Validation bitfield.
157e407b4c8SLawrence Tang 	json_object *validation =
158e407b4c8SLawrence Tang 		bitfield_to_ir(error_info->ValidationBits, 5,
159e407b4c8SLawrence Tang 			       ARM_ERROR_INFO_ENTRY_VALID_BITFIELD_NAMES);
1603d0e4f24SLawrence Tang 	json_object_object_add(error_info_ir, "validationBits", validation);
1613d0e4f24SLawrence Tang 
1623d0e4f24SLawrence Tang 	//The type of error information in this log.
163e407b4c8SLawrence Tang 	json_object *error_type = integer_to_readable_pair(
164e407b4c8SLawrence Tang 		error_info->Type, 4, ARM_ERROR_INFO_ENTRY_INFO_TYPES_KEYS,
165e407b4c8SLawrence Tang 		ARM_ERROR_INFO_ENTRY_INFO_TYPES_VALUES, "Unknown (Reserved)");
1663d0e4f24SLawrence Tang 	json_object_object_add(error_info_ir, "errorType", error_type);
1673d0e4f24SLawrence Tang 
1683d0e4f24SLawrence Tang 	//Multiple error count.
16922a467ceSLawrence Tang 	json_object *multiple_error = json_object_new_object();
170e407b4c8SLawrence Tang 	json_object_object_add(multiple_error, "value",
171e407b4c8SLawrence Tang 			       json_object_new_int(error_info->MultipleError));
172e407b4c8SLawrence Tang 	json_object_object_add(
173e407b4c8SLawrence Tang 		multiple_error, "type",
174e407b4c8SLawrence Tang 		json_object_new_string(error_info->MultipleError < 1 ?
175e407b4c8SLawrence Tang 					       "Single Error" :
176e407b4c8SLawrence Tang 					       "Multiple Errors"));
1773d0e4f24SLawrence Tang 	json_object_object_add(error_info_ir, "multipleError", multiple_error);
1783d0e4f24SLawrence Tang 
1793d0e4f24SLawrence Tang 	//Flags.
180e407b4c8SLawrence Tang 	json_object *flags = bitfield_to_ir(error_info->Flags, 4,
181e407b4c8SLawrence Tang 					    ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
1823d0e4f24SLawrence Tang 	json_object_object_add(error_info_ir, "flags", flags);
1833d0e4f24SLawrence Tang 
1843d0e4f24SLawrence Tang 	//Error information, split by type.
1853d0e4f24SLawrence Tang 	json_object *error_subinfo = NULL;
186e407b4c8SLawrence Tang 	switch (error_info->Type) {
18771570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_CACHE: //Cache
18871570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_TLB:   //TLB
189e407b4c8SLawrence Tang 		error_subinfo = cper_arm_cache_tlb_error_to_ir(
190e407b4c8SLawrence Tang 			(EFI_ARM_CACHE_ERROR_STRUCTURE *)&error_info
191e407b4c8SLawrence Tang 				->ErrorInformation,
192e407b4c8SLawrence Tang 			error_info);
1933d0e4f24SLawrence Tang 		break;
19471570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_BUS: //Bus
195e407b4c8SLawrence Tang 		error_subinfo = cper_arm_bus_error_to_ir(
196e407b4c8SLawrence Tang 			(EFI_ARM_BUS_ERROR_STRUCTURE *)&error_info
197e407b4c8SLawrence Tang 				->ErrorInformation);
1983d0e4f24SLawrence Tang 		break;
19971570a2aSLawrence Tang 
20071570a2aSLawrence Tang 	default:
20171570a2aSLawrence Tang 		//Unknown/microarch, so can't be made readable. Simply dump as a uint64 data object.
20271570a2aSLawrence Tang 		error_subinfo = json_object_new_object();
203e407b4c8SLawrence Tang 		json_object_object_add(
204e407b4c8SLawrence Tang 			error_subinfo, "data",
205e407b4c8SLawrence Tang 			json_object_new_uint64(
206e407b4c8SLawrence Tang 				*((UINT64 *)&error_info->ErrorInformation)));
20771570a2aSLawrence Tang 		break;
2083d0e4f24SLawrence Tang 	}
209e407b4c8SLawrence Tang 	json_object_object_add(error_info_ir, "errorInformation",
210e407b4c8SLawrence Tang 			       error_subinfo);
2113d0e4f24SLawrence Tang 
212b98ec66cSLawrence Tang 	//Virtual fault address, physical fault address.
213e407b4c8SLawrence Tang 	json_object_object_add(
214e407b4c8SLawrence Tang 		error_info_ir, "virtualFaultAddress",
215e407b4c8SLawrence Tang 		json_object_new_uint64(error_info->VirtualFaultAddress));
216e407b4c8SLawrence Tang 	json_object_object_add(
217e407b4c8SLawrence Tang 		error_info_ir, "physicalFaultAddress",
218e407b4c8SLawrence Tang 		json_object_new_uint64(error_info->PhysicalFaultAddress));
219b98ec66cSLawrence Tang 
2203d0e4f24SLawrence Tang 	return error_info_ir;
2213d0e4f24SLawrence Tang }
2223d0e4f24SLawrence Tang 
2237f21db6cSLawrence Tang //Converts a single ARM cache/TLB error information structure into JSON IR format.
224e407b4c8SLawrence Tang json_object *
225e407b4c8SLawrence Tang cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
226e407b4c8SLawrence Tang 			       EFI_ARM_ERROR_INFORMATION_ENTRY *error_info)
2273d0e4f24SLawrence Tang {
2287f21db6cSLawrence Tang 	json_object *cache_tlb_error_ir = json_object_new_object();
2293d0e4f24SLawrence Tang 
2307f21db6cSLawrence Tang 	//Validation bitfield.
231e407b4c8SLawrence Tang 	json_object *validation =
232e407b4c8SLawrence Tang 		bitfield_to_ir(cache_tlb_error->ValidationBits, 7,
233e407b4c8SLawrence Tang 			       ARM_CACHE_TLB_ERROR_VALID_BITFIELD_NAMES);
234e407b4c8SLawrence Tang 	json_object_object_add(cache_tlb_error_ir, "validationBits",
235e407b4c8SLawrence Tang 			       validation);
2367f21db6cSLawrence Tang 
2377f21db6cSLawrence Tang 	//Transaction type.
238e407b4c8SLawrence Tang 	json_object *transaction_type = integer_to_readable_pair(
239e407b4c8SLawrence Tang 		cache_tlb_error->TransactionType, 3,
2407f21db6cSLawrence Tang 		ARM_ERROR_TRANSACTION_TYPES_KEYS,
241e407b4c8SLawrence Tang 		ARM_ERROR_TRANSACTION_TYPES_VALUES, "Unknown (Reserved)");
242e407b4c8SLawrence Tang 	json_object_object_add(cache_tlb_error_ir, "transactionType",
243e407b4c8SLawrence Tang 			       transaction_type);
2447f21db6cSLawrence Tang 
2457f21db6cSLawrence Tang 	//Operation.
2467f21db6cSLawrence Tang 	json_object *operation;
247e407b4c8SLawrence Tang 	if (error_info->Type == 0) {
2487f21db6cSLawrence Tang 		//Cache operation.
249e407b4c8SLawrence Tang 		operation = integer_to_readable_pair(
250e407b4c8SLawrence Tang 			cache_tlb_error->Operation, 11,
2517f21db6cSLawrence Tang 			ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
2527f21db6cSLawrence Tang 			ARM_CACHE_BUS_OPERATION_TYPES_VALUES,
2537f21db6cSLawrence Tang 			"Unknown (Reserved)");
254e407b4c8SLawrence Tang 	} else {
2557f21db6cSLawrence Tang 		//TLB operation.
256e407b4c8SLawrence Tang 		operation = integer_to_readable_pair(
257e407b4c8SLawrence Tang 			cache_tlb_error->Operation, 9,
2587f21db6cSLawrence Tang 			ARM_TLB_OPERATION_TYPES_KEYS,
259e407b4c8SLawrence Tang 			ARM_TLB_OPERATION_TYPES_VALUES, "Unknown (Reserved)");
2607f21db6cSLawrence Tang 	}
2617f21db6cSLawrence Tang 	json_object_object_add(cache_tlb_error_ir, "operation", operation);
2627f21db6cSLawrence Tang 
2637f21db6cSLawrence Tang 	//Miscellaneous remaining fields.
264e407b4c8SLawrence Tang 	json_object_object_add(cache_tlb_error_ir, "level",
265e407b4c8SLawrence Tang 			       json_object_new_int(cache_tlb_error->Level));
266e407b4c8SLawrence Tang 	json_object_object_add(
267e407b4c8SLawrence Tang 		cache_tlb_error_ir, "processorContextCorrupt",
268e407b4c8SLawrence Tang 		json_object_new_boolean(
269e407b4c8SLawrence Tang 			cache_tlb_error->ProcessorContextCorrupt));
270e407b4c8SLawrence Tang 	json_object_object_add(
271e407b4c8SLawrence Tang 		cache_tlb_error_ir, "corrected",
272e407b4c8SLawrence Tang 		json_object_new_boolean(cache_tlb_error->Corrected));
273e407b4c8SLawrence Tang 	json_object_object_add(
274e407b4c8SLawrence Tang 		cache_tlb_error_ir, "precisePC",
275e407b4c8SLawrence Tang 		json_object_new_boolean(cache_tlb_error->PrecisePC));
276e407b4c8SLawrence Tang 	json_object_object_add(
277e407b4c8SLawrence Tang 		cache_tlb_error_ir, "restartablePC",
278e407b4c8SLawrence Tang 		json_object_new_boolean(cache_tlb_error->RestartablePC));
2797f21db6cSLawrence Tang 	return cache_tlb_error_ir;
2803d0e4f24SLawrence Tang }
2813d0e4f24SLawrence Tang 
2823d0e4f24SLawrence Tang //Converts a single ARM bus error information structure into JSON IR format.
2837f21db6cSLawrence Tang json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error)
2843d0e4f24SLawrence Tang {
2857f21db6cSLawrence Tang 	json_object *bus_error_ir = json_object_new_object();
2867f21db6cSLawrence Tang 
2877f21db6cSLawrence Tang 	//Validation bits.
288e407b4c8SLawrence Tang 	json_object *validation =
289e407b4c8SLawrence Tang 		bitfield_to_ir(bus_error->ValidationBits, 12,
290e407b4c8SLawrence Tang 			       ARM_BUS_ERROR_VALID_BITFIELD_NAMES);
2917f21db6cSLawrence Tang 	json_object_object_add(bus_error_ir, "validationBits", validation);
2927f21db6cSLawrence Tang 
2937f21db6cSLawrence Tang 	//Transaction type.
294e407b4c8SLawrence Tang 	json_object *transaction_type = integer_to_readable_pair(
295e407b4c8SLawrence Tang 		bus_error->TransactionType, 3, ARM_ERROR_TRANSACTION_TYPES_KEYS,
296e407b4c8SLawrence Tang 		ARM_ERROR_TRANSACTION_TYPES_VALUES, "Unknown (Reserved)");
297e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "transactionType",
298e407b4c8SLawrence Tang 			       transaction_type);
2997f21db6cSLawrence Tang 
3007f21db6cSLawrence Tang 	//Operation.
301e407b4c8SLawrence Tang 	json_object *operation = integer_to_readable_pair(
302e407b4c8SLawrence Tang 		bus_error->Operation, 7, ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
303e407b4c8SLawrence Tang 		ARM_CACHE_BUS_OPERATION_TYPES_VALUES, "Unknown (Reserved)");
3047f21db6cSLawrence Tang 	json_object_object_add(bus_error_ir, "operation", operation);
3057f21db6cSLawrence Tang 
3067f21db6cSLawrence Tang 	//Affinity level of bus error, + miscellaneous fields.
307e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "level",
308e407b4c8SLawrence Tang 			       json_object_new_int(bus_error->Level));
309e407b4c8SLawrence Tang 	json_object_object_add(
310e407b4c8SLawrence Tang 		bus_error_ir, "processorContextCorrupt",
311e407b4c8SLawrence Tang 		json_object_new_boolean(bus_error->ProcessorContextCorrupt));
312e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "corrected",
313e407b4c8SLawrence Tang 			       json_object_new_boolean(bus_error->Corrected));
314e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "precisePC",
315e407b4c8SLawrence Tang 			       json_object_new_boolean(bus_error->PrecisePC));
316e407b4c8SLawrence Tang 	json_object_object_add(
317e407b4c8SLawrence Tang 		bus_error_ir, "restartablePC",
318e407b4c8SLawrence Tang 		json_object_new_boolean(bus_error->RestartablePC));
319e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "timedOut",
320e407b4c8SLawrence Tang 			       json_object_new_boolean(bus_error->TimeOut));
3217f21db6cSLawrence Tang 
3227f21db6cSLawrence Tang 	//Participation type.
323e407b4c8SLawrence Tang 	json_object *participation_type = integer_to_readable_pair(
324e407b4c8SLawrence Tang 		bus_error->ParticipationType, 4,
3257f21db6cSLawrence Tang 		ARM_BUS_PARTICIPATION_TYPES_KEYS,
326e407b4c8SLawrence Tang 		ARM_BUS_PARTICIPATION_TYPES_VALUES, "Unknown");
327e407b4c8SLawrence Tang 	json_object_object_add(bus_error_ir, "participationType",
328e407b4c8SLawrence Tang 			       participation_type);
3297f21db6cSLawrence Tang 
3307f21db6cSLawrence Tang 	//Address space.
331e407b4c8SLawrence Tang 	json_object *address_space = integer_to_readable_pair(
332e407b4c8SLawrence Tang 		bus_error->AddressSpace, 3, ARM_BUS_ADDRESS_SPACE_TYPES_KEYS,
333e407b4c8SLawrence Tang 		ARM_BUS_ADDRESS_SPACE_TYPES_VALUES, "Unknown");
3347f21db6cSLawrence Tang 	json_object_object_add(bus_error_ir, "addressSpace", address_space);
3357f21db6cSLawrence Tang 
3367f21db6cSLawrence Tang 	//Memory access attributes.
3377f21db6cSLawrence Tang 	//todo: find the specification of these in the ARM ARM
338e407b4c8SLawrence Tang 	json_object_object_add(
339e407b4c8SLawrence Tang 		bus_error_ir, "memoryAttributes",
340e407b4c8SLawrence Tang 		json_object_new_int(bus_error->MemoryAddressAttributes));
3417f21db6cSLawrence Tang 
3427f21db6cSLawrence Tang 	//Access Mode
3437f21db6cSLawrence Tang 	json_object *access_mode = json_object_new_object();
344e407b4c8SLawrence Tang 	json_object_object_add(access_mode, "value",
345e407b4c8SLawrence Tang 			       json_object_new_int(bus_error->AccessMode));
346e407b4c8SLawrence Tang 	json_object_object_add(
347e407b4c8SLawrence Tang 		access_mode, "name",
348e407b4c8SLawrence Tang 		json_object_new_string(bus_error->AccessMode == 0 ? "Secure" :
349e407b4c8SLawrence Tang 								    "Normal"));
3507f21db6cSLawrence Tang 	json_object_object_add(bus_error_ir, "accessMode", access_mode);
3517f21db6cSLawrence Tang 
3527f21db6cSLawrence Tang 	return bus_error_ir;
3537f21db6cSLawrence Tang }
3547f21db6cSLawrence Tang 
3557f21db6cSLawrence Tang //Converts a single ARM processor context block into JSON IR.
356e407b4c8SLawrence Tang json_object *
357e407b4c8SLawrence Tang cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
358e407b4c8SLawrence Tang 				 void **cur_pos)
3597f21db6cSLawrence Tang {
3607f21db6cSLawrence Tang 	json_object *context_ir = json_object_new_object();
3617f21db6cSLawrence Tang 
36271570a2aSLawrence Tang 	//Version.
363e407b4c8SLawrence Tang 	json_object_object_add(context_ir, "version",
364e407b4c8SLawrence Tang 			       json_object_new_int(header->Version));
36571570a2aSLawrence Tang 
3667f21db6cSLawrence Tang 	//Add the context type.
367e407b4c8SLawrence Tang 	json_object *context_type = integer_to_readable_pair(
368e407b4c8SLawrence Tang 		header->RegisterContextType, 9,
3697f21db6cSLawrence Tang 		ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_KEYS,
3707f21db6cSLawrence Tang 		ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_VALUES,
3717f21db6cSLawrence Tang 		"Unknown (Reserved)");
3727f21db6cSLawrence Tang 	json_object_object_add(context_ir, "registerContextType", context_type);
3737f21db6cSLawrence Tang 
3747f21db6cSLawrence Tang 	//Register array size (bytes).
375e407b4c8SLawrence Tang 	json_object_object_add(
376e407b4c8SLawrence Tang 		context_ir, "registerArraySize",
377e407b4c8SLawrence Tang 		json_object_new_uint64(header->RegisterArraySize));
3787f21db6cSLawrence Tang 
3797f21db6cSLawrence Tang 	//The register array itself.
3807f21db6cSLawrence Tang 	*cur_pos = (void *)(header + 1);
3817f21db6cSLawrence Tang 	json_object *register_array = NULL;
382e407b4c8SLawrence Tang 	switch (header->RegisterContextType) {
3837f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
384e407b4c8SLawrence Tang 		register_array = uniform_struct_to_ir(
385e407b4c8SLawrence Tang 			(UINT32 *)cur_pos,
386e407b4c8SLawrence Tang 			sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
387e407b4c8SLawrence Tang 			ARM_AARCH32_GPR_NAMES);
3887f21db6cSLawrence Tang 		break;
3897f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
390e407b4c8SLawrence Tang 		register_array = uniform_struct_to_ir(
391e407b4c8SLawrence Tang 			(UINT32 *)cur_pos,
392e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
393e407b4c8SLawrence Tang 				sizeof(UINT32),
394e407b4c8SLawrence Tang 			ARM_AARCH32_EL1_REGISTER_NAMES);
3957f21db6cSLawrence Tang 		break;
3967f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
397e407b4c8SLawrence Tang 		register_array = uniform_struct_to_ir(
398e407b4c8SLawrence Tang 			(UINT32 *)cur_pos,
399e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
400e407b4c8SLawrence Tang 				sizeof(UINT32),
401e407b4c8SLawrence Tang 			ARM_AARCH32_EL2_REGISTER_NAMES);
4027f21db6cSLawrence Tang 		break;
4037f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
404e407b4c8SLawrence Tang 		register_array = uniform_struct_to_ir(
405e407b4c8SLawrence Tang 			(UINT32 *)cur_pos,
406e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
407e407b4c8SLawrence Tang 				sizeof(UINT32),
408e407b4c8SLawrence Tang 			ARM_AARCH32_SECURE_REGISTER_NAMES);
4097f21db6cSLawrence Tang 		break;
4107f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
411e407b4c8SLawrence Tang 		register_array = uniform_struct64_to_ir(
412e407b4c8SLawrence Tang 			(UINT64 *)cur_pos,
413e407b4c8SLawrence Tang 			sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
414e407b4c8SLawrence Tang 			ARM_AARCH64_GPR_NAMES);
4157f21db6cSLawrence Tang 		break;
4167f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
417e407b4c8SLawrence Tang 		register_array = uniform_struct64_to_ir(
418e407b4c8SLawrence Tang 			(UINT64 *)cur_pos,
419e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
420e407b4c8SLawrence Tang 				sizeof(UINT64),
421e407b4c8SLawrence Tang 			ARM_AARCH64_EL1_REGISTER_NAMES);
4227f21db6cSLawrence Tang 		break;
4237f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
424e407b4c8SLawrence Tang 		register_array = uniform_struct64_to_ir(
425e407b4c8SLawrence Tang 			(UINT64 *)cur_pos,
426e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
427e407b4c8SLawrence Tang 				sizeof(UINT64),
428e407b4c8SLawrence Tang 			ARM_AARCH64_EL2_REGISTER_NAMES);
4297f21db6cSLawrence Tang 		break;
4307f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
431e407b4c8SLawrence Tang 		register_array = uniform_struct64_to_ir(
432e407b4c8SLawrence Tang 			(UINT64 *)cur_pos,
433e407b4c8SLawrence Tang 			sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
434e407b4c8SLawrence Tang 				sizeof(UINT64),
435e407b4c8SLawrence Tang 			ARM_AARCH64_EL3_REGISTER_NAMES);
4367f21db6cSLawrence Tang 		break;
4377f21db6cSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_MISC:
438e407b4c8SLawrence Tang 		register_array = cper_arm_misc_register_array_to_ir(
439e407b4c8SLawrence Tang 			(EFI_ARM_MISC_CONTEXT_REGISTER *)cur_pos);
4407f21db6cSLawrence Tang 		break;
4417f21db6cSLawrence Tang 	default:
442d7e8ca34SLawrence Tang 		//Unknown register array type, add as base64 data instead.
4437f21db6cSLawrence Tang 		register_array = json_object_new_object();
444*f8fc7052SJohn Chung 		char *encoded = malloc(2 * header->RegisterArraySize);
445*f8fc7052SJohn Chung 		size_t encoded_len = 0;
446*f8fc7052SJohn Chung 		if (!encoded) {
447*f8fc7052SJohn Chung 			printf("Failed to allocate encode output buffer. \n");
448*f8fc7052SJohn Chung 		} else {
449*f8fc7052SJohn Chung 			base64_encode((const char *)cur_pos,
450*f8fc7052SJohn Chung 				      header->RegisterArraySize, encoded,
451*f8fc7052SJohn Chung 				      &encoded_len, 0);
452e407b4c8SLawrence Tang 			json_object_object_add(register_array, "data",
453*f8fc7052SJohn Chung 					       json_object_new_string_len(
454*f8fc7052SJohn Chung 						       encoded, encoded_len));
455d7e8ca34SLawrence Tang 			free(encoded);
456*f8fc7052SJohn Chung 		}
4577f21db6cSLawrence Tang 		break;
4587f21db6cSLawrence Tang 	}
4593636d3c2SLawrence Tang 	json_object_object_add(context_ir, "registerArray", register_array);
4607f21db6cSLawrence Tang 
4617f21db6cSLawrence Tang 	//Set the current position to after the processor context structure.
4627f21db6cSLawrence Tang 	*cur_pos = (UINT8 *)(*cur_pos) + header->RegisterArraySize;
4637f21db6cSLawrence Tang 
4647f21db6cSLawrence Tang 	return context_ir;
4657f21db6cSLawrence Tang }
4667f21db6cSLawrence Tang 
4677f21db6cSLawrence Tang //Converts a single CPER ARM miscellaneous register array to JSON IR format.
468e407b4c8SLawrence Tang json_object *
469e407b4c8SLawrence Tang cper_arm_misc_register_array_to_ir(EFI_ARM_MISC_CONTEXT_REGISTER *misc_register)
4707f21db6cSLawrence Tang {
4717f21db6cSLawrence Tang 	json_object *register_array = json_object_new_object();
4727f21db6cSLawrence Tang 	json_object *mrs_encoding = json_object_new_object();
473e407b4c8SLawrence Tang 	json_object_object_add(mrs_encoding, "op2",
474e407b4c8SLawrence Tang 			       json_object_new_uint64(misc_register->MrsOp2));
475e407b4c8SLawrence Tang 	json_object_object_add(mrs_encoding, "crm",
476e407b4c8SLawrence Tang 			       json_object_new_uint64(misc_register->MrsCrm));
477e407b4c8SLawrence Tang 	json_object_object_add(mrs_encoding, "crn",
478e407b4c8SLawrence Tang 			       json_object_new_uint64(misc_register->MrsCrn));
479e407b4c8SLawrence Tang 	json_object_object_add(mrs_encoding, "op1",
480e407b4c8SLawrence Tang 			       json_object_new_uint64(misc_register->MrsOp1));
481e407b4c8SLawrence Tang 	json_object_object_add(mrs_encoding, "o0",
482e407b4c8SLawrence Tang 			       json_object_new_uint64(misc_register->MrsO0));
4837f21db6cSLawrence Tang 	json_object_object_add(register_array, "mrsEncoding", mrs_encoding);
484e407b4c8SLawrence Tang 	json_object_object_add(register_array, "value",
485e407b4c8SLawrence Tang 			       json_object_new_uint64(misc_register->Value));
4867f21db6cSLawrence Tang 
4877f21db6cSLawrence Tang 	return register_array;
4883d0e4f24SLawrence Tang }
4897cd13908SLawrence Tang 
4907cd13908SLawrence Tang //Converts a single CPER-JSON ARM error section into CPER binary, outputting to the given stream.
4917cd13908SLawrence Tang void ir_section_arm_to_cper(json_object *section, FILE *out)
4927cd13908SLawrence Tang {
493e407b4c8SLawrence Tang 	EFI_ARM_ERROR_RECORD *section_cper =
494e407b4c8SLawrence Tang 		(EFI_ARM_ERROR_RECORD *)calloc(1, sizeof(EFI_ARM_ERROR_RECORD));
4957cd13908SLawrence Tang 
4967cd13908SLawrence Tang 	//Validation bits.
497e407b4c8SLawrence Tang 	section_cper->ValidFields = ir_to_bitfield(
498e407b4c8SLawrence Tang 		json_object_object_get(section, "validationBits"), 4,
499e407b4c8SLawrence Tang 		ARM_ERROR_VALID_BITFIELD_NAMES);
5007cd13908SLawrence Tang 
5017cd13908SLawrence Tang 	//Count of error/context info structures.
502e407b4c8SLawrence Tang 	section_cper->ErrInfoNum = json_object_get_int(
503e407b4c8SLawrence Tang 		json_object_object_get(section, "errorInfoNum"));
504e407b4c8SLawrence Tang 	section_cper->ContextInfoNum = json_object_get_int(
505e407b4c8SLawrence Tang 		json_object_object_get(section, "contextInfoNum"));
5067cd13908SLawrence Tang 
5077cd13908SLawrence Tang 	//Miscellaneous raw value fields.
508e407b4c8SLawrence Tang 	section_cper->SectionLength = json_object_get_uint64(
509e407b4c8SLawrence Tang 		json_object_object_get(section, "sectionLength"));
510e407b4c8SLawrence Tang 	section_cper->ErrorAffinityLevel = readable_pair_to_integer(
511e407b4c8SLawrence Tang 		json_object_object_get(section, "errorAffinity"));
512e407b4c8SLawrence Tang 	section_cper->MPIDR_EL1 = json_object_get_uint64(
513e407b4c8SLawrence Tang 		json_object_object_get(section, "mpidrEl1"));
514e407b4c8SLawrence Tang 	section_cper->MIDR_EL1 = json_object_get_uint64(
515e407b4c8SLawrence Tang 		json_object_object_get(section, "midrEl1"));
516e407b4c8SLawrence Tang 	section_cper->RunningState = json_object_get_boolean(
517e407b4c8SLawrence Tang 		json_object_object_get(section, "running"));
5187cd13908SLawrence Tang 
5197cd13908SLawrence Tang 	//Optional PSCI state.
5207cd13908SLawrence Tang 	json_object *psci_state = json_object_object_get(section, "psciState");
521*f8fc7052SJohn Chung 	if (psci_state != NULL) {
5227cd13908SLawrence Tang 		section_cper->PsciState = json_object_get_uint64(psci_state);
523*f8fc7052SJohn Chung 	}
5247cd13908SLawrence Tang 
5257cd13908SLawrence Tang 	//Flush header to stream.
5267cd13908SLawrence Tang 	fwrite(section_cper, sizeof(EFI_ARM_ERROR_RECORD), 1, out);
5277cd13908SLawrence Tang 	fflush(out);
5287cd13908SLawrence Tang 
5297cd13908SLawrence Tang 	//Error info structure array.
5307cd13908SLawrence Tang 	json_object *error_info = json_object_object_get(section, "errorInfo");
531*f8fc7052SJohn Chung 	for (int i = 0; i < section_cper->ErrInfoNum; i++) {
532e407b4c8SLawrence Tang 		ir_arm_error_info_to_cper(
533e407b4c8SLawrence Tang 			json_object_array_get_idx(error_info, i), out);
534*f8fc7052SJohn Chung 	}
5357cd13908SLawrence Tang 
5367cd13908SLawrence Tang 	//Context info structure array.
537e407b4c8SLawrence Tang 	json_object *context_info =
538e407b4c8SLawrence Tang 		json_object_object_get(section, "contextInfo");
539*f8fc7052SJohn Chung 	for (int i = 0; i < section_cper->ContextInfoNum; i++) {
540e407b4c8SLawrence Tang 		ir_arm_context_info_to_cper(
541e407b4c8SLawrence Tang 			json_object_array_get_idx(context_info, i), out);
542*f8fc7052SJohn Chung 	}
5437cd13908SLawrence Tang 
5447cd13908SLawrence Tang 	//Vendor specific error info.
545e407b4c8SLawrence Tang 	json_object *vendor_specific_info =
546e407b4c8SLawrence Tang 		json_object_object_get(section, "vendorSpecificInfo");
547e407b4c8SLawrence Tang 	if (vendor_specific_info != NULL) {
548e407b4c8SLawrence Tang 		json_object *vendor_info_string =
549e407b4c8SLawrence Tang 			json_object_object_get(vendor_specific_info, "data");
550e407b4c8SLawrence Tang 		int vendor_specific_len =
551e407b4c8SLawrence Tang 			json_object_get_string_len(vendor_info_string);
552*f8fc7052SJohn Chung 		char *decoded = malloc(vendor_specific_len);
553*f8fc7052SJohn Chung 		size_t decoded_len = 0;
554*f8fc7052SJohn Chung 		if (!decoded) {
555*f8fc7052SJohn Chung 			printf("Failed to allocate decode output buffer. \n");
556*f8fc7052SJohn Chung 		} else {
557*f8fc7052SJohn Chung 			base64_decode(
558*f8fc7052SJohn Chung 				json_object_get_string(vendor_info_string),
559*f8fc7052SJohn Chung 				vendor_specific_len, decoded, &decoded_len, 0);
56001e3a44dSLawrence Tang 
56101e3a44dSLawrence Tang 			//Write out to file.
562*f8fc7052SJohn Chung 			fwrite(decoded, decoded_len, 1, out);
5637cd13908SLawrence Tang 			fflush(out);
5647cd13908SLawrence Tang 			free(decoded);
5657cd13908SLawrence Tang 		}
566*f8fc7052SJohn Chung 	}
5677cd13908SLawrence Tang 
5687cd13908SLawrence Tang 	//Free remaining resources.
5697cd13908SLawrence Tang 	free(section_cper);
5707cd13908SLawrence Tang }
5717cd13908SLawrence Tang 
5727cd13908SLawrence Tang //Converts a single ARM error information structure into CPER binary, outputting to the given stream.
5737cd13908SLawrence Tang void ir_arm_error_info_to_cper(json_object *error_info, FILE *out)
5747cd13908SLawrence Tang {
5757cd13908SLawrence Tang 	EFI_ARM_ERROR_INFORMATION_ENTRY error_info_cper;
5767cd13908SLawrence Tang 
5777cd13908SLawrence Tang 	//Version, length.
578e407b4c8SLawrence Tang 	error_info_cper.Version = json_object_get_int(
579e407b4c8SLawrence Tang 		json_object_object_get(error_info, "version"));
580e407b4c8SLawrence Tang 	error_info_cper.Length = json_object_get_int(
581e407b4c8SLawrence Tang 		json_object_object_get(error_info, "length"));
5827cd13908SLawrence Tang 
5837cd13908SLawrence Tang 	//Validation bits.
584e407b4c8SLawrence Tang 	error_info_cper.ValidationBits = ir_to_bitfield(
585e407b4c8SLawrence Tang 		json_object_object_get(error_info, "validationBits"), 5,
586e407b4c8SLawrence Tang 		ARM_ERROR_INFO_ENTRY_VALID_BITFIELD_NAMES);
5877cd13908SLawrence Tang 
5887cd13908SLawrence Tang 	//Type, multiple error.
589e407b4c8SLawrence Tang 	error_info_cper.Type = (UINT8)readable_pair_to_integer(
590e407b4c8SLawrence Tang 		json_object_object_get(error_info, "type"));
591e407b4c8SLawrence Tang 	error_info_cper.MultipleError = (UINT16)readable_pair_to_integer(
592e407b4c8SLawrence Tang 		json_object_object_get(error_info, "multipleError"));
5937cd13908SLawrence Tang 
5947cd13908SLawrence Tang 	//Flags object.
595e407b4c8SLawrence Tang 	error_info_cper.Flags = (UINT8)ir_to_bitfield(
596e407b4c8SLawrence Tang 		json_object_object_get(error_info, "flags"), 4,
597e407b4c8SLawrence Tang 		ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
5987cd13908SLawrence Tang 
5997cd13908SLawrence Tang 	//Error information.
600e407b4c8SLawrence Tang 	json_object *error_info_information =
601e407b4c8SLawrence Tang 		json_object_object_get(error_info, "errorInformation");
602e407b4c8SLawrence Tang 	switch (error_info_cper.Type) {
60371570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_CACHE:
60471570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_TLB:
605e407b4c8SLawrence Tang 		ir_arm_error_cache_tlb_info_to_cper(
606e407b4c8SLawrence Tang 			error_info_information,
607e407b4c8SLawrence Tang 			&error_info_cper.ErrorInformation.CacheError);
60871570a2aSLawrence Tang 		break;
60971570a2aSLawrence Tang 
61071570a2aSLawrence Tang 	case ARM_ERROR_INFORMATION_TYPE_BUS:
611e407b4c8SLawrence Tang 		ir_arm_error_bus_info_to_cper(
612e407b4c8SLawrence Tang 			error_info_information,
613e407b4c8SLawrence Tang 			&error_info_cper.ErrorInformation.BusError);
61471570a2aSLawrence Tang 		break;
61571570a2aSLawrence Tang 
61671570a2aSLawrence Tang 	default:
61771570a2aSLawrence Tang 		//Unknown error information type.
61871570a2aSLawrence Tang 		*((UINT64 *)&error_info_cper.ErrorInformation) =
619e407b4c8SLawrence Tang 			json_object_get_uint64(json_object_object_get(
620e407b4c8SLawrence Tang 				error_info_information, "data"));
62171570a2aSLawrence Tang 		break;
62271570a2aSLawrence Tang 	}
6237cd13908SLawrence Tang 
6247cd13908SLawrence Tang 	//Virtual/physical fault address.
625e407b4c8SLawrence Tang 	error_info_cper.VirtualFaultAddress = json_object_get_uint64(
626e407b4c8SLawrence Tang 		json_object_object_get(error_info, "virtualFaultAddress"));
627e407b4c8SLawrence Tang 	error_info_cper.PhysicalFaultAddress = json_object_get_uint64(
628e407b4c8SLawrence Tang 		json_object_object_get(error_info, "physicalFaultAddress"));
6297cd13908SLawrence Tang 
6307cd13908SLawrence Tang 	//Write out to stream.
631e407b4c8SLawrence Tang 	fwrite(&error_info_cper, sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY), 1,
632e407b4c8SLawrence Tang 	       out);
6337cd13908SLawrence Tang 	fflush(out);
6347cd13908SLawrence Tang }
6357cd13908SLawrence Tang 
63671570a2aSLawrence Tang //Converts a single ARM cache/TLB error information structure into a CPER structure.
637e407b4c8SLawrence Tang void ir_arm_error_cache_tlb_info_to_cper(
638e407b4c8SLawrence Tang 	json_object *error_information,
639e407b4c8SLawrence Tang 	EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper)
64071570a2aSLawrence Tang {
64171570a2aSLawrence Tang 	//Validation bits.
642e407b4c8SLawrence Tang 	error_info_cper->ValidationBits = ir_to_bitfield(
643e407b4c8SLawrence Tang 		json_object_object_get(error_information, "validationBits"), 7,
644e407b4c8SLawrence Tang 		ARM_CACHE_TLB_ERROR_VALID_BITFIELD_NAMES);
64571570a2aSLawrence Tang 
64671570a2aSLawrence Tang 	//Miscellaneous value fields.
647e407b4c8SLawrence Tang 	error_info_cper->TransactionType = readable_pair_to_integer(
648e407b4c8SLawrence Tang 		json_object_object_get(error_information, "transactionType"));
649e407b4c8SLawrence Tang 	error_info_cper->Operation = readable_pair_to_integer(
650e407b4c8SLawrence Tang 		json_object_object_get(error_information, "operation"));
651e407b4c8SLawrence Tang 	error_info_cper->Level = json_object_get_uint64(
652e407b4c8SLawrence Tang 		json_object_object_get(error_information, "level"));
653e407b4c8SLawrence Tang 	error_info_cper->ProcessorContextCorrupt = json_object_get_boolean(
654e407b4c8SLawrence Tang 		json_object_object_get(error_information,
655e407b4c8SLawrence Tang 				       "processorContextCorrupt"));
656e407b4c8SLawrence Tang 	error_info_cper->Corrected = json_object_get_boolean(
657e407b4c8SLawrence Tang 		json_object_object_get(error_information, "corrected"));
658e407b4c8SLawrence Tang 	error_info_cper->PrecisePC = json_object_get_boolean(
659e407b4c8SLawrence Tang 		json_object_object_get(error_information, "precisePC"));
660e407b4c8SLawrence Tang 	error_info_cper->RestartablePC = json_object_get_boolean(
661e407b4c8SLawrence Tang 		json_object_object_get(error_information, "restartablePC"));
66271570a2aSLawrence Tang 	error_info_cper->Reserved = 0;
66371570a2aSLawrence Tang }
66471570a2aSLawrence Tang 
66571570a2aSLawrence Tang //Converts a single ARM bus error information structure into a CPER structure.
666e407b4c8SLawrence Tang void ir_arm_error_bus_info_to_cper(json_object *error_information,
667e407b4c8SLawrence Tang 				   EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper)
66871570a2aSLawrence Tang {
66971570a2aSLawrence Tang 	//Validation bits.
670e407b4c8SLawrence Tang 	error_info_cper->ValidationBits = ir_to_bitfield(
671e407b4c8SLawrence Tang 		json_object_object_get(error_information, "validationBits"), 7,
672e407b4c8SLawrence Tang 		ARM_BUS_ERROR_VALID_BITFIELD_NAMES);
67371570a2aSLawrence Tang 
67471570a2aSLawrence Tang 	//Miscellaneous value fields.
675e407b4c8SLawrence Tang 	error_info_cper->TransactionType = readable_pair_to_integer(
676e407b4c8SLawrence Tang 		json_object_object_get(error_information, "transactionType"));
677e407b4c8SLawrence Tang 	error_info_cper->Operation = readable_pair_to_integer(
678e407b4c8SLawrence Tang 		json_object_object_get(error_information, "operation"));
679e407b4c8SLawrence Tang 	error_info_cper->Level = json_object_get_uint64(
680e407b4c8SLawrence Tang 		json_object_object_get(error_information, "level"));
681e407b4c8SLawrence Tang 	error_info_cper->ProcessorContextCorrupt = json_object_get_boolean(
682e407b4c8SLawrence Tang 		json_object_object_get(error_information,
683e407b4c8SLawrence Tang 				       "processorContextCorrupt"));
684e407b4c8SLawrence Tang 	error_info_cper->Corrected = json_object_get_boolean(
685e407b4c8SLawrence Tang 		json_object_object_get(error_information, "corrected"));
686e407b4c8SLawrence Tang 	error_info_cper->PrecisePC = json_object_get_boolean(
687e407b4c8SLawrence Tang 		json_object_object_get(error_information, "precisePC"));
688e407b4c8SLawrence Tang 	error_info_cper->RestartablePC = json_object_get_boolean(
689e407b4c8SLawrence Tang 		json_object_object_get(error_information, "restartablePC"));
690e407b4c8SLawrence Tang 	error_info_cper->ParticipationType = readable_pair_to_integer(
691e407b4c8SLawrence Tang 		json_object_object_get(error_information, "participationType"));
692e407b4c8SLawrence Tang 	error_info_cper->AddressSpace = readable_pair_to_integer(
693e407b4c8SLawrence Tang 		json_object_object_get(error_information, "addressSpace"));
694e407b4c8SLawrence Tang 	error_info_cper->AccessMode = readable_pair_to_integer(
695e407b4c8SLawrence Tang 		json_object_object_get(error_information, "accessMode"));
696e407b4c8SLawrence Tang 	error_info_cper->MemoryAddressAttributes = json_object_get_uint64(
697e407b4c8SLawrence Tang 		json_object_object_get(error_information, "memoryAttributes"));
69871570a2aSLawrence Tang 	error_info_cper->Reserved = 0;
69971570a2aSLawrence Tang }
70071570a2aSLawrence Tang 
7017cd13908SLawrence Tang //Converts a single ARM context information structure into CPER binary, outputting to the given stream.
7027cd13908SLawrence Tang void ir_arm_context_info_to_cper(json_object *context_info, FILE *out)
7037cd13908SLawrence Tang {
70471570a2aSLawrence Tang 	EFI_ARM_CONTEXT_INFORMATION_HEADER info_header;
7057cd13908SLawrence Tang 
70671570a2aSLawrence Tang 	//Version, array size, context type.
707e407b4c8SLawrence Tang 	info_header.Version = json_object_get_int(
708e407b4c8SLawrence Tang 		json_object_object_get(context_info, "version"));
709e407b4c8SLawrence Tang 	info_header.RegisterArraySize = json_object_get_int(
710e407b4c8SLawrence Tang 		json_object_object_get(context_info, "registerArraySize"));
711e407b4c8SLawrence Tang 	info_header.RegisterContextType = readable_pair_to_integer(
712e407b4c8SLawrence Tang 		json_object_object_get(context_info, "registerContextType"));
71371570a2aSLawrence Tang 
71471570a2aSLawrence Tang 	//Flush to stream, write the register array itself.
715e407b4c8SLawrence Tang 	fwrite(&info_header, sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER), 1,
716e407b4c8SLawrence Tang 	       out);
71771570a2aSLawrence Tang 	fflush(out);
71871570a2aSLawrence Tang 
719e407b4c8SLawrence Tang 	json_object *register_array =
720e407b4c8SLawrence Tang 		json_object_object_get(context_info, "registerArray");
721e407b4c8SLawrence Tang 	switch (info_header.RegisterContextType) {
72271570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
72371570a2aSLawrence Tang 		ir_arm_aarch32_gpr_to_cper(register_array, out);
72471570a2aSLawrence Tang 		break;
72571570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
72671570a2aSLawrence Tang 		ir_arm_aarch32_el1_to_cper(register_array, out);
72771570a2aSLawrence Tang 		break;
72871570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
72971570a2aSLawrence Tang 		ir_arm_aarch32_el2_to_cper(register_array, out);
73071570a2aSLawrence Tang 		break;
73171570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
73271570a2aSLawrence Tang 		ir_arm_aarch32_secure_to_cper(register_array, out);
73371570a2aSLawrence Tang 		break;
73471570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
73571570a2aSLawrence Tang 		ir_arm_aarch64_gpr_to_cper(register_array, out);
73671570a2aSLawrence Tang 		break;
73771570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
73871570a2aSLawrence Tang 		ir_arm_aarch64_el1_to_cper(register_array, out);
73971570a2aSLawrence Tang 		break;
74071570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
74171570a2aSLawrence Tang 		ir_arm_aarch64_el2_to_cper(register_array, out);
74271570a2aSLawrence Tang 		break;
74371570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
74471570a2aSLawrence Tang 		ir_arm_aarch64_el3_to_cper(register_array, out);
74571570a2aSLawrence Tang 		break;
74671570a2aSLawrence Tang 	case EFI_ARM_CONTEXT_TYPE_MISC:
74771570a2aSLawrence Tang 		ir_arm_misc_registers_to_cper(register_array, out);
74871570a2aSLawrence Tang 		break;
74971570a2aSLawrence Tang 	default:
75071570a2aSLawrence Tang 		//Unknown register structure.
751*f8fc7052SJohn Chung 		ir_arm_unknown_register_to_cper(register_array, out);
75271570a2aSLawrence Tang 		break;
75371570a2aSLawrence Tang 	}
75471570a2aSLawrence Tang }
75571570a2aSLawrence Tang 
75671570a2aSLawrence Tang //Converts a single AARCH32 GPR CPER-JSON object to CPER binary, outputting to the given stream.
75771570a2aSLawrence Tang void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out)
75871570a2aSLawrence Tang {
75971570a2aSLawrence Tang 	//Get uniform register array.
76071570a2aSLawrence Tang 	EFI_ARM_V8_AARCH32_GPR reg_array;
76171570a2aSLawrence Tang 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
762e407b4c8SLawrence Tang 			     sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
763e407b4c8SLawrence Tang 			     ARM_AARCH32_GPR_NAMES);
76471570a2aSLawrence Tang 
76571570a2aSLawrence Tang 	//Flush to stream.
76671570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
76771570a2aSLawrence Tang 	fflush(out);
76871570a2aSLawrence Tang }
76971570a2aSLawrence Tang 
77071570a2aSLawrence Tang //Converts a single AARCH32 EL1 register set CPER-JSON object to CPER binary, outputting to the given stream.
77171570a2aSLawrence Tang void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out)
77271570a2aSLawrence Tang {
77371570a2aSLawrence Tang 	//Get uniform register array.
77471570a2aSLawrence Tang 	EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS reg_array;
77571570a2aSLawrence Tang 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
776e407b4c8SLawrence Tang 			     sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
777e407b4c8SLawrence Tang 				     sizeof(UINT32),
778e407b4c8SLawrence Tang 			     ARM_AARCH32_EL1_REGISTER_NAMES);
77971570a2aSLawrence Tang 
78071570a2aSLawrence Tang 	//Flush to stream.
78171570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
78271570a2aSLawrence Tang 	fflush(out);
78371570a2aSLawrence Tang }
78471570a2aSLawrence Tang 
78571570a2aSLawrence Tang //Converts a single AARCH32 EL2 register set CPER-JSON object to CPER binary, outputting to the given stream.
78671570a2aSLawrence Tang void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out)
78771570a2aSLawrence Tang {
78871570a2aSLawrence Tang 	//Get uniform register array.
78971570a2aSLawrence Tang 	EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS reg_array;
79071570a2aSLawrence Tang 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
791e407b4c8SLawrence Tang 			     sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
792e407b4c8SLawrence Tang 				     sizeof(UINT32),
793e407b4c8SLawrence Tang 			     ARM_AARCH32_EL2_REGISTER_NAMES);
79471570a2aSLawrence Tang 
79571570a2aSLawrence Tang 	//Flush to stream.
79671570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
79771570a2aSLawrence Tang 	fflush(out);
79871570a2aSLawrence Tang }
79971570a2aSLawrence Tang 
80071570a2aSLawrence Tang //Converts a single AARCH32 secure register set CPER-JSON object to CPER binary, outputting to the given stream.
80171570a2aSLawrence Tang void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out)
80271570a2aSLawrence Tang {
80371570a2aSLawrence Tang 	//Get uniform register array.
80471570a2aSLawrence Tang 	EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS reg_array;
80571570a2aSLawrence Tang 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
806e407b4c8SLawrence Tang 			     sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
807e407b4c8SLawrence Tang 				     sizeof(UINT32),
808e407b4c8SLawrence Tang 			     ARM_AARCH32_SECURE_REGISTER_NAMES);
80971570a2aSLawrence Tang 
81071570a2aSLawrence Tang 	//Flush to stream.
81171570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
81271570a2aSLawrence Tang 	fflush(out);
81371570a2aSLawrence Tang }
81471570a2aSLawrence Tang 
81571570a2aSLawrence Tang //Converts a single AARCH64 GPR CPER-JSON object to CPER binary, outputting to the given stream.
81671570a2aSLawrence Tang void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out)
81771570a2aSLawrence Tang {
81871570a2aSLawrence Tang 	//Get uniform register array.
81971570a2aSLawrence Tang 	EFI_ARM_V8_AARCH64_GPR reg_array;
82071570a2aSLawrence Tang 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
821e407b4c8SLawrence Tang 			       sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
822e407b4c8SLawrence Tang 			       ARM_AARCH64_GPR_NAMES);
82371570a2aSLawrence Tang 
82471570a2aSLawrence Tang 	//Flush to stream.
82571570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
82671570a2aSLawrence Tang 	fflush(out);
82771570a2aSLawrence Tang }
82871570a2aSLawrence Tang 
82971570a2aSLawrence Tang //Converts a single AARCH64 EL1 register set CPER-JSON object to CPER binary, outputting to the given stream.
83071570a2aSLawrence Tang void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out)
83171570a2aSLawrence Tang {
83271570a2aSLawrence Tang 	//Get uniform register array.
83371570a2aSLawrence Tang 	EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS reg_array;
83471570a2aSLawrence Tang 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
835e407b4c8SLawrence Tang 			       sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
836e407b4c8SLawrence Tang 				       sizeof(UINT64),
837e407b4c8SLawrence Tang 			       ARM_AARCH64_EL1_REGISTER_NAMES);
83871570a2aSLawrence Tang 
83971570a2aSLawrence Tang 	//Flush to stream.
84071570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
84171570a2aSLawrence Tang 	fflush(out);
84271570a2aSLawrence Tang }
84371570a2aSLawrence Tang 
84471570a2aSLawrence Tang //Converts a single AARCH64 EL2 register set CPER-JSON object to CPER binary, outputting to the given stream.
84571570a2aSLawrence Tang void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out)
84671570a2aSLawrence Tang {
84771570a2aSLawrence Tang 	//Get uniform register array.
84871570a2aSLawrence Tang 	EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS reg_array;
84971570a2aSLawrence Tang 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
850e407b4c8SLawrence Tang 			       sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
851e407b4c8SLawrence Tang 				       sizeof(UINT64),
852e407b4c8SLawrence Tang 			       ARM_AARCH64_EL2_REGISTER_NAMES);
85371570a2aSLawrence Tang 
85471570a2aSLawrence Tang 	//Flush to stream.
85571570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
85671570a2aSLawrence Tang 	fflush(out);
85771570a2aSLawrence Tang }
85871570a2aSLawrence Tang 
85971570a2aSLawrence Tang //Converts a single AARCH64 EL3 register set CPER-JSON object to CPER binary, outputting to the given stream.
86071570a2aSLawrence Tang void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out)
86171570a2aSLawrence Tang {
86271570a2aSLawrence Tang 	//Get uniform register array.
86371570a2aSLawrence Tang 	EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS reg_array;
86471570a2aSLawrence Tang 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
865e407b4c8SLawrence Tang 			       sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
866e407b4c8SLawrence Tang 				       sizeof(UINT64),
867e407b4c8SLawrence Tang 			       ARM_AARCH64_EL3_REGISTER_NAMES);
86871570a2aSLawrence Tang 
86971570a2aSLawrence Tang 	//Flush to stream.
87071570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
87171570a2aSLawrence Tang 	fflush(out);
87271570a2aSLawrence Tang }
87371570a2aSLawrence Tang 
87471570a2aSLawrence Tang //Converts a single ARM miscellaneous register set CPER-JSON object to CPER binary, outputting to the given stream.
87571570a2aSLawrence Tang void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out)
87671570a2aSLawrence Tang {
87771570a2aSLawrence Tang 	EFI_ARM_MISC_CONTEXT_REGISTER reg_array;
87871570a2aSLawrence Tang 
87971570a2aSLawrence Tang 	//MRS encoding information.
880e407b4c8SLawrence Tang 	json_object *mrs_encoding =
881e407b4c8SLawrence Tang 		json_object_object_get(registers, "mrsEncoding");
882e407b4c8SLawrence Tang 	reg_array.MrsOp2 = json_object_get_uint64(
883e407b4c8SLawrence Tang 		json_object_object_get(mrs_encoding, "op2"));
884e407b4c8SLawrence Tang 	reg_array.MrsCrm = json_object_get_uint64(
885e407b4c8SLawrence Tang 		json_object_object_get(mrs_encoding, "crm"));
886e407b4c8SLawrence Tang 	reg_array.MrsCrn = json_object_get_uint64(
887e407b4c8SLawrence Tang 		json_object_object_get(mrs_encoding, "crn"));
888e407b4c8SLawrence Tang 	reg_array.MrsOp1 = json_object_get_uint64(
889e407b4c8SLawrence Tang 		json_object_object_get(mrs_encoding, "op1"));
890e407b4c8SLawrence Tang 	reg_array.MrsO0 = json_object_get_uint64(
891e407b4c8SLawrence Tang 		json_object_object_get(mrs_encoding, "o0"));
89271570a2aSLawrence Tang 
89371570a2aSLawrence Tang 	//Actual register value.
894e407b4c8SLawrence Tang 	reg_array.Value = json_object_get_uint64(
895e407b4c8SLawrence Tang 		json_object_object_get(registers, "value"));
89671570a2aSLawrence Tang 
89771570a2aSLawrence Tang 	//Flush to stream.
89871570a2aSLawrence Tang 	fwrite(&reg_array, sizeof(reg_array), 1, out);
89971570a2aSLawrence Tang 	fflush(out);
90071570a2aSLawrence Tang }
90171570a2aSLawrence Tang 
90271570a2aSLawrence Tang //Converts a single ARM unknown register CPER-JSON object to CPER binary, outputting to the given stream.
903*f8fc7052SJohn Chung void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out)
90471570a2aSLawrence Tang {
90571570a2aSLawrence Tang 	//Get base64 represented data.
90671570a2aSLawrence Tang 	json_object *encoded = json_object_object_get(registers, "data");
907*f8fc7052SJohn Chung 	char *decoded = malloc(json_object_get_string_len(encoded));
908*f8fc7052SJohn Chung 	size_t decoded_len = 0;
909*f8fc7052SJohn Chung 	if (!decoded) {
910*f8fc7052SJohn Chung 		printf("Failed to allocate decode output buffer. \n");
911*f8fc7052SJohn Chung 	} else {
912*f8fc7052SJohn Chung 		base64_decode(json_object_get_string(encoded),
913*f8fc7052SJohn Chung 			      json_object_get_string_len(encoded), decoded,
914*f8fc7052SJohn Chung 			      &decoded_len, 0);
91571570a2aSLawrence Tang 
91671570a2aSLawrence Tang 		//Flush out to stream.
917*f8fc7052SJohn Chung 		fwrite(&decoded, decoded_len, 1, out);
91871570a2aSLawrence Tang 		fflush(out);
91971570a2aSLawrence Tang 		free(decoded);
9207cd13908SLawrence Tang 	}
921*f8fc7052SJohn Chung }
922