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> 9*5202bbb4SLawrence 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. 31e407b4c8SLawrence Tang void ir_header_to_cper(json_object *header_ir, 32e407b4c8SLawrence Tang EFI_COMMON_ERROR_RECORD_HEADER *header); 33e407b4c8SLawrence Tang void ir_section_descriptor_to_cper(json_object *section_descriptor_ir, 34e407b4c8SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptor); 35617949e4SLawrence Tang void ir_section_to_cper(json_object *section, 36617949e4SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptor, FILE *out); 37f0f95574SLawrence Tang 38f0f95574SLawrence Tang //Converts the given JSON IR CPER representation into CPER binary format, piped to the provided file stream. 390cb33793SLawrence Tang //This function performs no validation of the IR against the CPER-JSON specification. To ensure a safe call, 400cb33793SLawrence Tang //use validate_schema() from json-schema.h before attempting to call this function. 41f0f95574SLawrence Tang void ir_to_cper(json_object *ir, FILE *out) 42f0f95574SLawrence Tang { 43b44314c7SLawrence Tang //Create the CPER header. 44e407b4c8SLawrence Tang EFI_COMMON_ERROR_RECORD_HEADER *header = 45e407b4c8SLawrence Tang (EFI_COMMON_ERROR_RECORD_HEADER *)calloc( 46e407b4c8SLawrence Tang 1, sizeof(EFI_COMMON_ERROR_RECORD_HEADER)); 47b44314c7SLawrence Tang ir_header_to_cper(json_object_object_get(ir, "header"), header); 48b44314c7SLawrence Tang fwrite(header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, out); 49b44314c7SLawrence Tang fflush(out); 500cb33793SLawrence Tang 510cb33793SLawrence Tang //Create the CPER section descriptors. 52e407b4c8SLawrence Tang json_object *section_descriptors = 53e407b4c8SLawrence Tang json_object_object_get(ir, "sectionDescriptors"); 540cb33793SLawrence Tang int amt_descriptors = json_object_array_length(section_descriptors); 550cb33793SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptors[amt_descriptors]; 56e407b4c8SLawrence Tang for (int i = 0; i < amt_descriptors; i++) { 57e407b4c8SLawrence Tang descriptors[i] = (EFI_ERROR_SECTION_DESCRIPTOR *)calloc( 58e407b4c8SLawrence Tang 1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR)); 59e407b4c8SLawrence Tang ir_section_descriptor_to_cper( 60e407b4c8SLawrence Tang json_object_array_get_idx(section_descriptors, i), 61e407b4c8SLawrence Tang descriptors[i]); 62e407b4c8SLawrence Tang fwrite(descriptors[i], sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1, 63e407b4c8SLawrence Tang out); 640cb33793SLawrence Tang fflush(out); 650cb33793SLawrence Tang } 660cb33793SLawrence Tang 670cb33793SLawrence Tang //Run through each section in turn. 680cb33793SLawrence Tang json_object *sections = json_object_object_get(ir, "sections"); 690cb33793SLawrence Tang int amt_sections = json_object_array_length(sections); 70e407b4c8SLawrence Tang for (int i = 0; i < amt_sections; i++) { 710cb33793SLawrence Tang //Get the section itself from the IR. 720cb33793SLawrence Tang json_object *section = json_object_array_get_idx(sections, i); 730cb33793SLawrence Tang 74617949e4SLawrence Tang //Convert. 75617949e4SLawrence Tang ir_section_to_cper(section, descriptors[i], out); 760cb33793SLawrence Tang } 770cb33793SLawrence Tang 780cb33793SLawrence Tang //Free all remaining resources. 79b44314c7SLawrence Tang free(header); 800cb33793SLawrence Tang for (int i = 0; i < amt_descriptors; i++) 810cb33793SLawrence Tang free(descriptors[i]); 82b44314c7SLawrence Tang } 83b44314c7SLawrence Tang 84b44314c7SLawrence Tang //Converts a CPER-JSON IR header to a CPER header structure. 85e407b4c8SLawrence Tang void ir_header_to_cper(json_object *header_ir, 86e407b4c8SLawrence Tang EFI_COMMON_ERROR_RECORD_HEADER *header) 87b44314c7SLawrence Tang { 88b44314c7SLawrence Tang header->SignatureStart = 0x52455043; //CPER 89b44314c7SLawrence Tang 90b44314c7SLawrence Tang //Revision. 91b44314c7SLawrence Tang json_object *revision = json_object_object_get(header_ir, "revision"); 92e407b4c8SLawrence Tang int minor = 93e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "minor")); 94e407b4c8SLawrence Tang int major = 95e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "major")); 96b44314c7SLawrence Tang header->Revision = minor + (major << 8); 97b44314c7SLawrence Tang 98b44314c7SLawrence Tang header->SignatureEnd = 0xFFFFFFFF; 99b44314c7SLawrence Tang 100b44314c7SLawrence Tang //Section count. 101e407b4c8SLawrence Tang int section_count = json_object_get_int( 102e407b4c8SLawrence Tang json_object_object_get(header_ir, "sectionCount")); 103b44314c7SLawrence Tang header->SectionCount = (UINT16)section_count; 104b44314c7SLawrence Tang 105b44314c7SLawrence Tang //Error severity. 106b44314c7SLawrence Tang json_object *severity = json_object_object_get(header_ir, "severity"); 107e407b4c8SLawrence Tang header->ErrorSeverity = (UINT32)json_object_get_uint64( 108e407b4c8SLawrence Tang json_object_object_get(severity, "code")); 109b44314c7SLawrence Tang 110b44314c7SLawrence Tang //Validation bits. 111e407b4c8SLawrence Tang header->ValidationBits = ir_to_bitfield( 112e407b4c8SLawrence Tang json_object_object_get(header_ir, "validationBits"), 3, 113e407b4c8SLawrence Tang CPER_HEADER_VALID_BITFIELD_NAMES); 114b44314c7SLawrence Tang 115b44314c7SLawrence Tang //Record length. 116e407b4c8SLawrence Tang header->RecordLength = (UINT32)json_object_get_uint64( 117e407b4c8SLawrence Tang json_object_object_get(header_ir, "recordLength")); 118b44314c7SLawrence Tang 119b44314c7SLawrence Tang //Timestamp, if present. 120b44314c7SLawrence Tang json_object *timestamp = json_object_object_get(header_ir, "timestamp"); 121e407b4c8SLawrence Tang if (timestamp != NULL) { 122e407b4c8SLawrence Tang string_to_timestamp(&header->TimeStamp, 123e407b4c8SLawrence Tang json_object_get_string(timestamp)); 124e407b4c8SLawrence Tang header->TimeStamp.Flag = json_object_get_boolean( 125e407b4c8SLawrence Tang json_object_object_get(header_ir, 126e407b4c8SLawrence Tang "timestampIsPrecise")); 127b44314c7SLawrence Tang } 128b44314c7SLawrence Tang 129b44314c7SLawrence Tang //Various GUIDs. 130e407b4c8SLawrence Tang json_object *platform_id = 131e407b4c8SLawrence Tang json_object_object_get(header_ir, "platformID"); 132e407b4c8SLawrence Tang json_object *partition_id = 133e407b4c8SLawrence Tang json_object_object_get(header_ir, "partitionID"); 134b44314c7SLawrence Tang if (platform_id != NULL) 135e407b4c8SLawrence Tang string_to_guid(&header->PlatformID, 136e407b4c8SLawrence Tang json_object_get_string(platform_id)); 137b44314c7SLawrence Tang if (partition_id != NULL) 138e407b4c8SLawrence Tang string_to_guid(&header->PartitionID, 139e407b4c8SLawrence Tang json_object_get_string(partition_id)); 140e407b4c8SLawrence Tang string_to_guid(&header->CreatorID, 141e407b4c8SLawrence Tang json_object_get_string( 142e407b4c8SLawrence Tang json_object_object_get(header_ir, "creatorID"))); 143b44314c7SLawrence Tang 144b44314c7SLawrence Tang //Notification type. 145e407b4c8SLawrence Tang json_object *notification_type = 146e407b4c8SLawrence Tang json_object_object_get(header_ir, "notificationType"); 147e407b4c8SLawrence Tang string_to_guid(&header->NotificationType, 148e407b4c8SLawrence Tang json_object_get_string(json_object_object_get( 149e407b4c8SLawrence Tang notification_type, "guid"))); 150b44314c7SLawrence Tang 151b44314c7SLawrence Tang //Record ID, persistence info. 152e407b4c8SLawrence Tang header->RecordID = json_object_get_uint64( 153e407b4c8SLawrence Tang json_object_object_get(header_ir, "recordID")); 154e407b4c8SLawrence Tang header->PersistenceInfo = json_object_get_uint64( 155e407b4c8SLawrence Tang json_object_object_get(header_ir, "persistenceInfo")); 156b44314c7SLawrence Tang 157b44314c7SLawrence Tang //Flags. 158b44314c7SLawrence Tang json_object *flags = json_object_object_get(header_ir, "flags"); 159e407b4c8SLawrence Tang header->Flags = (UINT32)json_object_get_uint64( 160e407b4c8SLawrence Tang json_object_object_get(flags, "value")); 161f0f95574SLawrence Tang } 1620cb33793SLawrence Tang 163617949e4SLawrence Tang //Converts a single given IR section into CPER, outputting to the given stream. 164617949e4SLawrence Tang void ir_section_to_cper(json_object *section, 165617949e4SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptor, FILE *out) 166617949e4SLawrence Tang { 167617949e4SLawrence Tang //Find the correct section type, and parse. 168617949e4SLawrence Tang if (guid_equal(&descriptor->SectionType, 169617949e4SLawrence Tang &gEfiProcessorGenericErrorSectionGuid)) 170617949e4SLawrence Tang ir_section_generic_to_cper(section, out); 171617949e4SLawrence Tang else if (guid_equal(&descriptor->SectionType, 172617949e4SLawrence Tang &gEfiIa32X64ProcessorErrorSectionGuid)) 173617949e4SLawrence Tang ir_section_ia32x64_to_cper(section, out); 174617949e4SLawrence Tang // else if (guid_equal(&descriptor->SectionType, &gEfiIpfProcessorErrorSectionGuid)) 175617949e4SLawrence Tang // ir_section_ipf_to_cper(section, out); 176617949e4SLawrence Tang else if (guid_equal(&descriptor->SectionType, 177617949e4SLawrence Tang &gEfiArmProcessorErrorSectionGuid)) 178617949e4SLawrence Tang ir_section_arm_to_cper(section, out); 179617949e4SLawrence Tang else if (guid_equal(&descriptor->SectionType, 180617949e4SLawrence Tang &gEfiPlatformMemoryErrorSectionGuid)) 181617949e4SLawrence Tang ir_section_memory_to_cper(section, out); 182617949e4SLawrence Tang else if (guid_equal(&descriptor->SectionType, 183617949e4SLawrence Tang &gEfiPlatformMemoryError2SectionGuid)) 184617949e4SLawrence Tang ir_section_memory2_to_cper(section, out); 185617949e4SLawrence Tang else if (guid_equal(&descriptor->SectionType, 186617949e4SLawrence Tang &gEfiPcieErrorSectionGuid)) 187617949e4SLawrence Tang ir_section_pcie_to_cper(section, out); 188617949e4SLawrence Tang else if (guid_equal(&descriptor->SectionType, 189617949e4SLawrence Tang &gEfiFirmwareErrorSectionGuid)) 190617949e4SLawrence Tang ir_section_firmware_to_cper(section, out); 191617949e4SLawrence Tang else if (guid_equal(&descriptor->SectionType, 192617949e4SLawrence Tang &gEfiPciBusErrorSectionGuid)) 193617949e4SLawrence Tang ir_section_pci_bus_to_cper(section, out); 194617949e4SLawrence Tang else if (guid_equal(&descriptor->SectionType, 195617949e4SLawrence Tang &gEfiPciDevErrorSectionGuid)) 196617949e4SLawrence Tang ir_section_pci_dev_to_cper(section, out); 197617949e4SLawrence Tang else if (guid_equal(&descriptor->SectionType, 198617949e4SLawrence Tang &gEfiDMArGenericErrorSectionGuid)) 199617949e4SLawrence Tang ir_section_dmar_generic_to_cper(section, out); 200617949e4SLawrence Tang else if (guid_equal(&descriptor->SectionType, 201617949e4SLawrence Tang &gEfiDirectedIoDMArErrorSectionGuid)) 202617949e4SLawrence Tang ir_section_dmar_vtd_to_cper(section, out); 203617949e4SLawrence Tang else if (guid_equal(&descriptor->SectionType, 204617949e4SLawrence Tang &gEfiIommuDMArErrorSectionGuid)) 205617949e4SLawrence Tang ir_section_dmar_iommu_to_cper(section, out); 206617949e4SLawrence Tang else if (guid_equal(&descriptor->SectionType, 207617949e4SLawrence Tang &gEfiCcixPerLogErrorSectionGuid)) 208617949e4SLawrence Tang ir_section_ccix_per_to_cper(section, out); 209617949e4SLawrence Tang else if (guid_equal(&descriptor->SectionType, 210617949e4SLawrence Tang &gEfiCxlProtocolErrorSectionGuid)) 211617949e4SLawrence Tang ir_section_cxl_protocol_to_cper(section, out); 212617949e4SLawrence Tang else if (guid_equal(&descriptor->SectionType, 213617949e4SLawrence Tang &gEfiCxlGeneralMediaErrorSectionGuid) || 214617949e4SLawrence Tang guid_equal(&descriptor->SectionType, 215617949e4SLawrence Tang &gEfiCxlDramEventErrorSectionGuid) || 216617949e4SLawrence Tang guid_equal(&descriptor->SectionType, 217617949e4SLawrence Tang &gEfiCxlPhysicalSwitchErrorSectionGuid) || 218617949e4SLawrence Tang guid_equal(&descriptor->SectionType, 219617949e4SLawrence Tang &gEfiCxlVirtualSwitchErrorSectionGuid) || 220617949e4SLawrence Tang guid_equal(&descriptor->SectionType, 221617949e4SLawrence Tang &gEfiCxlMldPortErrorSectionGuid)) { 222617949e4SLawrence Tang ir_section_cxl_component_to_cper(section, out); 223617949e4SLawrence Tang } else { 224617949e4SLawrence Tang //Unknown GUID, so read as a base64 unknown section. 225617949e4SLawrence Tang json_object *encoded = json_object_object_get(section, "data"); 226617949e4SLawrence Tang UINT8 *decoded = 227617949e4SLawrence Tang b64_decode(json_object_get_string(encoded), 228617949e4SLawrence Tang json_object_get_string_len(encoded)); 229617949e4SLawrence Tang fwrite(decoded, descriptor->SectionLength, 1, out); 230617949e4SLawrence Tang fflush(out); 231617949e4SLawrence Tang free(decoded); 232617949e4SLawrence Tang } 233617949e4SLawrence Tang } 234617949e4SLawrence Tang 2350cb33793SLawrence Tang //Converts a single CPER-JSON IR section descriptor into a CPER structure. 236e407b4c8SLawrence Tang void ir_section_descriptor_to_cper(json_object *section_descriptor_ir, 237e407b4c8SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptor) 2380cb33793SLawrence Tang { 2390cb33793SLawrence Tang //Section offset, length. 240e407b4c8SLawrence Tang descriptor->SectionOffset = (UINT32)json_object_get_uint64( 241e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionOffset")); 242e407b4c8SLawrence Tang descriptor->SectionLength = (UINT32)json_object_get_uint64( 243e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionLength")); 2440cb33793SLawrence Tang 2450cb33793SLawrence Tang //Revision. 246e407b4c8SLawrence Tang json_object *revision = 247e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "revision"); 248e407b4c8SLawrence Tang int minor = 249e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "minor")); 250e407b4c8SLawrence Tang int major = 251e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "major")); 2520cb33793SLawrence Tang descriptor->Revision = minor + (major << 8); 2530cb33793SLawrence Tang 2540cb33793SLawrence Tang //Validation bits, flags. 255e407b4c8SLawrence Tang descriptor->SecValidMask = ir_to_bitfield( 256e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "validationBits"), 2570cb33793SLawrence Tang 2, CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES); 258e407b4c8SLawrence Tang descriptor->SectionFlags = ir_to_bitfield( 259e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "flags"), 8, 260e407b4c8SLawrence Tang CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES); 2610cb33793SLawrence Tang 2620cb33793SLawrence Tang //Section type. 263e407b4c8SLawrence Tang json_object *section_type = 264e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionType"); 265e407b4c8SLawrence Tang string_to_guid(&descriptor->SectionType, 266e407b4c8SLawrence Tang json_object_get_string( 267e407b4c8SLawrence Tang json_object_object_get(section_type, "data"))); 2680cb33793SLawrence Tang 2690cb33793SLawrence Tang //FRU ID, if present. 270e407b4c8SLawrence Tang json_object *fru_id = 271e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "fruID"); 2720cb33793SLawrence Tang if (fru_id != NULL) 273e407b4c8SLawrence Tang string_to_guid(&descriptor->FruId, 274e407b4c8SLawrence Tang json_object_get_string(fru_id)); 2750cb33793SLawrence Tang 2760cb33793SLawrence Tang //Severity code. 277e407b4c8SLawrence Tang json_object *severity = 278e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "severity"); 279e407b4c8SLawrence Tang descriptor->Severity = (UINT32)json_object_get_uint64( 280e407b4c8SLawrence Tang json_object_object_get(severity, "code")); 2810cb33793SLawrence Tang 2820cb33793SLawrence Tang //FRU text, if present. 283e407b4c8SLawrence Tang json_object *fru_text = 284e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "fruText"); 2850cb33793SLawrence Tang if (fru_text != NULL) 286e407b4c8SLawrence Tang strncpy(descriptor->FruString, json_object_get_string(fru_text), 287e407b4c8SLawrence Tang 20); 2880cb33793SLawrence Tang } 289617949e4SLawrence Tang 290617949e4SLawrence Tang //Converts IR for a given single section format CPER record into CPER binary. 291617949e4SLawrence Tang void ir_single_section_to_cper(json_object *ir, FILE *out) 292617949e4SLawrence Tang { 293617949e4SLawrence Tang //Create & write a section descriptor to file. 294617949e4SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *section_descriptor = 295617949e4SLawrence Tang (EFI_ERROR_SECTION_DESCRIPTOR *)calloc( 296617949e4SLawrence Tang 1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR)); 297617949e4SLawrence Tang ir_section_descriptor_to_cper( 298617949e4SLawrence Tang json_object_object_get(ir, "sectionDescriptor"), 299617949e4SLawrence Tang section_descriptor); 300617949e4SLawrence Tang fwrite(section_descriptor, sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1, 301617949e4SLawrence Tang out); 302617949e4SLawrence Tang fflush(out); 303617949e4SLawrence Tang 304617949e4SLawrence Tang //Write section to file. 305617949e4SLawrence Tang ir_section_to_cper(json_object_object_get(ir, "section"), 306617949e4SLawrence Tang section_descriptor, out); 307617949e4SLawrence Tang 308617949e4SLawrence Tang //Free remaining resources. 309617949e4SLawrence Tang free(section_descriptor); 310617949e4SLawrence Tang }