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