blob: b6333963e1133c0a1bf482870939866028fdcc14 [file] [log] [blame]
/**
* Describes functions for converting NVIDIA CPER sections from binary and JSON format
* into an intermediate format.
**/
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <json.h>
#include <libcper/Cper.h>
#include <libcper/cper-utils.h>
#include <libcper/sections/cper-section-nvidia.h>
#include <libcper/log.h>
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);
}