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