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