xref: /openbmc/libcper/sections/cper-section-arm.c (revision 17bc66a05a9cdc36f9d05c95dca0effdcfe606db)
1 /**
2  * Describes functions for converting ARM CPER sections from binary and JSON format
3  * into an intermediate format.
4  *
5  * Author: Lawrence.Tang@arm.com
6  **/
7 
8 #include <stdio.h>
9 #include <json.h>
10 #include <libcper/base64.h>
11 #include <libcper/Cper.h>
12 #include <libcper/cper-utils.h>
13 #include <libcper/sections/cper-section-arm.h>
14 
15 //Private pre-definitions.
16 json_object *
17 cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info);
18 json_object *
19 cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
20 				 void **cur_pos);
21 json_object *
22 cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
23 			       EFI_ARM_ERROR_INFORMATION_ENTRY *error_info);
24 json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error);
25 json_object *cper_arm_misc_register_array_to_ir(
26 	EFI_ARM_MISC_CONTEXT_REGISTER *misc_register);
27 void ir_arm_error_info_to_cper(json_object *error_info, FILE *out);
28 void ir_arm_context_info_to_cper(json_object *context_info, FILE *out);
29 void ir_arm_error_cache_tlb_info_to_cper(
30 	json_object *error_information,
31 	EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper);
32 void ir_arm_error_bus_info_to_cper(json_object *error_information,
33 				   EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper);
34 void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out);
35 void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out);
36 void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out);
37 void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out);
38 void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out);
39 void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out);
40 void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out);
41 void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out);
42 void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out);
43 void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out);
44 
45 //Converts the given processor-generic CPER section into JSON IR.
cper_section_arm_to_ir(void * section)46 json_object *cper_section_arm_to_ir(void *section)
47 {
48 	EFI_ARM_ERROR_RECORD *record = (EFI_ARM_ERROR_RECORD *)section;
49 	json_object *section_ir = json_object_new_object();
50 
51 	//Validation bits.
52 	json_object *validation = bitfield_to_ir(
53 		record->ValidFields, 4, ARM_ERROR_VALID_BITFIELD_NAMES);
54 	json_object_object_add(section_ir, "validationBits", validation);
55 
56 	//Number of error info and context info structures, and length.
57 	json_object_object_add(section_ir, "errorInfoNum",
58 			       json_object_new_int(record->ErrInfoNum));
59 	json_object_object_add(section_ir, "contextInfoNum",
60 			       json_object_new_int(record->ContextInfoNum));
61 	json_object_object_add(section_ir, "sectionLength",
62 			       json_object_new_uint64(record->SectionLength));
63 
64 	//Error affinity.
65 	json_object *error_affinity = json_object_new_object();
66 	json_object_object_add(error_affinity, "value",
67 			       json_object_new_int(record->ErrorAffinityLevel));
68 	json_object_object_add(
69 		error_affinity, "type",
70 		json_object_new_string(record->ErrorAffinityLevel < 4 ?
71 					       "Vendor Defined" :
72 					       "Reserved"));
73 	json_object_object_add(section_ir, "errorAffinity", error_affinity);
74 
75 	//Processor ID (MPIDR_EL1) and chip ID (MIDR_EL1).
76 	uint64_t sock;
77 	uint64_t mpidr_eli1 = record->MPIDR_EL1;
78 	json_object_object_add(section_ir, "mpidrEl1",
79 			       json_object_new_uint64(mpidr_eli1));
80 	//Arm Processor socket info
81 	sock = (mpidr_eli1 & ARM_SOCK_MASK) >> 32;
82 	json_object_object_add(section_ir, "affinity3",
83 			       json_object_new_uint64(sock));
84 
85 	json_object_object_add(section_ir, "midrEl1",
86 			       json_object_new_uint64(record->MIDR_EL1));
87 
88 	//Whether the processor is running, and the state of it if so.
89 	json_object_object_add(section_ir, "running",
90 			       json_object_new_boolean(record->RunningState &
91 						       0x1));
92 	if (!(record->RunningState >> 31)) {
93 		//Bit 32 of running state is on, so PSCI state information is included.
94 		//This can't be made human readable, as it is unknown whether this will be the pre-PSCI 1.0 format
95 		//or the newer Extended StateID format.
96 		json_object_object_add(
97 			section_ir, "psciState",
98 			json_object_new_uint64(record->PsciState));
99 	}
100 
101 	//Processor error structures.
102 	json_object *error_info_array = json_object_new_array();
103 	EFI_ARM_ERROR_INFORMATION_ENTRY *cur_error =
104 		(EFI_ARM_ERROR_INFORMATION_ENTRY *)(record + 1);
105 	for (int i = 0; i < record->ErrInfoNum; i++) {
106 		json_object_array_add(error_info_array,
107 				      cper_arm_error_info_to_ir(cur_error));
108 		cur_error++;
109 	}
110 	json_object_object_add(section_ir, "errorInfo", error_info_array);
111 
112 	//Processor context structures.
113 	//The current position is moved within the processing, as it is a dynamic size structure.
114 	uint8_t *cur_pos = (uint8_t *)cur_error;
115 	json_object *context_info_array = json_object_new_array();
116 	for (int i = 0; i < record->ContextInfoNum; i++) {
117 		EFI_ARM_CONTEXT_INFORMATION_HEADER *header =
118 			(EFI_ARM_CONTEXT_INFORMATION_HEADER *)cur_pos;
119 		json_object *processor_context =
120 			cper_arm_processor_context_to_ir(header,
121 							 (void **)&cur_pos);
122 		json_object_array_add(context_info_array, processor_context);
123 	}
124 	json_object_object_add(section_ir, "contextInfo", context_info_array);
125 
126 	//Is there any vendor-specific information following?
127 	if (cur_pos < (uint8_t *)section + record->SectionLength) {
128 		json_object *vendor_specific = json_object_new_object();
129 		size_t input_size =
130 			(uint8_t *)section + record->SectionLength - cur_pos;
131 		int32_t encoded_len = 0;
132 		char *encoded =
133 			base64_encode(cur_pos, input_size, &encoded_len);
134 		if (encoded == NULL) {
135 			return NULL;
136 		}
137 		json_object_object_add(vendor_specific, "data",
138 				       json_object_new_string_len(encoded,
139 								  encoded_len));
140 		free(encoded);
141 
142 		json_object_object_add(section_ir, "vendorSpecificInfo",
143 				       vendor_specific);
144 	}
145 
146 	return section_ir;
147 }
148 
149 //Converts a single ARM Process Error Information structure into JSON IR.
150 json_object *
cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY * error_info)151 cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info)
152 {
153 	json_object *error_info_ir = json_object_new_object();
154 
155 	//Version, length.
156 	json_object_object_add(error_info_ir, "version",
157 			       json_object_new_int(error_info->Version));
158 	json_object_object_add(error_info_ir, "length",
159 			       json_object_new_int(error_info->Length));
160 
161 	//Validation bitfield.
162 	json_object *validation =
163 		bitfield_to_ir(error_info->ValidationBits, 5,
164 			       ARM_ERROR_INFO_ENTRY_VALID_BITFIELD_NAMES);
165 	json_object_object_add(error_info_ir, "validationBits", validation);
166 
167 	//The type of error information in this log.
168 	json_object *error_type = integer_to_readable_pair(
169 		error_info->Type, 4, ARM_ERROR_INFO_ENTRY_INFO_TYPES_KEYS,
170 		ARM_ERROR_INFO_ENTRY_INFO_TYPES_VALUES, "Unknown (Reserved)");
171 	json_object_object_add(error_info_ir, "errorType", error_type);
172 
173 	//Multiple error count.
174 	json_object *multiple_error = json_object_new_object();
175 	json_object_object_add(multiple_error, "value",
176 			       json_object_new_int(error_info->MultipleError));
177 	json_object_object_add(
178 		multiple_error, "type",
179 		json_object_new_string(error_info->MultipleError < 1 ?
180 					       "Single Error" :
181 					       "Multiple Errors"));
182 	json_object_object_add(error_info_ir, "multipleError", multiple_error);
183 
184 	//Flags.
185 	json_object *flags = bitfield_to_ir(error_info->Flags, 4,
186 					    ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
187 	json_object_object_add(error_info_ir, "flags", flags);
188 
189 	//Error information, split by type.
190 	json_object *error_subinfo = NULL;
191 	switch (error_info->Type) {
192 	case ARM_ERROR_INFORMATION_TYPE_CACHE: //Cache
193 	case ARM_ERROR_INFORMATION_TYPE_TLB:   //TLB
194 		error_subinfo = cper_arm_cache_tlb_error_to_ir(
195 			(EFI_ARM_CACHE_ERROR_STRUCTURE *)&error_info
196 				->ErrorInformation,
197 			error_info);
198 		break;
199 	case ARM_ERROR_INFORMATION_TYPE_BUS: //Bus
200 		error_subinfo = cper_arm_bus_error_to_ir(
201 			(EFI_ARM_BUS_ERROR_STRUCTURE *)&error_info
202 				->ErrorInformation);
203 		break;
204 
205 	default:
206 		//Unknown/microarch, will not support.
207 		break;
208 	}
209 	json_object_object_add(error_info_ir, "errorInformation",
210 			       error_subinfo);
211 
212 	//Virtual fault address, physical fault address.
213 	json_object_object_add(
214 		error_info_ir, "virtualFaultAddress",
215 		json_object_new_uint64(error_info->VirtualFaultAddress));
216 	json_object_object_add(
217 		error_info_ir, "physicalFaultAddress",
218 		json_object_new_uint64(error_info->PhysicalFaultAddress));
219 
220 	return error_info_ir;
221 }
222 
223 //Converts a single ARM cache/TLB error information structure into JSON IR format.
224 json_object *
cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE * cache_tlb_error,EFI_ARM_ERROR_INFORMATION_ENTRY * error_info)225 cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
226 			       EFI_ARM_ERROR_INFORMATION_ENTRY *error_info)
227 {
228 	json_object *cache_tlb_error_ir = json_object_new_object();
229 	json_object *cache_tlb_prop = json_object_new_object();
230 	char *cache_tlb_propname;
231 
232 	//Validation bitfield.
233 	json_object *validation =
234 		bitfield_to_ir(cache_tlb_error->ValidationBits, 7,
235 			       ARM_CACHE_TLB_ERROR_VALID_BITFIELD_NAMES);
236 	json_object_object_add(cache_tlb_error_ir, "validationBits",
237 			       validation);
238 
239 	//Transaction type.
240 	json_object *transaction_type = integer_to_readable_pair(
241 		cache_tlb_error->TransactionType, 3,
242 		ARM_ERROR_TRANSACTION_TYPES_KEYS,
243 		ARM_ERROR_TRANSACTION_TYPES_VALUES, "Unknown (Reserved)");
244 	json_object_object_add(cache_tlb_error_ir, "transactionType",
245 			       transaction_type);
246 
247 	//Operation.
248 	json_object *operation;
249 	if (error_info->Type == 0) {
250 		//Cache operation.
251 		operation = integer_to_readable_pair(
252 			cache_tlb_error->Operation, 11,
253 			ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
254 			ARM_CACHE_BUS_OPERATION_TYPES_VALUES,
255 			"Unknown (Reserved)");
256 		cache_tlb_propname = "cacheError";
257 	} else {
258 		//TLB operation.
259 		operation = integer_to_readable_pair(
260 			cache_tlb_error->Operation, 9,
261 			ARM_TLB_OPERATION_TYPES_KEYS,
262 			ARM_TLB_OPERATION_TYPES_VALUES, "Unknown (Reserved)");
263 		cache_tlb_propname = "tlbError";
264 	}
265 	json_object_object_add(cache_tlb_error_ir, "operation", operation);
266 
267 	//Miscellaneous remaining fields.
268 	json_object_object_add(cache_tlb_error_ir, "level",
269 			       json_object_new_int(cache_tlb_error->Level));
270 	json_object_object_add(
271 		cache_tlb_error_ir, "processorContextCorrupt",
272 		json_object_new_boolean(
273 			cache_tlb_error->ProcessorContextCorrupt));
274 	json_object_object_add(
275 		cache_tlb_error_ir, "corrected",
276 		json_object_new_boolean(cache_tlb_error->Corrected));
277 	json_object_object_add(
278 		cache_tlb_error_ir, "precisePC",
279 		json_object_new_boolean(cache_tlb_error->PrecisePC));
280 	json_object_object_add(
281 		cache_tlb_error_ir, "restartablePC",
282 		json_object_new_boolean(cache_tlb_error->RestartablePC));
283 
284 	json_object_object_add(cache_tlb_prop, cache_tlb_propname,
285 			       cache_tlb_error_ir);
286 	return cache_tlb_prop;
287 }
288 
289 //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)290 json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error)
291 {
292 	json_object *bus_error_ir = json_object_new_object();
293 
294 	//Validation bits.
295 	json_object *validation =
296 		bitfield_to_ir(bus_error->ValidationBits, 12,
297 			       ARM_BUS_ERROR_VALID_BITFIELD_NAMES);
298 	json_object_object_add(bus_error_ir, "validationBits", validation);
299 
300 	//Transaction type.
301 	json_object *transaction_type = integer_to_readable_pair(
302 		bus_error->TransactionType, 3, ARM_ERROR_TRANSACTION_TYPES_KEYS,
303 		ARM_ERROR_TRANSACTION_TYPES_VALUES, "Unknown (Reserved)");
304 	json_object_object_add(bus_error_ir, "transactionType",
305 			       transaction_type);
306 
307 	//Operation.
308 	json_object *operation = integer_to_readable_pair(
309 		bus_error->Operation, 7, ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
310 		ARM_CACHE_BUS_OPERATION_TYPES_VALUES, "Unknown (Reserved)");
311 	json_object_object_add(bus_error_ir, "operation", operation);
312 
313 	//Affinity level of bus error, + miscellaneous fields.
314 	json_object_object_add(bus_error_ir, "level",
315 			       json_object_new_int(bus_error->Level));
316 	json_object_object_add(
317 		bus_error_ir, "processorContextCorrupt",
318 		json_object_new_boolean(bus_error->ProcessorContextCorrupt));
319 	json_object_object_add(bus_error_ir, "corrected",
320 			       json_object_new_boolean(bus_error->Corrected));
321 	json_object_object_add(bus_error_ir, "precisePC",
322 			       json_object_new_boolean(bus_error->PrecisePC));
323 	json_object_object_add(
324 		bus_error_ir, "restartablePC",
325 		json_object_new_boolean(bus_error->RestartablePC));
326 	json_object_object_add(bus_error_ir, "timedOut",
327 			       json_object_new_boolean(bus_error->TimeOut));
328 
329 	//Participation type.
330 	json_object *participation_type = integer_to_readable_pair(
331 		bus_error->ParticipationType, 4,
332 		ARM_BUS_PARTICIPATION_TYPES_KEYS,
333 		ARM_BUS_PARTICIPATION_TYPES_VALUES, "Unknown");
334 	json_object_object_add(bus_error_ir, "participationType",
335 			       participation_type);
336 
337 	//Address space.
338 	json_object *address_space = integer_to_readable_pair(
339 		bus_error->AddressSpace, 3, ARM_BUS_ADDRESS_SPACE_TYPES_KEYS,
340 		ARM_BUS_ADDRESS_SPACE_TYPES_VALUES, "Unknown");
341 	json_object_object_add(bus_error_ir, "addressSpace", address_space);
342 
343 	//Memory access attributes.
344 	//todo: find the specification of these in the ARM ARM
345 	json_object_object_add(
346 		bus_error_ir, "memoryAttributes",
347 		json_object_new_int(bus_error->MemoryAddressAttributes));
348 
349 	//Access Mode
350 	json_object *access_mode = json_object_new_object();
351 	json_object_object_add(access_mode, "value",
352 			       json_object_new_int(bus_error->AccessMode));
353 	json_object_object_add(
354 		access_mode, "name",
355 		json_object_new_string(bus_error->AccessMode == 0 ? "Secure" :
356 								    "Normal"));
357 	json_object_object_add(bus_error_ir, "accessMode", access_mode);
358 
359 	return bus_error_ir;
360 }
361 
362 //Converts a single ARM processor context block into JSON IR.
363 json_object *
cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER * header,void ** cur_pos)364 cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
365 				 void **cur_pos)
366 {
367 	json_object *context_ir = json_object_new_object();
368 
369 	//Version.
370 	json_object_object_add(context_ir, "version",
371 			       json_object_new_int(header->Version));
372 
373 	//Add the context type.
374 	json_object *context_type = integer_to_readable_pair(
375 		header->RegisterContextType, 9,
376 		ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_KEYS,
377 		ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_VALUES,
378 		"Unknown (Reserved)");
379 	json_object_object_add(context_ir, "registerContextType", context_type);
380 
381 	//Register array size (bytes).
382 	json_object_object_add(
383 		context_ir, "registerArraySize",
384 		json_object_new_uint64(header->RegisterArraySize));
385 
386 	//The register array itself.
387 	*cur_pos = (void *)(header + 1);
388 	json_object *register_array = NULL;
389 	switch (header->RegisterContextType) {
390 	case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
391 		register_array = uniform_struct_to_ir(
392 			(UINT32 *)cur_pos,
393 			sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
394 			ARM_AARCH32_GPR_NAMES);
395 		break;
396 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
397 		register_array = uniform_struct_to_ir(
398 			(UINT32 *)cur_pos,
399 			sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
400 				sizeof(UINT32),
401 			ARM_AARCH32_EL1_REGISTER_NAMES);
402 		break;
403 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
404 		register_array = uniform_struct_to_ir(
405 			(UINT32 *)cur_pos,
406 			sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
407 				sizeof(UINT32),
408 			ARM_AARCH32_EL2_REGISTER_NAMES);
409 		break;
410 	case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
411 		register_array = uniform_struct_to_ir(
412 			(UINT32 *)cur_pos,
413 			sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
414 				sizeof(UINT32),
415 			ARM_AARCH32_SECURE_REGISTER_NAMES);
416 		break;
417 	case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
418 		register_array = uniform_struct64_to_ir(
419 			(UINT64 *)cur_pos,
420 			sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
421 			ARM_AARCH64_GPR_NAMES);
422 		break;
423 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
424 		register_array = uniform_struct64_to_ir(
425 			(UINT64 *)cur_pos,
426 			sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
427 				sizeof(UINT64),
428 			ARM_AARCH64_EL1_REGISTER_NAMES);
429 		break;
430 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
431 		register_array = uniform_struct64_to_ir(
432 			(UINT64 *)cur_pos,
433 			sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
434 				sizeof(UINT64),
435 			ARM_AARCH64_EL2_REGISTER_NAMES);
436 		break;
437 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
438 		register_array = uniform_struct64_to_ir(
439 			(UINT64 *)cur_pos,
440 			sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
441 				sizeof(UINT64),
442 			ARM_AARCH64_EL3_REGISTER_NAMES);
443 		break;
444 	case EFI_ARM_CONTEXT_TYPE_MISC:
445 		register_array = cper_arm_misc_register_array_to_ir(
446 			(EFI_ARM_MISC_CONTEXT_REGISTER *)cur_pos);
447 		break;
448 	default:
449 		//Unknown register array type, add as base64 data instead.
450 		register_array = json_object_new_object();
451 		int32_t encoded_len = 0;
452 		char *encoded = base64_encode((UINT8 *)cur_pos,
453 					      header->RegisterArraySize,
454 					      &encoded_len);
455 		if (encoded == NULL) {
456 			printf("Failed to allocate encode output buffer. \n");
457 			return NULL;
458 		}
459 		json_object_object_add(register_array, "data",
460 				       json_object_new_string_len(encoded,
461 								  encoded_len));
462 		free(encoded);
463 
464 		break;
465 	}
466 	json_object_object_add(context_ir, "registerArray", register_array);
467 
468 	//Set the current position to after the processor context structure.
469 	*cur_pos = (UINT8 *)(*cur_pos) + header->RegisterArraySize;
470 
471 	return context_ir;
472 }
473 
474 //Converts a single CPER ARM miscellaneous register array to JSON IR format.
475 json_object *
cper_arm_misc_register_array_to_ir(EFI_ARM_MISC_CONTEXT_REGISTER * misc_register)476 cper_arm_misc_register_array_to_ir(EFI_ARM_MISC_CONTEXT_REGISTER *misc_register)
477 {
478 	json_object *register_array = json_object_new_object();
479 	json_object *mrs_encoding = json_object_new_object();
480 	json_object_object_add(mrs_encoding, "op2",
481 			       json_object_new_uint64(misc_register->MrsOp2));
482 	json_object_object_add(mrs_encoding, "crm",
483 			       json_object_new_uint64(misc_register->MrsCrm));
484 	json_object_object_add(mrs_encoding, "crn",
485 			       json_object_new_uint64(misc_register->MrsCrn));
486 	json_object_object_add(mrs_encoding, "op1",
487 			       json_object_new_uint64(misc_register->MrsOp1));
488 	json_object_object_add(mrs_encoding, "o0",
489 			       json_object_new_uint64(misc_register->MrsO0));
490 	json_object_object_add(register_array, "mrsEncoding", mrs_encoding);
491 	json_object_object_add(register_array, "value",
492 			       json_object_new_uint64(misc_register->Value));
493 
494 	return register_array;
495 }
496 
497 //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)498 void ir_section_arm_to_cper(json_object *section, FILE *out)
499 {
500 	EFI_ARM_ERROR_RECORD *section_cper =
501 		(EFI_ARM_ERROR_RECORD *)calloc(1, sizeof(EFI_ARM_ERROR_RECORD));
502 
503 	//Validation bits.
504 	section_cper->ValidFields = ir_to_bitfield(
505 		json_object_object_get(section, "validationBits"), 4,
506 		ARM_ERROR_VALID_BITFIELD_NAMES);
507 
508 	//Count of error/context info structures.
509 	section_cper->ErrInfoNum = json_object_get_int(
510 		json_object_object_get(section, "errorInfoNum"));
511 	section_cper->ContextInfoNum = json_object_get_int(
512 		json_object_object_get(section, "contextInfoNum"));
513 
514 	//Miscellaneous raw value fields.
515 	section_cper->SectionLength = json_object_get_uint64(
516 		json_object_object_get(section, "sectionLength"));
517 	section_cper->ErrorAffinityLevel = readable_pair_to_integer(
518 		json_object_object_get(section, "errorAffinity"));
519 	section_cper->MPIDR_EL1 = json_object_get_uint64(
520 		json_object_object_get(section, "mpidrEl1"));
521 	section_cper->MIDR_EL1 = json_object_get_uint64(
522 		json_object_object_get(section, "midrEl1"));
523 	section_cper->RunningState = json_object_get_boolean(
524 		json_object_object_get(section, "running"));
525 
526 	//Optional PSCI state.
527 	json_object *psci_state = json_object_object_get(section, "psciState");
528 	if (psci_state != NULL) {
529 		section_cper->PsciState = json_object_get_uint64(psci_state);
530 	}
531 
532 	//Flush header to stream.
533 	fwrite(section_cper, sizeof(EFI_ARM_ERROR_RECORD), 1, out);
534 	fflush(out);
535 
536 	//Error info structure array.
537 	json_object *error_info = json_object_object_get(section, "errorInfo");
538 	for (int i = 0; i < section_cper->ErrInfoNum; i++) {
539 		ir_arm_error_info_to_cper(
540 			json_object_array_get_idx(error_info, i), out);
541 	}
542 
543 	//Context info structure array.
544 	json_object *context_info =
545 		json_object_object_get(section, "contextInfo");
546 	for (int i = 0; i < section_cper->ContextInfoNum; i++) {
547 		ir_arm_context_info_to_cper(
548 			json_object_array_get_idx(context_info, i), out);
549 	}
550 
551 	//Vendor specific error info.
552 	json_object *vendor_specific_info =
553 		json_object_object_get(section, "vendorSpecificInfo");
554 	if (vendor_specific_info != NULL) {
555 		json_object *vendor_info_string =
556 			json_object_object_get(vendor_specific_info, "data");
557 		int vendor_specific_len =
558 			json_object_get_string_len(vendor_info_string);
559 
560 		int32_t decoded_len = 0;
561 
562 		UINT8 *decoded = base64_decode(
563 			json_object_get_string(vendor_info_string),
564 			vendor_specific_len, &decoded_len);
565 
566 		//Write out to file.
567 		fwrite(decoded, decoded_len, 1, out);
568 		fflush(out);
569 		free(decoded);
570 	}
571 
572 	//Free remaining resources.
573 	free(section_cper);
574 }
575 
576 //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)577 void ir_arm_error_info_to_cper(json_object *error_info, FILE *out)
578 {
579 	EFI_ARM_ERROR_INFORMATION_ENTRY error_info_cper;
580 
581 	//Version, length.
582 	error_info_cper.Version = json_object_get_int(
583 		json_object_object_get(error_info, "version"));
584 	error_info_cper.Length = json_object_get_int(
585 		json_object_object_get(error_info, "length"));
586 
587 	//Validation bits.
588 	error_info_cper.ValidationBits = ir_to_bitfield(
589 		json_object_object_get(error_info, "validationBits"), 5,
590 		ARM_ERROR_INFO_ENTRY_VALID_BITFIELD_NAMES);
591 
592 	//Type, multiple error.
593 	error_info_cper.Type = (UINT8)readable_pair_to_integer(
594 		json_object_object_get(error_info, "type"));
595 	error_info_cper.MultipleError = (UINT16)readable_pair_to_integer(
596 		json_object_object_get(error_info, "multipleError"));
597 
598 	//Flags object.
599 	error_info_cper.Flags = (UINT8)ir_to_bitfield(
600 		json_object_object_get(error_info, "flags"), 4,
601 		ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
602 
603 	//Error information.
604 	json_object *error_info_information =
605 		json_object_object_get(error_info, "errorInformation");
606 	json_object *error_info_prop = NULL;
607 
608 	switch (error_info_cper.Type) {
609 	case ARM_ERROR_INFORMATION_TYPE_CACHE:
610 		error_info_prop = json_object_object_get(error_info_information,
611 							 "cacheError");
612 		ir_arm_error_cache_tlb_info_to_cper(
613 			error_info_prop,
614 			&error_info_cper.ErrorInformation.CacheError);
615 		break;
616 	case ARM_ERROR_INFORMATION_TYPE_TLB:
617 		error_info_prop = json_object_object_get(error_info_information,
618 							 "tlbError");
619 		ir_arm_error_cache_tlb_info_to_cper(
620 			error_info_prop,
621 			&error_info_cper.ErrorInformation.CacheError);
622 		break;
623 
624 	case ARM_ERROR_INFORMATION_TYPE_BUS:
625 		ir_arm_error_bus_info_to_cper(
626 			error_info_information,
627 			&error_info_cper.ErrorInformation.BusError);
628 		break;
629 
630 	default:
631 		//Unknown error information type.
632 		break;
633 	}
634 
635 	//Virtual/physical fault address.
636 	error_info_cper.VirtualFaultAddress = json_object_get_uint64(
637 		json_object_object_get(error_info, "virtualFaultAddress"));
638 	error_info_cper.PhysicalFaultAddress = json_object_get_uint64(
639 		json_object_object_get(error_info, "physicalFaultAddress"));
640 
641 	//Write out to stream.
642 	fwrite(&error_info_cper, sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY), 1,
643 	       out);
644 	fflush(out);
645 }
646 
647 //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)648 void ir_arm_error_cache_tlb_info_to_cper(
649 	json_object *error_information,
650 	EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper)
651 {
652 	//Validation bits.
653 	error_info_cper->ValidationBits = ir_to_bitfield(
654 		json_object_object_get(error_information, "validationBits"), 7,
655 		ARM_CACHE_TLB_ERROR_VALID_BITFIELD_NAMES);
656 
657 	//Miscellaneous value fields.
658 	error_info_cper->TransactionType = readable_pair_to_integer(
659 		json_object_object_get(error_information, "transactionType"));
660 	error_info_cper->Operation = readable_pair_to_integer(
661 		json_object_object_get(error_information, "operation"));
662 	error_info_cper->Level = json_object_get_uint64(
663 		json_object_object_get(error_information, "level"));
664 	error_info_cper->ProcessorContextCorrupt = json_object_get_boolean(
665 		json_object_object_get(error_information,
666 				       "processorContextCorrupt"));
667 	error_info_cper->Corrected = json_object_get_boolean(
668 		json_object_object_get(error_information, "corrected"));
669 	error_info_cper->PrecisePC = json_object_get_boolean(
670 		json_object_object_get(error_information, "precisePC"));
671 	error_info_cper->RestartablePC = json_object_get_boolean(
672 		json_object_object_get(error_information, "restartablePC"));
673 	error_info_cper->Reserved = 0;
674 }
675 
676 //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)677 void ir_arm_error_bus_info_to_cper(json_object *error_information,
678 				   EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper)
679 {
680 	//Validation bits.
681 	error_info_cper->ValidationBits = ir_to_bitfield(
682 		json_object_object_get(error_information, "validationBits"), 7,
683 		ARM_BUS_ERROR_VALID_BITFIELD_NAMES);
684 
685 	//Miscellaneous value fields.
686 	error_info_cper->TransactionType = readable_pair_to_integer(
687 		json_object_object_get(error_information, "transactionType"));
688 	error_info_cper->Operation = readable_pair_to_integer(
689 		json_object_object_get(error_information, "operation"));
690 	error_info_cper->Level = json_object_get_uint64(
691 		json_object_object_get(error_information, "level"));
692 	error_info_cper->ProcessorContextCorrupt = json_object_get_boolean(
693 		json_object_object_get(error_information,
694 				       "processorContextCorrupt"));
695 	error_info_cper->Corrected = json_object_get_boolean(
696 		json_object_object_get(error_information, "corrected"));
697 	error_info_cper->PrecisePC = json_object_get_boolean(
698 		json_object_object_get(error_information, "precisePC"));
699 	error_info_cper->RestartablePC = json_object_get_boolean(
700 		json_object_object_get(error_information, "restartablePC"));
701 	error_info_cper->ParticipationType = readable_pair_to_integer(
702 		json_object_object_get(error_information, "participationType"));
703 	error_info_cper->AddressSpace = readable_pair_to_integer(
704 		json_object_object_get(error_information, "addressSpace"));
705 	error_info_cper->AccessMode = readable_pair_to_integer(
706 		json_object_object_get(error_information, "accessMode"));
707 	error_info_cper->MemoryAddressAttributes = json_object_get_uint64(
708 		json_object_object_get(error_information, "memoryAttributes"));
709 	error_info_cper->Reserved = 0;
710 }
711 
712 //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)713 void ir_arm_context_info_to_cper(json_object *context_info, FILE *out)
714 {
715 	EFI_ARM_CONTEXT_INFORMATION_HEADER info_header;
716 
717 	//Version, array size, context type.
718 	info_header.Version = json_object_get_int(
719 		json_object_object_get(context_info, "version"));
720 	info_header.RegisterArraySize = json_object_get_int(
721 		json_object_object_get(context_info, "registerArraySize"));
722 	info_header.RegisterContextType = readable_pair_to_integer(
723 		json_object_object_get(context_info, "registerContextType"));
724 
725 	//Flush to stream, write the register array itself.
726 	fwrite(&info_header, sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER), 1,
727 	       out);
728 	fflush(out);
729 
730 	json_object *register_array =
731 		json_object_object_get(context_info, "registerArray");
732 	switch (info_header.RegisterContextType) {
733 	case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
734 		ir_arm_aarch32_gpr_to_cper(register_array, out);
735 		break;
736 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
737 		ir_arm_aarch32_el1_to_cper(register_array, out);
738 		break;
739 	case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
740 		ir_arm_aarch32_el2_to_cper(register_array, out);
741 		break;
742 	case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
743 		ir_arm_aarch32_secure_to_cper(register_array, out);
744 		break;
745 	case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
746 		ir_arm_aarch64_gpr_to_cper(register_array, out);
747 		break;
748 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
749 		ir_arm_aarch64_el1_to_cper(register_array, out);
750 		break;
751 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
752 		ir_arm_aarch64_el2_to_cper(register_array, out);
753 		break;
754 	case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
755 		ir_arm_aarch64_el3_to_cper(register_array, out);
756 		break;
757 	case EFI_ARM_CONTEXT_TYPE_MISC:
758 		ir_arm_misc_registers_to_cper(register_array, out);
759 		break;
760 	default:
761 		//Unknown register structure.
762 		ir_arm_unknown_register_to_cper(register_array, out);
763 		break;
764 	}
765 }
766 
767 //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)768 void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out)
769 {
770 	//Get uniform register array.
771 	EFI_ARM_V8_AARCH32_GPR reg_array;
772 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
773 			     sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
774 			     ARM_AARCH32_GPR_NAMES);
775 
776 	//Flush to stream.
777 	fwrite(&reg_array, sizeof(reg_array), 1, out);
778 	fflush(out);
779 }
780 
781 //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)782 void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out)
783 {
784 	//Get uniform register array.
785 	EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS reg_array;
786 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
787 			     sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
788 				     sizeof(UINT32),
789 			     ARM_AARCH32_EL1_REGISTER_NAMES);
790 
791 	//Flush to stream.
792 	fwrite(&reg_array, sizeof(reg_array), 1, out);
793 	fflush(out);
794 }
795 
796 //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)797 void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out)
798 {
799 	//Get uniform register array.
800 	EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS reg_array;
801 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
802 			     sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
803 				     sizeof(UINT32),
804 			     ARM_AARCH32_EL2_REGISTER_NAMES);
805 
806 	//Flush to stream.
807 	fwrite(&reg_array, sizeof(reg_array), 1, out);
808 	fflush(out);
809 }
810 
811 //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)812 void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out)
813 {
814 	//Get uniform register array.
815 	EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS reg_array;
816 	ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
817 			     sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
818 				     sizeof(UINT32),
819 			     ARM_AARCH32_SECURE_REGISTER_NAMES);
820 
821 	//Flush to stream.
822 	fwrite(&reg_array, sizeof(reg_array), 1, out);
823 	fflush(out);
824 }
825 
826 //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)827 void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out)
828 {
829 	//Get uniform register array.
830 	EFI_ARM_V8_AARCH64_GPR reg_array;
831 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
832 			       sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
833 			       ARM_AARCH64_GPR_NAMES);
834 
835 	//Flush to stream.
836 	fwrite(&reg_array, sizeof(reg_array), 1, out);
837 	fflush(out);
838 }
839 
840 //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)841 void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out)
842 {
843 	//Get uniform register array.
844 	EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS reg_array;
845 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
846 			       sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
847 				       sizeof(UINT64),
848 			       ARM_AARCH64_EL1_REGISTER_NAMES);
849 
850 	//Flush to stream.
851 	fwrite(&reg_array, sizeof(reg_array), 1, out);
852 	fflush(out);
853 }
854 
855 //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)856 void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out)
857 {
858 	//Get uniform register array.
859 	EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS reg_array;
860 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
861 			       sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
862 				       sizeof(UINT64),
863 			       ARM_AARCH64_EL2_REGISTER_NAMES);
864 
865 	//Flush to stream.
866 	fwrite(&reg_array, sizeof(reg_array), 1, out);
867 	fflush(out);
868 }
869 
870 //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)871 void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out)
872 {
873 	//Get uniform register array.
874 	EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS reg_array;
875 	ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
876 			       sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
877 				       sizeof(UINT64),
878 			       ARM_AARCH64_EL3_REGISTER_NAMES);
879 
880 	//Flush to stream.
881 	fwrite(&reg_array, sizeof(reg_array), 1, out);
882 	fflush(out);
883 }
884 
885 //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)886 void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out)
887 {
888 	EFI_ARM_MISC_CONTEXT_REGISTER reg_array;
889 
890 	//MRS encoding information.
891 	json_object *mrs_encoding =
892 		json_object_object_get(registers, "mrsEncoding");
893 	reg_array.MrsOp2 = json_object_get_uint64(
894 		json_object_object_get(mrs_encoding, "op2"));
895 	reg_array.MrsCrm = json_object_get_uint64(
896 		json_object_object_get(mrs_encoding, "crm"));
897 	reg_array.MrsCrn = json_object_get_uint64(
898 		json_object_object_get(mrs_encoding, "crn"));
899 	reg_array.MrsOp1 = json_object_get_uint64(
900 		json_object_object_get(mrs_encoding, "op1"));
901 	reg_array.MrsO0 = json_object_get_uint64(
902 		json_object_object_get(mrs_encoding, "o0"));
903 
904 	//Actual register value.
905 	reg_array.Value = json_object_get_uint64(
906 		json_object_object_get(registers, "value"));
907 
908 	//Flush to stream.
909 	fwrite(&reg_array, sizeof(reg_array), 1, out);
910 	fflush(out);
911 }
912 
913 //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)914 void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out)
915 {
916 	//Get base64 represented data.
917 	json_object *encoded = json_object_object_get(registers, "data");
918 
919 	int32_t decoded_len = 0;
920 
921 	UINT8 *decoded = base64_decode(json_object_get_string(encoded),
922 				       json_object_get_string_len(encoded),
923 				       &decoded_len);
924 
925 	if (decoded == NULL) {
926 		printf("Failed to allocate decode output buffer. \n");
927 	} else {
928 		//Flush out to stream.
929 		fwrite(&decoded, decoded_len, 1, out);
930 		fflush(out);
931 		free(decoded);
932 	}
933 }
934