xref: /openbmc/libcper/sections/cper-section-arm.c (revision d6b62637dc5203821c87aeb0145fb8c7f9d607c7)
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 <string.h>
10 #include <json.h>
11 #include <libcper/base64.h>
12 #include <libcper/Cper.h>
13 #include <libcper/cper-utils.h>
14 #include <libcper/sections/cper-section-arm.h>
15 #include <libcper/log.h>
16 
17 //Private pre-definitions.
18 json_object *
19 cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info);
20 json_object *
21 cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
22 				 const UINT8 **cur_pos, UINT32 *remaining_size);
23 json_object *
24 cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
25 			       EFI_ARM_ERROR_INFORMATION_ENTRY *error_info);
26 json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error);
27 json_object *cper_arm_misc_register_array_to_ir(
28 	EFI_ARM_MISC_CONTEXT_REGISTER *misc_register);
29 void ir_arm_error_info_to_cper(json_object *error_info, FILE *out);
30 void ir_arm_context_info_to_cper(json_object *context_info, FILE *out);
31 void ir_arm_error_cache_tlb_info_to_cper(
32 	json_object *error_information,
33 	EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper);
34 void ir_arm_error_bus_info_to_cper(json_object *error_information,
35 				   EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper);
36 void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out);
37 void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out);
38 void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out);
39 void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out);
40 void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out);
41 void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out);
42 void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out);
43 void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out);
44 void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out);
45 void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out);
46 
47 //Converts the given processor-generic CPER section into JSON IR.
cper_section_arm_to_ir(const UINT8 * section,UINT32 size)48 json_object *cper_section_arm_to_ir(const UINT8 *section, UINT32 size)
49 {
50 	const UINT8 *cur_pos = section;
51 	UINT32 remaining_size = size;
52 
53 	if (remaining_size < sizeof(EFI_ARM_ERROR_RECORD)) {
54 		return NULL;
55 	}
56 	EFI_ARM_ERROR_RECORD *record = (EFI_ARM_ERROR_RECORD *)cur_pos;
57 	cur_pos += sizeof(EFI_ARM_ERROR_RECORD);
58 	remaining_size -= sizeof(EFI_ARM_ERROR_RECORD);
59 	json_object *section_ir = json_object_new_object();
60 
61 	//Length of ValidationBits from spec
62 	ValidationTypes ui64Type = { UINT_64T,
63 				     .value.ui64 = record->ValidFields };
64 
65 	//Number of error info and context info structures, and length.
66 	json_object_object_add(section_ir, "errorInfoNum",
67 			       json_object_new_int(record->ErrInfoNum));
68 	json_object_object_add(section_ir, "contextInfoNum",
69 			       json_object_new_int(record->ContextInfoNum));
70 	json_object_object_add(section_ir, "sectionLength",
71 			       json_object_new_uint64(record->SectionLength));
72 
73 	//Error affinity.
74 	if (isvalid_prop_to_ir(&ui64Type, 1)) {
75 		json_object *error_affinity = json_object_new_object();
76 		json_object_object_add(
77 			error_affinity, "value",
78 			json_object_new_int(record->ErrorAffinityLevel));
79 		json_object_object_add(
80 			error_affinity, "type",
81 			json_object_new_string(record->ErrorAffinityLevel < 4 ?
82 						       "Vendor Defined" :
83 						       "Reserved"));
84 		json_object_object_add(section_ir, "errorAffinity",
85 				       error_affinity);
86 	}
87 
88 	//Processor ID (MPIDR_EL1) and chip ID (MIDR_EL1).
89 	if (isvalid_prop_to_ir(&ui64Type, 0)) {
90 		uint64_t mpidr_eli1 = record->MPIDR_EL1;
91 		uint64_t sock;
92 		json_object_object_add(section_ir, "mpidrEl1",
93 				       json_object_new_uint64(mpidr_eli1));
94 
95 		//Arm Processor socket info dependes on mpidr_eli1
96 		sock = (mpidr_eli1 & ARM_SOCK_MASK) >> 32;
97 		json_object_object_add(section_ir, "affinity3",
98 				       json_object_new_uint64(sock));
99 	}
100 
101 	json_object_object_add(section_ir, "midrEl1",
102 			       json_object_new_uint64(record->MIDR_EL1));
103 
104 	if (isvalid_prop_to_ir(&ui64Type, 2)) {
105 		//Whether the processor is running, and the state of it if so.
106 		json_object_object_add(
107 			section_ir, "running",
108 			json_object_new_boolean(record->RunningState & 0x1));
109 	}
110 	if (!(record->RunningState >> 31)) {
111 		//Bit 32 of running state is on, so PSCI state information is included.
112 		//This can't be made human readable, as it is unknown whether this will be the pre-PSCI 1.0 format
113 		//or the newer Extended StateID format.
114 		json_object_object_add(
115 			section_ir, "psciState",
116 			json_object_new_uint64(record->PsciState));
117 	}
118 
119 	//Processor error structures.
120 	json_object *error_info_array = json_object_new_array();
121 	EFI_ARM_ERROR_INFORMATION_ENTRY *cur_error =
122 		(EFI_ARM_ERROR_INFORMATION_ENTRY *)(record + 1);
123 	if (remaining_size <
124 	    (record->ErrInfoNum * sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY))) {
125 		json_object_put(error_info_array);
126 		json_object_put(section_ir);
127 		cper_print_log(
128 			"Invalid CPER file: Invalid processor error info num.\n");
129 		return NULL;
130 	}
131 	for (int i = 0; i < record->ErrInfoNum; i++) {
132 		json_object_array_add(error_info_array,
133 				      cper_arm_error_info_to_ir(cur_error));
134 		cur_error++;
135 	}
136 
137 	cur_pos += (UINT32)(record->ErrInfoNum *
138 			    sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY));
139 	remaining_size -= (UINT32)(record->ErrInfoNum *
140 				   sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY));
141 
142 	json_object_object_add(section_ir, "errorInfo", error_info_array);
143 
144 	//Processor context structures.
145 	//The current position is moved within the processing, as it is a dynamic size structure.
146 	json_object *context_info_array = json_object_new_array();
147 	for (int i = 0; i < record->ContextInfoNum; i++) {
148 		if (remaining_size <
149 		    sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER)) {
150 			json_object_put(context_info_array);
151 			json_object_put(section_ir);
152 			cper_print_log(
153 				"Invalid CPER file: Invalid processor context info num.\n");
154 			return NULL;
155 		}
156 		EFI_ARM_CONTEXT_INFORMATION_HEADER *header =
157 			(EFI_ARM_CONTEXT_INFORMATION_HEADER *)cur_pos;
158 
159 		cur_pos += sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER);
160 		remaining_size -= sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER);
161 		json_object *processor_context =
162 			cper_arm_processor_context_to_ir(header, &cur_pos,
163 							 &remaining_size);
164 		if (processor_context == NULL) {
165 			json_object_put(context_info_array);
166 			json_object_put(section_ir);
167 			cper_print_log(
168 				"Invalid CPER file: Invalid processor context info num.\n");
169 			return NULL;
170 		}
171 		json_object_array_add(context_info_array, processor_context);
172 	}
173 	json_object_object_add(section_ir, "contextInfo", context_info_array);
174 
175 	//Is there any vendor-specific information following?
176 	if (isvalid_prop_to_ir(&ui64Type, 3)) {
177 		if (cur_pos < (uint8_t *)section + record->SectionLength) {
178 			json_object *vendor_specific = json_object_new_object();
179 			size_t input_size = (uint8_t *)section +
180 					    record->SectionLength - cur_pos;
181 			if (remaining_size < input_size) {
182 				json_object_put(vendor_specific);
183 				json_object_put(section_ir);
184 				cper_print_log(
185 					"Invalid CPER file: Invalid vendor-specific info length.\n");
186 				return NULL;
187 			}
188 			int32_t encoded_len = 0;
189 			char *encoded = base64_encode(cur_pos, input_size,
190 						      &encoded_len);
191 			if (encoded == NULL) {
192 				json_object_put(vendor_specific);
193 				json_object_put(section_ir);
194 				cper_print_log(
195 					"base64 encode of vendorSpecificInfo failed\n");
196 				return NULL;
197 			}
198 			json_object_object_add(vendor_specific, "data",
199 					       json_object_new_string_len(
200 						       encoded, encoded_len));
201 			free(encoded);
202 
203 			json_object_object_add(section_ir, "vendorSpecificInfo",
204 					       vendor_specific);
205 		} else {
206 			cper_print_log(
207 				"vendorSpecificInfo is marked valid but not present in binary\n");
208 		}
209 	}
210 
211 	return section_ir;
212 }
213 
214 //Converts a single ARM Process Error Information structure into JSON IR.
215 json_object *
cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY * error_info)216 cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info)
217 {
218 	json_object *error_info_ir = json_object_new_object();
219 
220 	//Version, length.
221 	json_object_object_add(error_info_ir, "version",
222 			       json_object_new_int(error_info->Version));
223 	json_object_object_add(error_info_ir, "length",
224 			       json_object_new_int(error_info->Length));
225 
226 	//Validation bitfield.
227 	ValidationTypes ui16Type = { UINT_16T,
228 				     .value.ui16 = error_info->ValidationBits };
229 
230 	//The type of error information in this log.
231 	json_object *error_type = integer_to_readable_pair(
232 		error_info->Type, 4, ARM_ERROR_INFO_ENTRY_INFO_TYPES_KEYS,
233 		ARM_ERROR_INFO_ENTRY_INFO_TYPES_VALUES, "Unknown (Reserved)");
234 	json_object_object_add(error_info_ir, "errorType", error_type);
235 
236 	//Multiple error count.
237 	if (isvalid_prop_to_ir(&ui16Type, 0)) {
238 		json_object *multiple_error = json_object_new_object();
239 		json_object_object_add(
240 			multiple_error, "value",
241 			json_object_new_int(error_info->MultipleError));
242 		json_object_object_add(
243 			multiple_error, "type",
244 			json_object_new_string(error_info->MultipleError < 1 ?
245 						       "Single Error" :
246 						       "Multiple Errors"));
247 		json_object_object_add(error_info_ir, "multipleError",
248 				       multiple_error);
249 	}
250 
251 	//Flags.
252 	if (isvalid_prop_to_ir(&ui16Type, 1)) {
253 		json_object *flags = bitfield_to_ir(
254 			error_info->Flags, 4, ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
255 		json_object_object_add(error_info_ir, "flags", flags);
256 	}
257 
258 	//Error information, split by type.
259 	if (isvalid_prop_to_ir(&ui16Type, 2)) {
260 		json_object *error_subinfo = NULL;
261 		switch (error_info->Type) {
262 		case ARM_ERROR_INFORMATION_TYPE_CACHE: //Cache
263 		case ARM_ERROR_INFORMATION_TYPE_TLB:   //TLB
264 			error_subinfo = cper_arm_cache_tlb_error_to_ir(
265 				(EFI_ARM_CACHE_ERROR_STRUCTURE *)&error_info
266 					->ErrorInformation,
267 				error_info);
268 			break;
269 		case ARM_ERROR_INFORMATION_TYPE_BUS: //Bus
270 			error_subinfo = cper_arm_bus_error_to_ir(
271 				(EFI_ARM_BUS_ERROR_STRUCTURE *)&error_info
272 					->ErrorInformation);
273 			break;
274 
275 		default:
276 			//Unknown/microarch, will not support.
277 			break;
278 		}
279 		if (error_subinfo != NULL) {
280 			json_object_object_add(error_info_ir,
281 					       "errorInformation",
282 					       error_subinfo);
283 		}
284 	}
285 
286 	//Virtual fault address, physical fault address.
287 	if (isvalid_prop_to_ir(&ui16Type, 3)) {
288 		json_object_object_add(
289 			error_info_ir, "virtualFaultAddress",
290 			json_object_new_uint64(
291 				error_info->VirtualFaultAddress));
292 	}
293 	if (isvalid_prop_to_ir(&ui16Type, 4)) {
294 		json_object_object_add(
295 			error_info_ir, "physicalFaultAddress",
296 			json_object_new_uint64(
297 				error_info->PhysicalFaultAddress));
298 	}
299 
300 	return error_info_ir;
301 }
302 
303 //Converts a single ARM cache/TLB error information structure into JSON IR format.
304 json_object *
cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE * cache_tlb_error,EFI_ARM_ERROR_INFORMATION_ENTRY * error_info)305 cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
306 			       EFI_ARM_ERROR_INFORMATION_ENTRY *error_info)
307 {
308 	json_object *cache_tlb_error_ir = json_object_new_object();
309 	json_object *cache_tlb_prop = json_object_new_object();
310 	char *cache_tlb_propname;
311 
312 	//Validation bitfield.
313 	ValidationTypes ui64Type = {
314 		UINT_64T, .value.ui64 = cache_tlb_error->ValidationBits
315 	};
316 
317 	//Transaction type.
318 	if (isvalid_prop_to_ir(&ui64Type, 0)) {
319 		json_object *transaction_type = integer_to_readable_pair(
320 			cache_tlb_error->TransactionType, 3,
321 			ARM_ERROR_TRANSACTION_TYPES_KEYS,
322 			ARM_ERROR_TRANSACTION_TYPES_VALUES,
323 			"Unknown (Reserved)");
324 		json_object_object_add(cache_tlb_error_ir, "transactionType",
325 				       transaction_type);
326 	}
327 
328 	//Operation.
329 	bool cacheErrorFlag = 1;
330 	if (error_info->Type == 0) {
331 		cache_tlb_propname = "cacheError";
332 	} else {
333 		//TLB operation.
334 		cache_tlb_propname = "tlbError";
335 		cacheErrorFlag = 0;
336 	}
337 
338 	if (isvalid_prop_to_ir(&ui64Type, 1)) {
339 		json_object *operation;
340 
341 		if (cacheErrorFlag) {
342 			//Cache operation.
343 			operation = integer_to_readable_pair(
344 				cache_tlb_error->Operation, 11,
345 				ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
346 				ARM_CACHE_BUS_OPERATION_TYPES_VALUES,
347 				"Unknown (Reserved)");
348 		} else {
349 			operation = integer_to_readable_pair(
350 				cache_tlb_error->Operation, 9,
351 				ARM_TLB_OPERATION_TYPES_KEYS,
352 				ARM_TLB_OPERATION_TYPES_VALUES,
353 				"Unknown (Reserved)");
354 		}
355 		json_object_object_add(cache_tlb_error_ir, "operation",
356 				       operation);
357 	}
358 
359 	//Miscellaneous remaining fields.
360 	if (isvalid_prop_to_ir(&ui64Type, 2)) {
361 		json_object_object_add(
362 			cache_tlb_error_ir, "level",
363 			json_object_new_int(cache_tlb_error->Level));
364 	}
365 	if (isvalid_prop_to_ir(&ui64Type, 3)) {
366 		json_object_object_add(
367 			cache_tlb_error_ir, "processorContextCorrupt",
368 			json_object_new_boolean(
369 				cache_tlb_error->ProcessorContextCorrupt));
370 	}
371 	if (isvalid_prop_to_ir(&ui64Type, 4)) {
372 		json_object_object_add(
373 			cache_tlb_error_ir, "corrected",
374 			json_object_new_boolean(cache_tlb_error->Corrected));
375 	}
376 	if (isvalid_prop_to_ir(&ui64Type, 5)) {
377 		json_object_object_add(
378 			cache_tlb_error_ir, "precisePC",
379 			json_object_new_boolean(cache_tlb_error->PrecisePC));
380 	}
381 	if (isvalid_prop_to_ir(&ui64Type, 6)) {
382 		json_object_object_add(cache_tlb_error_ir, "restartablePC",
383 				       json_object_new_boolean(
384 					       cache_tlb_error->RestartablePC));
385 	}
386 
387 	json_object_object_add(cache_tlb_prop, cache_tlb_propname,
388 			       cache_tlb_error_ir);
389 
390 	return cache_tlb_prop;
391 }
392 
393 //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)394 json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error)
395 {
396 	json_object *bus_error_ir = json_object_new_object();
397 	json_object *bus_prop = json_object_new_object();
398 	char *bus_propname = "busError";
399 
400 	//Validation bits.
401 	ValidationTypes ui64Type = { UINT_64T,
402 				     .value.ui64 = bus_error->ValidationBits };
403 
404 	//Transaction type.
405 	if (isvalid_prop_to_ir(&ui64Type, 0)) {
406 		json_object *transaction_type = integer_to_readable_pair(
407 			bus_error->TransactionType, 3,
408 			ARM_ERROR_TRANSACTION_TYPES_KEYS,
409 			ARM_ERROR_TRANSACTION_TYPES_VALUES,
410 			"Unknown (Reserved)");
411 		json_object_object_add(bus_error_ir, "transactionType",
412 				       transaction_type);
413 	}
414 
415 	//Operation.
416 	if (isvalid_prop_to_ir(&ui64Type, 1)) {
417 		json_object *operation = integer_to_readable_pair(
418 			bus_error->Operation, 7,
419 			ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
420 			ARM_CACHE_BUS_OPERATION_TYPES_VALUES,
421 			"Unknown (Reserved)");
422 		json_object_object_add(bus_error_ir, "operation", operation);
423 	}
424 
425 	if (isvalid_prop_to_ir(&ui64Type, 2)) {
426 		//Affinity level of bus error, + miscellaneous fields.
427 		json_object_object_add(bus_error_ir, "level",
428 				       json_object_new_int(bus_error->Level));
429 	}
430 	if (isvalid_prop_to_ir(&ui64Type, 3)) {
431 		json_object_object_add(
432 			bus_error_ir, "processorContextCorrupt",
433 			json_object_new_boolean(
434 				bus_error->ProcessorContextCorrupt));
435 	}
436 	if (isvalid_prop_to_ir(&ui64Type, 4)) {
437 		json_object_object_add(
438 			bus_error_ir, "corrected",
439 			json_object_new_boolean(bus_error->Corrected));
440 	}
441 	if (isvalid_prop_to_ir(&ui64Type, 5)) {
442 		json_object_object_add(
443 			bus_error_ir, "precisePC",
444 			json_object_new_boolean(bus_error->PrecisePC));
445 	}
446 	if (isvalid_prop_to_ir(&ui64Type, 6)) {
447 		json_object_object_add(
448 			bus_error_ir, "restartablePC",
449 			json_object_new_boolean(bus_error->RestartablePC));
450 	}
451 
452 	//Participation type.
453 	if (isvalid_prop_to_ir(&ui64Type, 7)) {
454 		json_object *participation_type = integer_to_readable_pair(
455 			bus_error->ParticipationType, 4,
456 			ARM_BUS_PARTICIPATION_TYPES_KEYS,
457 			ARM_BUS_PARTICIPATION_TYPES_VALUES, "Unknown");
458 		json_object_object_add(bus_error_ir, "participationType",
459 				       participation_type);
460 	}
461 	if (isvalid_prop_to_ir(&ui64Type, 8)) {
462 		json_object_object_add(
463 			bus_error_ir, "timedOut",
464 			json_object_new_boolean(bus_error->TimeOut));
465 	}
466 
467 	//Address space.
468 	if (isvalid_prop_to_ir(&ui64Type, 9)) {
469 		json_object *address_space = integer_to_readable_pair(
470 			bus_error->AddressSpace, 3,
471 			ARM_BUS_ADDRESS_SPACE_TYPES_KEYS,
472 			ARM_BUS_ADDRESS_SPACE_TYPES_VALUES, "Unknown");
473 		json_object_object_add(bus_error_ir, "addressSpace",
474 				       address_space);
475 	}
476 
477 	//Memory access attributes.
478 	//todo: find the specification of these in the ARM ARM
479 	if (isvalid_prop_to_ir(&ui64Type, 10)) {
480 		json_object_object_add(
481 			bus_error_ir, "memoryAttributes",
482 			json_object_new_int(
483 				bus_error->MemoryAddressAttributes));
484 	}
485 
486 	//Access Mode
487 	if (isvalid_prop_to_ir(&ui64Type, 8)) {
488 		json_object *access_mode = json_object_new_object();
489 		json_object_object_add(
490 			access_mode, "value",
491 			json_object_new_int(bus_error->AccessMode));
492 		json_object_object_add(
493 			access_mode, "name",
494 			json_object_new_string(bus_error->AccessMode == 0 ?
495 						       "Secure" :
496 						       "Normal"));
497 		json_object_object_add(bus_error_ir, "accessMode", access_mode);
498 	}
499 	json_object_object_add(bus_prop, bus_propname, bus_error_ir);
500 
501 	return bus_prop;
502 }
503 
504 //Converts a single ARM processor context block into JSON IR.
505 json_object *
cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER * header,const UINT8 ** cur_pos,UINT32 * remaining_size)506 cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
507 				 const UINT8 **cur_pos, UINT32 *remaining_size)
508 {
509 	if (header->RegisterArraySize > *remaining_size) {
510 		cper_print_log(
511 			"Invalid CPER file: Invalid processor context info num.\n");
512 		return NULL;
513 	}
514 
515 	json_object *context_ir = json_object_new_object();
516 
517 	//Version.
518 	json_object_object_add(context_ir, "version",
519 			       json_object_new_int(header->Version));
520 
521 	//Add the context type.
522 	json_object *context_type = integer_to_readable_pair(
523 		header->RegisterContextType,
524 		ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_COUNT,
525 		ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_KEYS,
526 		ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_VALUES,
527 		"Unknown (Reserved)");
528 	json_object_object_add(context_ir, "registerContextType", context_type);
529 
530 	//Register array size (bytes).
531 	json_object_object_add(
532 		context_ir, "registerArraySize",
533 		json_object_new_uint64(header->RegisterArraySize));
534 
535 	//The register array itself.
536 	json_object *register_array = NULL;
537 	switch (header->RegisterContextType) {
538 	case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
539 		if (*remaining_size < sizeof(EFI_ARM_V8_AARCH32_GPR)) {
540 			cper_print_log(
541 				"Invalid CPER file: Invalid processor context info num.\n");
542 			goto fail;
543 		}
544 		if (header->RegisterArraySize <
545 		    sizeof(EFI_ARM_V8_AARCH32_GPR)) {
546 			cper_print_log(
547 				"Invalid CPER file: Not enough bytes for aarch32 gpr\n");
548 			goto fail;
549 		}
550 		register_array = uniform_struct_to_ir(
551 			(UINT32 *)*cur_pos,
552 			sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
553 			ARM_AARCH32_GPR_NAMES);
554 		break;
555 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
556 		if (*remaining_size <
557 		    sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS)) {
558 			cper_print_log(
559 				"Invalid CPER file: Invalid processor context info num.\n");
560 			goto fail;
561 		}
562 		if (header->RegisterArraySize <
563 		    sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS)) {
564 			cper_print_log(
565 				"Invalid CPER file: Not enough bytes for aarch32 el1\n");
566 			goto fail;
567 		}
568 		register_array = uniform_struct_to_ir(
569 			(UINT32 *)*cur_pos,
570 			sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
571 				sizeof(UINT32),
572 			ARM_AARCH32_EL1_REGISTER_NAMES);
573 		break;
574 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
575 		if (*remaining_size <
576 		    sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS)) {
577 			cper_print_log(
578 				"Invalid CPER file: Invalid processor context info num.\n");
579 			goto fail;
580 		}
581 		if (header->RegisterArraySize <
582 		    sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS)) {
583 			cper_print_log(
584 				"Invalid CPER file: Not enough bytes for aarch32 el2\n");
585 			goto fail;
586 		}
587 		register_array = uniform_struct_to_ir(
588 			(UINT32 *)*cur_pos,
589 			sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
590 				sizeof(UINT32),
591 			ARM_AARCH32_EL2_REGISTER_NAMES);
592 
593 		break;
594 	case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
595 		if (*remaining_size <
596 		    sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS)) {
597 			json_object_put(context_ir);
598 			cper_print_log(
599 				"Invalid CPER file: Invalid processor context info num.\n");
600 			return NULL;
601 		}
602 		if (header->RegisterArraySize <
603 		    sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS)) {
604 			cper_print_log(
605 				"Invalid CPER file: Not enough bytes for aarch32 secure\n");
606 			goto fail;
607 		}
608 		register_array = uniform_struct_to_ir(
609 			(UINT32 *)*cur_pos,
610 			sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
611 				sizeof(UINT32),
612 			ARM_AARCH32_SECURE_REGISTER_NAMES);
613 		break;
614 	case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
615 		if (*remaining_size < sizeof(EFI_ARM_V8_AARCH64_GPR)) {
616 			cper_print_log(
617 				"Invalid CPER file: Invalid processor context info num.\n");
618 			goto fail;
619 		}
620 		if (header->RegisterArraySize <
621 		    sizeof(EFI_ARM_V8_AARCH64_GPR)) {
622 			cper_print_log(
623 				"Invalid CPER file: Not enough bytes for aarch64 gpr\n");
624 			goto fail;
625 		}
626 		register_array = uniform_struct64_to_ir(
627 			(UINT64 *)*cur_pos,
628 			sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
629 			ARM_AARCH64_GPR_NAMES);
630 		break;
631 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
632 		if (*remaining_size <
633 		    sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS)) {
634 			cper_print_log(
635 				"Invalid CPER file: Invalid processor context info num.\n");
636 			goto fail;
637 		}
638 		if (header->RegisterArraySize <
639 		    sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS)) {
640 			cper_print_log(
641 				"Invalid CPER file: Not enough bytes for aarch64 el1\n");
642 			goto fail;
643 		}
644 		register_array = uniform_struct64_to_ir(
645 			(UINT64 *)*cur_pos,
646 			sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
647 				sizeof(UINT64),
648 			ARM_AARCH64_EL1_REGISTER_NAMES);
649 		break;
650 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
651 		if (*remaining_size <
652 		    sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS)) {
653 			cper_print_log(
654 				"Invalid CPER file: Invalid processor context info num.\n");
655 			goto fail;
656 		}
657 		if (header->RegisterArraySize <
658 		    sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS)) {
659 			cper_print_log(
660 				"Invalid CPER file: Not enough bytes for aarch64 el2\n");
661 			goto fail;
662 		}
663 		register_array = uniform_struct64_to_ir(
664 			(UINT64 *)*cur_pos,
665 			sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
666 				sizeof(UINT64),
667 			ARM_AARCH64_EL2_REGISTER_NAMES);
668 		break;
669 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
670 		if (*remaining_size <
671 		    sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS)) {
672 			cper_print_log(
673 				"Invalid CPER file: Invalid processor context info num.\n");
674 			goto fail;
675 		}
676 		if (header->RegisterArraySize <
677 		    sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS)) {
678 			cper_print_log(
679 				"Invalid CPER file: Not enough bytes for aarch64 el3\n");
680 			goto fail;
681 		}
682 		register_array = uniform_struct64_to_ir(
683 			(UINT64 *)*cur_pos,
684 			sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
685 				sizeof(UINT64),
686 			ARM_AARCH64_EL3_REGISTER_NAMES);
687 		break;
688 	case EFI_ARM_CONTEXT_TYPE_MISC:
689 		if (*remaining_size < sizeof(EFI_ARM_MISC_CONTEXT_REGISTER)) {
690 			cper_print_log(
691 				"Invalid CPER file: Invalid processor context info num.\n");
692 			goto fail;
693 		}
694 		if (header->RegisterArraySize <
695 		    sizeof(EFI_ARM_MISC_CONTEXT_REGISTER)) {
696 			cper_print_log(
697 				"Invalid CPER file: Not enough bytes for misc\n");
698 			goto fail;
699 		}
700 		register_array = cper_arm_misc_register_array_to_ir(
701 			(EFI_ARM_MISC_CONTEXT_REGISTER *)*cur_pos);
702 		break;
703 	default:
704 		if (*remaining_size < header->RegisterArraySize) {
705 			cper_print_log(
706 				"Invalid CPER file: Invalid processor context info num.\n");
707 			goto fail;
708 		}
709 		//Unknown register array type, add as base64 data instead.
710 		int32_t encoded_len = 0;
711 		char *encoded = base64_encode((UINT8 *)*cur_pos,
712 					      header->RegisterArraySize,
713 					      &encoded_len);
714 		if (encoded == NULL) {
715 			goto fail;
716 		}
717 		register_array = json_object_new_object();
718 		json_object_object_add(register_array, "data",
719 				       json_object_new_string_len(encoded,
720 								  encoded_len));
721 		free(encoded);
722 
723 		break;
724 	}
725 	json_object_object_add(context_ir, "registerArray", register_array);
726 
727 	//Set the current position to after the processor context structure.
728 	*cur_pos = (UINT8 *)(*cur_pos) + header->RegisterArraySize;
729 	*remaining_size -= header->RegisterArraySize;
730 
731 	return context_ir;
732 
733 fail:
734 	json_object_put(context_ir);
735 	return NULL;
736 }
737 
738 //Converts a single CPER ARM miscellaneous register array to JSON IR format.
739 json_object *
cper_arm_misc_register_array_to_ir(EFI_ARM_MISC_CONTEXT_REGISTER * misc_register)740 cper_arm_misc_register_array_to_ir(EFI_ARM_MISC_CONTEXT_REGISTER *misc_register)
741 {
742 	json_object *register_array = json_object_new_object();
743 	json_object *mrs_encoding = json_object_new_object();
744 	json_object_object_add(mrs_encoding, "op2",
745 			       json_object_new_uint64(misc_register->MrsOp2));
746 	json_object_object_add(mrs_encoding, "crm",
747 			       json_object_new_uint64(misc_register->MrsCrm));
748 	json_object_object_add(mrs_encoding, "crn",
749 			       json_object_new_uint64(misc_register->MrsCrn));
750 	json_object_object_add(mrs_encoding, "op1",
751 			       json_object_new_uint64(misc_register->MrsOp1));
752 	json_object_object_add(mrs_encoding, "o0",
753 			       json_object_new_uint64(misc_register->MrsO0));
754 	json_object_object_add(register_array, "mrsEncoding", mrs_encoding);
755 	json_object_object_add(register_array, "value",
756 			       json_object_new_uint64(misc_register->Value));
757 
758 	return register_array;
759 }
760 
761 //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)762 void ir_section_arm_to_cper(json_object *section, FILE *out)
763 {
764 	EFI_ARM_ERROR_RECORD section_cper;
765 	memset(&section_cper, 0, sizeof(section_cper));
766 
767 	//Validation bits.
768 	struct json_object *obj = NULL;
769 	ValidationTypes u32Type = { UINT_32T, .value.ui32 = 0 };
770 
771 	//Count of error/context info structures.
772 	section_cper.ErrInfoNum = json_object_get_int(
773 		json_object_object_get(section, "errorInfoNum"));
774 	section_cper.ContextInfoNum = json_object_get_int(
775 		json_object_object_get(section, "contextInfoNum"));
776 
777 	//Miscellaneous raw value fields.
778 	section_cper.SectionLength = json_object_get_uint64(
779 		json_object_object_get(section, "sectionLength"));
780 	if (json_object_object_get_ex(section, "mpidrEl1", &obj)) {
781 		section_cper.MPIDR_EL1 = json_object_get_uint64(obj);
782 		add_to_valid_bitfield(&u32Type, 0);
783 	}
784 	if (json_object_object_get_ex(section, "errorAffinity", &obj)) {
785 		section_cper.ErrorAffinityLevel = readable_pair_to_integer(obj);
786 		add_to_valid_bitfield(&u32Type, 1);
787 	}
788 	section_cper.MIDR_EL1 = json_object_get_uint64(
789 		json_object_object_get(section, "midrEl1"));
790 	if (json_object_object_get_ex(section, "running", &obj)) {
791 		section_cper.RunningState = json_object_get_boolean(obj);
792 		add_to_valid_bitfield(&u32Type, 2);
793 	}
794 
795 	//Optional PSCI state.
796 	json_object *psci_state = json_object_object_get(section, "psciState");
797 	if (psci_state != NULL) {
798 		section_cper.PsciState = json_object_get_uint64(psci_state);
799 	}
800 
801 	//Validationbits for EFI_ARM_ERROR_RECORD should also consider vendorSpecificInfo
802 	bool vendorSpecificPresent =
803 		json_object_object_get_ex(section, "vendorSpecificInfo", &obj);
804 	json_object *vendor_specific_info = obj;
805 	if (vendorSpecificPresent) {
806 		add_to_valid_bitfield(&u32Type, 3);
807 	}
808 
809 	section_cper.ValidFields = u32Type.value.ui32;
810 
811 	//Flush header to stream.
812 	fwrite(&section_cper, sizeof(section_cper), 1, out);
813 
814 	//Error info structure array.
815 
816 	json_object *error_info = json_object_object_get(section, "errorInfo");
817 	for (int i = 0; i < section_cper.ErrInfoNum; i++) {
818 		ir_arm_error_info_to_cper(
819 			json_object_array_get_idx(error_info, i), out);
820 	}
821 
822 	//Context info structure array.
823 	json_object *context_info =
824 		json_object_object_get(section, "contextInfo");
825 	for (int i = 0; i < section_cper.ContextInfoNum; i++) {
826 		ir_arm_context_info_to_cper(
827 			json_object_array_get_idx(context_info, i), out);
828 	}
829 
830 	//Vendor specific error info.
831 	if (vendorSpecificPresent) {
832 		json_object *vendor_info_string =
833 			json_object_object_get(vendor_specific_info, "data");
834 		int vendor_specific_len =
835 			json_object_get_string_len(vendor_info_string);
836 
837 		int32_t decoded_len = 0;
838 
839 		UINT8 *decoded = base64_decode(
840 			json_object_get_string(vendor_info_string),
841 			vendor_specific_len, &decoded_len);
842 
843 		//Write out to file.
844 		fwrite(decoded, decoded_len, 1, out);
845 		free(decoded);
846 	}
847 
848 	fflush(out);
849 }
850 
851 //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)852 void ir_arm_error_info_to_cper(json_object *error_info, FILE *out)
853 {
854 	EFI_ARM_ERROR_INFORMATION_ENTRY error_info_cper;
855 	memset(&error_info_cper, 0, sizeof(error_info_cper));
856 	struct json_object *obj = NULL;
857 	ValidationTypes ui16Type = { UINT_16T, .value.ui16 = 0 };
858 
859 	//Version, length.
860 	error_info_cper.Version = json_object_get_int(
861 		json_object_object_get(error_info, "version"));
862 	error_info_cper.Length = json_object_get_int(
863 		json_object_object_get(error_info, "length"));
864 
865 	//Type, multiple error.
866 	error_info_cper.Type = (UINT8)readable_pair_to_integer(
867 		json_object_object_get(error_info, "errorType"));
868 
869 	if (json_object_object_get_ex(error_info, "multipleError", &obj)) {
870 		error_info_cper.MultipleError =
871 			(UINT16)readable_pair_to_integer(obj);
872 		add_to_valid_bitfield(&ui16Type, 0);
873 	} else {
874 		error_info_cper.MultipleError = 0;
875 	}
876 
877 	//Flags object.
878 	if (json_object_object_get_ex(error_info, "flags", &obj)) {
879 		error_info_cper.Flags = (UINT8)ir_to_bitfield(
880 			obj, 4, ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
881 		add_to_valid_bitfield(&ui16Type, 1);
882 	} else {
883 		error_info_cper.Flags = 0;
884 	}
885 
886 	//Error information.
887 	if (json_object_object_get_ex(error_info, "errorInformation", &obj)) {
888 		json_object *error_info_information = obj;
889 		json_object *error_info_prop = NULL;
890 		switch (error_info_cper.Type) {
891 		case ARM_ERROR_INFORMATION_TYPE_CACHE:
892 			error_info_cper.ErrorInformation.Value = 0;
893 			error_info_prop = json_object_object_get(
894 				error_info_information, "cacheError");
895 			ir_arm_error_cache_tlb_info_to_cper(
896 				error_info_prop,
897 				&error_info_cper.ErrorInformation.CacheError);
898 			break;
899 		case ARM_ERROR_INFORMATION_TYPE_TLB:
900 			error_info_cper.ErrorInformation.Value = 0;
901 			error_info_prop = json_object_object_get(
902 				error_info_information, "tlbError");
903 			ir_arm_error_cache_tlb_info_to_cper(
904 				error_info_prop,
905 				&error_info_cper.ErrorInformation.CacheError);
906 			break;
907 
908 		case ARM_ERROR_INFORMATION_TYPE_BUS:
909 			error_info_cper.ErrorInformation.Value = 0;
910 			error_info_prop = json_object_object_get(
911 				error_info_information, "busError");
912 			ir_arm_error_bus_info_to_cper(
913 				error_info_prop,
914 				&error_info_cper.ErrorInformation.BusError);
915 			break;
916 
917 		default:
918 			//Unknown error information type.
919 			break;
920 		}
921 		add_to_valid_bitfield(&ui16Type, 2);
922 	}
923 
924 	//Virtual/physical fault address.
925 	if (json_object_object_get_ex(error_info, "virtualFaultAddress",
926 				      &obj)) {
927 		error_info_cper.VirtualFaultAddress =
928 			json_object_get_uint64(obj);
929 		add_to_valid_bitfield(&ui16Type, 3);
930 	} else {
931 		error_info_cper.VirtualFaultAddress = 0;
932 	}
933 
934 	if (json_object_object_get_ex(error_info, "physicalFaultAddress",
935 				      &obj)) {
936 		error_info_cper.PhysicalFaultAddress =
937 			json_object_get_uint64(obj);
938 		add_to_valid_bitfield(&ui16Type, 4);
939 	} else {
940 		error_info_cper.PhysicalFaultAddress = 0;
941 	}
942 	error_info_cper.ValidationBits = ui16Type.value.ui16;
943 
944 	//Write out to stream.
945 	fwrite(&error_info_cper, sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY), 1,
946 	       out);
947 }
948 
949 //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)950 void ir_arm_error_cache_tlb_info_to_cper(
951 	json_object *error_information,
952 	EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper)
953 {
954 	// //Validation bits.
955 	ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
956 	struct json_object *obj = NULL;
957 
958 	//Miscellaneous value fields.
959 	if (json_object_object_get_ex(error_information, "transactionType",
960 				      &obj)) {
961 		error_info_cper->TransactionType =
962 			readable_pair_to_integer(obj);
963 		add_to_valid_bitfield(&ui64Type, 0);
964 	}
965 	if (json_object_object_get_ex(error_information, "operation", &obj)) {
966 		error_info_cper->Operation = readable_pair_to_integer(obj);
967 		add_to_valid_bitfield(&ui64Type, 1);
968 	}
969 	if (json_object_object_get_ex(error_information, "level", &obj)) {
970 		error_info_cper->Level = json_object_get_uint64(obj);
971 		add_to_valid_bitfield(&ui64Type, 2);
972 	}
973 	if (json_object_object_get_ex(error_information,
974 				      "processorContextCorrupt", &obj)) {
975 		error_info_cper->ProcessorContextCorrupt =
976 			json_object_get_boolean(obj);
977 		add_to_valid_bitfield(&ui64Type, 3);
978 	}
979 	if (json_object_object_get_ex(error_information, "corrected", &obj)) {
980 		error_info_cper->Corrected = json_object_get_boolean(obj);
981 		add_to_valid_bitfield(&ui64Type, 4);
982 	}
983 	if (json_object_object_get_ex(error_information, "precisePC", &obj)) {
984 		error_info_cper->PrecisePC = json_object_get_boolean(obj);
985 		add_to_valid_bitfield(&ui64Type, 5);
986 	}
987 	if (json_object_object_get_ex(error_information, "restartablePC",
988 				      &obj)) {
989 		error_info_cper->RestartablePC = json_object_get_boolean(obj);
990 		add_to_valid_bitfield(&ui64Type, 6);
991 	}
992 	error_info_cper->Reserved = 0;
993 	error_info_cper->ValidationBits = ui64Type.value.ui64;
994 }
995 
996 //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)997 void ir_arm_error_bus_info_to_cper(json_object *error_information,
998 				   EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper)
999 {
1000 	//Validation bits.
1001 	ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
1002 	struct json_object *obj = NULL;
1003 
1004 	memset(error_info_cper, 0, sizeof(EFI_ARM_BUS_ERROR_STRUCTURE));
1005 
1006 	//Miscellaneous value fields.
1007 	if (json_object_object_get_ex(error_information, "transactionType",
1008 				      &obj)) {
1009 		error_info_cper->TransactionType =
1010 			readable_pair_to_integer(obj);
1011 		add_to_valid_bitfield(&ui64Type, 0);
1012 	} else {
1013 		error_info_cper->TransactionType = 0;
1014 	}
1015 	if (json_object_object_get_ex(error_information, "operation", &obj)) {
1016 		error_info_cper->Operation = readable_pair_to_integer(obj);
1017 		add_to_valid_bitfield(&ui64Type, 1);
1018 	} else {
1019 		error_info_cper->Operation = 0;
1020 	}
1021 	if (json_object_object_get_ex(error_information, "level", &obj)) {
1022 		error_info_cper->Level = json_object_get_uint64(obj);
1023 		add_to_valid_bitfield(&ui64Type, 2);
1024 	} else {
1025 		error_info_cper->Level = 0;
1026 	}
1027 	if (json_object_object_get_ex(error_information,
1028 				      "processorContextCorrupt", &obj)) {
1029 		error_info_cper->ProcessorContextCorrupt =
1030 			json_object_get_boolean(obj);
1031 		add_to_valid_bitfield(&ui64Type, 3);
1032 	} else {
1033 		error_info_cper->ProcessorContextCorrupt = 0;
1034 	}
1035 	if (json_object_object_get_ex(error_information, "corrected", &obj)) {
1036 		error_info_cper->Corrected = json_object_get_boolean(obj);
1037 		add_to_valid_bitfield(&ui64Type, 4);
1038 	} else {
1039 		error_info_cper->Corrected = 0;
1040 	}
1041 	if (json_object_object_get_ex(error_information, "precisePC", &obj)) {
1042 		error_info_cper->PrecisePC = json_object_get_boolean(obj);
1043 		add_to_valid_bitfield(&ui64Type, 5);
1044 	} else {
1045 		error_info_cper->PrecisePC = 0;
1046 	}
1047 	if (json_object_object_get_ex(error_information, "restartablePC",
1048 				      &obj)) {
1049 		error_info_cper->RestartablePC = json_object_get_boolean(obj);
1050 		add_to_valid_bitfield(&ui64Type, 6);
1051 	} else {
1052 		error_info_cper->RestartablePC = 0;
1053 	}
1054 	if (json_object_object_get_ex(error_information, "participationType",
1055 				      &obj)) {
1056 		error_info_cper->ParticipationType =
1057 			readable_pair_to_integer(obj);
1058 		add_to_valid_bitfield(&ui64Type, 7);
1059 	} else {
1060 		error_info_cper->ParticipationType = 0;
1061 	}
1062 	if (json_object_object_get_ex(error_information, "timedOut", &obj)) {
1063 		error_info_cper->TimeOut = json_object_get_boolean(obj);
1064 		add_to_valid_bitfield(&ui64Type, 8);
1065 	} else {
1066 		error_info_cper->TimeOut = 0;
1067 	}
1068 	if (json_object_object_get_ex(error_information, "addressSpace",
1069 				      &obj)) {
1070 		error_info_cper->AddressSpace = readable_pair_to_integer(obj);
1071 		add_to_valid_bitfield(&ui64Type, 9);
1072 	} else {
1073 		error_info_cper->AddressSpace = 0;
1074 	}
1075 	if (json_object_object_get_ex(error_information, "accessMode", &obj)) {
1076 		error_info_cper->AccessMode = readable_pair_to_integer(obj);
1077 		add_to_valid_bitfield(&ui64Type, 11);
1078 	} else {
1079 		error_info_cper->AccessMode = 0;
1080 	}
1081 	if (json_object_object_get_ex(error_information, "memoryAttributes",
1082 				      &obj)) {
1083 		error_info_cper->MemoryAddressAttributes =
1084 			json_object_get_uint64(obj);
1085 		add_to_valid_bitfield(&ui64Type, 10);
1086 	} else {
1087 		error_info_cper->MemoryAddressAttributes = 0;
1088 	}
1089 	error_info_cper->Reserved = 0;
1090 	error_info_cper->ValidationBits = ui64Type.value.ui64;
1091 }
1092 
1093 //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)1094 void ir_arm_context_info_to_cper(json_object *context_info, FILE *out)
1095 {
1096 	EFI_ARM_CONTEXT_INFORMATION_HEADER info_header;
1097 
1098 	//Version, array size, context type.
1099 	info_header.Version = json_object_get_int(
1100 		json_object_object_get(context_info, "version"));
1101 	info_header.RegisterArraySize = json_object_get_int(
1102 		json_object_object_get(context_info, "registerArraySize"));
1103 	info_header.RegisterContextType = readable_pair_to_integer(
1104 		json_object_object_get(context_info, "registerContextType"));
1105 
1106 	//Flush to stream, write the register array itself.
1107 	fwrite(&info_header, sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER), 1,
1108 	       out);
1109 	fflush(out);
1110 
1111 	json_object *register_array =
1112 		json_object_object_get(context_info, "registerArray");
1113 	switch (info_header.RegisterContextType) {
1114 	case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
1115 		ir_arm_aarch32_gpr_to_cper(register_array, out);
1116 		break;
1117 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
1118 		ir_arm_aarch32_el1_to_cper(register_array, out);
1119 		break;
1120 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
1121 		ir_arm_aarch32_el2_to_cper(register_array, out);
1122 		break;
1123 	case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
1124 		ir_arm_aarch32_secure_to_cper(register_array, out);
1125 		break;
1126 	case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
1127 		ir_arm_aarch64_gpr_to_cper(register_array, out);
1128 		break;
1129 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
1130 		ir_arm_aarch64_el1_to_cper(register_array, out);
1131 		break;
1132 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
1133 		ir_arm_aarch64_el2_to_cper(register_array, out);
1134 		break;
1135 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
1136 		ir_arm_aarch64_el3_to_cper(register_array, out);
1137 		break;
1138 	case EFI_ARM_CONTEXT_TYPE_MISC:
1139 		ir_arm_misc_registers_to_cper(register_array, out);
1140 		break;
1141 	default:
1142 		//Unknown register structure.
1143 		ir_arm_unknown_register_to_cper(register_array, out);
1144 		break;
1145 	}
1146 }
1147 
1148 //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)1149 void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out)
1150 {
1151 	//Get uniform register array.
1152 	EFI_ARM_V8_AARCH32_GPR reg_array;
1153 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1154 			     sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
1155 			     ARM_AARCH32_GPR_NAMES);
1156 
1157 	//Flush to stream.
1158 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1159 	fflush(out);
1160 }
1161 
1162 //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)1163 void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out)
1164 {
1165 	//Get uniform register array.
1166 	EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS reg_array;
1167 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1168 			     sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
1169 				     sizeof(UINT32),
1170 			     ARM_AARCH32_EL1_REGISTER_NAMES);
1171 
1172 	//Flush to stream.
1173 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1174 	fflush(out);
1175 }
1176 
1177 //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)1178 void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out)
1179 {
1180 	//Get uniform register array.
1181 	EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS reg_array;
1182 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1183 			     sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
1184 				     sizeof(UINT32),
1185 			     ARM_AARCH32_EL2_REGISTER_NAMES);
1186 
1187 	//Flush to stream.
1188 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1189 	fflush(out);
1190 }
1191 
1192 //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)1193 void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out)
1194 {
1195 	//Get uniform register array.
1196 	EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS reg_array;
1197 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1198 			     sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
1199 				     sizeof(UINT32),
1200 			     ARM_AARCH32_SECURE_REGISTER_NAMES);
1201 
1202 	//Flush to stream.
1203 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1204 	fflush(out);
1205 }
1206 
1207 //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)1208 void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out)
1209 {
1210 	//Get uniform register array.
1211 	EFI_ARM_V8_AARCH64_GPR reg_array;
1212 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1213 			       sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
1214 			       ARM_AARCH64_GPR_NAMES);
1215 
1216 	//Flush to stream.
1217 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1218 	fflush(out);
1219 }
1220 
1221 //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)1222 void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out)
1223 {
1224 	//Get uniform register array.
1225 	EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS reg_array;
1226 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1227 			       sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
1228 				       sizeof(UINT64),
1229 			       ARM_AARCH64_EL1_REGISTER_NAMES);
1230 
1231 	//Flush to stream.
1232 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1233 	fflush(out);
1234 }
1235 
1236 //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)1237 void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out)
1238 {
1239 	//Get uniform register array.
1240 	EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS reg_array;
1241 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1242 			       sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
1243 				       sizeof(UINT64),
1244 			       ARM_AARCH64_EL2_REGISTER_NAMES);
1245 
1246 	//Flush to stream.
1247 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1248 	fflush(out);
1249 }
1250 
1251 //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)1252 void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out)
1253 {
1254 	//Get uniform register array.
1255 	EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS reg_array;
1256 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1257 			       sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
1258 				       sizeof(UINT64),
1259 			       ARM_AARCH64_EL3_REGISTER_NAMES);
1260 
1261 	//Flush to stream.
1262 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1263 	fflush(out);
1264 }
1265 
1266 //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)1267 void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out)
1268 {
1269 	EFI_ARM_MISC_CONTEXT_REGISTER reg_array;
1270 
1271 	//MRS encoding information.
1272 	json_object *mrs_encoding =
1273 		json_object_object_get(registers, "mrsEncoding");
1274 	reg_array.MrsOp2 = json_object_get_uint64(
1275 		json_object_object_get(mrs_encoding, "op2"));
1276 	reg_array.MrsCrm = json_object_get_uint64(
1277 		json_object_object_get(mrs_encoding, "crm"));
1278 	reg_array.MrsCrn = json_object_get_uint64(
1279 		json_object_object_get(mrs_encoding, "crn"));
1280 	reg_array.MrsOp1 = json_object_get_uint64(
1281 		json_object_object_get(mrs_encoding, "op1"));
1282 	reg_array.MrsO0 = json_object_get_uint64(
1283 		json_object_object_get(mrs_encoding, "o0"));
1284 
1285 	//Actual register value.
1286 	reg_array.Value = json_object_get_uint64(
1287 		json_object_object_get(registers, "value"));
1288 
1289 	//Flush to stream.
1290 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1291 	fflush(out);
1292 }
1293 
1294 //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)1295 void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out)
1296 {
1297 	//Get base64 represented data.
1298 	json_object *encoded = json_object_object_get(registers, "data");
1299 
1300 	int32_t decoded_len = 0;
1301 
1302 	UINT8 *decoded = base64_decode(json_object_get_string(encoded),
1303 				       json_object_get_string_len(encoded),
1304 				       &decoded_len);
1305 
1306 	if (decoded == NULL) {
1307 		cper_print_log("Failed to allocate decode output buffer. \n");
1308 	} else {
1309 		//Flush out to stream.
1310 		fwrite(&decoded, decoded_len, 1, out);
1311 		fflush(out);
1312 		free(decoded);
1313 	}
1314 }
1315