1f0f95574SLawrence Tang /** 2f0f95574SLawrence Tang * Describes functions for parsing JSON IR CPER data into binary CPER format. 3f0f95574SLawrence Tang * 4f0f95574SLawrence Tang * Author: Lawrence.Tang@arm.com 5f0f95574SLawrence Tang **/ 6f0f95574SLawrence Tang 7f0f95574SLawrence Tang #include <stdio.h> 80cb33793SLawrence Tang #include <string.h> 9f0f95574SLawrence Tang #include "json.h" 100cb33793SLawrence Tang #include "b64.h" 11b44314c7SLawrence Tang #include "edk/Cper.h" 12f0f95574SLawrence Tang #include "cper-parse.h" 13b44314c7SLawrence Tang #include "cper-utils.h" 140cb33793SLawrence Tang #include "sections/cper-section-generic.h" 150cb33793SLawrence Tang #include "sections/cper-section-ia32x64.h" 160cb33793SLawrence Tang #include "sections/cper-section-arm.h" 170cb33793SLawrence Tang #include "sections/cper-section-memory.h" 180cb33793SLawrence Tang #include "sections/cper-section-pcie.h" 190cb33793SLawrence Tang #include "sections/cper-section-pci-bus.h" 200cb33793SLawrence Tang #include "sections/cper-section-pci-dev.h" 210cb33793SLawrence Tang #include "sections/cper-section-firmware.h" 220cb33793SLawrence Tang #include "sections/cper-section-dmar-generic.h" 230cb33793SLawrence Tang #include "sections/cper-section-dmar-vtd.h" 240cb33793SLawrence Tang #include "sections/cper-section-dmar-iommu.h" 250cb33793SLawrence Tang #include "sections/cper-section-ccix-per.h" 260cb33793SLawrence Tang #include "sections/cper-section-cxl-protocol.h" 270cb33793SLawrence Tang #include "sections/cper-section-ipf.h" 280cb33793SLawrence Tang #include "sections/cper-section-cxl-component.h" 29b44314c7SLawrence Tang 30b44314c7SLawrence Tang //Private pre-declarations. 31b44314c7SLawrence Tang void ir_header_to_cper(json_object* header_ir, EFI_COMMON_ERROR_RECORD_HEADER* header); 320cb33793SLawrence Tang void ir_section_descriptor_to_cper(json_object* section_descriptor_ir, EFI_ERROR_SECTION_DESCRIPTOR* descriptor); 33f0f95574SLawrence Tang 34f0f95574SLawrence Tang //Converts the given JSON IR CPER representation into CPER binary format, piped to the provided file stream. 350cb33793SLawrence Tang //This function performs no validation of the IR against the CPER-JSON specification. To ensure a safe call, 360cb33793SLawrence Tang //use validate_schema() from json-schema.h before attempting to call this function. 37f0f95574SLawrence Tang void ir_to_cper(json_object* ir, FILE* out) 38f0f95574SLawrence Tang { 39b44314c7SLawrence Tang //Create the CPER header. 40b44314c7SLawrence Tang EFI_COMMON_ERROR_RECORD_HEADER* header = (EFI_COMMON_ERROR_RECORD_HEADER*)calloc(1, sizeof(EFI_COMMON_ERROR_RECORD_HEADER)); 41b44314c7SLawrence Tang ir_header_to_cper(json_object_object_get(ir, "header"), header); 42b44314c7SLawrence Tang fwrite(header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, out); 43b44314c7SLawrence Tang fflush(out); 440cb33793SLawrence Tang 450cb33793SLawrence Tang //Create the CPER section descriptors. 460cb33793SLawrence Tang json_object* section_descriptors = json_object_object_get(ir, "sectionDescriptors"); 470cb33793SLawrence Tang int amt_descriptors = json_object_array_length(section_descriptors); 480cb33793SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR* descriptors[amt_descriptors]; 490cb33793SLawrence Tang for (int i=0; i<amt_descriptors; i++) 500cb33793SLawrence Tang { 510cb33793SLawrence Tang descriptors[i] = (EFI_ERROR_SECTION_DESCRIPTOR*)calloc(1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR)); 520cb33793SLawrence Tang ir_section_descriptor_to_cper(json_object_array_get_idx(section_descriptors, i), descriptors[i]); 530cb33793SLawrence Tang fwrite(descriptors[i], sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1, out); 540cb33793SLawrence Tang fflush(out); 550cb33793SLawrence Tang } 560cb33793SLawrence Tang 570cb33793SLawrence Tang //Run through each section in turn. 580cb33793SLawrence Tang json_object* sections = json_object_object_get(ir, "sections"); 590cb33793SLawrence Tang int amt_sections = json_object_array_length(sections); 600cb33793SLawrence Tang for (int i=0; i<amt_sections; i++) 610cb33793SLawrence Tang { 620cb33793SLawrence Tang //Get the section itself from the IR. 630cb33793SLawrence Tang json_object* section = json_object_array_get_idx(sections, i); 640cb33793SLawrence Tang 650cb33793SLawrence Tang //Find the correct section type, and parse. 660cb33793SLawrence Tang if (guid_equal(&descriptors[i]->SectionType, &gEfiProcessorGenericErrorSectionGuid)) 670cb33793SLawrence Tang ir_section_generic_to_cper(section, out); 68d0c88849SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, &gEfiIa32X64ProcessorErrorSectionGuid)) 69d0c88849SLawrence Tang ir_section_ia32x64_to_cper(section, out); 700cb33793SLawrence Tang // else if (guid_equal(&descriptors[i]->SectionType, &gEfiIpfProcessorErrorSectionGuid)) 710cb33793SLawrence Tang // ir_section_ipf_to_cper(section, out); 7271570a2aSLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, &gEfiArmProcessorErrorSectionGuid)) 7371570a2aSLawrence Tang ir_section_arm_to_cper(section, out); 743b7f45b5SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, &gEfiPlatformMemoryErrorSectionGuid)) 753b7f45b5SLawrence Tang ir_section_memory_to_cper(section, out); 763b7f45b5SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, &gEfiPlatformMemoryError2SectionGuid)) 773b7f45b5SLawrence Tang ir_section_memory2_to_cper(section, out); 783b7f45b5SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, &gEfiPcieErrorSectionGuid)) 793b7f45b5SLawrence Tang ir_section_pcie_to_cper(section, out); 80205dd1d7SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, &gEfiFirmwareErrorSectionGuid)) 81205dd1d7SLawrence Tang ir_section_firmware_to_cper(section, out); 82205dd1d7SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, &gEfiPciBusErrorSectionGuid)) 83205dd1d7SLawrence Tang ir_section_pci_bus_to_cper(section, out); 84205dd1d7SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, &gEfiPciDevErrorSectionGuid)) 85205dd1d7SLawrence Tang ir_section_pci_dev_to_cper(section, out); 86205dd1d7SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, &gEfiDMArGenericErrorSectionGuid)) 87205dd1d7SLawrence Tang ir_section_dmar_generic_to_cper(section, out); 88205dd1d7SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, &gEfiDirectedIoDMArErrorSectionGuid)) 89205dd1d7SLawrence Tang ir_section_dmar_vtd_to_cper(section, out); 90205dd1d7SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, &gEfiIommuDMArErrorSectionGuid)) 91205dd1d7SLawrence Tang ir_section_dmar_iommu_to_cper(section, out); 92*aec83900SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, &gEfiCcixPerLogErrorSectionGuid)) 93*aec83900SLawrence Tang ir_section_ccix_per_to_cper(section, out); 94*aec83900SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, &gEfiCxlProtocolErrorSectionGuid)) 95*aec83900SLawrence Tang ir_section_cxl_protocol_to_cper(section, out); 96*aec83900SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, &gEfiCxlGeneralMediaErrorSectionGuid) 97*aec83900SLawrence Tang || guid_equal(&descriptors[i]->SectionType, &gEfiCxlDramEventErrorSectionGuid) 98*aec83900SLawrence Tang || guid_equal(&descriptors[i]->SectionType, &gEfiCxlPhysicalSwitchErrorSectionGuid) 99*aec83900SLawrence Tang || guid_equal(&descriptors[i]->SectionType, &gEfiCxlVirtualSwitchErrorSectionGuid) 100*aec83900SLawrence Tang || guid_equal(&descriptors[i]->SectionType, &gEfiCxlMldPortErrorSectionGuid)) 101*aec83900SLawrence Tang { 102*aec83900SLawrence Tang ir_section_cxl_component_to_cper(section, out); 103*aec83900SLawrence Tang } 1040cb33793SLawrence Tang else 1050cb33793SLawrence Tang { 1060cb33793SLawrence Tang //Unknown GUID, so read as a base64 unknown section. 1070cb33793SLawrence Tang json_object* encoded = json_object_object_get(section, "data"); 1080cb33793SLawrence Tang UINT8* decoded = b64_decode(json_object_get_string(encoded), json_object_get_string_len(encoded)); 1090cb33793SLawrence Tang fwrite(decoded, descriptors[i]->SectionLength, 1, out); 1100cb33793SLawrence Tang fflush(out); 1110cb33793SLawrence Tang free(decoded); 1120cb33793SLawrence Tang } 1130cb33793SLawrence Tang } 1140cb33793SLawrence Tang 1150cb33793SLawrence Tang //Free all remaining resources. 116b44314c7SLawrence Tang free(header); 1170cb33793SLawrence Tang for (int i=0; i<amt_descriptors; i++) 1180cb33793SLawrence Tang free(descriptors[i]); 119b44314c7SLawrence Tang } 120b44314c7SLawrence Tang 121b44314c7SLawrence Tang //Converts a CPER-JSON IR header to a CPER header structure. 122b44314c7SLawrence Tang void ir_header_to_cper(json_object* header_ir, EFI_COMMON_ERROR_RECORD_HEADER* header) 123b44314c7SLawrence Tang { 124b44314c7SLawrence Tang header->SignatureStart = 0x52455043; //CPER 125b44314c7SLawrence Tang 126b44314c7SLawrence Tang //Revision. 127b44314c7SLawrence Tang json_object* revision = json_object_object_get(header_ir, "revision"); 128b44314c7SLawrence Tang int minor = json_object_get_int(json_object_object_get(revision, "minor")); 129b44314c7SLawrence Tang int major = json_object_get_int(json_object_object_get(revision, "major")); 130b44314c7SLawrence Tang header->Revision = minor + (major << 8); 131b44314c7SLawrence Tang 132b44314c7SLawrence Tang header->SignatureEnd = 0xFFFFFFFF; 133b44314c7SLawrence Tang 134b44314c7SLawrence Tang //Section count. 135b44314c7SLawrence Tang int section_count = json_object_get_int(json_object_object_get(header_ir, "sectionCount")); 136b44314c7SLawrence Tang header->SectionCount = (UINT16)section_count; 137b44314c7SLawrence Tang 138b44314c7SLawrence Tang //Error severity. 139b44314c7SLawrence Tang json_object* severity = json_object_object_get(header_ir, "severity"); 140b44314c7SLawrence Tang header->ErrorSeverity = (UINT32)json_object_get_uint64(json_object_object_get(severity, "code")); 141b44314c7SLawrence Tang 142b44314c7SLawrence Tang //Validation bits. 143b44314c7SLawrence Tang header->ValidationBits = ir_to_bitfield(json_object_object_get(header_ir, "validationBits"), 144b44314c7SLawrence Tang 3, CPER_HEADER_VALID_BITFIELD_NAMES); 145b44314c7SLawrence Tang 146b44314c7SLawrence Tang //Record length. 147b44314c7SLawrence Tang header->RecordLength = (UINT32)json_object_get_uint64(json_object_object_get(header_ir, "recordLength")); 148b44314c7SLawrence Tang 149b44314c7SLawrence Tang //Timestamp, if present. 150b44314c7SLawrence Tang json_object* timestamp = json_object_object_get(header_ir, "timestamp"); 151b44314c7SLawrence Tang if (timestamp != NULL) 152b44314c7SLawrence Tang { 153b44314c7SLawrence Tang string_to_timestamp(&header->TimeStamp, json_object_get_string(timestamp)); 154b44314c7SLawrence Tang header->TimeStamp.Flag = json_object_get_boolean(json_object_object_get(header_ir, "timestampIsPrecise")); 155b44314c7SLawrence Tang } 156b44314c7SLawrence Tang 157b44314c7SLawrence Tang //Various GUIDs. 158b44314c7SLawrence Tang json_object* platform_id = json_object_object_get(header_ir, "platformID"); 159b44314c7SLawrence Tang json_object* partition_id = json_object_object_get(header_ir, "partitionID"); 160b44314c7SLawrence Tang if (platform_id != NULL) 161b44314c7SLawrence Tang string_to_guid(&header->PlatformID, json_object_get_string(platform_id)); 162b44314c7SLawrence Tang if (partition_id != NULL) 163b44314c7SLawrence Tang string_to_guid(&header->PartitionID, json_object_get_string(partition_id)); 164b44314c7SLawrence Tang string_to_guid(&header->CreatorID, json_object_get_string(json_object_object_get(header_ir, "creatorID"))); 165b44314c7SLawrence Tang 166b44314c7SLawrence Tang //Notification type. 167b44314c7SLawrence Tang json_object* notification_type = json_object_object_get(header_ir, "notificationType"); 168b44314c7SLawrence Tang string_to_guid(&header->NotificationType, json_object_get_string(json_object_object_get(notification_type, "guid"))); 169b44314c7SLawrence Tang 170b44314c7SLawrence Tang //Record ID, persistence info. 171b44314c7SLawrence Tang header->RecordID = json_object_get_uint64(json_object_object_get(header_ir, "recordID")); 172b44314c7SLawrence Tang header->PersistenceInfo = json_object_get_uint64(json_object_object_get(header_ir, "persistenceInfo")); 173b44314c7SLawrence Tang 174b44314c7SLawrence Tang //Flags. 175b44314c7SLawrence Tang json_object* flags = json_object_object_get(header_ir, "flags"); 176b44314c7SLawrence Tang header->Flags = (UINT32)json_object_get_uint64(json_object_object_get(flags, "value")); 177f0f95574SLawrence Tang } 1780cb33793SLawrence Tang 1790cb33793SLawrence Tang //Converts a single CPER-JSON IR section descriptor into a CPER structure. 1800cb33793SLawrence Tang void ir_section_descriptor_to_cper(json_object* section_descriptor_ir, EFI_ERROR_SECTION_DESCRIPTOR* descriptor) 1810cb33793SLawrence Tang { 1820cb33793SLawrence Tang //Section offset, length. 1830cb33793SLawrence Tang descriptor->SectionOffset = (UINT32)json_object_get_uint64(json_object_object_get(section_descriptor_ir, "sectionOffset")); 1840cb33793SLawrence Tang descriptor->SectionLength = (UINT32)json_object_get_uint64(json_object_object_get(section_descriptor_ir, "sectionLength")); 1850cb33793SLawrence Tang 1860cb33793SLawrence Tang //Revision. 1870cb33793SLawrence Tang json_object* revision = json_object_object_get(section_descriptor_ir, "revision"); 1880cb33793SLawrence Tang int minor = json_object_get_int(json_object_object_get(revision, "minor")); 1890cb33793SLawrence Tang int major = json_object_get_int(json_object_object_get(revision, "major")); 1900cb33793SLawrence Tang descriptor->Revision = minor + (major << 8); 1910cb33793SLawrence Tang 1920cb33793SLawrence Tang //Validation bits, flags. 1930cb33793SLawrence Tang descriptor->SecValidMask = ir_to_bitfield(json_object_object_get(section_descriptor_ir, "validationBits"), 1940cb33793SLawrence Tang 2, CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES); 1950cb33793SLawrence Tang descriptor->SectionFlags = ir_to_bitfield(json_object_object_get(section_descriptor_ir, "flags"), 1960cb33793SLawrence Tang 8, CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES); 1970cb33793SLawrence Tang 1980cb33793SLawrence Tang //Section type. 1990cb33793SLawrence Tang json_object* section_type = json_object_object_get(section_descriptor_ir, "sectionType"); 2000cb33793SLawrence Tang string_to_guid(&descriptor->SectionType, json_object_get_string(json_object_object_get(section_type, "data"))); 2010cb33793SLawrence Tang 2020cb33793SLawrence Tang //FRU ID, if present. 2030cb33793SLawrence Tang json_object* fru_id = json_object_object_get(section_descriptor_ir, "fruID"); 2040cb33793SLawrence Tang if (fru_id != NULL) 2050cb33793SLawrence Tang string_to_guid(&descriptor->FruId, json_object_get_string(fru_id)); 2060cb33793SLawrence Tang 2070cb33793SLawrence Tang //Severity code. 2080cb33793SLawrence Tang json_object* severity = json_object_object_get(section_descriptor_ir, "severity"); 2090cb33793SLawrence Tang descriptor->Severity = (UINT32)json_object_get_uint64(json_object_object_get(severity, "code")); 2100cb33793SLawrence Tang 2110cb33793SLawrence Tang //FRU text, if present. 2120cb33793SLawrence Tang json_object* fru_text = json_object_object_get(section_descriptor_ir, "fruText"); 2130cb33793SLawrence Tang if (fru_text != NULL) 2140cb33793SLawrence Tang strncpy(descriptor->FruString, json_object_get_string(fru_text), 20); 2150cb33793SLawrence Tang }