/** * Describes functions for converting NVIDIA CPER sections from binary and JSON format * into an intermediate format. **/ #include #include #include #include #include #include #include #include void parse_cmet_info(EFI_NVIDIA_REGISTER_DATA *regPtr, UINT8 NumberRegs, size_t size, json_object *section_ir) { json_object *regarr = json_object_new_array(); for (int i = 0; i < NumberRegs; i++, regPtr++) { json_object *reg = NULL; if (sizeof(EFI_NVIDIA_ERROR_DATA) + i * sizeof(EFI_NVIDIA_REGISTER_DATA) < size) { reg = json_object_new_object(); add_int_hex_64(reg, "ChannelAddress", regPtr->Address); add_int(reg, "ErrorCount", regPtr->CmetInfo.ErrorCount); add_bool(reg, "ChannelEnabled", regPtr->CmetInfo.ChannelEnabled); add_bool(reg, "ChannelIsSpare", regPtr->CmetInfo.ChannelIsSpare); add_dict(reg, "DisabledReason", regPtr->CmetInfo.DisabledReason, channel_disable_reason_dict, channel_disable_reason_dict_size); } else { reg = json_object_new_null(); } json_object_array_add(regarr, reg); } json_object_object_add(section_ir, "CMETInfo", regarr); } void parse_fwerror(EFI_NVIDIA_REGISTER_DATA *regPtr, UINT8 NumberRegs, size_t size, json_object *section_ir) { (void)NumberRegs; json_object *fwinfo; if (sizeof(EFI_NVIDIA_ERROR_DATA) + sizeof(EFI_NVIDIA_FWERROR) > size) { fwinfo = json_object_new_null(); } else { fwinfo = json_object_new_object(); EFI_NVIDIA_FWERROR *fwerror = (EFI_NVIDIA_FWERROR *)regPtr; add_untrusted_string(fwinfo, "initiating_firmware", fwerror->initiating_firmware, sizeof(fwerror->initiating_firmware)); add_int_hex_64(fwinfo, "task_checkpoint", fwerror->task_checkpoint); add_int_hex_64(fwinfo, "mb1_error_code", fwerror->mb1_error_code); add_untrusted_string(fwinfo, "mb1_version_string", fwerror->mb1_version_string, sizeof(fwerror->mb1_version_string)); add_int_hex_64(fwinfo, "bad_pages_retired_mask", fwerror->bad_pages_retired_mask); add_int_hex_64(fwinfo, "training_or_alias_check_retired_mask", fwerror->training_or_alias_check_retired_mask); } json_object_object_add(section_ir, "FWErrorInfo", fwinfo); } void parse_registers(EFI_NVIDIA_REGISTER_DATA *regPtr, UINT8 NumberRegs, size_t size, json_object *section_ir) { // Registers (Address Value pairs). json_object *regarr = json_object_new_array(); for (int i = 0; i < NumberRegs; i++, regPtr++) { json_object *reg = NULL; if (sizeof(EFI_NVIDIA_ERROR_DATA) + i * sizeof(EFI_NVIDIA_REGISTER_DATA) < size) { reg = json_object_new_object(); json_object_object_add( reg, "address", json_object_new_uint64(regPtr->Address)); json_object_object_add( reg, "value", json_object_new_uint64(regPtr->Value)); } else { reg = json_object_new_null(); } json_object_array_add(regarr, reg); } json_object_object_add(section_ir, "registers", regarr); } typedef struct { const char *ip_signature; void (*callback)(EFI_NVIDIA_REGISTER_DATA *, UINT8, size_t, json_object *); } NV_SECTION_CALLBACKS; NV_SECTION_CALLBACKS section_handlers[] = { { "CMET-INFO\0", &parse_cmet_info }, { "FWERROR\0", &parse_fwerror }, { "", &parse_registers }, }; //Converts a single NVIDIA CPER section into JSON IR. json_object *cper_section_nvidia_to_ir(const UINT8 *section, UINT32 size) { if (size < sizeof(EFI_NVIDIA_ERROR_DATA)) { return NULL; } EFI_NVIDIA_ERROR_DATA *nvidia_error = (EFI_NVIDIA_ERROR_DATA *)section; json_object *section_ir = json_object_new_object(); add_untrusted_string(section_ir, "signature", nvidia_error->Signature, sizeof(nvidia_error->Signature)); json_object *severity = json_object_new_object(); json_object_object_add(severity, "code", json_object_new_uint64(nvidia_error->Severity)); json_object_object_add(severity, "name", json_object_new_string(severity_to_string( nvidia_error->Severity))); json_object_object_add(section_ir, "severity", severity); json_object_object_add(section_ir, "errorType", json_object_new_int(nvidia_error->ErrorType)); json_object_object_add( section_ir, "errorInstance", json_object_new_int(nvidia_error->ErrorInstance)); json_object_object_add(section_ir, "socket", json_object_new_int(nvidia_error->Socket)); json_object_object_add(section_ir, "registerCount", json_object_new_int(nvidia_error->NumberRegs)); json_object_object_add( section_ir, "instanceBase", json_object_new_uint64(nvidia_error->InstanceBase)); for (long unsigned int i = 0; i < sizeof(section_handlers) / sizeof(section_handlers[0]); i++) { const char *ip_signature = section_handlers[i].ip_signature; if (strncmp(nvidia_error->Signature, ip_signature, strlen(ip_signature)) == 0) { section_handlers[i].callback(&nvidia_error->Register[0], nvidia_error->NumberRegs, size, section_ir); break; } } return section_ir; } //Converts a single NVIDIA CPER-JSON section into CPER binary, outputting to the given stream. void ir_section_nvidia_to_cper(json_object *section, FILE *out) { json_object *regarr = json_object_object_get(section, "registers"); int numRegs = json_object_array_length(regarr); size_t section_sz = offsetof(EFI_NVIDIA_ERROR_DATA, Register) + numRegs * sizeof(EFI_NVIDIA_REGISTER_DATA); EFI_NVIDIA_ERROR_DATA *section_cper = (EFI_NVIDIA_ERROR_DATA *)calloc(1, section_sz); //Signature. strncpy(section_cper->Signature, json_object_get_string( json_object_object_get(section, "signature")), sizeof(section_cper->Signature) - 1); section_cper->Signature[sizeof(section_cper->Signature) - 1] = '\0'; //Fields. section_cper->ErrorType = json_object_get_int( json_object_object_get(section, "errorType")); section_cper->ErrorInstance = json_object_get_int( json_object_object_get(section, "errorInstance")); json_object *severity = json_object_object_get(section, "severity"); section_cper->Severity = (UINT8)json_object_get_uint64( json_object_object_get(severity, "code")); section_cper->Socket = json_object_get_int(json_object_object_get(section, "socket")); section_cper->NumberRegs = json_object_get_int( json_object_object_get(section, "registerCount")); section_cper->InstanceBase = json_object_get_uint64( json_object_object_get(section, "instanceBase")); // Registers (Address Value pairs). EFI_NVIDIA_REGISTER_DATA *regPtr = section_cper->Register; for (int i = 0; i < numRegs; i++, regPtr++) { json_object *reg = json_object_array_get_idx(regarr, i); regPtr->Address = json_object_get_uint64( json_object_object_get(reg, "address")); regPtr->Value = json_object_get_uint64( json_object_object_get(reg, "value")); } //Write to stream, free resources. fwrite(section_cper, section_sz, 1, out); fflush(out); free(section_cper); }