xref: /openbmc/libcper/sections/cper-section-arm.c (revision 043d5f4b4f95d9f2a4f8182850ed0e6f2b076b15)
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 == ARM_ERROR_INFORMATION_TYPE_CACHE) {
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
1051 	if (json_object_object_get_ex(error_info, "errorType", &obj)) {
1052 		error_info_cper.Type = readable_pair_to_integer(obj);
1053 	} else {
1054 		error_info_cper.Type = 0;
1055 	}
1056 
1057 	//multiple error.
1058 	if (json_object_object_get_ex(error_info, "multipleError", &obj)) {
1059 		error_info_cper.MultipleError =
1060 			(UINT16)readable_pair_to_integer(obj);
1061 		add_to_valid_bitfield(&ui16Type, 0);
1062 	} else {
1063 		error_info_cper.MultipleError = 0;
1064 	}
1065 
1066 	//Flags object.
1067 	if (json_object_object_get_ex(error_info, "flags", &obj)) {
1068 		error_info_cper.Flags = (UINT8)ir_to_bitfield(
1069 			obj, 4, ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
1070 		add_to_valid_bitfield(&ui16Type, 1);
1071 	} else {
1072 		error_info_cper.Flags = 0;
1073 	}
1074 
1075 	//Error information.
1076 	if (json_object_object_get_ex(error_info, "errorInformation", &obj)) {
1077 		json_object *error_info_information = obj;
1078 		json_object *error_info_prop = NULL;
1079 		switch (error_info_cper.Type) {
1080 		case ARM_ERROR_INFORMATION_TYPE_CACHE:
1081 			error_info_cper.ErrorInformation.Value = 0;
1082 			error_info_prop = json_object_object_get(
1083 				error_info_information, "cacheError");
1084 			ir_arm_error_cache_tlb_info_to_cper(
1085 				error_info_prop,
1086 				&error_info_cper.ErrorInformation.CacheError);
1087 			break;
1088 		case ARM_ERROR_INFORMATION_TYPE_TLB:
1089 			error_info_cper.ErrorInformation.Value = 0;
1090 			error_info_prop = json_object_object_get(
1091 				error_info_information, "tlbError");
1092 			ir_arm_error_cache_tlb_info_to_cper(
1093 				error_info_prop,
1094 				&error_info_cper.ErrorInformation.CacheError);
1095 			break;
1096 
1097 		case ARM_ERROR_INFORMATION_TYPE_BUS:
1098 			error_info_cper.ErrorInformation.Value = 0;
1099 			error_info_prop = json_object_object_get(
1100 				error_info_information, "busError");
1101 			ir_arm_error_bus_info_to_cper(
1102 				error_info_prop,
1103 				&error_info_cper.ErrorInformation.BusError);
1104 			break;
1105 
1106 		default:
1107 			//Unknown error information type.
1108 			break;
1109 		}
1110 		add_to_valid_bitfield(&ui16Type, 2);
1111 	}
1112 
1113 	//Virtual/physical fault address.
1114 	if (json_object_object_get_ex(error_info, "virtualFaultAddress",
1115 				      &obj)) {
1116 		error_info_cper.VirtualFaultAddress =
1117 			json_object_get_uint64(obj);
1118 		add_to_valid_bitfield(&ui16Type, 3);
1119 	} else {
1120 		error_info_cper.VirtualFaultAddress = 0;
1121 	}
1122 
1123 	if (json_object_object_get_ex(error_info, "physicalFaultAddress",
1124 				      &obj)) {
1125 		error_info_cper.PhysicalFaultAddress =
1126 			json_object_get_uint64(obj);
1127 		add_to_valid_bitfield(&ui16Type, 4);
1128 	} else {
1129 		error_info_cper.PhysicalFaultAddress = 0;
1130 	}
1131 	error_info_cper.ValidationBits = ui16Type.value.ui16;
1132 
1133 	//Write out to stream.
1134 	fwrite(&error_info_cper, sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY), 1,
1135 	       out);
1136 }
1137 
1138 //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)1139 void ir_arm_error_cache_tlb_info_to_cper(
1140 	json_object *error_information,
1141 	EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper)
1142 {
1143 	// //Validation bits.
1144 	ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
1145 	struct json_object *obj = NULL;
1146 
1147 	//Miscellaneous value fields.
1148 	if (json_object_object_get_ex(error_information, "transactionType",
1149 				      &obj)) {
1150 		error_info_cper->TransactionType =
1151 			readable_pair_to_integer(obj);
1152 		add_to_valid_bitfield(&ui64Type, 0);
1153 	}
1154 	if (json_object_object_get_ex(error_information, "operation", &obj)) {
1155 		error_info_cper->Operation = readable_pair_to_integer(obj);
1156 		add_to_valid_bitfield(&ui64Type, 1);
1157 	}
1158 	if (json_object_object_get_ex(error_information, "level", &obj)) {
1159 		error_info_cper->Level = json_object_get_uint64(obj);
1160 		add_to_valid_bitfield(&ui64Type, 2);
1161 	}
1162 	if (json_object_object_get_ex(error_information,
1163 				      "processorContextCorrupt", &obj)) {
1164 		error_info_cper->ProcessorContextCorrupt =
1165 			json_object_get_boolean(obj);
1166 		add_to_valid_bitfield(&ui64Type, 3);
1167 	}
1168 	if (json_object_object_get_ex(error_information, "corrected", &obj)) {
1169 		error_info_cper->Corrected = json_object_get_boolean(obj);
1170 		add_to_valid_bitfield(&ui64Type, 4);
1171 	}
1172 	if (json_object_object_get_ex(error_information, "precisePC", &obj)) {
1173 		error_info_cper->PrecisePC = json_object_get_boolean(obj);
1174 		add_to_valid_bitfield(&ui64Type, 5);
1175 	}
1176 	if (json_object_object_get_ex(error_information, "restartablePC",
1177 				      &obj)) {
1178 		error_info_cper->RestartablePC = json_object_get_boolean(obj);
1179 		add_to_valid_bitfield(&ui64Type, 6);
1180 	}
1181 	error_info_cper->Reserved = 0;
1182 	error_info_cper->ValidationBits = ui64Type.value.ui64;
1183 }
1184 
1185 //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)1186 void ir_arm_error_bus_info_to_cper(json_object *error_information,
1187 				   EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper)
1188 {
1189 	//Validation bits.
1190 	ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
1191 	struct json_object *obj = NULL;
1192 
1193 	//Miscellaneous value fields.
1194 	if (json_object_object_get_ex(error_information, "transactionType",
1195 				      &obj)) {
1196 		error_info_cper->TransactionType =
1197 			readable_pair_to_integer(obj);
1198 		add_to_valid_bitfield(&ui64Type, 0);
1199 	} else {
1200 		error_info_cper->TransactionType = 0;
1201 	}
1202 	if (json_object_object_get_ex(error_information, "operation", &obj)) {
1203 		error_info_cper->Operation = readable_pair_to_integer(obj);
1204 		add_to_valid_bitfield(&ui64Type, 1);
1205 	} else {
1206 		error_info_cper->Operation = 0;
1207 	}
1208 	if (json_object_object_get_ex(error_information, "level", &obj)) {
1209 		error_info_cper->Level = json_object_get_uint64(obj);
1210 		add_to_valid_bitfield(&ui64Type, 2);
1211 	} else {
1212 		error_info_cper->Level = 0;
1213 	}
1214 	if (json_object_object_get_ex(error_information,
1215 				      "processorContextCorrupt", &obj)) {
1216 		error_info_cper->ProcessorContextCorrupt =
1217 			json_object_get_boolean(obj);
1218 		add_to_valid_bitfield(&ui64Type, 3);
1219 	} else {
1220 		error_info_cper->ProcessorContextCorrupt = 0;
1221 	}
1222 	if (json_object_object_get_ex(error_information, "corrected", &obj)) {
1223 		error_info_cper->Corrected = json_object_get_boolean(obj);
1224 		add_to_valid_bitfield(&ui64Type, 4);
1225 	} else {
1226 		error_info_cper->Corrected = 0;
1227 	}
1228 	if (json_object_object_get_ex(error_information, "precisePC", &obj)) {
1229 		error_info_cper->PrecisePC = json_object_get_boolean(obj);
1230 		add_to_valid_bitfield(&ui64Type, 5);
1231 	} else {
1232 		error_info_cper->PrecisePC = 0;
1233 	}
1234 	if (json_object_object_get_ex(error_information, "restartablePC",
1235 				      &obj)) {
1236 		error_info_cper->RestartablePC = json_object_get_boolean(obj);
1237 		add_to_valid_bitfield(&ui64Type, 6);
1238 	} else {
1239 		error_info_cper->RestartablePC = 0;
1240 	}
1241 	if (json_object_object_get_ex(error_information, "participationType",
1242 				      &obj)) {
1243 		error_info_cper->ParticipationType =
1244 			readable_pair_to_integer(obj);
1245 		add_to_valid_bitfield(&ui64Type, 7);
1246 	} else {
1247 		error_info_cper->ParticipationType = 0;
1248 	}
1249 	if (json_object_object_get_ex(error_information, "timedOut", &obj)) {
1250 		error_info_cper->TimeOut = json_object_get_boolean(obj);
1251 		add_to_valid_bitfield(&ui64Type, 8);
1252 	} else {
1253 		error_info_cper->TimeOut = 0;
1254 	}
1255 	if (json_object_object_get_ex(error_information, "addressSpace",
1256 				      &obj)) {
1257 		error_info_cper->AddressSpace = readable_pair_to_integer(obj);
1258 		add_to_valid_bitfield(&ui64Type, 9);
1259 	} else {
1260 		error_info_cper->AddressSpace = 0;
1261 	}
1262 	if (json_object_object_get_ex(error_information, "accessMode", &obj)) {
1263 		error_info_cper->AccessMode = readable_pair_to_integer(obj);
1264 		add_to_valid_bitfield(&ui64Type, 11);
1265 	} else {
1266 		error_info_cper->AccessMode = 0;
1267 	}
1268 	if (json_object_object_get_ex(error_information, "memoryAttributes",
1269 				      &obj)) {
1270 		error_info_cper->MemoryAddressAttributes =
1271 			json_object_get_uint64(obj);
1272 		add_to_valid_bitfield(&ui64Type, 10);
1273 	} else {
1274 		error_info_cper->MemoryAddressAttributes = 0;
1275 	}
1276 	error_info_cper->Reserved = 0;
1277 	error_info_cper->ValidationBits = ui64Type.value.ui64;
1278 }
1279 
1280 //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)1281 void ir_arm_context_info_to_cper(json_object *context_info, FILE *out)
1282 {
1283 	EFI_ARM_CONTEXT_INFORMATION_HEADER info_header;
1284 
1285 	//Version, array size, context type.
1286 	info_header.Version = json_object_get_int(
1287 		json_object_object_get(context_info, "version"));
1288 	info_header.RegisterArraySize = json_object_get_int(
1289 		json_object_object_get(context_info, "registerArraySize"));
1290 	info_header.RegisterContextType = readable_pair_to_integer(
1291 		json_object_object_get(context_info, "registerContextType"));
1292 
1293 	//Flush to stream, write the register array itself.
1294 	fwrite(&info_header, sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER), 1,
1295 	       out);
1296 	fflush(out);
1297 
1298 	json_object *register_array =
1299 		json_object_object_get(context_info, "registerArray");
1300 	switch (info_header.RegisterContextType) {
1301 	case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
1302 		ir_arm_aarch32_gpr_to_cper(register_array, out);
1303 		break;
1304 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
1305 		ir_arm_aarch32_el1_to_cper(register_array, out);
1306 		break;
1307 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
1308 		ir_arm_aarch32_el2_to_cper(register_array, out);
1309 		break;
1310 	case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
1311 		ir_arm_aarch32_secure_to_cper(register_array, out);
1312 		break;
1313 	case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
1314 		ir_arm_aarch64_gpr_to_cper(register_array, out);
1315 		break;
1316 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
1317 		ir_arm_aarch64_el1_to_cper(register_array, out);
1318 		break;
1319 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
1320 		ir_arm_aarch64_el2_to_cper(register_array, out);
1321 		break;
1322 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
1323 		ir_arm_aarch64_el3_to_cper(register_array, out);
1324 		break;
1325 	case EFI_ARM_CONTEXT_TYPE_MISC:
1326 		ir_arm_misc_registers_to_cper(register_array, out);
1327 		break;
1328 	default:
1329 		//Unknown register structure.
1330 		ir_arm_unknown_register_to_cper(register_array, out);
1331 		break;
1332 	}
1333 }
1334 
1335 //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)1336 void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out)
1337 {
1338 	//Get uniform register array.
1339 	EFI_ARM_V8_AARCH32_GPR reg_array;
1340 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1341 			     sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
1342 			     ARM_AARCH32_GPR_NAMES);
1343 
1344 	//Flush to stream.
1345 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1346 	fflush(out);
1347 }
1348 
1349 //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)1350 void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out)
1351 {
1352 	//Get uniform register array.
1353 	EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS reg_array;
1354 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1355 			     sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
1356 				     sizeof(UINT32),
1357 			     ARM_AARCH32_EL1_REGISTER_NAMES);
1358 
1359 	//Flush to stream.
1360 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1361 	fflush(out);
1362 }
1363 
1364 //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)1365 void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out)
1366 {
1367 	//Get uniform register array.
1368 	EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS reg_array;
1369 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1370 			     sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
1371 				     sizeof(UINT32),
1372 			     ARM_AARCH32_EL2_REGISTER_NAMES);
1373 
1374 	//Flush to stream.
1375 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1376 	fflush(out);
1377 }
1378 
1379 //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)1380 void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out)
1381 {
1382 	//Get uniform register array.
1383 	EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS reg_array;
1384 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1385 			     sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
1386 				     sizeof(UINT32),
1387 			     ARM_AARCH32_SECURE_REGISTER_NAMES);
1388 
1389 	//Flush to stream.
1390 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1391 	fflush(out);
1392 }
1393 
1394 //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)1395 void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out)
1396 {
1397 	//Get uniform register array.
1398 	EFI_ARM_V8_AARCH64_GPR reg_array;
1399 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1400 			       sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
1401 			       ARM_AARCH64_GPR_NAMES);
1402 
1403 	//Flush to stream.
1404 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1405 	fflush(out);
1406 }
1407 
1408 //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)1409 void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out)
1410 {
1411 	//Get uniform register array.
1412 	EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS reg_array;
1413 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1414 			       sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
1415 				       sizeof(UINT64),
1416 			       ARM_AARCH64_EL1_REGISTER_NAMES);
1417 
1418 	//Flush to stream.
1419 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1420 	fflush(out);
1421 }
1422 
1423 //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)1424 void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out)
1425 {
1426 	//Get uniform register array.
1427 	EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS reg_array;
1428 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1429 			       sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
1430 				       sizeof(UINT64),
1431 			       ARM_AARCH64_EL2_REGISTER_NAMES);
1432 
1433 	//Flush to stream.
1434 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1435 	fflush(out);
1436 }
1437 
1438 //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)1439 void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out)
1440 {
1441 	//Get uniform register array.
1442 	EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS reg_array;
1443 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1444 			       sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
1445 				       sizeof(UINT64),
1446 			       ARM_AARCH64_EL3_REGISTER_NAMES);
1447 
1448 	//Flush to stream.
1449 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1450 	fflush(out);
1451 }
1452 
1453 //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)1454 void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out)
1455 {
1456 	EFI_ARM_MISC_CONTEXT_REGISTER reg_array;
1457 
1458 	//MRS encoding information.
1459 	json_object *mrs_encoding =
1460 		json_object_object_get(registers, "mrsEncoding");
1461 	reg_array.MrsOp2 = json_object_get_uint64(
1462 		json_object_object_get(mrs_encoding, "op2"));
1463 	reg_array.MrsCrm = json_object_get_uint64(
1464 		json_object_object_get(mrs_encoding, "crm"));
1465 	reg_array.MrsCrn = json_object_get_uint64(
1466 		json_object_object_get(mrs_encoding, "crn"));
1467 	reg_array.MrsOp1 = json_object_get_uint64(
1468 		json_object_object_get(mrs_encoding, "op1"));
1469 	reg_array.MrsO0 = json_object_get_uint64(
1470 		json_object_object_get(mrs_encoding, "o0"));
1471 
1472 	//Actual register value.
1473 	reg_array.Value = json_object_get_uint64(
1474 		json_object_object_get(registers, "value"));
1475 
1476 	//Flush to stream.
1477 	fwrite(&reg_array, sizeof(reg_array), 1, out);
1478 	fflush(out);
1479 }
1480 
1481 //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)1482 void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out)
1483 {
1484 	//Get base64 represented data.
1485 	json_object *encoded = json_object_object_get(registers, "data");
1486 
1487 	int32_t decoded_len = 0;
1488 
1489 	UINT8 *decoded = base64_decode(json_object_get_string(encoded),
1490 				       json_object_get_string_len(encoded),
1491 				       &decoded_len);
1492 
1493 	if (decoded == NULL) {
1494 		cper_print_log("Failed to allocate decode output buffer. \n");
1495 	} else {
1496 		//Flush out to stream.
1497 		fwrite(&decoded, decoded_len, 1, out);
1498 		fflush(out);
1499 		free(decoded);
1500 	}
1501 }
1502