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. 31*e407b4c8SLawrence Tang void ir_header_to_cper(json_object *header_ir, 32*e407b4c8SLawrence Tang EFI_COMMON_ERROR_RECORD_HEADER *header); 33*e407b4c8SLawrence Tang void ir_section_descriptor_to_cper(json_object *section_descriptor_ir, 34*e407b4c8SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptor); 35f0f95574SLawrence Tang 36f0f95574SLawrence Tang //Converts the given JSON IR CPER representation into CPER binary format, piped to the provided file stream. 370cb33793SLawrence Tang //This function performs no validation of the IR against the CPER-JSON specification. To ensure a safe call, 380cb33793SLawrence Tang //use validate_schema() from json-schema.h before attempting to call this function. 39f0f95574SLawrence Tang void ir_to_cper(json_object *ir, FILE *out) 40f0f95574SLawrence Tang { 41b44314c7SLawrence Tang //Create the CPER header. 42*e407b4c8SLawrence Tang EFI_COMMON_ERROR_RECORD_HEADER *header = 43*e407b4c8SLawrence Tang (EFI_COMMON_ERROR_RECORD_HEADER *)calloc( 44*e407b4c8SLawrence Tang 1, sizeof(EFI_COMMON_ERROR_RECORD_HEADER)); 45b44314c7SLawrence Tang ir_header_to_cper(json_object_object_get(ir, "header"), header); 46b44314c7SLawrence Tang fwrite(header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, out); 47b44314c7SLawrence Tang fflush(out); 480cb33793SLawrence Tang 490cb33793SLawrence Tang //Create the CPER section descriptors. 50*e407b4c8SLawrence Tang json_object *section_descriptors = 51*e407b4c8SLawrence Tang json_object_object_get(ir, "sectionDescriptors"); 520cb33793SLawrence Tang int amt_descriptors = json_object_array_length(section_descriptors); 530cb33793SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptors[amt_descriptors]; 54*e407b4c8SLawrence Tang for (int i = 0; i < amt_descriptors; i++) { 55*e407b4c8SLawrence Tang descriptors[i] = (EFI_ERROR_SECTION_DESCRIPTOR *)calloc( 56*e407b4c8SLawrence Tang 1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR)); 57*e407b4c8SLawrence Tang ir_section_descriptor_to_cper( 58*e407b4c8SLawrence Tang json_object_array_get_idx(section_descriptors, i), 59*e407b4c8SLawrence Tang descriptors[i]); 60*e407b4c8SLawrence Tang fwrite(descriptors[i], sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1, 61*e407b4c8SLawrence Tang out); 620cb33793SLawrence Tang fflush(out); 630cb33793SLawrence Tang } 640cb33793SLawrence Tang 650cb33793SLawrence Tang //Run through each section in turn. 660cb33793SLawrence Tang json_object *sections = json_object_object_get(ir, "sections"); 670cb33793SLawrence Tang int amt_sections = json_object_array_length(sections); 68*e407b4c8SLawrence Tang for (int i = 0; i < amt_sections; i++) { 690cb33793SLawrence Tang //Get the section itself from the IR. 700cb33793SLawrence Tang json_object *section = json_object_array_get_idx(sections, i); 710cb33793SLawrence Tang 720cb33793SLawrence Tang //Find the correct section type, and parse. 73*e407b4c8SLawrence Tang if (guid_equal(&descriptors[i]->SectionType, 74*e407b4c8SLawrence Tang &gEfiProcessorGenericErrorSectionGuid)) 750cb33793SLawrence Tang ir_section_generic_to_cper(section, out); 76*e407b4c8SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, 77*e407b4c8SLawrence Tang &gEfiIa32X64ProcessorErrorSectionGuid)) 78d0c88849SLawrence Tang ir_section_ia32x64_to_cper(section, out); 790cb33793SLawrence Tang // else if (guid_equal(&descriptors[i]->SectionType, &gEfiIpfProcessorErrorSectionGuid)) 800cb33793SLawrence Tang // ir_section_ipf_to_cper(section, out); 81*e407b4c8SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, 82*e407b4c8SLawrence Tang &gEfiArmProcessorErrorSectionGuid)) 8371570a2aSLawrence Tang ir_section_arm_to_cper(section, out); 84*e407b4c8SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, 85*e407b4c8SLawrence Tang &gEfiPlatformMemoryErrorSectionGuid)) 863b7f45b5SLawrence Tang ir_section_memory_to_cper(section, out); 87*e407b4c8SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, 88*e407b4c8SLawrence Tang &gEfiPlatformMemoryError2SectionGuid)) 893b7f45b5SLawrence Tang ir_section_memory2_to_cper(section, out); 90*e407b4c8SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, 91*e407b4c8SLawrence Tang &gEfiPcieErrorSectionGuid)) 923b7f45b5SLawrence Tang ir_section_pcie_to_cper(section, out); 93*e407b4c8SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, 94*e407b4c8SLawrence Tang &gEfiFirmwareErrorSectionGuid)) 95205dd1d7SLawrence Tang ir_section_firmware_to_cper(section, out); 96*e407b4c8SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, 97*e407b4c8SLawrence Tang &gEfiPciBusErrorSectionGuid)) 98205dd1d7SLawrence Tang ir_section_pci_bus_to_cper(section, out); 99*e407b4c8SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, 100*e407b4c8SLawrence Tang &gEfiPciDevErrorSectionGuid)) 101205dd1d7SLawrence Tang ir_section_pci_dev_to_cper(section, out); 102*e407b4c8SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, 103*e407b4c8SLawrence Tang &gEfiDMArGenericErrorSectionGuid)) 104205dd1d7SLawrence Tang ir_section_dmar_generic_to_cper(section, out); 105*e407b4c8SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, 106*e407b4c8SLawrence Tang &gEfiDirectedIoDMArErrorSectionGuid)) 107205dd1d7SLawrence Tang ir_section_dmar_vtd_to_cper(section, out); 108*e407b4c8SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, 109*e407b4c8SLawrence Tang &gEfiIommuDMArErrorSectionGuid)) 110205dd1d7SLawrence Tang ir_section_dmar_iommu_to_cper(section, out); 111*e407b4c8SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, 112*e407b4c8SLawrence Tang &gEfiCcixPerLogErrorSectionGuid)) 113aec83900SLawrence Tang ir_section_ccix_per_to_cper(section, out); 114*e407b4c8SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, 115*e407b4c8SLawrence Tang &gEfiCxlProtocolErrorSectionGuid)) 116aec83900SLawrence Tang ir_section_cxl_protocol_to_cper(section, out); 117*e407b4c8SLawrence Tang else if (guid_equal(&descriptors[i]->SectionType, 118*e407b4c8SLawrence Tang &gEfiCxlGeneralMediaErrorSectionGuid) || 119*e407b4c8SLawrence Tang guid_equal(&descriptors[i]->SectionType, 120*e407b4c8SLawrence Tang &gEfiCxlDramEventErrorSectionGuid) || 121*e407b4c8SLawrence Tang guid_equal(&descriptors[i]->SectionType, 122*e407b4c8SLawrence Tang &gEfiCxlPhysicalSwitchErrorSectionGuid) || 123*e407b4c8SLawrence Tang guid_equal(&descriptors[i]->SectionType, 124*e407b4c8SLawrence Tang &gEfiCxlVirtualSwitchErrorSectionGuid) || 125*e407b4c8SLawrence Tang guid_equal(&descriptors[i]->SectionType, 126*e407b4c8SLawrence Tang &gEfiCxlMldPortErrorSectionGuid)) { 127aec83900SLawrence Tang ir_section_cxl_component_to_cper(section, out); 128*e407b4c8SLawrence Tang } else { 1290cb33793SLawrence Tang //Unknown GUID, so read as a base64 unknown section. 130*e407b4c8SLawrence Tang json_object *encoded = 131*e407b4c8SLawrence Tang json_object_object_get(section, "data"); 132*e407b4c8SLawrence Tang UINT8 *decoded = 133*e407b4c8SLawrence Tang b64_decode(json_object_get_string(encoded), 134*e407b4c8SLawrence Tang json_object_get_string_len(encoded)); 1350cb33793SLawrence Tang fwrite(decoded, descriptors[i]->SectionLength, 1, out); 1360cb33793SLawrence Tang fflush(out); 1370cb33793SLawrence Tang free(decoded); 1380cb33793SLawrence Tang } 1390cb33793SLawrence Tang } 1400cb33793SLawrence Tang 1410cb33793SLawrence Tang //Free all remaining resources. 142b44314c7SLawrence Tang free(header); 1430cb33793SLawrence Tang for (int i = 0; i < amt_descriptors; i++) 1440cb33793SLawrence Tang free(descriptors[i]); 145b44314c7SLawrence Tang } 146b44314c7SLawrence Tang 147b44314c7SLawrence Tang //Converts a CPER-JSON IR header to a CPER header structure. 148*e407b4c8SLawrence Tang void ir_header_to_cper(json_object *header_ir, 149*e407b4c8SLawrence Tang EFI_COMMON_ERROR_RECORD_HEADER *header) 150b44314c7SLawrence Tang { 151b44314c7SLawrence Tang header->SignatureStart = 0x52455043; //CPER 152b44314c7SLawrence Tang 153b44314c7SLawrence Tang //Revision. 154b44314c7SLawrence Tang json_object *revision = json_object_object_get(header_ir, "revision"); 155*e407b4c8SLawrence Tang int minor = 156*e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "minor")); 157*e407b4c8SLawrence Tang int major = 158*e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "major")); 159b44314c7SLawrence Tang header->Revision = minor + (major << 8); 160b44314c7SLawrence Tang 161b44314c7SLawrence Tang header->SignatureEnd = 0xFFFFFFFF; 162b44314c7SLawrence Tang 163b44314c7SLawrence Tang //Section count. 164*e407b4c8SLawrence Tang int section_count = json_object_get_int( 165*e407b4c8SLawrence Tang json_object_object_get(header_ir, "sectionCount")); 166b44314c7SLawrence Tang header->SectionCount = (UINT16)section_count; 167b44314c7SLawrence Tang 168b44314c7SLawrence Tang //Error severity. 169b44314c7SLawrence Tang json_object *severity = json_object_object_get(header_ir, "severity"); 170*e407b4c8SLawrence Tang header->ErrorSeverity = (UINT32)json_object_get_uint64( 171*e407b4c8SLawrence Tang json_object_object_get(severity, "code")); 172b44314c7SLawrence Tang 173b44314c7SLawrence Tang //Validation bits. 174*e407b4c8SLawrence Tang header->ValidationBits = ir_to_bitfield( 175*e407b4c8SLawrence Tang json_object_object_get(header_ir, "validationBits"), 3, 176*e407b4c8SLawrence Tang CPER_HEADER_VALID_BITFIELD_NAMES); 177b44314c7SLawrence Tang 178b44314c7SLawrence Tang //Record length. 179*e407b4c8SLawrence Tang header->RecordLength = (UINT32)json_object_get_uint64( 180*e407b4c8SLawrence Tang json_object_object_get(header_ir, "recordLength")); 181b44314c7SLawrence Tang 182b44314c7SLawrence Tang //Timestamp, if present. 183b44314c7SLawrence Tang json_object *timestamp = json_object_object_get(header_ir, "timestamp"); 184*e407b4c8SLawrence Tang if (timestamp != NULL) { 185*e407b4c8SLawrence Tang string_to_timestamp(&header->TimeStamp, 186*e407b4c8SLawrence Tang json_object_get_string(timestamp)); 187*e407b4c8SLawrence Tang header->TimeStamp.Flag = json_object_get_boolean( 188*e407b4c8SLawrence Tang json_object_object_get(header_ir, 189*e407b4c8SLawrence Tang "timestampIsPrecise")); 190b44314c7SLawrence Tang } 191b44314c7SLawrence Tang 192b44314c7SLawrence Tang //Various GUIDs. 193*e407b4c8SLawrence Tang json_object *platform_id = 194*e407b4c8SLawrence Tang json_object_object_get(header_ir, "platformID"); 195*e407b4c8SLawrence Tang json_object *partition_id = 196*e407b4c8SLawrence Tang json_object_object_get(header_ir, "partitionID"); 197b44314c7SLawrence Tang if (platform_id != NULL) 198*e407b4c8SLawrence Tang string_to_guid(&header->PlatformID, 199*e407b4c8SLawrence Tang json_object_get_string(platform_id)); 200b44314c7SLawrence Tang if (partition_id != NULL) 201*e407b4c8SLawrence Tang string_to_guid(&header->PartitionID, 202*e407b4c8SLawrence Tang json_object_get_string(partition_id)); 203*e407b4c8SLawrence Tang string_to_guid(&header->CreatorID, 204*e407b4c8SLawrence Tang json_object_get_string( 205*e407b4c8SLawrence Tang json_object_object_get(header_ir, "creatorID"))); 206b44314c7SLawrence Tang 207b44314c7SLawrence Tang //Notification type. 208*e407b4c8SLawrence Tang json_object *notification_type = 209*e407b4c8SLawrence Tang json_object_object_get(header_ir, "notificationType"); 210*e407b4c8SLawrence Tang string_to_guid(&header->NotificationType, 211*e407b4c8SLawrence Tang json_object_get_string(json_object_object_get( 212*e407b4c8SLawrence Tang notification_type, "guid"))); 213b44314c7SLawrence Tang 214b44314c7SLawrence Tang //Record ID, persistence info. 215*e407b4c8SLawrence Tang header->RecordID = json_object_get_uint64( 216*e407b4c8SLawrence Tang json_object_object_get(header_ir, "recordID")); 217*e407b4c8SLawrence Tang header->PersistenceInfo = json_object_get_uint64( 218*e407b4c8SLawrence Tang json_object_object_get(header_ir, "persistenceInfo")); 219b44314c7SLawrence Tang 220b44314c7SLawrence Tang //Flags. 221b44314c7SLawrence Tang json_object *flags = json_object_object_get(header_ir, "flags"); 222*e407b4c8SLawrence Tang header->Flags = (UINT32)json_object_get_uint64( 223*e407b4c8SLawrence Tang json_object_object_get(flags, "value")); 224f0f95574SLawrence Tang } 2250cb33793SLawrence Tang 2260cb33793SLawrence Tang //Converts a single CPER-JSON IR section descriptor into a CPER structure. 227*e407b4c8SLawrence Tang void ir_section_descriptor_to_cper(json_object *section_descriptor_ir, 228*e407b4c8SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptor) 2290cb33793SLawrence Tang { 2300cb33793SLawrence Tang //Section offset, length. 231*e407b4c8SLawrence Tang descriptor->SectionOffset = (UINT32)json_object_get_uint64( 232*e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionOffset")); 233*e407b4c8SLawrence Tang descriptor->SectionLength = (UINT32)json_object_get_uint64( 234*e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionLength")); 2350cb33793SLawrence Tang 2360cb33793SLawrence Tang //Revision. 237*e407b4c8SLawrence Tang json_object *revision = 238*e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "revision"); 239*e407b4c8SLawrence Tang int minor = 240*e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "minor")); 241*e407b4c8SLawrence Tang int major = 242*e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "major")); 2430cb33793SLawrence Tang descriptor->Revision = minor + (major << 8); 2440cb33793SLawrence Tang 2450cb33793SLawrence Tang //Validation bits, flags. 246*e407b4c8SLawrence Tang descriptor->SecValidMask = ir_to_bitfield( 247*e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "validationBits"), 2480cb33793SLawrence Tang 2, CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES); 249*e407b4c8SLawrence Tang descriptor->SectionFlags = ir_to_bitfield( 250*e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "flags"), 8, 251*e407b4c8SLawrence Tang CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES); 2520cb33793SLawrence Tang 2530cb33793SLawrence Tang //Section type. 254*e407b4c8SLawrence Tang json_object *section_type = 255*e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionType"); 256*e407b4c8SLawrence Tang string_to_guid(&descriptor->SectionType, 257*e407b4c8SLawrence Tang json_object_get_string( 258*e407b4c8SLawrence Tang json_object_object_get(section_type, "data"))); 2590cb33793SLawrence Tang 2600cb33793SLawrence Tang //FRU ID, if present. 261*e407b4c8SLawrence Tang json_object *fru_id = 262*e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "fruID"); 2630cb33793SLawrence Tang if (fru_id != NULL) 264*e407b4c8SLawrence Tang string_to_guid(&descriptor->FruId, 265*e407b4c8SLawrence Tang json_object_get_string(fru_id)); 2660cb33793SLawrence Tang 2670cb33793SLawrence Tang //Severity code. 268*e407b4c8SLawrence Tang json_object *severity = 269*e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "severity"); 270*e407b4c8SLawrence Tang descriptor->Severity = (UINT32)json_object_get_uint64( 271*e407b4c8SLawrence Tang json_object_object_get(severity, "code")); 2720cb33793SLawrence Tang 2730cb33793SLawrence Tang //FRU text, if present. 274*e407b4c8SLawrence Tang json_object *fru_text = 275*e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "fruText"); 2760cb33793SLawrence Tang if (fru_text != NULL) 277*e407b4c8SLawrence Tang strncpy(descriptor->FruString, json_object_get_string(fru_text), 278*e407b4c8SLawrence Tang 20); 2790cb33793SLawrence Tang }