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