xref: /openbmc/libcper/sections/cper-section-ia32x64.c (revision f125142cd92122fea035c12c82890a00cfc1ef7a)
1 /**
2  * Describes functions for converting IA32/x64 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-ia32x64.h>
14 #include <libcper/log.h>
15 #include <string.h>
16 
17 //Private pre-definitions.
18 json_object *cper_ia32x64_processor_error_info_to_ir(
19 	EFI_IA32_X64_PROCESS_ERROR_INFO *error_info);
20 json_object *cper_ia32x64_cache_tlb_check_to_ir(
21 	EFI_IA32_X64_CACHE_CHECK_INFO *cache_tlb_check);
22 json_object *
23 cper_ia32x64_bus_check_to_ir(EFI_IA32_X64_BUS_CHECK_INFO *bus_check);
24 json_object *cper_ia32x64_ms_check_to_ir(EFI_IA32_X64_MS_CHECK_INFO *ms_check);
25 json_object *cper_ia32x64_processor_context_info_to_ir(
26 	EFI_IA32_X64_PROCESSOR_CONTEXT_INFO *context_info, void **cur_pos,
27 	UINT32 *remaining_size);
28 json_object *
29 cper_ia32x64_register_32bit_to_ir(EFI_CONTEXT_IA32_REGISTER_STATE *registers);
30 json_object *
31 cper_ia32x64_register_64bit_to_ir(EFI_CONTEXT_X64_REGISTER_STATE *registers);
32 void ir_ia32x64_error_info_to_cper(json_object *error_info, FILE *out);
33 void ir_ia32x64_context_info_to_cper(json_object *context_info, FILE *out);
34 void ir_ia32x64_cache_tlb_check_error_to_cper(
35 	json_object *check_info,
36 	EFI_IA32_X64_CACHE_CHECK_INFO *check_info_cper);
37 void ir_ia32x64_bus_check_error_to_cper(
38 	json_object *check_info, EFI_IA32_X64_BUS_CHECK_INFO *check_info_cper);
39 void ir_ia32x64_ms_check_error_to_cper(
40 	json_object *check_info, EFI_IA32_X64_MS_CHECK_INFO *check_info_cper);
41 void ir_ia32x64_ia32_registers_to_cper(json_object *registers, FILE *out);
42 void ir_ia32x64_x64_registers_to_cper(json_object *registers, FILE *out);
43 
44 //////////////////
45 /// CPER TO IR ///
46 //////////////////
47 
48 //Converts the IA32/x64 error section described in the given descriptor into intermediate format.
cper_section_ia32x64_to_ir(const UINT8 * section,UINT32 size,char ** desc_string)49 json_object *cper_section_ia32x64_to_ir(const UINT8 *section, UINT32 size,
50 					char **desc_string)
51 {
52 	int outstr_len = 0;
53 
54 	*desc_string = NULL;
55 	if (size < sizeof(EFI_IA32_X64_PROCESSOR_ERROR_RECORD)) {
56 		cper_print_log("Error: IA32/x64 section too small\n");
57 		return NULL;
58 	}
59 
60 	*desc_string = calloc(1, SECTION_DESC_STRING_SIZE);
61 	if (*desc_string == NULL) {
62 		cper_print_log(
63 			"Error: Failed to allocate IA32/x64 desc string\n");
64 		return NULL;
65 	}
66 	outstr_len = snprintf(*desc_string, SECTION_DESC_STRING_SIZE,
67 			      "An IA32/x64 Processor Error occurred");
68 	if (outstr_len < 0) {
69 		cper_print_log(
70 			"Error: Could not write to IA32/x64 description string\n");
71 	} else if (outstr_len > SECTION_DESC_STRING_SIZE) {
72 		cper_print_log(
73 			"Error: IA32/x64 description string truncated\n");
74 	}
75 	EFI_IA32_X64_PROCESSOR_ERROR_RECORD *record =
76 		(EFI_IA32_X64_PROCESSOR_ERROR_RECORD *)section;
77 	UINT32 remaining_size =
78 		size - sizeof(EFI_IA32_X64_PROCESSOR_ERROR_RECORD);
79 	json_object *record_ir = json_object_new_object();
80 
81 	//Validation bits.
82 	//validation bits contain information
83 	//about processorErrorInfoNum and processorContextInfoNum.
84 	//Ensure this is decoded properly in IR->CPER
85 	int processor_error_info_num = (record->ValidFields >> 2) & 0x3F;
86 	json_object_object_add(record_ir, "processorErrorInfoNum",
87 			       json_object_new_int(processor_error_info_num));
88 	int processor_context_info_num = (record->ValidFields >> 8) & 0x3F;
89 	json_object_object_add(record_ir, "processorContextInfoNum",
90 			       json_object_new_int(processor_context_info_num));
91 
92 	ValidationTypes ui64Type = { UINT_64T,
93 				     .value.ui64 = record->ValidFields };
94 
95 	//APIC ID.
96 	if (isvalid_prop_to_ir(&ui64Type, 0)) {
97 		json_object_object_add(record_ir, "localAPICID",
98 				       json_object_new_uint64(record->ApicId));
99 	}
100 
101 	//CPUID information.
102 	if (isvalid_prop_to_ir(&ui64Type, 1)) {
103 		json_object *cpuid_info_ir = json_object_new_object();
104 		EFI_IA32_X64_CPU_ID *cpuid_info =
105 			(EFI_IA32_X64_CPU_ID *)record->CpuIdInfo;
106 		json_object_object_add(cpuid_info_ir, "eax",
107 				       json_object_new_uint64(cpuid_info->Eax));
108 		json_object_object_add(cpuid_info_ir, "ebx",
109 				       json_object_new_uint64(cpuid_info->Ebx));
110 		json_object_object_add(cpuid_info_ir, "ecx",
111 				       json_object_new_uint64(cpuid_info->Ecx));
112 		json_object_object_add(cpuid_info_ir, "edx",
113 				       json_object_new_uint64(cpuid_info->Edx));
114 		json_object_object_add(record_ir, "cpuidInfo", cpuid_info_ir);
115 	}
116 
117 	//Processor error information, of the amount described above.
118 	EFI_IA32_X64_PROCESS_ERROR_INFO *current_error_info =
119 		(EFI_IA32_X64_PROCESS_ERROR_INFO *)(record + 1);
120 	json_object *error_info_array = json_object_new_array();
121 	if (remaining_size < (processor_error_info_num *
122 			      sizeof(EFI_IA32_X64_PROCESS_ERROR_INFO))) {
123 		json_object_put(error_info_array);
124 		json_object_put(record_ir);
125 		free(*desc_string);
126 		*desc_string = NULL;
127 		cper_print_log(
128 			"Invalid CPER file: Invalid processor error info num.\n");
129 		return NULL;
130 	}
131 
132 	for (int i = 0; i < processor_error_info_num; i++) {
133 		json_object_array_add(error_info_array,
134 				      cper_ia32x64_processor_error_info_to_ir(
135 					      current_error_info));
136 		current_error_info++;
137 	}
138 	remaining_size -= processor_error_info_num *
139 			  sizeof(EFI_IA32_X64_PROCESS_ERROR_INFO);
140 
141 	json_object_object_add(record_ir, "processorErrorInfo",
142 			       error_info_array);
143 
144 	//Processor context information, of the amount described above.
145 	if (remaining_size < (processor_context_info_num *
146 			      sizeof(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO))) {
147 		json_object_put(record_ir);
148 		free(*desc_string);
149 		*desc_string = NULL;
150 		cper_print_log(
151 			"Invalid CPER file: Invalid processor context info num.\n");
152 		return NULL;
153 	}
154 	EFI_IA32_X64_PROCESSOR_CONTEXT_INFO *current_context_info =
155 		(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO *)current_error_info;
156 	void *cur_pos = (void *)current_context_info;
157 	json_object *context_info_array = json_object_new_array();
158 	for (int i = 0; i < processor_context_info_num; i++) {
159 		json_object *context_info =
160 			cper_ia32x64_processor_context_info_to_ir(
161 				current_context_info, &cur_pos,
162 				&remaining_size);
163 		json_object_array_add(context_info_array, context_info);
164 		current_context_info =
165 			(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO *)cur_pos;
166 
167 		//The context array is a non-fixed size, pointer is shifted within the above function.
168 	}
169 
170 	json_object_object_add(record_ir, "processorContextInfo",
171 			       context_info_array);
172 
173 	return record_ir;
174 }
175 
176 EFI_GUID *gEfiIa32x64ErrorTypeGuids[] = {
177 	&gEfiIa32x64ErrorTypeCacheCheckGuid,
178 	&gEfiIa32x64ErrorTypeTlbCheckGuid,
179 	&gEfiIa32x64ErrorTypeBusCheckGuid,
180 	&gEfiIa32x64ErrorTypeMsCheckGuid,
181 };
182 
183 //Converts a single IA32/x64 processor error info block into JSON IR format.
cper_ia32x64_processor_error_info_to_ir(EFI_IA32_X64_PROCESS_ERROR_INFO * error_info)184 json_object *cper_ia32x64_processor_error_info_to_ir(
185 	EFI_IA32_X64_PROCESS_ERROR_INFO *error_info)
186 {
187 	json_object *error_info_ir = json_object_new_object();
188 	json_object *type = json_object_new_object();
189 
190 	//Error structure type (as GUID).
191 	add_guid(type, "guid", &error_info->ErrorType);
192 
193 	//Get the error structure type as a readable string.
194 	const char *readable_type = "Unknown";
195 
196 	const char *readable_names[] = {
197 		"Cache Check Error",
198 		"TLB Check Error",
199 		"Bus Check Error",
200 		"MS Check Error",
201 	};
202 
203 	int index = select_guid_from_list(
204 		&error_info->ErrorType, gEfiIa32x64ErrorTypeGuids,
205 		sizeof(gEfiIa32x64ErrorTypeGuids) / sizeof(EFI_GUID *));
206 
207 	if (index < (int)(sizeof(readable_names) / sizeof(char *))) {
208 		readable_type = readable_names[index];
209 	}
210 
211 	json_object_object_add(type, "name",
212 			       json_object_new_string(readable_type));
213 	json_object_object_add(error_info_ir, "type", type);
214 
215 	//Validation bits.
216 	ValidationTypes ui64Type = { UINT_64T,
217 				     .value.ui64 = error_info->ValidFields };
218 
219 	//Add the check information on a per-structure basis.
220 	//Cache and TLB check information are identical, so can be equated.
221 	if (isvalid_prop_to_ir(&ui64Type, 0)) {
222 		json_object *check_information = NULL;
223 
224 		switch (index) {
225 		case 0:
226 		case 1:
227 			check_information = cper_ia32x64_cache_tlb_check_to_ir(
228 				(EFI_IA32_X64_CACHE_CHECK_INFO *)&error_info
229 					->CheckInfo);
230 			break;
231 		case 2:
232 			check_information = cper_ia32x64_bus_check_to_ir(
233 				(EFI_IA32_X64_BUS_CHECK_INFO *)&error_info
234 					->CheckInfo);
235 			break;
236 		case 3:
237 			check_information = cper_ia32x64_ms_check_to_ir(
238 				(EFI_IA32_X64_MS_CHECK_INFO *)&error_info
239 					->CheckInfo);
240 			break;
241 		default:
242 			//Unknown check information.
243 			cper_print_log(
244 				"WARN: Invalid/unknown check information GUID found in IA32/x64 CPER section. Ignoring.\n");
245 			break;
246 		}
247 		if (check_information != NULL) {
248 			json_object_object_add(error_info_ir, "checkInfo",
249 					       check_information);
250 		}
251 	}
252 
253 	//Target, requestor, and responder identifiers.
254 	if (isvalid_prop_to_ir(&ui64Type, 1)) {
255 		json_object_object_add(
256 			error_info_ir, "targetAddressID",
257 			json_object_new_uint64(error_info->TargetId));
258 	}
259 	if (isvalid_prop_to_ir(&ui64Type, 2)) {
260 		json_object_object_add(
261 			error_info_ir, "requestorID",
262 			json_object_new_uint64(error_info->RequestorId));
263 	}
264 	if (isvalid_prop_to_ir(&ui64Type, 3)) {
265 		json_object_object_add(
266 			error_info_ir, "responderID",
267 			json_object_new_uint64(error_info->ResponderId));
268 	}
269 	if (isvalid_prop_to_ir(&ui64Type, 4)) {
270 		json_object_object_add(
271 			error_info_ir, "instructionPointer",
272 			json_object_new_uint64(error_info->InstructionIP));
273 	}
274 
275 	return error_info_ir;
276 }
277 
278 //Converts a single IA32/x64 cache or TLB check check info block into JSON IR format.
cper_ia32x64_cache_tlb_check_to_ir(EFI_IA32_X64_CACHE_CHECK_INFO * cache_tlb_check)279 json_object *cper_ia32x64_cache_tlb_check_to_ir(
280 	EFI_IA32_X64_CACHE_CHECK_INFO *cache_tlb_check)
281 {
282 	json_object *cache_tlb_check_ir = json_object_new_object();
283 
284 	//Validation bits.
285 	ValidationTypes ui64Type = {
286 		UINT_64T, .value.ui64 = cache_tlb_check->ValidFields
287 	};
288 
289 	//Transaction type.
290 	if (isvalid_prop_to_ir(&ui64Type, 0)) {
291 		json_object *transaction_type = integer_to_readable_pair(
292 			cache_tlb_check->TransactionType, 3,
293 			IA32X64_CHECK_INFO_TRANSACTION_TYPES_KEYS,
294 			IA32X64_CHECK_INFO_TRANSACTION_TYPES_VALUES,
295 			"Unknown (Reserved)");
296 		json_object_object_add(cache_tlb_check_ir, "transactionType",
297 				       transaction_type);
298 	}
299 
300 	//Operation.
301 	if (isvalid_prop_to_ir(&ui64Type, 1)) {
302 		json_object *operation = integer_to_readable_pair(
303 			cache_tlb_check->Operation, 9,
304 			IA32X64_CHECK_INFO_OPERATION_TYPES_KEYS,
305 			IA32X64_CHECK_INFO_OPERATION_TYPES_VALUES,
306 			"Unknown (Reserved)");
307 		json_object_object_add(cache_tlb_check_ir, "operation",
308 				       operation);
309 	}
310 
311 	//Affected cache/TLB level.
312 	if (isvalid_prop_to_ir(&ui64Type, 2)) {
313 		json_object_object_add(
314 			cache_tlb_check_ir, "level",
315 			json_object_new_uint64(cache_tlb_check->Level));
316 	}
317 
318 	//Miscellaneous boolean fields.
319 	if (isvalid_prop_to_ir(&ui64Type, 3)) {
320 		json_object_object_add(
321 			cache_tlb_check_ir, "processorContextCorrupt",
322 			json_object_new_boolean(
323 				cache_tlb_check->ContextCorrupt));
324 	}
325 	if (isvalid_prop_to_ir(&ui64Type, 4)) {
326 		json_object_object_add(
327 			cache_tlb_check_ir, "uncorrected",
328 			json_object_new_boolean(
329 				cache_tlb_check->ErrorUncorrected));
330 	}
331 	if (isvalid_prop_to_ir(&ui64Type, 5)) {
332 		json_object_object_add(
333 			cache_tlb_check_ir, "preciseIP",
334 			json_object_new_boolean(cache_tlb_check->PreciseIp));
335 	}
336 	if (isvalid_prop_to_ir(&ui64Type, 6)) {
337 		json_object_object_add(cache_tlb_check_ir, "restartableIP",
338 				       json_object_new_boolean(
339 					       cache_tlb_check->RestartableIp));
340 	}
341 	if (isvalid_prop_to_ir(&ui64Type, 7)) {
342 		json_object_object_add(
343 			cache_tlb_check_ir, "overflow",
344 			json_object_new_boolean(cache_tlb_check->Overflow));
345 	}
346 
347 	return cache_tlb_check_ir;
348 }
349 
350 //Converts a single IA32/x64 bus check check info block into JSON IR format.
351 json_object *
cper_ia32x64_bus_check_to_ir(EFI_IA32_X64_BUS_CHECK_INFO * bus_check)352 cper_ia32x64_bus_check_to_ir(EFI_IA32_X64_BUS_CHECK_INFO *bus_check)
353 {
354 	json_object *bus_check_ir = json_object_new_object();
355 
356 	//Validation bits.
357 	ValidationTypes ui64Type = { UINT_64T,
358 				     .value.ui64 = bus_check->ValidFields };
359 
360 	//Transaction type.
361 	if (isvalid_prop_to_ir(&ui64Type, 0)) {
362 		json_object *transaction_type = integer_to_readable_pair(
363 			bus_check->TransactionType, 3,
364 			IA32X64_CHECK_INFO_TRANSACTION_TYPES_KEYS,
365 			IA32X64_CHECK_INFO_TRANSACTION_TYPES_VALUES,
366 			"Unknown (Reserved)");
367 		json_object_object_add(bus_check_ir, "transactionType",
368 				       transaction_type);
369 	}
370 
371 	//Operation.
372 	if (isvalid_prop_to_ir(&ui64Type, 1)) {
373 		json_object *operation = integer_to_readable_pair(
374 			bus_check->Operation, 9,
375 			IA32X64_CHECK_INFO_OPERATION_TYPES_KEYS,
376 			IA32X64_CHECK_INFO_OPERATION_TYPES_VALUES,
377 			"Unknown (Reserved)");
378 		json_object_object_add(bus_check_ir, "operation", operation);
379 	}
380 
381 	//Affected bus level.
382 	if (isvalid_prop_to_ir(&ui64Type, 2)) {
383 		json_object_object_add(
384 			bus_check_ir, "level",
385 			json_object_new_uint64(bus_check->Level));
386 	}
387 
388 	//Miscellaneous boolean fields.
389 	if (isvalid_prop_to_ir(&ui64Type, 3)) {
390 		json_object_object_add(
391 			bus_check_ir, "processorContextCorrupt",
392 			json_object_new_boolean(bus_check->ContextCorrupt));
393 	}
394 	if (isvalid_prop_to_ir(&ui64Type, 4)) {
395 		json_object_object_add(
396 			bus_check_ir, "uncorrected",
397 			json_object_new_boolean(bus_check->ErrorUncorrected));
398 	}
399 	if (isvalid_prop_to_ir(&ui64Type, 5)) {
400 		json_object_object_add(
401 			bus_check_ir, "preciseIP",
402 			json_object_new_boolean(bus_check->PreciseIp));
403 	}
404 	if (isvalid_prop_to_ir(&ui64Type, 6)) {
405 		json_object_object_add(
406 			bus_check_ir, "restartableIP",
407 			json_object_new_boolean(bus_check->RestartableIp));
408 	}
409 	if (isvalid_prop_to_ir(&ui64Type, 7)) {
410 		json_object_object_add(
411 			bus_check_ir, "overflow",
412 			json_object_new_boolean(bus_check->Overflow));
413 	}
414 	if (isvalid_prop_to_ir(&ui64Type, 9)) {
415 		json_object_object_add(
416 			bus_check_ir, "timedOut",
417 			json_object_new_boolean(bus_check->TimeOut));
418 	}
419 
420 	//Participation type.
421 	if (isvalid_prop_to_ir(&ui64Type, 8)) {
422 		json_object *participation_type = integer_to_readable_pair(
423 			bus_check->ParticipationType, 4,
424 			IA32X64_BUS_CHECK_INFO_PARTICIPATION_TYPES_KEYS,
425 			IA32X64_BUS_CHECK_INFO_PARTICIPATION_TYPES_VALUES,
426 			"Unknown");
427 		json_object_object_add(bus_check_ir, "participationType",
428 				       participation_type);
429 	}
430 
431 	//Address space.
432 	if (isvalid_prop_to_ir(&ui64Type, 10)) {
433 		json_object *address_space = integer_to_readable_pair(
434 			bus_check->AddressSpace, 4,
435 			IA32X64_BUS_CHECK_INFO_ADDRESS_SPACE_TYPES_KEYS,
436 			IA32X64_BUS_CHECK_INFO_ADDRESS_SPACE_TYPES_VALUES,
437 			"Unknown");
438 		json_object_object_add(bus_check_ir, "addressSpace",
439 				       address_space);
440 	}
441 
442 	return bus_check_ir;
443 }
444 
445 //Converts a single IA32/x64 MS check check info block into JSON IR format.
cper_ia32x64_ms_check_to_ir(EFI_IA32_X64_MS_CHECK_INFO * ms_check)446 json_object *cper_ia32x64_ms_check_to_ir(EFI_IA32_X64_MS_CHECK_INFO *ms_check)
447 {
448 	json_object *ms_check_ir = json_object_new_object();
449 	ValidationTypes ui64Type = { UINT_64T,
450 				     .value.ui64 = ms_check->ValidFields };
451 	//Validation bits.
452 	//Error type (operation that caused the error).
453 	if (isvalid_prop_to_ir(&ui64Type, 0)) {
454 		json_object *error_type = integer_to_readable_pair(
455 			ms_check->ErrorType, 4,
456 			IA32X64_MS_CHECK_INFO_ERROR_TYPES_KEYS,
457 			IA32X64_MS_CHECK_INFO_ERROR_TYPES_VALUES,
458 			"Unknown (Processor Specific)");
459 		json_object_object_add(ms_check_ir, "errorType", error_type);
460 	}
461 
462 	//Miscellaneous fields.
463 	if (isvalid_prop_to_ir(&ui64Type, 1)) {
464 		json_object_object_add(
465 			ms_check_ir, "processorContextCorrupt",
466 			json_object_new_boolean(ms_check->ContextCorrupt));
467 	}
468 	if (isvalid_prop_to_ir(&ui64Type, 2)) {
469 		json_object_object_add(
470 			ms_check_ir, "uncorrected",
471 			json_object_new_boolean(ms_check->ErrorUncorrected));
472 	}
473 	if (isvalid_prop_to_ir(&ui64Type, 3)) {
474 		json_object_object_add(
475 			ms_check_ir, "preciseIP",
476 			json_object_new_boolean(ms_check->PreciseIp));
477 	}
478 	if (isvalid_prop_to_ir(&ui64Type, 4)) {
479 		json_object_object_add(
480 			ms_check_ir, "restartableIP",
481 			json_object_new_boolean(ms_check->RestartableIp));
482 	}
483 	if (isvalid_prop_to_ir(&ui64Type, 5)) {
484 		json_object_object_add(
485 			ms_check_ir, "overflow",
486 			json_object_new_boolean(ms_check->Overflow));
487 	}
488 
489 	return ms_check_ir;
490 }
491 
492 //Converts a single IA32/x64 processor context info entry into JSON IR format.
cper_ia32x64_processor_context_info_to_ir(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO * context_info,void ** cur_pos,UINT32 * remaining_size)493 json_object *cper_ia32x64_processor_context_info_to_ir(
494 	EFI_IA32_X64_PROCESSOR_CONTEXT_INFO *context_info, void **cur_pos,
495 	UINT32 *remaining_size)
496 {
497 	if (*remaining_size < sizeof(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO)) {
498 		return NULL;
499 	}
500 	*remaining_size -= sizeof(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO);
501 	json_object *context_info_ir = json_object_new_object();
502 
503 	//Register context type.
504 	json_object *context_type = integer_to_readable_pair(
505 		context_info->RegisterType, IA32X64_REGISTER_CONTEXT_TYPES_SIZE,
506 		IA32X64_REGISTER_CONTEXT_TYPES_KEYS,
507 		IA32X64_REGISTER_CONTEXT_TYPES_VALUES, "Unknown (Reserved)");
508 	json_object_object_add(context_info_ir, "registerContextType",
509 			       context_type);
510 
511 	//Register array size, MSR and MM address.
512 	json_object_object_add(context_info_ir, "registerArraySize",
513 			       json_object_new_uint64(context_info->ArraySize));
514 	json_object_object_add(
515 		context_info_ir, "msrAddress",
516 		json_object_new_uint64(context_info->MsrAddress));
517 	json_object_object_add(
518 		context_info_ir, "mmRegisterAddress",
519 		json_object_new_uint64(context_info->MmRegisterAddress));
520 
521 	//Register array.
522 	json_object *register_array = NULL;
523 	if (context_info->RegisterType == EFI_REG_CONTEXT_TYPE_IA32) {
524 		if (*remaining_size < sizeof(EFI_CONTEXT_IA32_REGISTER_STATE)) {
525 			return context_info_ir;
526 		}
527 		EFI_CONTEXT_IA32_REGISTER_STATE *register_state =
528 			(EFI_CONTEXT_IA32_REGISTER_STATE *)(context_info + 1);
529 		register_array =
530 			cper_ia32x64_register_32bit_to_ir(register_state);
531 		*cur_pos = (void *)(register_state + 1);
532 		*remaining_size -= sizeof(EFI_CONTEXT_IA32_REGISTER_STATE);
533 	} else if (context_info->RegisterType == EFI_REG_CONTEXT_TYPE_X64) {
534 		if (*remaining_size < sizeof(EFI_CONTEXT_X64_REGISTER_STATE)) {
535 			return context_info_ir;
536 		}
537 		EFI_CONTEXT_X64_REGISTER_STATE *register_state =
538 			(EFI_CONTEXT_X64_REGISTER_STATE *)(context_info + 1);
539 		register_array =
540 			cper_ia32x64_register_64bit_to_ir(register_state);
541 		*cur_pos = (void *)(register_state + 1);
542 		*remaining_size -= sizeof(EFI_CONTEXT_X64_REGISTER_STATE);
543 	} else {
544 		//No parseable data, just dump as base64 and shift the head to the next item.
545 		*cur_pos = (void *)(context_info + 1);
546 		if (*remaining_size < context_info->ArraySize) {
547 			return context_info_ir;
548 		}
549 		int32_t encoded_len = 0;
550 		char *encoded = base64_encode((UINT8 *)*cur_pos,
551 					      context_info->ArraySize,
552 					      &encoded_len);
553 		if (encoded == NULL) {
554 			cper_print_log(
555 				"Failed to allocate encode output buffer. \n");
556 		} else {
557 			register_array = json_object_new_object();
558 			json_object_object_add(register_array, "data",
559 					       json_object_new_string_len(
560 						       encoded, encoded_len));
561 			free(encoded);
562 		}
563 
564 		*cur_pos =
565 			(void *)(((char *)*cur_pos) + context_info->ArraySize);
566 		*remaining_size -= context_info->ArraySize;
567 	}
568 	if (register_array != NULL) {
569 		json_object_object_add(context_info_ir, "registerArray",
570 				       register_array);
571 	}
572 
573 	return context_info_ir;
574 }
575 
576 //Converts a single CPER IA32 register state into JSON IR format.
577 json_object *
cper_ia32x64_register_32bit_to_ir(EFI_CONTEXT_IA32_REGISTER_STATE * registers)578 cper_ia32x64_register_32bit_to_ir(EFI_CONTEXT_IA32_REGISTER_STATE *registers)
579 {
580 	json_object *ia32_registers = json_object_new_object();
581 	json_object_object_add(ia32_registers, "eax",
582 			       json_object_new_uint64(registers->Eax));
583 	json_object_object_add(ia32_registers, "ebx",
584 			       json_object_new_uint64(registers->Ebx));
585 	json_object_object_add(ia32_registers, "ecx",
586 			       json_object_new_uint64(registers->Ecx));
587 	json_object_object_add(ia32_registers, "edx",
588 			       json_object_new_uint64(registers->Edx));
589 	json_object_object_add(ia32_registers, "esi",
590 			       json_object_new_uint64(registers->Esi));
591 	json_object_object_add(ia32_registers, "edi",
592 			       json_object_new_uint64(registers->Edi));
593 	json_object_object_add(ia32_registers, "ebp",
594 			       json_object_new_uint64(registers->Ebp));
595 	json_object_object_add(ia32_registers, "esp",
596 			       json_object_new_uint64(registers->Esp));
597 	json_object_object_add(ia32_registers, "cs",
598 			       json_object_new_uint64(registers->Cs));
599 	json_object_object_add(ia32_registers, "ds",
600 			       json_object_new_uint64(registers->Ds));
601 	json_object_object_add(ia32_registers, "ss",
602 			       json_object_new_uint64(registers->Ss));
603 	json_object_object_add(ia32_registers, "es",
604 			       json_object_new_uint64(registers->Es));
605 	json_object_object_add(ia32_registers, "fs",
606 			       json_object_new_uint64(registers->Fs));
607 	json_object_object_add(ia32_registers, "gs",
608 			       json_object_new_uint64(registers->Gs));
609 	json_object_object_add(ia32_registers, "eflags",
610 			       json_object_new_uint64(registers->Eflags));
611 	json_object_object_add(ia32_registers, "eip",
612 			       json_object_new_uint64(registers->Eip));
613 	json_object_object_add(ia32_registers, "cr0",
614 			       json_object_new_uint64(registers->Cr0));
615 	json_object_object_add(ia32_registers, "cr1",
616 			       json_object_new_uint64(registers->Cr1));
617 	json_object_object_add(ia32_registers, "cr2",
618 			       json_object_new_uint64(registers->Cr2));
619 	json_object_object_add(ia32_registers, "cr3",
620 			       json_object_new_uint64(registers->Cr3));
621 	json_object_object_add(ia32_registers, "cr4",
622 			       json_object_new_uint64(registers->Cr4));
623 	json_object_object_add(
624 		ia32_registers, "gdtr",
625 		json_object_new_uint64(registers->Gdtr[0] +
626 				       ((UINT64)registers->Gdtr[1] << 32)));
627 	json_object_object_add(
628 		ia32_registers, "idtr",
629 		json_object_new_uint64(registers->Idtr[0] +
630 				       ((UINT64)registers->Idtr[1] << 32)));
631 	json_object_object_add(ia32_registers, "ldtr",
632 			       json_object_new_uint64(registers->Ldtr));
633 	json_object_object_add(ia32_registers, "tr",
634 			       json_object_new_uint64(registers->Tr));
635 
636 	return ia32_registers;
637 }
638 
639 //Converts a single CPER x64 register state into JSON IR format.
640 json_object *
cper_ia32x64_register_64bit_to_ir(EFI_CONTEXT_X64_REGISTER_STATE * registers)641 cper_ia32x64_register_64bit_to_ir(EFI_CONTEXT_X64_REGISTER_STATE *registers)
642 {
643 	json_object *x64_registers = json_object_new_object();
644 	json_object_object_add(x64_registers, "rax",
645 			       json_object_new_uint64(registers->Rax));
646 	json_object_object_add(x64_registers, "rbx",
647 			       json_object_new_uint64(registers->Rbx));
648 	json_object_object_add(x64_registers, "rcx",
649 			       json_object_new_uint64(registers->Rcx));
650 	json_object_object_add(x64_registers, "rdx",
651 			       json_object_new_uint64(registers->Rdx));
652 	json_object_object_add(x64_registers, "rsi",
653 			       json_object_new_uint64(registers->Rsi));
654 	json_object_object_add(x64_registers, "rdi",
655 			       json_object_new_uint64(registers->Rdi));
656 	json_object_object_add(x64_registers, "rbp",
657 			       json_object_new_uint64(registers->Rbp));
658 	json_object_object_add(x64_registers, "rsp",
659 			       json_object_new_uint64(registers->Rsp));
660 	json_object_object_add(x64_registers, "r8",
661 			       json_object_new_uint64(registers->R8));
662 	json_object_object_add(x64_registers, "r9",
663 			       json_object_new_uint64(registers->R9));
664 	json_object_object_add(x64_registers, "r10",
665 			       json_object_new_uint64(registers->R10));
666 	json_object_object_add(x64_registers, "r11",
667 			       json_object_new_uint64(registers->R11));
668 	json_object_object_add(x64_registers, "r12",
669 			       json_object_new_uint64(registers->R12));
670 	json_object_object_add(x64_registers, "r13",
671 			       json_object_new_uint64(registers->R13));
672 	json_object_object_add(x64_registers, "r14",
673 			       json_object_new_uint64(registers->R14));
674 	json_object_object_add(x64_registers, "r15",
675 			       json_object_new_uint64(registers->R15));
676 	json_object_object_add(x64_registers, "cs",
677 			       json_object_new_int(registers->Cs));
678 	json_object_object_add(x64_registers, "ds",
679 			       json_object_new_int(registers->Ds));
680 	json_object_object_add(x64_registers, "ss",
681 			       json_object_new_int(registers->Ss));
682 	json_object_object_add(x64_registers, "es",
683 			       json_object_new_int(registers->Es));
684 	json_object_object_add(x64_registers, "fs",
685 			       json_object_new_int(registers->Fs));
686 	json_object_object_add(x64_registers, "gs",
687 			       json_object_new_int(registers->Gs));
688 	json_object_object_add(x64_registers, "rflags",
689 			       json_object_new_uint64(registers->Rflags));
690 	json_object_object_add(x64_registers, "eip",
691 			       json_object_new_uint64(registers->Rip));
692 	json_object_object_add(x64_registers, "cr0",
693 			       json_object_new_uint64(registers->Cr0));
694 	json_object_object_add(x64_registers, "cr1",
695 			       json_object_new_uint64(registers->Cr1));
696 	json_object_object_add(x64_registers, "cr2",
697 			       json_object_new_uint64(registers->Cr2));
698 	json_object_object_add(x64_registers, "cr3",
699 			       json_object_new_uint64(registers->Cr3));
700 	json_object_object_add(x64_registers, "cr4",
701 			       json_object_new_uint64(registers->Cr4));
702 	json_object_object_add(x64_registers, "cr8",
703 			       json_object_new_uint64(registers->Cr8));
704 	json_object_object_add(x64_registers, "gdtr_0",
705 			       json_object_new_uint64(registers->Gdtr[0]));
706 	json_object_object_add(x64_registers, "gdtr_1",
707 			       json_object_new_uint64(registers->Gdtr[1]));
708 	json_object_object_add(x64_registers, "idtr_0",
709 			       json_object_new_uint64(registers->Idtr[0]));
710 	json_object_object_add(x64_registers, "idtr_1",
711 			       json_object_new_uint64(registers->Idtr[1]));
712 	json_object_object_add(x64_registers, "ldtr",
713 			       json_object_new_int(registers->Ldtr));
714 	json_object_object_add(x64_registers, "tr",
715 			       json_object_new_int(registers->Tr));
716 
717 	return x64_registers;
718 }
719 
720 //////////////////
721 /// IR TO CPER ///
722 //////////////////
723 
724 //Converts a single IA32/x64 CPER-JSON section into CPER binary, outputting to the provided stream.
ir_section_ia32x64_to_cper(json_object * section,FILE * out)725 void ir_section_ia32x64_to_cper(json_object *section, FILE *out)
726 {
727 	EFI_IA32_X64_PROCESSOR_ERROR_RECORD *section_cper =
728 		(EFI_IA32_X64_PROCESSOR_ERROR_RECORD *)calloc(
729 			1, sizeof(EFI_IA32_X64_PROCESSOR_ERROR_RECORD));
730 
731 	uint64_t valid = 0x0;
732 
733 	int proc_error_info_num = json_object_get_int(json_object_object_get(
734 					  section, "processorErrorInfoNum")) &
735 				  0x3F;
736 	int proc_ctx_info_num = json_object_get_int(json_object_object_get(
737 					section, "processorContextInfoNum")) &
738 				0x3F;
739 	valid |= proc_error_info_num << 2;
740 	valid |= proc_ctx_info_num << 8;
741 
742 	ValidationTypes ui64Type = { UINT_64T, .value.ui64 = valid };
743 	struct json_object *obj = NULL;
744 
745 	//Local APIC ID.
746 	if (json_object_object_get_ex(section, "localAPICID", &obj)) {
747 		section_cper->ApicId = json_object_get_uint64(obj);
748 		add_to_valid_bitfield(&ui64Type, 0);
749 	}
750 
751 	//CPUID info.
752 	if (json_object_object_get_ex(section, "cpuidInfo", &obj)) {
753 		json_object *cpuid_info = obj;
754 		EFI_IA32_X64_CPU_ID *cpuid_info_cper =
755 			(EFI_IA32_X64_CPU_ID *)section_cper->CpuIdInfo;
756 		cpuid_info_cper->Eax = json_object_get_uint64(
757 			json_object_object_get(cpuid_info, "eax"));
758 		cpuid_info_cper->Ebx = json_object_get_uint64(
759 			json_object_object_get(cpuid_info, "ebx"));
760 		cpuid_info_cper->Ecx = json_object_get_uint64(
761 			json_object_object_get(cpuid_info, "ecx"));
762 		cpuid_info_cper->Edx = json_object_get_uint64(
763 			json_object_object_get(cpuid_info, "edx"));
764 		add_to_valid_bitfield(&ui64Type, 1);
765 	}
766 	section_cper->ValidFields = ui64Type.value.ui64;
767 
768 	//Flush the header to file before dealing w/ info sections.
769 	fwrite(section_cper, sizeof(EFI_IA32_X64_PROCESSOR_ERROR_RECORD), 1,
770 	       out);
771 	fflush(out);
772 	free(section_cper);
773 
774 	//Iterate and deal with sections.
775 	json_object *error_info =
776 		json_object_object_get(section, "processorErrorInfo");
777 	json_object *context_info =
778 		json_object_object_get(section, "processorContextInfo");
779 	for (int i = 0; i < proc_error_info_num; i++) {
780 		ir_ia32x64_error_info_to_cper(
781 			json_object_array_get_idx(error_info, i), out);
782 	}
783 	for (int i = 0; i < proc_ctx_info_num; i++) {
784 		ir_ia32x64_context_info_to_cper(
785 			json_object_array_get_idx(context_info, i), out);
786 	}
787 }
788 
789 //Converts a single CPER-JSON IA32/x64 error information structure into CPER binary, outputting to the
790 //provided stream.
ir_ia32x64_error_info_to_cper(json_object * error_info,FILE * out)791 void ir_ia32x64_error_info_to_cper(json_object *error_info, FILE *out)
792 {
793 	EFI_IA32_X64_PROCESS_ERROR_INFO *error_info_cper =
794 		(EFI_IA32_X64_PROCESS_ERROR_INFO *)calloc(
795 			1, sizeof(EFI_IA32_X64_PROCESS_ERROR_INFO));
796 
797 	//Error structure type.
798 	json_object *type = json_object_object_get(error_info, "type");
799 	string_to_guid(
800 		&error_info_cper->ErrorType,
801 		json_object_get_string(json_object_object_get(type, "guid")));
802 
803 	//Validation bits.
804 	ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
805 	struct json_object *obj = NULL;
806 
807 	//Check information, parsed based on the error type.
808 	if (json_object_object_get_ex(error_info, "checkInfo", &obj)) {
809 		json_object *check_info = obj;
810 
811 		int index = select_guid_from_list(
812 			&error_info_cper->ErrorType, gEfiIa32x64ErrorTypeGuids,
813 			sizeof(gEfiIa32x64ErrorTypeGuids) / sizeof(EFI_GUID *));
814 
815 		switch (index) {
816 		case 0:
817 		case 1:
818 			ir_ia32x64_cache_tlb_check_error_to_cper(
819 				check_info,
820 				(EFI_IA32_X64_CACHE_CHECK_INFO
821 					 *)&error_info_cper->CheckInfo);
822 			break;
823 		case 2:
824 			ir_ia32x64_bus_check_error_to_cper(
825 				check_info,
826 				(EFI_IA32_X64_BUS_CHECK_INFO *)&error_info_cper
827 					->CheckInfo);
828 			break;
829 		case 3:
830 			ir_ia32x64_ms_check_error_to_cper(
831 				check_info,
832 				(EFI_IA32_X64_MS_CHECK_INFO *)&error_info_cper
833 					->CheckInfo);
834 			break;
835 		default:
836 			//Unknown check information.
837 			cper_print_log(
838 				"WARN: Invalid/unknown check information GUID found in IA32/x64 CPER section. Ignoring.\n");
839 			break;
840 		}
841 		add_to_valid_bitfield(&ui64Type, 0);
842 	}
843 
844 	//Miscellaneous numeric fields.
845 	if (json_object_object_get_ex(error_info, "targetAddressID", &obj)) {
846 		error_info_cper->TargetId = json_object_get_uint64(obj);
847 		add_to_valid_bitfield(&ui64Type, 1);
848 	}
849 	if (json_object_object_get_ex(error_info, "requestorID", &obj)) {
850 		error_info_cper->RequestorId = json_object_get_uint64(obj);
851 		add_to_valid_bitfield(&ui64Type, 2);
852 	}
853 	if (json_object_object_get_ex(error_info, "responderID", &obj)) {
854 		error_info_cper->ResponderId = json_object_get_uint64(obj);
855 		add_to_valid_bitfield(&ui64Type, 3);
856 	}
857 	if (json_object_object_get_ex(error_info, "instructionPointer", &obj)) {
858 		error_info_cper->InstructionIP = json_object_get_uint64(obj);
859 		add_to_valid_bitfield(&ui64Type, 4);
860 	}
861 
862 	error_info_cper->ValidFields = ui64Type.value.ui64;
863 	//Write out to stream, then free resources.
864 	fwrite(error_info_cper, sizeof(EFI_IA32_X64_PROCESS_ERROR_INFO), 1,
865 	       out);
866 	fflush(out);
867 	free(error_info_cper);
868 }
869 
870 //Converts a single CPER-JSON IA32/x64 cache/TLB check error info structure to CPER binary.
ir_ia32x64_cache_tlb_check_error_to_cper(json_object * check_info,EFI_IA32_X64_CACHE_CHECK_INFO * check_info_cper)871 void ir_ia32x64_cache_tlb_check_error_to_cper(
872 	json_object *check_info, EFI_IA32_X64_CACHE_CHECK_INFO *check_info_cper)
873 {
874 	//Validation bits.
875 	ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
876 	struct json_object *obj = NULL;
877 
878 	//Transaction type, operation.
879 	if (json_object_object_get_ex(check_info, "transactionType", &obj)) {
880 		check_info_cper->TransactionType =
881 			readable_pair_to_integer(obj);
882 		add_to_valid_bitfield(&ui64Type, 0);
883 	}
884 	if (json_object_object_get_ex(check_info, "operation", &obj)) {
885 		check_info_cper->Operation = readable_pair_to_integer(obj);
886 		add_to_valid_bitfield(&ui64Type, 1);
887 	}
888 
889 	//Miscellaneous raw value fields.
890 	if (json_object_object_get_ex(check_info, "level", &obj)) {
891 		check_info_cper->Level = json_object_get_uint64(obj);
892 		add_to_valid_bitfield(&ui64Type, 2);
893 	}
894 	if (json_object_object_get_ex(check_info, "processorContextCorrupt",
895 				      &obj)) {
896 		check_info_cper->ContextCorrupt = json_object_get_boolean(obj);
897 		add_to_valid_bitfield(&ui64Type, 3);
898 	}
899 	if (json_object_object_get_ex(check_info, "uncorrected", &obj)) {
900 		check_info_cper->ErrorUncorrected =
901 			json_object_get_boolean(obj);
902 		add_to_valid_bitfield(&ui64Type, 4);
903 	}
904 	if (json_object_object_get_ex(check_info, "preciseIP", &obj)) {
905 		check_info_cper->PreciseIp = json_object_get_boolean(obj);
906 		add_to_valid_bitfield(&ui64Type, 5);
907 	}
908 	if (json_object_object_get_ex(check_info, "restartableIP", &obj)) {
909 		check_info_cper->RestartableIp = json_object_get_boolean(obj);
910 		add_to_valid_bitfield(&ui64Type, 6);
911 	}
912 	if (json_object_object_get_ex(check_info, "overflow", &obj)) {
913 		check_info_cper->Overflow = json_object_get_boolean(obj);
914 		add_to_valid_bitfield(&ui64Type, 7);
915 	}
916 	check_info_cper->ValidFields = ui64Type.value.ui64;
917 }
918 
919 //Converts a single CPER-JSON IA32/x64 bus error info structure to CPER binary.
ir_ia32x64_bus_check_error_to_cper(json_object * check_info,EFI_IA32_X64_BUS_CHECK_INFO * check_info_cper)920 void ir_ia32x64_bus_check_error_to_cper(
921 	json_object *check_info, EFI_IA32_X64_BUS_CHECK_INFO *check_info_cper)
922 {
923 	//Validation bits.
924 	ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
925 	struct json_object *obj = NULL;
926 
927 	//Readable pair fields.
928 	if (json_object_object_get_ex(check_info, "transactionType", &obj)) {
929 		check_info_cper->TransactionType =
930 			readable_pair_to_integer(obj);
931 		add_to_valid_bitfield(&ui64Type, 0);
932 	}
933 	if (json_object_object_get_ex(check_info, "operation", &obj)) {
934 		check_info_cper->Operation = readable_pair_to_integer(obj);
935 		add_to_valid_bitfield(&ui64Type, 1);
936 	}
937 	if (json_object_object_get_ex(check_info, "participationType", &obj)) {
938 		check_info_cper->ParticipationType =
939 			readable_pair_to_integer(obj);
940 		add_to_valid_bitfield(&ui64Type, 8);
941 	}
942 
943 	if (json_object_object_get_ex(check_info, "addressSpace", &obj)) {
944 		check_info_cper->AddressSpace = readable_pair_to_integer(obj);
945 		add_to_valid_bitfield(&ui64Type, 10);
946 	}
947 
948 	//Miscellaneous raw value fields.
949 	if (json_object_object_get_ex(check_info, "level", &obj)) {
950 		check_info_cper->Level = json_object_get_uint64(obj);
951 		add_to_valid_bitfield(&ui64Type, 2);
952 	}
953 	if (json_object_object_get_ex(check_info, "processorContextCorrupt",
954 				      &obj)) {
955 		check_info_cper->ContextCorrupt = json_object_get_boolean(obj);
956 		add_to_valid_bitfield(&ui64Type, 3);
957 	}
958 	if (json_object_object_get_ex(check_info, "uncorrected", &obj)) {
959 		check_info_cper->ErrorUncorrected =
960 			json_object_get_boolean(obj);
961 		add_to_valid_bitfield(&ui64Type, 4);
962 	}
963 	if (json_object_object_get_ex(check_info, "preciseIP", &obj)) {
964 		check_info_cper->PreciseIp = json_object_get_boolean(obj);
965 		add_to_valid_bitfield(&ui64Type, 5);
966 	}
967 	if (json_object_object_get_ex(check_info, "restartableIP", &obj)) {
968 		check_info_cper->RestartableIp = json_object_get_boolean(obj);
969 		add_to_valid_bitfield(&ui64Type, 6);
970 	}
971 	if (json_object_object_get_ex(check_info, "overflow", &obj)) {
972 		check_info_cper->Overflow = json_object_get_boolean(obj);
973 		add_to_valid_bitfield(&ui64Type, 7);
974 	}
975 	if (json_object_object_get_ex(check_info, "timedOut", &obj)) {
976 		check_info_cper->TimeOut = json_object_get_boolean(obj);
977 		add_to_valid_bitfield(&ui64Type, 9);
978 	}
979 	check_info_cper->ValidFields = ui64Type.value.ui64;
980 }
981 
982 //Converts a single CPER-JSON IA32/x64 MS error info structure to CPER binary.
ir_ia32x64_ms_check_error_to_cper(json_object * check_info,EFI_IA32_X64_MS_CHECK_INFO * check_info_cper)983 void ir_ia32x64_ms_check_error_to_cper(
984 	json_object *check_info, EFI_IA32_X64_MS_CHECK_INFO *check_info_cper)
985 {
986 	//Validation bits.
987 	ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
988 	struct json_object *obj = NULL;
989 
990 	//Type of MS check error.
991 	if (json_object_object_get_ex(check_info, "errorType", &obj)) {
992 		check_info_cper->ErrorType = readable_pair_to_integer(obj);
993 		add_to_valid_bitfield(&ui64Type, 0);
994 	}
995 
996 	//Miscellaneous raw value fields.
997 	if (json_object_object_get_ex(check_info, "processorContextCorrupt",
998 				      &obj)) {
999 		check_info_cper->ContextCorrupt = json_object_get_boolean(obj);
1000 		add_to_valid_bitfield(&ui64Type, 1);
1001 	}
1002 	if (json_object_object_get_ex(check_info, "uncorrected", &obj)) {
1003 		check_info_cper->ErrorUncorrected =
1004 			json_object_get_boolean(obj);
1005 		add_to_valid_bitfield(&ui64Type, 2);
1006 	}
1007 	if (json_object_object_get_ex(check_info, "preciseIP", &obj)) {
1008 		check_info_cper->PreciseIp = json_object_get_boolean(obj);
1009 		add_to_valid_bitfield(&ui64Type, 3);
1010 	}
1011 	if (json_object_object_get_ex(check_info, "restartableIP", &obj)) {
1012 		check_info_cper->RestartableIp = json_object_get_boolean(obj);
1013 		add_to_valid_bitfield(&ui64Type, 4);
1014 	}
1015 	if (json_object_object_get_ex(check_info, "overflow", &obj)) {
1016 		check_info_cper->Overflow = json_object_get_boolean(obj);
1017 		add_to_valid_bitfield(&ui64Type, 5);
1018 	}
1019 	check_info_cper->ValidFields = ui64Type.value.ui64;
1020 }
1021 
1022 //Converts a single CPER-JSON IA32/x64 context information structure into CPER binary, outputting to the
1023 //provided stream.
ir_ia32x64_context_info_to_cper(json_object * context_info,FILE * out)1024 void ir_ia32x64_context_info_to_cper(json_object *context_info, FILE *out)
1025 {
1026 	EFI_IA32_X64_PROCESSOR_CONTEXT_INFO *context_info_cper =
1027 		(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO *)calloc(
1028 			1, sizeof(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO));
1029 
1030 	//Register context type.
1031 	context_info_cper->RegisterType = (UINT16)readable_pair_to_integer(
1032 		json_object_object_get(context_info, "registerContextType"));
1033 
1034 	//Miscellaneous numeric fields.
1035 	context_info_cper->ArraySize = (UINT16)json_object_get_uint64(
1036 		json_object_object_get(context_info, "registerArraySize"));
1037 	context_info_cper->MsrAddress = (UINT32)json_object_get_uint64(
1038 		json_object_object_get(context_info, "msrAddress"));
1039 	context_info_cper->MmRegisterAddress = json_object_get_uint64(
1040 		json_object_object_get(context_info, "mmRegisterAddress"));
1041 
1042 	//Flush header to stream.
1043 	fwrite(context_info_cper, sizeof(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO),
1044 	       1, out);
1045 	fflush(out);
1046 
1047 	//Handle the register array, depending on type provided.
1048 	json_object *register_array =
1049 		json_object_object_get(context_info, "registerArray");
1050 	if (context_info_cper->RegisterType == EFI_REG_CONTEXT_TYPE_IA32) {
1051 		ir_ia32x64_ia32_registers_to_cper(register_array, out);
1052 	} else if (context_info_cper->RegisterType ==
1053 		   EFI_REG_CONTEXT_TYPE_X64) {
1054 		ir_ia32x64_x64_registers_to_cper(register_array, out);
1055 	} else {
1056 		//Unknown/structure is not defined.
1057 		json_object *encoded =
1058 			json_object_object_get(register_array, "data");
1059 		int32_t decoded_len = 0;
1060 		const char *j_string = json_object_get_string(encoded);
1061 		int j_size = json_object_get_string_len(encoded);
1062 		UINT8 *decoded = base64_decode(j_string, j_size, &decoded_len);
1063 		if (decoded == NULL) {
1064 			cper_print_log(
1065 				"Failed to allocate decode output buffer. \n");
1066 		} else {
1067 			fwrite(decoded, decoded_len, 1, out);
1068 			fflush(out);
1069 			free(decoded);
1070 		}
1071 	}
1072 
1073 	//Free remaining resources.
1074 	free(context_info_cper);
1075 }
1076 
1077 //Converts a single CPER-JSON IA32 register array into CPER binary, outputting to the given stream.
ir_ia32x64_ia32_registers_to_cper(json_object * registers,FILE * out)1078 void ir_ia32x64_ia32_registers_to_cper(json_object *registers, FILE *out)
1079 {
1080 	EFI_CONTEXT_IA32_REGISTER_STATE register_state;
1081 	register_state.Eax = (UINT32)json_object_get_uint64(
1082 		json_object_object_get(registers, "eax"));
1083 	register_state.Ebx = (UINT32)json_object_get_uint64(
1084 		json_object_object_get(registers, "ebx"));
1085 	register_state.Ecx = (UINT32)json_object_get_uint64(
1086 		json_object_object_get(registers, "ecx"));
1087 	register_state.Edx = (UINT32)json_object_get_uint64(
1088 		json_object_object_get(registers, "edx"));
1089 	register_state.Esi = (UINT32)json_object_get_uint64(
1090 		json_object_object_get(registers, "esi"));
1091 	register_state.Edi = (UINT32)json_object_get_uint64(
1092 		json_object_object_get(registers, "edi"));
1093 	register_state.Ebp = (UINT32)json_object_get_uint64(
1094 		json_object_object_get(registers, "ebp"));
1095 	register_state.Esp = (UINT32)json_object_get_uint64(
1096 		json_object_object_get(registers, "esp"));
1097 	register_state.Cs = (UINT16)json_object_get_uint64(
1098 		json_object_object_get(registers, "cs"));
1099 	register_state.Ds = (UINT32)json_object_get_uint64(
1100 		json_object_object_get(registers, "ds"));
1101 	register_state.Ss = (UINT16)json_object_get_uint64(
1102 		json_object_object_get(registers, "ss"));
1103 	register_state.Es = (UINT16)json_object_get_uint64(
1104 		json_object_object_get(registers, "es"));
1105 	register_state.Fs = (UINT16)json_object_get_uint64(
1106 		json_object_object_get(registers, "fs"));
1107 	register_state.Gs = (UINT16)json_object_get_uint64(
1108 		json_object_object_get(registers, "gs"));
1109 	register_state.Eflags = (UINT32)json_object_get_uint64(
1110 		json_object_object_get(registers, "eflags"));
1111 	register_state.Eip = (UINT32)json_object_get_uint64(
1112 		json_object_object_get(registers, "eip"));
1113 	register_state.Cr0 = (UINT32)json_object_get_uint64(
1114 		json_object_object_get(registers, "cr0"));
1115 	register_state.Cr1 = (UINT32)json_object_get_uint64(
1116 		json_object_object_get(registers, "cr1"));
1117 	register_state.Cr2 = (UINT32)json_object_get_uint64(
1118 		json_object_object_get(registers, "cr2"));
1119 	register_state.Cr3 = (UINT32)json_object_get_uint64(
1120 		json_object_object_get(registers, "cr3"));
1121 	register_state.Cr4 = (UINT32)json_object_get_uint64(
1122 		json_object_object_get(registers, "cr4"));
1123 
1124 	//64-bit registers are split into two 32-bit parts.
1125 	UINT64 gdtr = json_object_get_uint64(
1126 		json_object_object_get(registers, "gdtr"));
1127 	register_state.Gdtr[0] = gdtr & 0xFFFFFFFF;
1128 	register_state.Gdtr[1] = gdtr >> 32;
1129 	UINT64 idtr = json_object_get_uint64(
1130 		json_object_object_get(registers, "idtr"));
1131 	register_state.Idtr[0] = idtr & 0xFFFFFFFF;
1132 	register_state.Idtr[1] = idtr >> 32;
1133 
1134 	//16-bit registers.
1135 	register_state.Ldtr = (UINT16)json_object_get_uint64(
1136 		json_object_object_get(registers, "ldtr"));
1137 	register_state.Tr = (UINT16)json_object_get_uint64(
1138 		json_object_object_get(registers, "tr"));
1139 
1140 	//Write out to stream.
1141 	fwrite(&register_state, sizeof(EFI_CONTEXT_IA32_REGISTER_STATE), 1,
1142 	       out);
1143 	fflush(out);
1144 }
1145 
1146 //Converts a single CPER-JSON x64 register array into CPER binary, outputting to the given stream.
ir_ia32x64_x64_registers_to_cper(json_object * registers,FILE * out)1147 void ir_ia32x64_x64_registers_to_cper(json_object *registers, FILE *out)
1148 {
1149 	EFI_CONTEXT_X64_REGISTER_STATE register_state;
1150 	register_state.Rax = json_object_get_uint64(
1151 		json_object_object_get(registers, "rax"));
1152 	register_state.Rbx = json_object_get_uint64(
1153 		json_object_object_get(registers, "rbx"));
1154 	register_state.Rcx = json_object_get_uint64(
1155 		json_object_object_get(registers, "rcx"));
1156 	register_state.Rdx = json_object_get_uint64(
1157 		json_object_object_get(registers, "rdx"));
1158 	register_state.Rsi = json_object_get_uint64(
1159 		json_object_object_get(registers, "rsi"));
1160 	register_state.Rdi = json_object_get_uint64(
1161 		json_object_object_get(registers, "rdi"));
1162 	register_state.Rbp = json_object_get_uint64(
1163 		json_object_object_get(registers, "rbp"));
1164 	register_state.Rsp = json_object_get_uint64(
1165 		json_object_object_get(registers, "rsp"));
1166 	register_state.R8 =
1167 		json_object_get_uint64(json_object_object_get(registers, "r8"));
1168 	register_state.R9 =
1169 		json_object_get_uint64(json_object_object_get(registers, "r9"));
1170 	register_state.R10 = json_object_get_uint64(
1171 		json_object_object_get(registers, "r10"));
1172 	register_state.R11 = json_object_get_uint64(
1173 		json_object_object_get(registers, "r11"));
1174 	register_state.R12 = json_object_get_uint64(
1175 		json_object_object_get(registers, "r12"));
1176 	register_state.R13 = json_object_get_uint64(
1177 		json_object_object_get(registers, "r13"));
1178 	register_state.R14 = json_object_get_uint64(
1179 		json_object_object_get(registers, "r14"));
1180 	register_state.R15 = json_object_get_uint64(
1181 		json_object_object_get(registers, "r15"));
1182 	register_state.Cs = (UINT16)json_object_get_int(
1183 		json_object_object_get(registers, "cs"));
1184 	register_state.Ds = (UINT16)json_object_get_int(
1185 		json_object_object_get(registers, "ds"));
1186 	register_state.Ss = (UINT16)json_object_get_int(
1187 		json_object_object_get(registers, "ss"));
1188 	register_state.Es = (UINT16)json_object_get_int(
1189 		json_object_object_get(registers, "es"));
1190 	register_state.Fs = (UINT16)json_object_get_int(
1191 		json_object_object_get(registers, "fs"));
1192 	register_state.Gs = (UINT16)json_object_get_int(
1193 		json_object_object_get(registers, "gs"));
1194 	register_state.Resv1 = 0;
1195 	register_state.Rflags = json_object_get_uint64(
1196 		json_object_object_get(registers, "rflags"));
1197 	register_state.Rip = json_object_get_uint64(
1198 		json_object_object_get(registers, "eip"));
1199 	register_state.Cr0 = json_object_get_uint64(
1200 		json_object_object_get(registers, "cr0"));
1201 	register_state.Cr1 = json_object_get_uint64(
1202 		json_object_object_get(registers, "cr1"));
1203 	register_state.Cr2 = json_object_get_uint64(
1204 		json_object_object_get(registers, "cr2"));
1205 	register_state.Cr3 = json_object_get_uint64(
1206 		json_object_object_get(registers, "cr3"));
1207 	register_state.Cr4 = json_object_get_uint64(
1208 		json_object_object_get(registers, "cr4"));
1209 	register_state.Cr8 = json_object_get_uint64(
1210 		json_object_object_get(registers, "cr8"));
1211 	register_state.Gdtr[0] = json_object_get_uint64(
1212 		json_object_object_get(registers, "gdtr_0"));
1213 	register_state.Gdtr[1] = json_object_get_uint64(
1214 		json_object_object_get(registers, "gdtr_1"));
1215 	register_state.Idtr[0] = json_object_get_uint64(
1216 		json_object_object_get(registers, "idtr_0"));
1217 	register_state.Idtr[1] = json_object_get_uint64(
1218 		json_object_object_get(registers, "idtr_1"));
1219 	register_state.Ldtr = (UINT16)json_object_get_int(
1220 		json_object_object_get(registers, "ldtr"));
1221 	register_state.Tr = (UINT16)json_object_get_int(
1222 		json_object_object_get(registers, "tr"));
1223 
1224 	//Write out to stream.
1225 	fwrite(&register_state, sizeof(EFI_CONTEXT_X64_REGISTER_STATE), 1, out);
1226 	fflush(out);
1227 }
1228