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