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