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