blob: 82904b5633a9db6ae1589efe47d97f845b1dd9f3 [file] [log] [blame]
/**
* Describes functions for parsing JSON IR CPER data into binary CPER format.
*
* Author: Lawrence.Tang@arm.com
**/
#include <stdio.h>
#include <string.h>
#include "json.h"
#include "b64.h"
#include "edk/Cper.h"
#include "cper-parse.h"
#include "cper-utils.h"
#include "sections/cper-section-generic.h"
#include "sections/cper-section-ia32x64.h"
#include "sections/cper-section-arm.h"
#include "sections/cper-section-memory.h"
#include "sections/cper-section-pcie.h"
#include "sections/cper-section-pci-bus.h"
#include "sections/cper-section-pci-dev.h"
#include "sections/cper-section-firmware.h"
#include "sections/cper-section-dmar-generic.h"
#include "sections/cper-section-dmar-vtd.h"
#include "sections/cper-section-dmar-iommu.h"
#include "sections/cper-section-ccix-per.h"
#include "sections/cper-section-cxl-protocol.h"
#include "sections/cper-section-ipf.h"
#include "sections/cper-section-cxl-component.h"
//Private pre-declarations.
void ir_header_to_cper(json_object* header_ir, EFI_COMMON_ERROR_RECORD_HEADER* header);
void ir_section_descriptor_to_cper(json_object* section_descriptor_ir, EFI_ERROR_SECTION_DESCRIPTOR* descriptor);
//Converts the given JSON IR CPER representation into CPER binary format, piped to the provided file stream.
//This function performs no validation of the IR against the CPER-JSON specification. To ensure a safe call,
//use validate_schema() from json-schema.h before attempting to call this function.
void ir_to_cper(json_object* ir, FILE* out)
{
//Create the CPER header.
EFI_COMMON_ERROR_RECORD_HEADER* header = (EFI_COMMON_ERROR_RECORD_HEADER*)calloc(1, sizeof(EFI_COMMON_ERROR_RECORD_HEADER));
ir_header_to_cper(json_object_object_get(ir, "header"), header);
fwrite(header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, out);
fflush(out);
//Create the CPER section descriptors.
json_object* section_descriptors = json_object_object_get(ir, "sectionDescriptors");
int amt_descriptors = json_object_array_length(section_descriptors);
EFI_ERROR_SECTION_DESCRIPTOR* descriptors[amt_descriptors];
for (int i=0; i<amt_descriptors; i++)
{
descriptors[i] = (EFI_ERROR_SECTION_DESCRIPTOR*)calloc(1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR));
ir_section_descriptor_to_cper(json_object_array_get_idx(section_descriptors, i), descriptors[i]);
fwrite(descriptors[i], sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1, out);
fflush(out);
}
//Run through each section in turn.
json_object* sections = json_object_object_get(ir, "sections");
int amt_sections = json_object_array_length(sections);
for (int i=0; i<amt_sections; i++)
{
//Get the section itself from the IR.
json_object* section = json_object_array_get_idx(sections, i);
//Find the correct section type, and parse.
if (guid_equal(&descriptors[i]->SectionType, &gEfiProcessorGenericErrorSectionGuid))
ir_section_generic_to_cper(section, out);
else if (guid_equal(&descriptors[i]->SectionType, &gEfiIa32X64ProcessorErrorSectionGuid))
ir_section_ia32x64_to_cper(section, out);
// else if (guid_equal(&descriptors[i]->SectionType, &gEfiIpfProcessorErrorSectionGuid))
// ir_section_ipf_to_cper(section, out);
else if (guid_equal(&descriptors[i]->SectionType, &gEfiArmProcessorErrorSectionGuid))
ir_section_arm_to_cper(section, out);
else if (guid_equal(&descriptors[i]->SectionType, &gEfiPlatformMemoryErrorSectionGuid))
ir_section_memory_to_cper(section, out);
else if (guid_equal(&descriptors[i]->SectionType, &gEfiPlatformMemoryError2SectionGuid))
ir_section_memory2_to_cper(section, out);
else if (guid_equal(&descriptors[i]->SectionType, &gEfiPcieErrorSectionGuid))
ir_section_pcie_to_cper(section, out);
else if (guid_equal(&descriptors[i]->SectionType, &gEfiFirmwareErrorSectionGuid))
ir_section_firmware_to_cper(section, out);
else if (guid_equal(&descriptors[i]->SectionType, &gEfiPciBusErrorSectionGuid))
ir_section_pci_bus_to_cper(section, out);
else if (guid_equal(&descriptors[i]->SectionType, &gEfiPciDevErrorSectionGuid))
ir_section_pci_dev_to_cper(section, out);
else if (guid_equal(&descriptors[i]->SectionType, &gEfiDMArGenericErrorSectionGuid))
ir_section_dmar_generic_to_cper(section, out);
else if (guid_equal(&descriptors[i]->SectionType, &gEfiDirectedIoDMArErrorSectionGuid))
ir_section_dmar_vtd_to_cper(section, out);
else if (guid_equal(&descriptors[i]->SectionType, &gEfiIommuDMArErrorSectionGuid))
ir_section_dmar_iommu_to_cper(section, out);
else if (guid_equal(&descriptors[i]->SectionType, &gEfiCcixPerLogErrorSectionGuid))
ir_section_ccix_per_to_cper(section, out);
else if (guid_equal(&descriptors[i]->SectionType, &gEfiCxlProtocolErrorSectionGuid))
ir_section_cxl_protocol_to_cper(section, out);
else if (guid_equal(&descriptors[i]->SectionType, &gEfiCxlGeneralMediaErrorSectionGuid)
|| guid_equal(&descriptors[i]->SectionType, &gEfiCxlDramEventErrorSectionGuid)
|| guid_equal(&descriptors[i]->SectionType, &gEfiCxlPhysicalSwitchErrorSectionGuid)
|| guid_equal(&descriptors[i]->SectionType, &gEfiCxlVirtualSwitchErrorSectionGuid)
|| guid_equal(&descriptors[i]->SectionType, &gEfiCxlMldPortErrorSectionGuid))
{
ir_section_cxl_component_to_cper(section, out);
}
else
{
//Unknown GUID, so read as a base64 unknown section.
json_object* encoded = json_object_object_get(section, "data");
UINT8* decoded = b64_decode(json_object_get_string(encoded), json_object_get_string_len(encoded));
fwrite(decoded, descriptors[i]->SectionLength, 1, out);
fflush(out);
free(decoded);
}
}
//Free all remaining resources.
free(header);
for (int i=0; i<amt_descriptors; i++)
free(descriptors[i]);
}
//Converts a CPER-JSON IR header to a CPER header structure.
void ir_header_to_cper(json_object* header_ir, EFI_COMMON_ERROR_RECORD_HEADER* header)
{
header->SignatureStart = 0x52455043; //CPER
//Revision.
json_object* revision = json_object_object_get(header_ir, "revision");
int minor = json_object_get_int(json_object_object_get(revision, "minor"));
int major = json_object_get_int(json_object_object_get(revision, "major"));
header->Revision = minor + (major << 8);
header->SignatureEnd = 0xFFFFFFFF;
//Section count.
int section_count = json_object_get_int(json_object_object_get(header_ir, "sectionCount"));
header->SectionCount = (UINT16)section_count;
//Error severity.
json_object* severity = json_object_object_get(header_ir, "severity");
header->ErrorSeverity = (UINT32)json_object_get_uint64(json_object_object_get(severity, "code"));
//Validation bits.
header->ValidationBits = ir_to_bitfield(json_object_object_get(header_ir, "validationBits"),
3, CPER_HEADER_VALID_BITFIELD_NAMES);
//Record length.
header->RecordLength = (UINT32)json_object_get_uint64(json_object_object_get(header_ir, "recordLength"));
//Timestamp, if present.
json_object* timestamp = json_object_object_get(header_ir, "timestamp");
if (timestamp != NULL)
{
string_to_timestamp(&header->TimeStamp, json_object_get_string(timestamp));
header->TimeStamp.Flag = json_object_get_boolean(json_object_object_get(header_ir, "timestampIsPrecise"));
}
//Various GUIDs.
json_object* platform_id = json_object_object_get(header_ir, "platformID");
json_object* partition_id = json_object_object_get(header_ir, "partitionID");
if (platform_id != NULL)
string_to_guid(&header->PlatformID, json_object_get_string(platform_id));
if (partition_id != NULL)
string_to_guid(&header->PartitionID, json_object_get_string(partition_id));
string_to_guid(&header->CreatorID, json_object_get_string(json_object_object_get(header_ir, "creatorID")));
//Notification type.
json_object* notification_type = json_object_object_get(header_ir, "notificationType");
string_to_guid(&header->NotificationType, json_object_get_string(json_object_object_get(notification_type, "guid")));
//Record ID, persistence info.
header->RecordID = json_object_get_uint64(json_object_object_get(header_ir, "recordID"));
header->PersistenceInfo = json_object_get_uint64(json_object_object_get(header_ir, "persistenceInfo"));
//Flags.
json_object* flags = json_object_object_get(header_ir, "flags");
header->Flags = (UINT32)json_object_get_uint64(json_object_object_get(flags, "value"));
}
//Converts a single CPER-JSON IR section descriptor into a CPER structure.
void ir_section_descriptor_to_cper(json_object* section_descriptor_ir, EFI_ERROR_SECTION_DESCRIPTOR* descriptor)
{
//Section offset, length.
descriptor->SectionOffset = (UINT32)json_object_get_uint64(json_object_object_get(section_descriptor_ir, "sectionOffset"));
descriptor->SectionLength = (UINT32)json_object_get_uint64(json_object_object_get(section_descriptor_ir, "sectionLength"));
//Revision.
json_object* revision = json_object_object_get(section_descriptor_ir, "revision");
int minor = json_object_get_int(json_object_object_get(revision, "minor"));
int major = json_object_get_int(json_object_object_get(revision, "major"));
descriptor->Revision = minor + (major << 8);
//Validation bits, flags.
descriptor->SecValidMask = ir_to_bitfield(json_object_object_get(section_descriptor_ir, "validationBits"),
2, CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES);
descriptor->SectionFlags = ir_to_bitfield(json_object_object_get(section_descriptor_ir, "flags"),
8, CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES);
//Section type.
json_object* section_type = json_object_object_get(section_descriptor_ir, "sectionType");
string_to_guid(&descriptor->SectionType, json_object_get_string(json_object_object_get(section_type, "data")));
//FRU ID, if present.
json_object* fru_id = json_object_object_get(section_descriptor_ir, "fruID");
if (fru_id != NULL)
string_to_guid(&descriptor->FruId, json_object_get_string(fru_id));
//Severity code.
json_object* severity = json_object_object_get(section_descriptor_ir, "severity");
descriptor->Severity = (UINT32)json_object_get_uint64(json_object_object_get(severity, "code"));
//FRU text, if present.
json_object* fru_text = json_object_object_get(section_descriptor_ir, "fruText");
if (fru_text != NULL)
strncpy(descriptor->FruString, json_object_get_string(fru_text), 20);
}