blob: a2f806a6c2f63735af9d97141f7565b56386df39 [file] [log] [blame]
Lawrence Tang794312c2022-07-05 14:46:10 +01001/**
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"
Lawrence Tangd7e8ca32022-07-07 10:25:53 +010010#include "b64.h"
Lawrence Tang794312c2022-07-05 14:46:10 +010011#include "../edk/Cper.h"
12#include "../cper-utils.h"
13#include "cper-section-ia32x64.h"
14
15//Private pre-definitions.
16json_object* cper_ia32x64_processor_error_info_to_ir(EFI_IA32_X64_PROCESS_ERROR_INFO* error_info);
17json_object* cper_ia32x64_cache_tlb_check_to_ir(EFI_IA32_X64_CACHE_CHECK_INFO* cache_tlb_check);
18json_object* cper_ia32x64_bus_check_to_ir(EFI_IA32_X64_BUS_CHECK_INFO* bus_check);
19json_object* cper_ia32x64_ms_check_to_ir(EFI_IA32_X64_MS_CHECK_INFO* ms_check);
20json_object* cper_ia32x64_processor_context_info_to_ir(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO* context_info, void** cur_pos);
21json_object* cper_ia32x64_register_32bit_to_ir(EFI_CONTEXT_IA32_REGISTER_STATE* registers);
22json_object* cper_ia32x64_register_64bit_to_ir(EFI_CONTEXT_X64_REGISTER_STATE* registers);
Lawrence Tangd0c88842022-07-13 14:51:17 +010023void ir_ia32x64_error_info_to_cper(json_object* error_info, FILE* out);
24void ir_ia32x64_context_info_to_cper(json_object* context_info, FILE* out);
25void ir_ia32x64_cache_tlb_check_error_to_cper(json_object* check_info, EFI_IA32_X64_CACHE_CHECK_INFO* check_info_cper);
26void ir_ia32x64_bus_check_error_to_cper(json_object* check_info, EFI_IA32_X64_BUS_CHECK_INFO* check_info_cper);
27void ir_ia32x64_ms_check_error_to_cper(json_object* check_info, EFI_IA32_X64_MS_CHECK_INFO* check_info_cper);
28void ir_ia32x64_ia32_registers_to_cper(json_object* registers, FILE* out);
29void ir_ia32x64_x64_registers_to_cper(json_object* registers, FILE* out);
30
31//////////////////
32/// CPER TO IR ///
33//////////////////
Lawrence Tang794312c2022-07-05 14:46:10 +010034
35//Converts the IA32/x64 error section described in the given descriptor into intermediate format.
36json_object* cper_section_ia32x64_to_ir(void* section, EFI_ERROR_SECTION_DESCRIPTOR* descriptor)
37{
38 EFI_IA32_X64_PROCESSOR_ERROR_RECORD* record = (EFI_IA32_X64_PROCESSOR_ERROR_RECORD*)section;
39 json_object* record_ir = json_object_new_object();
40
Lawrence Tang12c1f652022-07-08 15:29:37 +010041 //Validation bits.
42 json_object* validationBits = json_object_new_object();
43 json_object_object_add(validationBits, "localAPICIDValid", json_object_new_boolean(record->ValidFields & 0b1));
44 json_object_object_add(validationBits, "cpuIDInfoValid", json_object_new_boolean((record->ValidFields >> 1) & 0b1));
Lawrence Tang2800cd82022-07-05 16:08:20 +010045 int processor_error_info_num = (record->ValidFields >> 2) & 0b111111;
Lawrence Tang12c1f652022-07-08 15:29:37 +010046 json_object_object_add(validationBits, "processorErrorInfoNum", json_object_new_int(processor_error_info_num));
Lawrence Tang2800cd82022-07-05 16:08:20 +010047 int processor_context_info_num = (record->ValidFields >> 8) & 0b111111;
Lawrence Tang12c1f652022-07-08 15:29:37 +010048 json_object_object_add(validationBits, "processorContextInfoNum", json_object_new_int(processor_context_info_num));
49 json_object_object_add(record_ir, "validationBits", validationBits);
Lawrence Tang794312c2022-07-05 14:46:10 +010050
51 //APIC ID.
52 json_object_object_add(record_ir, "localAPICID", json_object_new_uint64(record->ApicId));
53
Lawrence Tang9a785c22022-07-07 15:47:17 +010054 //CPUID information.
55 json_object* cpuid_info_ir = json_object_new_object();
56 EFI_IA32_X64_CPU_ID* cpuid_info = (EFI_IA32_X64_CPU_ID*)record->CpuIdInfo;
57 json_object_object_add(cpuid_info_ir, "eax", json_object_new_uint64(cpuid_info->Eax));
58 json_object_object_add(cpuid_info_ir, "ebx", json_object_new_uint64(cpuid_info->Ebx));
59 json_object_object_add(cpuid_info_ir, "ecx", json_object_new_uint64(cpuid_info->Ecx));
60 json_object_object_add(cpuid_info_ir, "edx", json_object_new_uint64(cpuid_info->Edx));
61 json_object_object_add(record_ir, "cpuidInfo", cpuid_info_ir);
Lawrence Tang794312c2022-07-05 14:46:10 +010062
63 //Processor error information, of the amount described above.
64 EFI_IA32_X64_PROCESS_ERROR_INFO* current_error_info = (EFI_IA32_X64_PROCESS_ERROR_INFO*)(record + 1);
65 json_object* error_info_array = json_object_new_array();
66 for (int i=0; i<processor_error_info_num; i++)
67 {
68 json_object_array_add(error_info_array, cper_ia32x64_processor_error_info_to_ir(current_error_info));
69 current_error_info++;
70 }
71 json_object_object_add(record_ir, "processorErrorInfo", error_info_array);
72
73 //Processor context information, of the amount described above.
Lawrence Tangaacf0e22022-07-20 13:28:52 +010074 EFI_IA32_X64_PROCESSOR_CONTEXT_INFO* current_context_info = (EFI_IA32_X64_PROCESSOR_CONTEXT_INFO*)current_error_info;
Lawrence Tang01e3a442022-07-20 15:14:50 +010075 void* cur_pos = (void*)current_context_info;
Lawrence Tang794312c2022-07-05 14:46:10 +010076 json_object* context_info_array = json_object_new_array();
77 for (int i=0; i<processor_context_info_num; i++)
78 {
Lawrence Tang01e3a442022-07-20 15:14:50 +010079 json_object_array_add(context_info_array, cper_ia32x64_processor_context_info_to_ir(current_context_info, &cur_pos));
80 current_context_info = (EFI_IA32_X64_PROCESSOR_CONTEXT_INFO*)cur_pos;
Lawrence Tang794312c2022-07-05 14:46:10 +010081 //The context array is a non-fixed size, pointer is shifted within the above function.
82 }
83 json_object_object_add(record_ir, "processorContextInfo", context_info_array);
84
85 return record_ir;
86}
87
88//Converts a single IA32/x64 processor error info block into JSON IR format.
89json_object* cper_ia32x64_processor_error_info_to_ir(EFI_IA32_X64_PROCESS_ERROR_INFO* error_info)
90{
91 json_object* error_info_ir = json_object_new_object();
92
93 //Error structure type (as GUID).
94 char error_type[GUID_STRING_LENGTH];
95 guid_to_string(error_type, &error_info->ErrorType);
96 json_object_object_add(error_info_ir, "type", json_object_new_string(error_type));
97
98 //Validation bits.
Lawrence Tang22a467c2022-07-05 17:21:06 +010099 json_object* validation = bitfield_to_ir(error_info->ValidFields, 5, IA32X64_PROCESSOR_ERROR_VALID_BITFIELD_NAMES);
Lawrence Tang794312c2022-07-05 14:46:10 +0100100 json_object_object_add(error_info_ir, "validationBits", validation);
101
102 //Add the check information on a per-structure basis.
103 //Cache and TLB check information are identical, so can be equated.
Lawrence Tangd34f2b12022-07-19 15:36:31 +0100104 json_object* check_information = NULL;
Lawrence Tang794312c2022-07-05 14:46:10 +0100105 if (guid_equal(&error_info->ErrorType, &gEfiIa32x64ErrorTypeCacheCheckGuid)
106 || guid_equal(&error_info->ErrorType, &gEfiIa32x64ErrorTypeTlbCheckGuid))
107 {
Lawrence Tangd34f2b12022-07-19 15:36:31 +0100108 check_information = cper_ia32x64_cache_tlb_check_to_ir((EFI_IA32_X64_CACHE_CHECK_INFO*)&error_info->CheckInfo);
Lawrence Tang794312c2022-07-05 14:46:10 +0100109 }
110 else if (guid_equal(&error_info->ErrorType, &gEfiIa32x64ErrorTypeBusCheckGuid))
Lawrence Tangd34f2b12022-07-19 15:36:31 +0100111 {
112 check_information = cper_ia32x64_bus_check_to_ir((EFI_IA32_X64_BUS_CHECK_INFO*)&error_info->CheckInfo);
113 }
Lawrence Tang794312c2022-07-05 14:46:10 +0100114 else if (guid_equal(&error_info->ErrorType, &gEfiIa32x64ErrorTypeMsCheckGuid))
Lawrence Tangd34f2b12022-07-19 15:36:31 +0100115 {
116 check_information = cper_ia32x64_ms_check_to_ir((EFI_IA32_X64_MS_CHECK_INFO*)&error_info->CheckInfo);
117 }
118 else
119 {
120 //Unknown check information.
121 printf("WARN: Invalid/unknown check information GUID found in IA32/x64 CPER section. Ignoring.\n");
122 }
123 json_object_object_add(error_info_ir, "checkInfo", check_information);
Lawrence Tang794312c2022-07-05 14:46:10 +0100124
125 //Target, requestor, and responder identifiers.
Lawrence Tang3636d3c2022-07-11 12:16:25 +0100126 json_object_object_add(error_info_ir, "targetAddressID", json_object_new_uint64(error_info->TargetId));
127 json_object_object_add(error_info_ir, "requestorID", json_object_new_uint64(error_info->RequestorId));
128 json_object_object_add(error_info_ir, "responderID", json_object_new_uint64(error_info->ResponderId));
Lawrence Tang794312c2022-07-05 14:46:10 +0100129 json_object_object_add(error_info_ir, "instructionPointer", json_object_new_uint64(error_info->InstructionIP));
130
131 return error_info_ir;
132}
133
134//Converts a single IA32/x64 cache or TLB check check info block into JSON IR format.
135json_object* cper_ia32x64_cache_tlb_check_to_ir(EFI_IA32_X64_CACHE_CHECK_INFO* cache_tlb_check)
136{
137 json_object* cache_tlb_check_ir = json_object_new_object();
138
139 //Validation bits.
140 json_object* validation = bitfield_to_ir(cache_tlb_check->ValidFields, 8, IA32X64_CHECK_INFO_VALID_BITFIELD_NAMES);
141 json_object_object_add(cache_tlb_check_ir, "validationBits", validation);
142
143 //Transaction type.
144 json_object* transaction_type = integer_to_readable_pair(cache_tlb_check->TransactionType, 3,
145 IA32X64_CHECK_INFO_TRANSACTION_TYPES_KEYS,
146 IA32X64_CHECK_INFO_TRANSACTION_TYPES_VALUES,
147 "Unknown (Reserved)");
148 json_object_object_add(cache_tlb_check_ir, "transactionType", transaction_type);
149
150 //Operation.
151 json_object* operation = integer_to_readable_pair(cache_tlb_check->Operation, 9,
152 IA32X64_CHECK_INFO_OPERATION_TYPES_KEYS,
153 IA32X64_CHECK_INFO_OPERATION_TYPES_VALUES,
154 "Unknown (Reserved)");
155 json_object_object_add(cache_tlb_check_ir, "operation", operation);
156
157 //Affected cache/TLB level.
158 json_object_object_add(cache_tlb_check_ir, "level", json_object_new_uint64(cache_tlb_check->Level));
159
160 //Miscellaneous boolean fields.
161 json_object_object_add(cache_tlb_check_ir, "processorContextCorrupt", json_object_new_boolean(cache_tlb_check->ContextCorrupt));
162 json_object_object_add(cache_tlb_check_ir, "uncorrected", json_object_new_boolean(cache_tlb_check->ErrorUncorrected));
163 json_object_object_add(cache_tlb_check_ir, "preciseIP", json_object_new_boolean(cache_tlb_check->PreciseIp));
164 json_object_object_add(cache_tlb_check_ir, "restartableIP", json_object_new_boolean(cache_tlb_check->RestartableIp));
165 json_object_object_add(cache_tlb_check_ir, "overflow", json_object_new_boolean(cache_tlb_check->Overflow));
166
167 return cache_tlb_check_ir;
168}
169
170//Converts a single IA32/x64 bus check check info block into JSON IR format.
171json_object* cper_ia32x64_bus_check_to_ir(EFI_IA32_X64_BUS_CHECK_INFO* bus_check)
172{
173 json_object* bus_check_ir = json_object_new_object();
174
175 //Validation bits.
176 json_object* validation = bitfield_to_ir(bus_check->ValidFields, 11, IA32X64_CHECK_INFO_VALID_BITFIELD_NAMES);
177 json_object_object_add(bus_check_ir, "validationBits", validation);
178
179 //Transaction type.
180 json_object* transaction_type = integer_to_readable_pair(bus_check->TransactionType, 3,
181 IA32X64_CHECK_INFO_TRANSACTION_TYPES_KEYS,
182 IA32X64_CHECK_INFO_TRANSACTION_TYPES_VALUES,
183 "Unknown (Reserved)");
184 json_object_object_add(bus_check_ir, "transactionType", transaction_type);
185
186 //Operation.
187 json_object* operation = integer_to_readable_pair(bus_check->Operation, 9,
188 IA32X64_CHECK_INFO_OPERATION_TYPES_KEYS,
189 IA32X64_CHECK_INFO_OPERATION_TYPES_VALUES,
190 "Unknown (Reserved)");
191 json_object_object_add(bus_check_ir, "operation", operation);
192
193 //Affected bus level.
194 json_object_object_add(bus_check_ir, "level", json_object_new_uint64(bus_check->Level));
195
196 //Miscellaneous boolean fields.
197 json_object_object_add(bus_check_ir, "processorContextCorrupt", json_object_new_boolean(bus_check->ContextCorrupt));
198 json_object_object_add(bus_check_ir, "uncorrected", json_object_new_boolean(bus_check->ErrorUncorrected));
199 json_object_object_add(bus_check_ir, "preciseIP", json_object_new_boolean(bus_check->PreciseIp));
200 json_object_object_add(bus_check_ir, "restartableIP", json_object_new_boolean(bus_check->RestartableIp));
201 json_object_object_add(bus_check_ir, "overflow", json_object_new_boolean(bus_check->Overflow));
202 json_object_object_add(bus_check_ir, "timedOut", json_object_new_boolean(bus_check->TimeOut));
203
204 //Participation type.
205 json_object* participation_type = integer_to_readable_pair(bus_check->ParticipationType, 4,
206 IA32X64_BUS_CHECK_INFO_PARTICIPATION_TYPES_KEYS,
207 IA32X64_BUS_CHECK_INFO_PARTICIPATION_TYPES_VALUES,
208 "Unknown");
209 json_object_object_add(bus_check_ir, "participationType", participation_type);
210
211 //Address space.
212 json_object* address_space = integer_to_readable_pair(bus_check->AddressSpace, 4,
213 IA32X64_BUS_CHECK_INFO_ADDRESS_SPACE_TYPES_KEYS,
214 IA32X64_BUS_CHECK_INFO_ADDRESS_SPACE_TYPES_VALUES,
215 "Unknown");
216 json_object_object_add(bus_check_ir, "addressSpace", address_space);
217
218 return bus_check_ir;
219}
220
221//Converts a single IA32/x64 MS check check info block into JSON IR format.
222json_object* cper_ia32x64_ms_check_to_ir(EFI_IA32_X64_MS_CHECK_INFO* ms_check)
223{
224 json_object* ms_check_ir = json_object_new_object();
225
226 //Validation bits.
Lawrence Tang3636d3c2022-07-11 12:16:25 +0100227 json_object* validation = bitfield_to_ir(ms_check->ValidFields, 6, IA32X64_CHECK_INFO_MS_CHECK_VALID_BITFIELD_NAMES);
Lawrence Tang794312c2022-07-05 14:46:10 +0100228 json_object_object_add(ms_check_ir, "validationBits", validation);
229
230 //Error type (operation that caused the error).
231 json_object* error_type = integer_to_readable_pair(ms_check->ErrorType, 4,
232 IA32X64_MS_CHECK_INFO_ERROR_TYPES_KEYS,
233 IA32X64_MS_CHECK_INFO_ERROR_TYPES_VALUES,
234 "Unknown (Processor Specific)");
235 json_object_object_add(ms_check_ir, "errorType", error_type);
236
237 //Miscellaneous fields.
238 json_object_object_add(ms_check_ir, "processorContextCorrupt", json_object_new_boolean(ms_check->ContextCorrupt));
239 json_object_object_add(ms_check_ir, "uncorrected", json_object_new_boolean(ms_check->ErrorUncorrected));
240 json_object_object_add(ms_check_ir, "preciseIP", json_object_new_boolean(ms_check->PreciseIp));
241 json_object_object_add(ms_check_ir, "restartableIP", json_object_new_boolean(ms_check->RestartableIp));
242 json_object_object_add(ms_check_ir, "overflow", json_object_new_boolean(ms_check->Overflow));
243
244 return ms_check_ir;
245}
246
247//Converts a single IA32/x64 processor context info entry into JSON IR format.
248json_object* cper_ia32x64_processor_context_info_to_ir(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO* context_info, void** cur_pos)
249{
250 json_object* context_info_ir = json_object_new_object();
251
252 //Register context type.
253 json_object* context_type = integer_to_readable_pair(context_info->RegisterType, 8,
254 IA32X64_REGISTER_CONTEXT_TYPES_KEYS,
255 IA32X64_REGISTER_CONTEXT_TYPES_VALUES,
256 "Unknown (Reserved)");
257 json_object_object_add(context_info_ir, "registerContextType", context_type);
258
259 //Register array size, MSR and MM address.
260 json_object_object_add(context_info_ir, "registerArraySize", json_object_new_uint64(context_info->ArraySize));
261 json_object_object_add(context_info_ir, "msrAddress", json_object_new_uint64(context_info->MsrAddress));
262 json_object_object_add(context_info_ir, "mmRegisterAddress", json_object_new_uint64(context_info->MmRegisterAddress));
263
264 //Register array.
265 json_object* register_array = NULL;
Lawrence Tangd0c88842022-07-13 14:51:17 +0100266 if (context_info->RegisterType == EFI_REG_CONTEXT_TYPE_IA32)
Lawrence Tang794312c2022-07-05 14:46:10 +0100267 {
268 EFI_CONTEXT_IA32_REGISTER_STATE* register_state = (EFI_CONTEXT_IA32_REGISTER_STATE*)(context_info + 1);
269 register_array = cper_ia32x64_register_32bit_to_ir(register_state);
270 *cur_pos = (void*)(register_state + 1);
271 }
Lawrence Tangd0c88842022-07-13 14:51:17 +0100272 else if (context_info->RegisterType == EFI_REG_CONTEXT_TYPE_X64)
Lawrence Tang794312c2022-07-05 14:46:10 +0100273 {
274 EFI_CONTEXT_X64_REGISTER_STATE* register_state = (EFI_CONTEXT_X64_REGISTER_STATE*)(context_info + 1);
275 register_array = cper_ia32x64_register_64bit_to_ir(register_state);
276 *cur_pos = (void*)(register_state + 1);
277 }
278 else
279 {
Lawrence Tangd7e8ca32022-07-07 10:25:53 +0100280 //No parseable data, just dump as base64 and shift the head to the next item.
Lawrence Tang794312c2022-07-05 14:46:10 +0100281 *cur_pos = (void*)(context_info + 1);
Lawrence Tangd7e8ca32022-07-07 10:25:53 +0100282
Lawrence Tangd34f2b12022-07-19 15:36:31 +0100283 char* encoded = b64_encode((unsigned char*)*cur_pos, context_info->ArraySize);
Lawrence Tangd7e8ca32022-07-07 10:25:53 +0100284 register_array = json_object_new_object();
285 json_object_object_add(register_array, "data", json_object_new_string(encoded));
286 free(encoded);
287
Lawrence Tang7f21db62022-07-06 11:09:39 +0100288 *cur_pos = (void*)(((char*)*cur_pos) + context_info->ArraySize);
Lawrence Tang794312c2022-07-05 14:46:10 +0100289 }
290 json_object_object_add(context_info_ir, "registerArray", register_array);
291
292 return context_info_ir;
293}
294
295//Converts a single CPER IA32 register state into JSON IR format.
296json_object* cper_ia32x64_register_32bit_to_ir(EFI_CONTEXT_IA32_REGISTER_STATE* registers)
297{
298 json_object* ia32_registers = json_object_new_object();
Lawrence Tang3636d3c2022-07-11 12:16:25 +0100299 json_object_object_add(ia32_registers, "eax", json_object_new_uint64(registers->Eax));
300 json_object_object_add(ia32_registers, "ebx", json_object_new_uint64(registers->Ebx));
301 json_object_object_add(ia32_registers, "ecx", json_object_new_uint64(registers->Ecx));
302 json_object_object_add(ia32_registers, "edx", json_object_new_uint64(registers->Edx));
303 json_object_object_add(ia32_registers, "esi", json_object_new_uint64(registers->Esi));
304 json_object_object_add(ia32_registers, "edi", json_object_new_uint64(registers->Edi));
305 json_object_object_add(ia32_registers, "ebp", json_object_new_uint64(registers->Ebp));
306 json_object_object_add(ia32_registers, "esp", json_object_new_uint64(registers->Esp));
307 json_object_object_add(ia32_registers, "cs", json_object_new_uint64(registers->Cs));
308 json_object_object_add(ia32_registers, "ds", json_object_new_uint64(registers->Ds));
309 json_object_object_add(ia32_registers, "ss", json_object_new_uint64(registers->Ss));
310 json_object_object_add(ia32_registers, "es", json_object_new_uint64(registers->Es));
311 json_object_object_add(ia32_registers, "fs", json_object_new_uint64(registers->Fs));
312 json_object_object_add(ia32_registers, "gs", json_object_new_uint64(registers->Gs));
313 json_object_object_add(ia32_registers, "eflags", json_object_new_uint64(registers->Eflags));
314 json_object_object_add(ia32_registers, "eip", json_object_new_uint64(registers->Eip));
315 json_object_object_add(ia32_registers, "cr0", json_object_new_uint64(registers->Cr0));
316 json_object_object_add(ia32_registers, "cr1", json_object_new_uint64(registers->Cr1));
317 json_object_object_add(ia32_registers, "cr2", json_object_new_uint64(registers->Cr2));
318 json_object_object_add(ia32_registers, "cr3", json_object_new_uint64(registers->Cr3));
319 json_object_object_add(ia32_registers, "cr4", json_object_new_uint64(registers->Cr4));
Lawrence Tangf0f95572022-07-07 16:56:22 +0100320 json_object_object_add(ia32_registers, "gdtr", json_object_new_uint64(registers->Gdtr[0] + ((UINT64)registers->Gdtr[1] << 32)));
321 json_object_object_add(ia32_registers, "idtr", json_object_new_uint64(registers->Idtr[0] + ((UINT64)registers->Idtr[1] << 32)));
Lawrence Tang3636d3c2022-07-11 12:16:25 +0100322 json_object_object_add(ia32_registers, "ldtr", json_object_new_uint64(registers->Ldtr));
323 json_object_object_add(ia32_registers, "tr", json_object_new_uint64(registers->Tr));
Lawrence Tang794312c2022-07-05 14:46:10 +0100324
325 return ia32_registers;
326}
327
328//Converts a single CPER x64 register state into JSON IR format.
329json_object* cper_ia32x64_register_64bit_to_ir(EFI_CONTEXT_X64_REGISTER_STATE* registers)
330{
331 json_object* x64_registers = json_object_new_object();
332 json_object_object_add(x64_registers, "rax", json_object_new_uint64(registers->Rax));
333 json_object_object_add(x64_registers, "rbx", json_object_new_uint64(registers->Rbx));
334 json_object_object_add(x64_registers, "rcx", json_object_new_uint64(registers->Rcx));
335 json_object_object_add(x64_registers, "rdx", json_object_new_uint64(registers->Rdx));
336 json_object_object_add(x64_registers, "rsi", json_object_new_uint64(registers->Rsi));
337 json_object_object_add(x64_registers, "rdi", json_object_new_uint64(registers->Rdi));
338 json_object_object_add(x64_registers, "rbp", json_object_new_uint64(registers->Rbp));
339 json_object_object_add(x64_registers, "rsp", json_object_new_uint64(registers->Rsp));
340 json_object_object_add(x64_registers, "r8", json_object_new_uint64(registers->R8));
341 json_object_object_add(x64_registers, "r9", json_object_new_uint64(registers->R9));
342 json_object_object_add(x64_registers, "r10", json_object_new_uint64(registers->R10));
343 json_object_object_add(x64_registers, "r11", json_object_new_uint64(registers->R11));
344 json_object_object_add(x64_registers, "r12", json_object_new_uint64(registers->R12));
345 json_object_object_add(x64_registers, "r13", json_object_new_uint64(registers->R13));
346 json_object_object_add(x64_registers, "r14", json_object_new_uint64(registers->R14));
347 json_object_object_add(x64_registers, "r15", json_object_new_uint64(registers->R15));
348 json_object_object_add(x64_registers, "cs", json_object_new_int(registers->Cs));
349 json_object_object_add(x64_registers, "ds", json_object_new_int(registers->Ds));
350 json_object_object_add(x64_registers, "ss", json_object_new_int(registers->Ss));
351 json_object_object_add(x64_registers, "es", json_object_new_int(registers->Es));
352 json_object_object_add(x64_registers, "fs", json_object_new_int(registers->Fs));
353 json_object_object_add(x64_registers, "gs", json_object_new_int(registers->Gs));
354 json_object_object_add(x64_registers, "rflags", json_object_new_uint64(registers->Rflags));
355 json_object_object_add(x64_registers, "eip", json_object_new_uint64(registers->Rip));
356 json_object_object_add(x64_registers, "cr0", json_object_new_uint64(registers->Cr0));
357 json_object_object_add(x64_registers, "cr1", json_object_new_uint64(registers->Cr1));
358 json_object_object_add(x64_registers, "cr2", json_object_new_uint64(registers->Cr2));
359 json_object_object_add(x64_registers, "cr3", json_object_new_uint64(registers->Cr3));
360 json_object_object_add(x64_registers, "cr4", json_object_new_uint64(registers->Cr4));
Lawrence Tang151c6ca2022-07-07 16:21:40 +0100361 json_object_object_add(x64_registers, "cr8", json_object_new_uint64(registers->Cr8));
Lawrence Tang794312c2022-07-05 14:46:10 +0100362 json_object_object_add(x64_registers, "gdtr_0", json_object_new_uint64(registers->Gdtr[0]));
363 json_object_object_add(x64_registers, "gdtr_1", json_object_new_uint64(registers->Gdtr[1]));
364 json_object_object_add(x64_registers, "idtr_0", json_object_new_uint64(registers->Idtr[0]));
365 json_object_object_add(x64_registers, "idtr_1", json_object_new_uint64(registers->Idtr[1]));
366 json_object_object_add(x64_registers, "ldtr", json_object_new_int(registers->Ldtr));
367 json_object_object_add(x64_registers, "tr", json_object_new_int(registers->Tr));
368
369 return x64_registers;
Lawrence Tangd0c88842022-07-13 14:51:17 +0100370}
371
372//////////////////
373/// IR TO CPER ///
374//////////////////
375
376//Converts a single IA32/x64 CPER-JSON section into CPER binary, outputting to the provided stream.
377void ir_section_ia32x64_to_cper(json_object* section, FILE* out)
378{
379 EFI_IA32_X64_PROCESSOR_ERROR_RECORD* section_cper =
380 (EFI_IA32_X64_PROCESSOR_ERROR_RECORD*)calloc(1, sizeof(EFI_IA32_X64_PROCESSOR_ERROR_RECORD));
381
382 //Validation bits.
383 json_object* validation = json_object_object_get(section, "validationBits");
384 section_cper->ValidFields = 0x0;
385 section_cper->ValidFields |= json_object_get_boolean(json_object_object_get(validation, "localAPICIDValid"));
386 section_cper->ValidFields |= json_object_get_boolean(json_object_object_get(validation, "cpuIDInfoValid")) << 1;
387 int proc_error_info_num = json_object_get_int(json_object_object_get(validation, "processorErrorInfoNum")) & 0b111111;
388 int proc_ctx_info_num = json_object_get_int(json_object_object_get(validation, "processorContextInfoNum")) & 0b111111;
389 section_cper->ValidFields |= proc_error_info_num << 2;
390 section_cper->ValidFields |= proc_ctx_info_num << 8;
391
392 //Local APIC ID.
393 section_cper->ApicId = json_object_get_uint64(json_object_object_get(section, "localAPICID"));
394
395 //CPUID info.
396 json_object* cpuid_info = json_object_object_get(section, "cpuidInfo");
397 EFI_IA32_X64_CPU_ID* cpuid_info_cper = (EFI_IA32_X64_CPU_ID*)section_cper->CpuIdInfo;
398 cpuid_info_cper->Eax = json_object_get_uint64(json_object_object_get(cpuid_info, "eax"));
399 cpuid_info_cper->Ebx = json_object_get_uint64(json_object_object_get(cpuid_info, "ebx"));
400 cpuid_info_cper->Ecx = json_object_get_uint64(json_object_object_get(cpuid_info, "ecx"));
401 cpuid_info_cper->Edx = json_object_get_uint64(json_object_object_get(cpuid_info, "edx"));
402
403 //Flush the header to file before dealing w/ info sections.
404 fwrite(section_cper, sizeof(EFI_IA32_X64_PROCESSOR_ERROR_RECORD), 1, out);
405 fflush(out);
406 free(section_cper);
407
408 //Iterate and deal with sections.
409 json_object* error_info = json_object_object_get(section, "processorErrorInfo");
410 json_object* context_info = json_object_object_get(section, "processorContextInfo");
411 for (int i=0; i<proc_error_info_num; i++)
412 ir_ia32x64_error_info_to_cper(json_object_array_get_idx(error_info, i), out);
413 for (int i=0; i<proc_ctx_info_num; i++)
414 ir_ia32x64_context_info_to_cper(json_object_array_get_idx(context_info, i), out);
415}
416
417//Converts a single CPER-JSON IA32/x64 error information structure into CPER binary, outputting to the
418//provided stream.
419void ir_ia32x64_error_info_to_cper(json_object* error_info, FILE* out)
420{
421 EFI_IA32_X64_PROCESS_ERROR_INFO* error_info_cper =
422 (EFI_IA32_X64_PROCESS_ERROR_INFO*)calloc(1, sizeof(EFI_IA32_X64_PROCESS_ERROR_INFO));
423
424 //Error structure type.
425 string_to_guid(&error_info_cper->ErrorType, json_object_get_string(json_object_object_get(error_info, "type")));
426
427 //Validation bits.
428 error_info_cper->ValidFields = ir_to_bitfield(json_object_object_get(error_info, "validationBits"),
429 5, IA32X64_PROCESSOR_ERROR_VALID_BITFIELD_NAMES);
430
431 //Check information, parsed based on the error type.
432 json_object* check_info = json_object_object_get(error_info, "checkInfo");
433 if (guid_equal(&error_info_cper->ErrorType, &gEfiIa32x64ErrorTypeCacheCheckGuid)
434 || guid_equal(&error_info_cper->ErrorType, &gEfiIa32x64ErrorTypeTlbCheckGuid))
435 {
436 ir_ia32x64_cache_tlb_check_error_to_cper(check_info, (EFI_IA32_X64_CACHE_CHECK_INFO*)&error_info_cper->CheckInfo);
437 }
438 else if (guid_equal(&error_info_cper->ErrorType, &gEfiIa32x64ErrorTypeBusCheckGuid))
439 ir_ia32x64_bus_check_error_to_cper(check_info, (EFI_IA32_X64_BUS_CHECK_INFO*)&error_info_cper->CheckInfo);
440 else if (guid_equal(&error_info_cper->ErrorType, &gEfiIa32x64ErrorTypeMsCheckGuid))
441 ir_ia32x64_ms_check_error_to_cper(check_info, (EFI_IA32_X64_MS_CHECK_INFO*)&error_info_cper->CheckInfo);
442
443 //Miscellaneous numeric fields.
444 error_info_cper->TargetId = json_object_get_uint64(json_object_object_get(error_info, "targetAddressID"));
445 error_info_cper->RequestorId = json_object_get_uint64(json_object_object_get(error_info, "requestorID"));
446 error_info_cper->ResponderId = json_object_get_uint64(json_object_object_get(error_info, "responderID"));
447 error_info_cper->InstructionIP = json_object_get_uint64(json_object_object_get(error_info, "instructionPointer"));
448
449 //Write out to stream, then free resources.
450 fwrite(error_info_cper, sizeof(EFI_IA32_X64_PROCESS_ERROR_INFO), 1, out);
451 fflush(out);
452 free(error_info_cper);
453}
454
455//Converts a single CPER-JSON IA32/x64 cache/TLB check error info structure to CPER binary.
456void ir_ia32x64_cache_tlb_check_error_to_cper(json_object* check_info, EFI_IA32_X64_CACHE_CHECK_INFO* check_info_cper)
457{
458 //Validation bits.
459 check_info_cper->ValidFields = ir_to_bitfield(json_object_object_get(check_info, "validationBits"),
460 8, IA32X64_CHECK_INFO_VALID_BITFIELD_NAMES);
461
462 //Transaction type, operation.
463 check_info_cper->TransactionType = readable_pair_to_integer(json_object_object_get(check_info, "transactionType"));
464 check_info_cper->Operation = readable_pair_to_integer(json_object_object_get(check_info, "operation"));
465
466 //Miscellaneous raw value fields.
467 check_info_cper->Level = json_object_get_uint64(json_object_object_get(check_info, "level"));
468 check_info_cper->ContextCorrupt = json_object_get_boolean(json_object_object_get(check_info, "processorContextCorrupt"));
469 check_info_cper->ErrorUncorrected = json_object_get_boolean(json_object_object_get(check_info, "uncorrected"));
470 check_info_cper->PreciseIp = json_object_get_boolean(json_object_object_get(check_info, "preciseIP"));
471 check_info_cper->RestartableIp = json_object_get_boolean(json_object_object_get(check_info, "restartableIP"));
472 check_info_cper->Overflow = json_object_get_boolean(json_object_object_get(check_info, "overflow"));
473}
474
475//Converts a single CPER-JSON IA32/x64 bus error info structure to CPER binary.
476void ir_ia32x64_bus_check_error_to_cper(json_object* check_info, EFI_IA32_X64_BUS_CHECK_INFO* check_info_cper)
477{
478 //Validation bits.
479 check_info_cper->ValidFields = ir_to_bitfield(json_object_object_get(check_info, "validationBits"),
480 11, IA32X64_CHECK_INFO_VALID_BITFIELD_NAMES);
481
482 //Readable pair fields.
483 check_info_cper->TransactionType = readable_pair_to_integer(json_object_object_get(check_info, "transactionType"));
484 check_info_cper->Operation = readable_pair_to_integer(json_object_object_get(check_info, "operation"));
485 check_info_cper->ParticipationType = readable_pair_to_integer(json_object_object_get(check_info, "participationType"));
486 check_info_cper->AddressSpace = readable_pair_to_integer(json_object_object_get(check_info, "addressSpace"));
487
488 //Miscellaneous raw value fields.
489 check_info_cper->Level = json_object_get_uint64(json_object_object_get(check_info, "level"));
490 check_info_cper->ContextCorrupt = json_object_get_boolean(json_object_object_get(check_info, "processorContextCorrupt"));
491 check_info_cper->ErrorUncorrected = json_object_get_boolean(json_object_object_get(check_info, "uncorrected"));
492 check_info_cper->PreciseIp = json_object_get_boolean(json_object_object_get(check_info, "preciseIP"));
493 check_info_cper->RestartableIp = json_object_get_boolean(json_object_object_get(check_info, "restartableIP"));
494 check_info_cper->Overflow = json_object_get_boolean(json_object_object_get(check_info, "overflow"));
495 check_info_cper->TimeOut = json_object_get_boolean(json_object_object_get(check_info, "timedOut"));
496}
497
498//Converts a single CPER-JSON IA32/x64 MS error info structure to CPER binary.
499void ir_ia32x64_ms_check_error_to_cper(json_object* check_info, EFI_IA32_X64_MS_CHECK_INFO* check_info_cper)
500{
501 //Validation bits.
502 check_info_cper->ValidFields = ir_to_bitfield(json_object_object_get(check_info, "validationBits"),
503 6, IA32X64_CHECK_INFO_MS_CHECK_VALID_BITFIELD_NAMES);
504
505 //Type of MS check error.
506 check_info_cper->ErrorType = readable_pair_to_integer(json_object_object_get(check_info, "errorType"));
507
508 //Miscellaneous raw value fields.
509 check_info_cper->ContextCorrupt = json_object_get_boolean(json_object_object_get(check_info, "processorContextCorrupt"));
510 check_info_cper->ErrorUncorrected = json_object_get_boolean(json_object_object_get(check_info, "uncorrected"));
511 check_info_cper->PreciseIp = json_object_get_boolean(json_object_object_get(check_info, "preciseIP"));
512 check_info_cper->RestartableIp = json_object_get_boolean(json_object_object_get(check_info, "restartableIP"));
513 check_info_cper->Overflow = json_object_get_boolean(json_object_object_get(check_info, "overflow"));
514}
515
516//Converts a single CPER-JSON IA32/x64 context information structure into CPER binary, outputting to the
517//provided stream.
518void ir_ia32x64_context_info_to_cper(json_object* context_info, FILE* out)
519{
520 EFI_IA32_X64_PROCESSOR_CONTEXT_INFO* context_info_cper =
521 (EFI_IA32_X64_PROCESSOR_CONTEXT_INFO*)calloc(1, sizeof(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO));
522
523 //Register context type.
524 context_info_cper->RegisterType = (UINT16)readable_pair_to_integer(json_object_object_get(context_info, "registerContextType"));
525
526 //Miscellaneous numeric fields.
527 context_info_cper->ArraySize = (UINT16)json_object_get_uint64(json_object_object_get(context_info, "registerArraySize"));
Lawrence Tangaacf0e22022-07-20 13:28:52 +0100528 context_info_cper->MsrAddress = (UINT32)json_object_get_uint64(json_object_object_get(context_info, "msrAddress"));
529 context_info_cper->MmRegisterAddress = json_object_get_uint64(json_object_object_get(context_info, "mmRegisterAddress"));
Lawrence Tangd0c88842022-07-13 14:51:17 +0100530
531 //Flush header to stream.
532 fwrite(context_info_cper, sizeof(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO), 1, out);
533 fflush(out);
534
535 //Handle the register array, depending on type provided.
536 json_object* register_array = json_object_object_get(context_info, "registerArray");
Lawrence Tangaacf0e22022-07-20 13:28:52 +0100537 if (context_info_cper->RegisterType == EFI_REG_CONTEXT_TYPE_IA32)
Lawrence Tangd0c88842022-07-13 14:51:17 +0100538 {
Lawrence Tangaacf0e22022-07-20 13:28:52 +0100539 ir_ia32x64_ia32_registers_to_cper(register_array, out);
540 }
541 else if (context_info_cper->RegisterType == EFI_REG_CONTEXT_TYPE_X64)
542 {
543 ir_ia32x64_x64_registers_to_cper(register_array, out);
544 }
545 else
546 {
547 //Unknown/structure is not defined.
548 json_object* encoded = json_object_object_get(register_array, "data");
549 char* decoded = b64_decode(json_object_get_string(encoded), json_object_get_string_len(encoded));
550 fwrite(decoded, context_info_cper->ArraySize, 1, out);
551 fflush(out);
Lawrence Tangd0c88842022-07-13 14:51:17 +0100552 }
553
554 //Free remaining resources.
555 free(context_info_cper);
556}
557
558//Converts a single CPER-JSON IA32 register array into CPER binary, outputting to the given stream.
559void ir_ia32x64_ia32_registers_to_cper(json_object* registers, FILE* out)
560{
Lawrence Tangbd9a84a2022-07-13 15:41:16 +0100561 EFI_CONTEXT_IA32_REGISTER_STATE register_state;
562 register_state.Eax = (UINT32)json_object_get_uint64(json_object_object_get(registers, "eax"));
563 register_state.Ebx = (UINT32)json_object_get_uint64(json_object_object_get(registers, "ebx"));
564 register_state.Ecx = (UINT32)json_object_get_uint64(json_object_object_get(registers, "ecx"));
565 register_state.Edx = (UINT32)json_object_get_uint64(json_object_object_get(registers, "edx"));
566 register_state.Esi = (UINT32)json_object_get_uint64(json_object_object_get(registers, "esi"));
567 register_state.Edi = (UINT32)json_object_get_uint64(json_object_object_get(registers, "edi"));
568 register_state.Ebp = (UINT32)json_object_get_uint64(json_object_object_get(registers, "ebp"));
569 register_state.Esp = (UINT32)json_object_get_uint64(json_object_object_get(registers, "esp"));
Lawrence Tang04750a92022-07-20 16:45:11 +0100570 register_state.Cs = (UINT16)json_object_get_uint64(json_object_object_get(registers, "cs"));
Lawrence Tangbd9a84a2022-07-13 15:41:16 +0100571 register_state.Ds = (UINT32)json_object_get_uint64(json_object_object_get(registers, "ds"));
Lawrence Tang04750a92022-07-20 16:45:11 +0100572 register_state.Ss = (UINT16)json_object_get_uint64(json_object_object_get(registers, "ss"));
573 register_state.Es = (UINT16)json_object_get_uint64(json_object_object_get(registers, "es"));
574 register_state.Fs = (UINT16)json_object_get_uint64(json_object_object_get(registers, "fs"));
575 register_state.Gs = (UINT16)json_object_get_uint64(json_object_object_get(registers, "gs"));
Lawrence Tangbd9a84a2022-07-13 15:41:16 +0100576 register_state.Eflags = (UINT32)json_object_get_uint64(json_object_object_get(registers, "eflags"));
577 register_state.Eip = (UINT32)json_object_get_uint64(json_object_object_get(registers, "eip"));
578 register_state.Cr0 = (UINT32)json_object_get_uint64(json_object_object_get(registers, "cr0"));
579 register_state.Cr1 = (UINT32)json_object_get_uint64(json_object_object_get(registers, "cr1"));
580 register_state.Cr2 = (UINT32)json_object_get_uint64(json_object_object_get(registers, "cr2"));
581 register_state.Cr3 = (UINT32)json_object_get_uint64(json_object_object_get(registers, "cr3"));
582 register_state.Cr4 = (UINT32)json_object_get_uint64(json_object_object_get(registers, "cr4"));
583
584 //64-bit registers are split into two 32-bit parts.
585 UINT64 gdtr = json_object_get_uint64(json_object_object_get(registers, "gdtr"));
Lawrence Tang04750a92022-07-20 16:45:11 +0100586 register_state.Gdtr[0] = gdtr & 0xFFFFFFFF;
587 register_state.Gdtr[1] = gdtr >> 32;
Lawrence Tangbd9a84a2022-07-13 15:41:16 +0100588 UINT64 idtr = json_object_get_uint64(json_object_object_get(registers, "idtr"));
Lawrence Tang04750a92022-07-20 16:45:11 +0100589 register_state.Idtr[0] = idtr & 0xFFFFFFFF;
590 register_state.Idtr[1] = idtr >> 32;
Lawrence Tangbd9a84a2022-07-13 15:41:16 +0100591
592 //16-bit registers.
593 register_state.Ldtr = (UINT16)json_object_get_uint64(json_object_object_get(registers, "ldtr"));
594 register_state.Tr = (UINT16)json_object_get_uint64(json_object_object_get(registers, "tr"));
595
596 //Write out to stream.
597 fwrite(&register_state, sizeof(EFI_CONTEXT_IA32_REGISTER_STATE), 1, out);
598 fflush(out);
Lawrence Tangd0c88842022-07-13 14:51:17 +0100599}
600
601//Converts a single CPER-JSON x64 register array into CPER binary, outputting to the given stream.
602void ir_ia32x64_x64_registers_to_cper(json_object* registers, FILE* out)
603{
Lawrence Tangbd9a84a2022-07-13 15:41:16 +0100604 EFI_CONTEXT_X64_REGISTER_STATE register_state;
605 register_state.Rax = json_object_get_uint64(json_object_object_get(registers, "rax"));
606 register_state.Rbx = json_object_get_uint64(json_object_object_get(registers, "rbx"));
607 register_state.Rcx = json_object_get_uint64(json_object_object_get(registers, "rcx"));
608 register_state.Rdx = json_object_get_uint64(json_object_object_get(registers, "rdx"));
609 register_state.Rsi = json_object_get_uint64(json_object_object_get(registers, "rsi"));
610 register_state.Rdi = json_object_get_uint64(json_object_object_get(registers, "rdi"));
611 register_state.Rbp = json_object_get_uint64(json_object_object_get(registers, "rbp"));
612 register_state.Rsp = json_object_get_uint64(json_object_object_get(registers, "rsp"));
613 register_state.R8 = json_object_get_uint64(json_object_object_get(registers, "r8"));
614 register_state.R9 = json_object_get_uint64(json_object_object_get(registers, "r9"));
615 register_state.R10 = json_object_get_uint64(json_object_object_get(registers, "r10"));
616 register_state.R11 = json_object_get_uint64(json_object_object_get(registers, "r11"));
617 register_state.R12 = json_object_get_uint64(json_object_object_get(registers, "r12"));
618 register_state.R13 = json_object_get_uint64(json_object_object_get(registers, "r13"));
619 register_state.R14 = json_object_get_uint64(json_object_object_get(registers, "r14"));
620 register_state.R15 = json_object_get_uint64(json_object_object_get(registers, "r15"));
Lawrence Tang04750a92022-07-20 16:45:11 +0100621 register_state.Cs = (UINT16)json_object_get_int(json_object_object_get(registers, "cs"));
622 register_state.Ds = (UINT16)json_object_get_int(json_object_object_get(registers, "ds"));
623 register_state.Ss = (UINT16)json_object_get_int(json_object_object_get(registers, "ss"));
624 register_state.Es = (UINT16)json_object_get_int(json_object_object_get(registers, "es"));
625 register_state.Fs = (UINT16)json_object_get_int(json_object_object_get(registers, "fs"));
626 register_state.Gs = (UINT16)json_object_get_int(json_object_object_get(registers, "gs"));
627 register_state.Resv1 = 0;
Lawrence Tangbd9a84a2022-07-13 15:41:16 +0100628 register_state.Rflags = json_object_get_uint64(json_object_object_get(registers, "rflags"));
629 register_state.Rip = json_object_get_uint64(json_object_object_get(registers, "eip"));
630 register_state.Cr0 = json_object_get_uint64(json_object_object_get(registers, "cr0"));
631 register_state.Cr1 = json_object_get_uint64(json_object_object_get(registers, "cr1"));
632 register_state.Cr2 = json_object_get_uint64(json_object_object_get(registers, "cr2"));
633 register_state.Cr3 = json_object_get_uint64(json_object_object_get(registers, "cr3"));
634 register_state.Cr4 = json_object_get_uint64(json_object_object_get(registers, "cr4"));
635 register_state.Cr8 = json_object_get_uint64(json_object_object_get(registers, "cr8"));
636 register_state.Gdtr[0] = json_object_get_uint64(json_object_object_get(registers, "gdtr_0"));
637 register_state.Gdtr[1] = json_object_get_uint64(json_object_object_get(registers, "gdtr_1"));
638 register_state.Idtr[0] = json_object_get_uint64(json_object_object_get(registers, "idtr_0"));
639 register_state.Idtr[1] = json_object_get_uint64(json_object_object_get(registers, "idtr_1"));
Lawrence Tang04750a92022-07-20 16:45:11 +0100640 register_state.Ldtr = (UINT16)json_object_get_int(json_object_object_get(registers, "ldtr"));
641 register_state.Tr = (UINT16)json_object_get_int(json_object_object_get(registers, "tr"));
Lawrence Tangbd9a84a2022-07-13 15:41:16 +0100642
643 //Write out to stream.
Lawrence Tang04750a92022-07-20 16:45:11 +0100644 fwrite(&register_state, sizeof(EFI_CONTEXT_X64_REGISTER_STATE), 1, out);
Lawrence Tangbd9a84a2022-07-13 15:41:16 +0100645 fflush(out);
Lawrence Tang794312c2022-07-05 14:46:10 +0100646}