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 "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, will not support.
200 		break;
201 	}
202 	json_object_object_add(error_info_ir, "errorInformation",
203 			       error_subinfo);
204 
205 	//Virtual fault address, physical fault address.
206 	json_object_object_add(
207 		error_info_ir, "virtualFaultAddress",
208 		json_object_new_uint64(error_info->VirtualFaultAddress));
209 	json_object_object_add(
210 		error_info_ir, "physicalFaultAddress",
211 		json_object_new_uint64(error_info->PhysicalFaultAddress));
212 
213 	return error_info_ir;
214 }
215 
216 //Converts a single ARM cache/TLB error information structure into JSON IR format.
217 json_object *
cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE * cache_tlb_error,EFI_ARM_ERROR_INFORMATION_ENTRY * error_info)218 cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
219 			       EFI_ARM_ERROR_INFORMATION_ENTRY *error_info)
220 {
221 	json_object *cache_tlb_error_ir = json_object_new_object();
222 	json_object *cache_tlb_prop = json_object_new_object();
223 	char *cache_tlb_propname;
224 
225 	//Validation bitfield.
226 	json_object *validation =
227 		bitfield_to_ir(cache_tlb_error->ValidationBits, 7,
228 			       ARM_CACHE_TLB_ERROR_VALID_BITFIELD_NAMES);
229 	json_object_object_add(cache_tlb_error_ir, "validationBits",
230 			       validation);
231 
232 	//Transaction type.
233 	json_object *transaction_type = integer_to_readable_pair(
234 		cache_tlb_error->TransactionType, 3,
235 		ARM_ERROR_TRANSACTION_TYPES_KEYS,
236 		ARM_ERROR_TRANSACTION_TYPES_VALUES, "Unknown (Reserved)");
237 	json_object_object_add(cache_tlb_error_ir, "transactionType",
238 			       transaction_type);
239 
240 	//Operation.
241 	json_object *operation;
242 	if (error_info->Type == 0) {
243 		//Cache operation.
244 		operation = integer_to_readable_pair(
245 			cache_tlb_error->Operation, 11,
246 			ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
247 			ARM_CACHE_BUS_OPERATION_TYPES_VALUES,
248 			"Unknown (Reserved)");
249 		cache_tlb_propname = "cacheError";
250 	} else {
251 		//TLB operation.
252 		operation = integer_to_readable_pair(
253 			cache_tlb_error->Operation, 9,
254 			ARM_TLB_OPERATION_TYPES_KEYS,
255 			ARM_TLB_OPERATION_TYPES_VALUES, "Unknown (Reserved)");
256 		cache_tlb_propname = "tlbError";
257 	}
258 	json_object_object_add(cache_tlb_error_ir, "operation", operation);
259 
260 	//Miscellaneous remaining fields.
261 	json_object_object_add(cache_tlb_error_ir, "level",
262 			       json_object_new_int(cache_tlb_error->Level));
263 	json_object_object_add(
264 		cache_tlb_error_ir, "processorContextCorrupt",
265 		json_object_new_boolean(
266 			cache_tlb_error->ProcessorContextCorrupt));
267 	json_object_object_add(
268 		cache_tlb_error_ir, "corrected",
269 		json_object_new_boolean(cache_tlb_error->Corrected));
270 	json_object_object_add(
271 		cache_tlb_error_ir, "precisePC",
272 		json_object_new_boolean(cache_tlb_error->PrecisePC));
273 	json_object_object_add(
274 		cache_tlb_error_ir, "restartablePC",
275 		json_object_new_boolean(cache_tlb_error->RestartablePC));
276 
277 	json_object_object_add(cache_tlb_prop, cache_tlb_propname,
278 			       cache_tlb_error_ir);
279 	return cache_tlb_prop;
280 }
281 
282 //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)283 json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error)
284 {
285 	json_object *bus_error_ir = json_object_new_object();
286 
287 	//Validation bits.
288 	json_object *validation =
289 		bitfield_to_ir(bus_error->ValidationBits, 12,
290 			       ARM_BUS_ERROR_VALID_BITFIELD_NAMES);
291 	json_object_object_add(bus_error_ir, "validationBits", validation);
292 
293 	//Transaction type.
294 	json_object *transaction_type = integer_to_readable_pair(
295 		bus_error->TransactionType, 3, ARM_ERROR_TRANSACTION_TYPES_KEYS,
296 		ARM_ERROR_TRANSACTION_TYPES_VALUES, "Unknown (Reserved)");
297 	json_object_object_add(bus_error_ir, "transactionType",
298 			       transaction_type);
299 
300 	//Operation.
301 	json_object *operation = integer_to_readable_pair(
302 		bus_error->Operation, 7, ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
303 		ARM_CACHE_BUS_OPERATION_TYPES_VALUES, "Unknown (Reserved)");
304 	json_object_object_add(bus_error_ir, "operation", operation);
305 
306 	//Affinity level of bus error, + miscellaneous fields.
307 	json_object_object_add(bus_error_ir, "level",
308 			       json_object_new_int(bus_error->Level));
309 	json_object_object_add(
310 		bus_error_ir, "processorContextCorrupt",
311 		json_object_new_boolean(bus_error->ProcessorContextCorrupt));
312 	json_object_object_add(bus_error_ir, "corrected",
313 			       json_object_new_boolean(bus_error->Corrected));
314 	json_object_object_add(bus_error_ir, "precisePC",
315 			       json_object_new_boolean(bus_error->PrecisePC));
316 	json_object_object_add(
317 		bus_error_ir, "restartablePC",
318 		json_object_new_boolean(bus_error->RestartablePC));
319 	json_object_object_add(bus_error_ir, "timedOut",
320 			       json_object_new_boolean(bus_error->TimeOut));
321 
322 	//Participation type.
323 	json_object *participation_type = integer_to_readable_pair(
324 		bus_error->ParticipationType, 4,
325 		ARM_BUS_PARTICIPATION_TYPES_KEYS,
326 		ARM_BUS_PARTICIPATION_TYPES_VALUES, "Unknown");
327 	json_object_object_add(bus_error_ir, "participationType",
328 			       participation_type);
329 
330 	//Address space.
331 	json_object *address_space = integer_to_readable_pair(
332 		bus_error->AddressSpace, 3, ARM_BUS_ADDRESS_SPACE_TYPES_KEYS,
333 		ARM_BUS_ADDRESS_SPACE_TYPES_VALUES, "Unknown");
334 	json_object_object_add(bus_error_ir, "addressSpace", address_space);
335 
336 	//Memory access attributes.
337 	//todo: find the specification of these in the ARM ARM
338 	json_object_object_add(
339 		bus_error_ir, "memoryAttributes",
340 		json_object_new_int(bus_error->MemoryAddressAttributes));
341 
342 	//Access Mode
343 	json_object *access_mode = json_object_new_object();
344 	json_object_object_add(access_mode, "value",
345 			       json_object_new_int(bus_error->AccessMode));
346 	json_object_object_add(
347 		access_mode, "name",
348 		json_object_new_string(bus_error->AccessMode == 0 ? "Secure" :
349 								    "Normal"));
350 	json_object_object_add(bus_error_ir, "accessMode", access_mode);
351 
352 	return bus_error_ir;
353 }
354 
355 //Converts a single ARM processor context block into JSON IR.
356 json_object *
cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER * header,void ** cur_pos)357 cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
358 				 void **cur_pos)
359 {
360 	json_object *context_ir = json_object_new_object();
361 
362 	//Version.
363 	json_object_object_add(context_ir, "version",
364 			       json_object_new_int(header->Version));
365 
366 	//Add the context type.
367 	json_object *context_type = integer_to_readable_pair(
368 		header->RegisterContextType, 9,
369 		ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_KEYS,
370 		ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_VALUES,
371 		"Unknown (Reserved)");
372 	json_object_object_add(context_ir, "registerContextType", context_type);
373 
374 	//Register array size (bytes).
375 	json_object_object_add(
376 		context_ir, "registerArraySize",
377 		json_object_new_uint64(header->RegisterArraySize));
378 
379 	//The register array itself.
380 	*cur_pos = (void *)(header + 1);
381 	json_object *register_array = NULL;
382 	switch (header->RegisterContextType) {
383 	case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
384 		register_array = uniform_struct_to_ir(
385 			(UINT32 *)cur_pos,
386 			sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
387 			ARM_AARCH32_GPR_NAMES);
388 		break;
389 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
390 		register_array = uniform_struct_to_ir(
391 			(UINT32 *)cur_pos,
392 			sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
393 				sizeof(UINT32),
394 			ARM_AARCH32_EL1_REGISTER_NAMES);
395 		break;
396 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
397 		register_array = uniform_struct_to_ir(
398 			(UINT32 *)cur_pos,
399 			sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
400 				sizeof(UINT32),
401 			ARM_AARCH32_EL2_REGISTER_NAMES);
402 		break;
403 	case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
404 		register_array = uniform_struct_to_ir(
405 			(UINT32 *)cur_pos,
406 			sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
407 				sizeof(UINT32),
408 			ARM_AARCH32_SECURE_REGISTER_NAMES);
409 		break;
410 	case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
411 		register_array = uniform_struct64_to_ir(
412 			(UINT64 *)cur_pos,
413 			sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
414 			ARM_AARCH64_GPR_NAMES);
415 		break;
416 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
417 		register_array = uniform_struct64_to_ir(
418 			(UINT64 *)cur_pos,
419 			sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
420 				sizeof(UINT64),
421 			ARM_AARCH64_EL1_REGISTER_NAMES);
422 		break;
423 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
424 		register_array = uniform_struct64_to_ir(
425 			(UINT64 *)cur_pos,
426 			sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
427 				sizeof(UINT64),
428 			ARM_AARCH64_EL2_REGISTER_NAMES);
429 		break;
430 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
431 		register_array = uniform_struct64_to_ir(
432 			(UINT64 *)cur_pos,
433 			sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
434 				sizeof(UINT64),
435 			ARM_AARCH64_EL3_REGISTER_NAMES);
436 		break;
437 	case EFI_ARM_CONTEXT_TYPE_MISC:
438 		register_array = cper_arm_misc_register_array_to_ir(
439 			(EFI_ARM_MISC_CONTEXT_REGISTER *)cur_pos);
440 		break;
441 	default:
442 		//Unknown register array type, add as base64 data instead.
443 		register_array = json_object_new_object();
444 		int32_t encoded_len = 0;
445 		char *encoded = base64_encode((UINT8 *)cur_pos,
446 					      header->RegisterArraySize,
447 					      &encoded_len);
448 		if (encoded == NULL) {
449 			printf("Failed to allocate encode output buffer. \n");
450 			return NULL;
451 		}
452 		json_object_object_add(register_array, "data",
453 				       json_object_new_string_len(encoded,
454 								  encoded_len));
455 		free(encoded);
456 
457 		break;
458 	}
459 	json_object_object_add(context_ir, "registerArray", register_array);
460 
461 	//Set the current position to after the processor context structure.
462 	*cur_pos = (UINT8 *)(*cur_pos) + header->RegisterArraySize;
463 
464 	return context_ir;
465 }
466 
467 //Converts a single CPER ARM miscellaneous register array to JSON IR format.
468 json_object *
cper_arm_misc_register_array_to_ir(EFI_ARM_MISC_CONTEXT_REGISTER * misc_register)469 cper_arm_misc_register_array_to_ir(EFI_ARM_MISC_CONTEXT_REGISTER *misc_register)
470 {
471 	json_object *register_array = json_object_new_object();
472 	json_object *mrs_encoding = json_object_new_object();
473 	json_object_object_add(mrs_encoding, "op2",
474 			       json_object_new_uint64(misc_register->MrsOp2));
475 	json_object_object_add(mrs_encoding, "crm",
476 			       json_object_new_uint64(misc_register->MrsCrm));
477 	json_object_object_add(mrs_encoding, "crn",
478 			       json_object_new_uint64(misc_register->MrsCrn));
479 	json_object_object_add(mrs_encoding, "op1",
480 			       json_object_new_uint64(misc_register->MrsOp1));
481 	json_object_object_add(mrs_encoding, "o0",
482 			       json_object_new_uint64(misc_register->MrsO0));
483 	json_object_object_add(register_array, "mrsEncoding", mrs_encoding);
484 	json_object_object_add(register_array, "value",
485 			       json_object_new_uint64(misc_register->Value));
486 
487 	return register_array;
488 }
489 
490 //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)491 void ir_section_arm_to_cper(json_object *section, FILE *out)
492 {
493 	EFI_ARM_ERROR_RECORD *section_cper =
494 		(EFI_ARM_ERROR_RECORD *)calloc(1, sizeof(EFI_ARM_ERROR_RECORD));
495 
496 	//Validation bits.
497 	section_cper->ValidFields = ir_to_bitfield(
498 		json_object_object_get(section, "validationBits"), 4,
499 		ARM_ERROR_VALID_BITFIELD_NAMES);
500 
501 	//Count of error/context info structures.
502 	section_cper->ErrInfoNum = json_object_get_int(
503 		json_object_object_get(section, "errorInfoNum"));
504 	section_cper->ContextInfoNum = json_object_get_int(
505 		json_object_object_get(section, "contextInfoNum"));
506 
507 	//Miscellaneous raw value fields.
508 	section_cper->SectionLength = json_object_get_uint64(
509 		json_object_object_get(section, "sectionLength"));
510 	section_cper->ErrorAffinityLevel = readable_pair_to_integer(
511 		json_object_object_get(section, "errorAffinity"));
512 	section_cper->MPIDR_EL1 = json_object_get_uint64(
513 		json_object_object_get(section, "mpidrEl1"));
514 	section_cper->MIDR_EL1 = json_object_get_uint64(
515 		json_object_object_get(section, "midrEl1"));
516 	section_cper->RunningState = json_object_get_boolean(
517 		json_object_object_get(section, "running"));
518 
519 	//Optional PSCI state.
520 	json_object *psci_state = json_object_object_get(section, "psciState");
521 	if (psci_state != NULL) {
522 		section_cper->PsciState = json_object_get_uint64(psci_state);
523 	}
524 
525 	//Flush header to stream.
526 	fwrite(section_cper, sizeof(EFI_ARM_ERROR_RECORD), 1, out);
527 	fflush(out);
528 
529 	//Error info structure array.
530 	json_object *error_info = json_object_object_get(section, "errorInfo");
531 	for (int i = 0; i < section_cper->ErrInfoNum; i++) {
532 		ir_arm_error_info_to_cper(
533 			json_object_array_get_idx(error_info, i), out);
534 	}
535 
536 	//Context info structure array.
537 	json_object *context_info =
538 		json_object_object_get(section, "contextInfo");
539 	for (int i = 0; i < section_cper->ContextInfoNum; i++) {
540 		ir_arm_context_info_to_cper(
541 			json_object_array_get_idx(context_info, i), out);
542 	}
543 
544 	//Vendor specific error info.
545 	json_object *vendor_specific_info =
546 		json_object_object_get(section, "vendorSpecificInfo");
547 	if (vendor_specific_info != NULL) {
548 		json_object *vendor_info_string =
549 			json_object_object_get(vendor_specific_info, "data");
550 		int vendor_specific_len =
551 			json_object_get_string_len(vendor_info_string);
552 
553 		int32_t decoded_len = 0;
554 
555 		UINT8 *decoded = base64_decode(
556 			json_object_get_string(vendor_info_string),
557 			vendor_specific_len, &decoded_len);
558 
559 		//Write out to file.
560 		fwrite(decoded, decoded_len, 1, out);
561 		fflush(out);
562 		free(decoded);
563 	}
564 
565 	//Free remaining resources.
566 	free(section_cper);
567 }
568 
569 //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)570 void ir_arm_error_info_to_cper(json_object *error_info, FILE *out)
571 {
572 	EFI_ARM_ERROR_INFORMATION_ENTRY error_info_cper;
573 
574 	//Version, length.
575 	error_info_cper.Version = json_object_get_int(
576 		json_object_object_get(error_info, "version"));
577 	error_info_cper.Length = json_object_get_int(
578 		json_object_object_get(error_info, "length"));
579 
580 	//Validation bits.
581 	error_info_cper.ValidationBits = ir_to_bitfield(
582 		json_object_object_get(error_info, "validationBits"), 5,
583 		ARM_ERROR_INFO_ENTRY_VALID_BITFIELD_NAMES);
584 
585 	//Type, multiple error.
586 	error_info_cper.Type = (UINT8)readable_pair_to_integer(
587 		json_object_object_get(error_info, "type"));
588 	error_info_cper.MultipleError = (UINT16)readable_pair_to_integer(
589 		json_object_object_get(error_info, "multipleError"));
590 
591 	//Flags object.
592 	error_info_cper.Flags = (UINT8)ir_to_bitfield(
593 		json_object_object_get(error_info, "flags"), 4,
594 		ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
595 
596 	//Error information.
597 	json_object *error_info_information =
598 		json_object_object_get(error_info, "errorInformation");
599 	json_object *error_info_prop = NULL;
600 
601 	switch (error_info_cper.Type) {
602 	case ARM_ERROR_INFORMATION_TYPE_CACHE:
603 		error_info_prop = json_object_object_get(error_info_information,
604 							 "cacheError");
605 		ir_arm_error_cache_tlb_info_to_cper(
606 			error_info_prop,
607 			&error_info_cper.ErrorInformation.CacheError);
608 		break;
609 	case ARM_ERROR_INFORMATION_TYPE_TLB:
610 		error_info_prop = json_object_object_get(error_info_information,
611 							 "tlbError");
612 		ir_arm_error_cache_tlb_info_to_cper(
613 			error_info_prop,
614 			&error_info_cper.ErrorInformation.CacheError);
615 		break;
616 
617 	case ARM_ERROR_INFORMATION_TYPE_BUS:
618 		ir_arm_error_bus_info_to_cper(
619 			error_info_information,
620 			&error_info_cper.ErrorInformation.BusError);
621 		break;
622 
623 	default:
624 		//Unknown error information type.
625 		break;
626 	}
627 
628 	//Virtual/physical fault address.
629 	error_info_cper.VirtualFaultAddress = json_object_get_uint64(
630 		json_object_object_get(error_info, "virtualFaultAddress"));
631 	error_info_cper.PhysicalFaultAddress = json_object_get_uint64(
632 		json_object_object_get(error_info, "physicalFaultAddress"));
633 
634 	//Write out to stream.
635 	fwrite(&error_info_cper, sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY), 1,
636 	       out);
637 	fflush(out);
638 }
639 
640 //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)641 void ir_arm_error_cache_tlb_info_to_cper(
642 	json_object *error_information,
643 	EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper)
644 {
645 	//Validation bits.
646 	error_info_cper->ValidationBits = ir_to_bitfield(
647 		json_object_object_get(error_information, "validationBits"), 7,
648 		ARM_CACHE_TLB_ERROR_VALID_BITFIELD_NAMES);
649 
650 	//Miscellaneous value fields.
651 	error_info_cper->TransactionType = readable_pair_to_integer(
652 		json_object_object_get(error_information, "transactionType"));
653 	error_info_cper->Operation = readable_pair_to_integer(
654 		json_object_object_get(error_information, "operation"));
655 	error_info_cper->Level = json_object_get_uint64(
656 		json_object_object_get(error_information, "level"));
657 	error_info_cper->ProcessorContextCorrupt = json_object_get_boolean(
658 		json_object_object_get(error_information,
659 				       "processorContextCorrupt"));
660 	error_info_cper->Corrected = json_object_get_boolean(
661 		json_object_object_get(error_information, "corrected"));
662 	error_info_cper->PrecisePC = json_object_get_boolean(
663 		json_object_object_get(error_information, "precisePC"));
664 	error_info_cper->RestartablePC = json_object_get_boolean(
665 		json_object_object_get(error_information, "restartablePC"));
666 	error_info_cper->Reserved = 0;
667 }
668 
669 //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)670 void ir_arm_error_bus_info_to_cper(json_object *error_information,
671 				   EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper)
672 {
673 	//Validation bits.
674 	error_info_cper->ValidationBits = ir_to_bitfield(
675 		json_object_object_get(error_information, "validationBits"), 7,
676 		ARM_BUS_ERROR_VALID_BITFIELD_NAMES);
677 
678 	//Miscellaneous value fields.
679 	error_info_cper->TransactionType = readable_pair_to_integer(
680 		json_object_object_get(error_information, "transactionType"));
681 	error_info_cper->Operation = readable_pair_to_integer(
682 		json_object_object_get(error_information, "operation"));
683 	error_info_cper->Level = json_object_get_uint64(
684 		json_object_object_get(error_information, "level"));
685 	error_info_cper->ProcessorContextCorrupt = json_object_get_boolean(
686 		json_object_object_get(error_information,
687 				       "processorContextCorrupt"));
688 	error_info_cper->Corrected = json_object_get_boolean(
689 		json_object_object_get(error_information, "corrected"));
690 	error_info_cper->PrecisePC = json_object_get_boolean(
691 		json_object_object_get(error_information, "precisePC"));
692 	error_info_cper->RestartablePC = json_object_get_boolean(
693 		json_object_object_get(error_information, "restartablePC"));
694 	error_info_cper->ParticipationType = readable_pair_to_integer(
695 		json_object_object_get(error_information, "participationType"));
696 	error_info_cper->AddressSpace = readable_pair_to_integer(
697 		json_object_object_get(error_information, "addressSpace"));
698 	error_info_cper->AccessMode = readable_pair_to_integer(
699 		json_object_object_get(error_information, "accessMode"));
700 	error_info_cper->MemoryAddressAttributes = json_object_get_uint64(
701 		json_object_object_get(error_information, "memoryAttributes"));
702 	error_info_cper->Reserved = 0;
703 }
704 
705 //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)706 void ir_arm_context_info_to_cper(json_object *context_info, FILE *out)
707 {
708 	EFI_ARM_CONTEXT_INFORMATION_HEADER info_header;
709 
710 	//Version, array size, context type.
711 	info_header.Version = json_object_get_int(
712 		json_object_object_get(context_info, "version"));
713 	info_header.RegisterArraySize = json_object_get_int(
714 		json_object_object_get(context_info, "registerArraySize"));
715 	info_header.RegisterContextType = readable_pair_to_integer(
716 		json_object_object_get(context_info, "registerContextType"));
717 
718 	//Flush to stream, write the register array itself.
719 	fwrite(&info_header, sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER), 1,
720 	       out);
721 	fflush(out);
722 
723 	json_object *register_array =
724 		json_object_object_get(context_info, "registerArray");
725 	switch (info_header.RegisterContextType) {
726 	case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
727 		ir_arm_aarch32_gpr_to_cper(register_array, out);
728 		break;
729 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
730 		ir_arm_aarch32_el1_to_cper(register_array, out);
731 		break;
732 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
733 		ir_arm_aarch32_el2_to_cper(register_array, out);
734 		break;
735 	case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
736 		ir_arm_aarch32_secure_to_cper(register_array, out);
737 		break;
738 	case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
739 		ir_arm_aarch64_gpr_to_cper(register_array, out);
740 		break;
741 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
742 		ir_arm_aarch64_el1_to_cper(register_array, out);
743 		break;
744 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
745 		ir_arm_aarch64_el2_to_cper(register_array, out);
746 		break;
747 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
748 		ir_arm_aarch64_el3_to_cper(register_array, out);
749 		break;
750 	case EFI_ARM_CONTEXT_TYPE_MISC:
751 		ir_arm_misc_registers_to_cper(register_array, out);
752 		break;
753 	default:
754 		//Unknown register structure.
755 		ir_arm_unknown_register_to_cper(register_array, out);
756 		break;
757 	}
758 }
759 
760 //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)761 void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out)
762 {
763 	//Get uniform register array.
764 	EFI_ARM_V8_AARCH32_GPR reg_array;
765 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
766 			     sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
767 			     ARM_AARCH32_GPR_NAMES);
768 
769 	//Flush to stream.
770 	fwrite(&reg_array, sizeof(reg_array), 1, out);
771 	fflush(out);
772 }
773 
774 //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)775 void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out)
776 {
777 	//Get uniform register array.
778 	EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS reg_array;
779 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
780 			     sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
781 				     sizeof(UINT32),
782 			     ARM_AARCH32_EL1_REGISTER_NAMES);
783 
784 	//Flush to stream.
785 	fwrite(&reg_array, sizeof(reg_array), 1, out);
786 	fflush(out);
787 }
788 
789 //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)790 void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out)
791 {
792 	//Get uniform register array.
793 	EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS reg_array;
794 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
795 			     sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
796 				     sizeof(UINT32),
797 			     ARM_AARCH32_EL2_REGISTER_NAMES);
798 
799 	//Flush to stream.
800 	fwrite(&reg_array, sizeof(reg_array), 1, out);
801 	fflush(out);
802 }
803 
804 //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)805 void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out)
806 {
807 	//Get uniform register array.
808 	EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS reg_array;
809 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
810 			     sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
811 				     sizeof(UINT32),
812 			     ARM_AARCH32_SECURE_REGISTER_NAMES);
813 
814 	//Flush to stream.
815 	fwrite(&reg_array, sizeof(reg_array), 1, out);
816 	fflush(out);
817 }
818 
819 //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)820 void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out)
821 {
822 	//Get uniform register array.
823 	EFI_ARM_V8_AARCH64_GPR reg_array;
824 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
825 			       sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
826 			       ARM_AARCH64_GPR_NAMES);
827 
828 	//Flush to stream.
829 	fwrite(&reg_array, sizeof(reg_array), 1, out);
830 	fflush(out);
831 }
832 
833 //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)834 void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out)
835 {
836 	//Get uniform register array.
837 	EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS reg_array;
838 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
839 			       sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
840 				       sizeof(UINT64),
841 			       ARM_AARCH64_EL1_REGISTER_NAMES);
842 
843 	//Flush to stream.
844 	fwrite(&reg_array, sizeof(reg_array), 1, out);
845 	fflush(out);
846 }
847 
848 //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)849 void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out)
850 {
851 	//Get uniform register array.
852 	EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS reg_array;
853 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
854 			       sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
855 				       sizeof(UINT64),
856 			       ARM_AARCH64_EL2_REGISTER_NAMES);
857 
858 	//Flush to stream.
859 	fwrite(&reg_array, sizeof(reg_array), 1, out);
860 	fflush(out);
861 }
862 
863 //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)864 void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out)
865 {
866 	//Get uniform register array.
867 	EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS reg_array;
868 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
869 			       sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
870 				       sizeof(UINT64),
871 			       ARM_AARCH64_EL3_REGISTER_NAMES);
872 
873 	//Flush to stream.
874 	fwrite(&reg_array, sizeof(reg_array), 1, out);
875 	fflush(out);
876 }
877 
878 //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)879 void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out)
880 {
881 	EFI_ARM_MISC_CONTEXT_REGISTER reg_array;
882 
883 	//MRS encoding information.
884 	json_object *mrs_encoding =
885 		json_object_object_get(registers, "mrsEncoding");
886 	reg_array.MrsOp2 = json_object_get_uint64(
887 		json_object_object_get(mrs_encoding, "op2"));
888 	reg_array.MrsCrm = json_object_get_uint64(
889 		json_object_object_get(mrs_encoding, "crm"));
890 	reg_array.MrsCrn = json_object_get_uint64(
891 		json_object_object_get(mrs_encoding, "crn"));
892 	reg_array.MrsOp1 = json_object_get_uint64(
893 		json_object_object_get(mrs_encoding, "op1"));
894 	reg_array.MrsO0 = json_object_get_uint64(
895 		json_object_object_get(mrs_encoding, "o0"));
896 
897 	//Actual register value.
898 	reg_array.Value = json_object_get_uint64(
899 		json_object_object_get(registers, "value"));
900 
901 	//Flush to stream.
902 	fwrite(&reg_array, sizeof(reg_array), 1, out);
903 	fflush(out);
904 }
905 
906 //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)907 void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out)
908 {
909 	//Get base64 represented data.
910 	json_object *encoded = json_object_object_get(registers, "data");
911 
912 	int32_t decoded_len = 0;
913 
914 	UINT8 *decoded = base64_decode(json_object_get_string(encoded),
915 				       json_object_get_string_len(encoded),
916 				       &decoded_len);
917 
918 	if (decoded == NULL) {
919 		printf("Failed to allocate decode output buffer. \n");
920 	} else {
921 		//Flush out to stream.
922 		fwrite(&decoded, decoded_len, 1, out);
923 		fflush(out);
924 		free(decoded);
925 	}
926 }
927