1 /** 2 * Describes functions for parsing JSON IR CPER data into binary CPER format. 3 * 4 * Author: Lawrence.Tang@arm.com 5 **/ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include "json.h" 10 #include "b64.h" 11 #include "edk/Cper.h" 12 #include "cper-parse.h" 13 #include "cper-utils.h" 14 #include "sections/cper-section-generic.h" 15 #include "sections/cper-section-ia32x64.h" 16 #include "sections/cper-section-arm.h" 17 #include "sections/cper-section-memory.h" 18 #include "sections/cper-section-pcie.h" 19 #include "sections/cper-section-pci-bus.h" 20 #include "sections/cper-section-pci-dev.h" 21 #include "sections/cper-section-firmware.h" 22 #include "sections/cper-section-dmar-generic.h" 23 #include "sections/cper-section-dmar-vtd.h" 24 #include "sections/cper-section-dmar-iommu.h" 25 #include "sections/cper-section-ccix-per.h" 26 #include "sections/cper-section-cxl-protocol.h" 27 #include "sections/cper-section-ipf.h" 28 #include "sections/cper-section-cxl-component.h" 29 30 //Private pre-declarations. 31 void ir_header_to_cper(json_object* header_ir, EFI_COMMON_ERROR_RECORD_HEADER* header); 32 void ir_section_descriptor_to_cper(json_object* section_descriptor_ir, EFI_ERROR_SECTION_DESCRIPTOR* descriptor); 33 34 //Converts the given JSON IR CPER representation into CPER binary format, piped to the provided file stream. 35 //This function performs no validation of the IR against the CPER-JSON specification. To ensure a safe call, 36 //use validate_schema() from json-schema.h before attempting to call this function. 37 void ir_to_cper(json_object* ir, FILE* out) 38 { 39 //Create the CPER header. 40 EFI_COMMON_ERROR_RECORD_HEADER* header = (EFI_COMMON_ERROR_RECORD_HEADER*)calloc(1, sizeof(EFI_COMMON_ERROR_RECORD_HEADER)); 41 ir_header_to_cper(json_object_object_get(ir, "header"), header); 42 fwrite(header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, out); 43 fflush(out); 44 45 //Create the CPER section descriptors. 46 json_object* section_descriptors = json_object_object_get(ir, "sectionDescriptors"); 47 int amt_descriptors = json_object_array_length(section_descriptors); 48 EFI_ERROR_SECTION_DESCRIPTOR* descriptors[amt_descriptors]; 49 for (int i=0; i<amt_descriptors; i++) 50 { 51 descriptors[i] = (EFI_ERROR_SECTION_DESCRIPTOR*)calloc(1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR)); 52 ir_section_descriptor_to_cper(json_object_array_get_idx(section_descriptors, i), descriptors[i]); 53 fwrite(descriptors[i], sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1, out); 54 fflush(out); 55 } 56 57 //Run through each section in turn. 58 json_object* sections = json_object_object_get(ir, "sections"); 59 int amt_sections = json_object_array_length(sections); 60 for (int i=0; i<amt_sections; i++) 61 { 62 //Get the section itself from the IR. 63 json_object* section = json_object_array_get_idx(sections, i); 64 65 //Find the correct section type, and parse. 66 if (guid_equal(&descriptors[i]->SectionType, &gEfiProcessorGenericErrorSectionGuid)) 67 ir_section_generic_to_cper(section, out); 68 else if (guid_equal(&descriptors[i]->SectionType, &gEfiIa32X64ProcessorErrorSectionGuid)) 69 ir_section_ia32x64_to_cper(section, out); 70 // else if (guid_equal(&descriptors[i]->SectionType, &gEfiIpfProcessorErrorSectionGuid)) 71 // ir_section_ipf_to_cper(section, out); 72 else if (guid_equal(&descriptors[i]->SectionType, &gEfiArmProcessorErrorSectionGuid)) 73 ir_section_arm_to_cper(section, out); 74 else if (guid_equal(&descriptors[i]->SectionType, &gEfiPlatformMemoryErrorSectionGuid)) 75 ir_section_memory_to_cper(section, out); 76 else if (guid_equal(&descriptors[i]->SectionType, &gEfiPlatformMemoryError2SectionGuid)) 77 ir_section_memory2_to_cper(section, out); 78 else if (guid_equal(&descriptors[i]->SectionType, &gEfiPcieErrorSectionGuid)) 79 ir_section_pcie_to_cper(section, out); 80 else if (guid_equal(&descriptors[i]->SectionType, &gEfiFirmwareErrorSectionGuid)) 81 ir_section_firmware_to_cper(section, out); 82 else if (guid_equal(&descriptors[i]->SectionType, &gEfiPciBusErrorSectionGuid)) 83 ir_section_pci_bus_to_cper(section, out); 84 else if (guid_equal(&descriptors[i]->SectionType, &gEfiPciDevErrorSectionGuid)) 85 ir_section_pci_dev_to_cper(section, out); 86 else if (guid_equal(&descriptors[i]->SectionType, &gEfiDMArGenericErrorSectionGuid)) 87 ir_section_dmar_generic_to_cper(section, out); 88 else if (guid_equal(&descriptors[i]->SectionType, &gEfiDirectedIoDMArErrorSectionGuid)) 89 ir_section_dmar_vtd_to_cper(section, out); 90 else if (guid_equal(&descriptors[i]->SectionType, &gEfiIommuDMArErrorSectionGuid)) 91 ir_section_dmar_iommu_to_cper(section, out); 92 else if (guid_equal(&descriptors[i]->SectionType, &gEfiCcixPerLogErrorSectionGuid)) 93 ir_section_ccix_per_to_cper(section, out); 94 else if (guid_equal(&descriptors[i]->SectionType, &gEfiCxlProtocolErrorSectionGuid)) 95 ir_section_cxl_protocol_to_cper(section, out); 96 else if (guid_equal(&descriptors[i]->SectionType, &gEfiCxlGeneralMediaErrorSectionGuid) 97 || guid_equal(&descriptors[i]->SectionType, &gEfiCxlDramEventErrorSectionGuid) 98 || guid_equal(&descriptors[i]->SectionType, &gEfiCxlPhysicalSwitchErrorSectionGuid) 99 || guid_equal(&descriptors[i]->SectionType, &gEfiCxlVirtualSwitchErrorSectionGuid) 100 || guid_equal(&descriptors[i]->SectionType, &gEfiCxlMldPortErrorSectionGuid)) 101 { 102 ir_section_cxl_component_to_cper(section, out); 103 } 104 else 105 { 106 //Unknown GUID, so read as a base64 unknown section. 107 json_object* encoded = json_object_object_get(section, "data"); 108 UINT8* decoded = b64_decode(json_object_get_string(encoded), json_object_get_string_len(encoded)); 109 fwrite(decoded, descriptors[i]->SectionLength, 1, out); 110 fflush(out); 111 free(decoded); 112 } 113 } 114 115 //Free all remaining resources. 116 free(header); 117 for (int i=0; i<amt_descriptors; i++) 118 free(descriptors[i]); 119 } 120 121 //Converts a CPER-JSON IR header to a CPER header structure. 122 void ir_header_to_cper(json_object* header_ir, EFI_COMMON_ERROR_RECORD_HEADER* header) 123 { 124 header->SignatureStart = 0x52455043; //CPER 125 126 //Revision. 127 json_object* revision = json_object_object_get(header_ir, "revision"); 128 int minor = json_object_get_int(json_object_object_get(revision, "minor")); 129 int major = json_object_get_int(json_object_object_get(revision, "major")); 130 header->Revision = minor + (major << 8); 131 132 header->SignatureEnd = 0xFFFFFFFF; 133 134 //Section count. 135 int section_count = json_object_get_int(json_object_object_get(header_ir, "sectionCount")); 136 header->SectionCount = (UINT16)section_count; 137 138 //Error severity. 139 json_object* severity = json_object_object_get(header_ir, "severity"); 140 header->ErrorSeverity = (UINT32)json_object_get_uint64(json_object_object_get(severity, "code")); 141 142 //Validation bits. 143 header->ValidationBits = ir_to_bitfield(json_object_object_get(header_ir, "validationBits"), 144 3, CPER_HEADER_VALID_BITFIELD_NAMES); 145 146 //Record length. 147 header->RecordLength = (UINT32)json_object_get_uint64(json_object_object_get(header_ir, "recordLength")); 148 149 //Timestamp, if present. 150 json_object* timestamp = json_object_object_get(header_ir, "timestamp"); 151 if (timestamp != NULL) 152 { 153 string_to_timestamp(&header->TimeStamp, json_object_get_string(timestamp)); 154 header->TimeStamp.Flag = json_object_get_boolean(json_object_object_get(header_ir, "timestampIsPrecise")); 155 } 156 157 //Various GUIDs. 158 json_object* platform_id = json_object_object_get(header_ir, "platformID"); 159 json_object* partition_id = json_object_object_get(header_ir, "partitionID"); 160 if (platform_id != NULL) 161 string_to_guid(&header->PlatformID, json_object_get_string(platform_id)); 162 if (partition_id != NULL) 163 string_to_guid(&header->PartitionID, json_object_get_string(partition_id)); 164 string_to_guid(&header->CreatorID, json_object_get_string(json_object_object_get(header_ir, "creatorID"))); 165 166 //Notification type. 167 json_object* notification_type = json_object_object_get(header_ir, "notificationType"); 168 string_to_guid(&header->NotificationType, json_object_get_string(json_object_object_get(notification_type, "guid"))); 169 170 //Record ID, persistence info. 171 header->RecordID = json_object_get_uint64(json_object_object_get(header_ir, "recordID")); 172 header->PersistenceInfo = json_object_get_uint64(json_object_object_get(header_ir, "persistenceInfo")); 173 174 //Flags. 175 json_object* flags = json_object_object_get(header_ir, "flags"); 176 header->Flags = (UINT32)json_object_get_uint64(json_object_object_get(flags, "value")); 177 } 178 179 //Converts a single CPER-JSON IR section descriptor into a CPER structure. 180 void ir_section_descriptor_to_cper(json_object* section_descriptor_ir, EFI_ERROR_SECTION_DESCRIPTOR* descriptor) 181 { 182 //Section offset, length. 183 descriptor->SectionOffset = (UINT32)json_object_get_uint64(json_object_object_get(section_descriptor_ir, "sectionOffset")); 184 descriptor->SectionLength = (UINT32)json_object_get_uint64(json_object_object_get(section_descriptor_ir, "sectionLength")); 185 186 //Revision. 187 json_object* revision = json_object_object_get(section_descriptor_ir, "revision"); 188 int minor = json_object_get_int(json_object_object_get(revision, "minor")); 189 int major = json_object_get_int(json_object_object_get(revision, "major")); 190 descriptor->Revision = minor + (major << 8); 191 192 //Validation bits, flags. 193 descriptor->SecValidMask = ir_to_bitfield(json_object_object_get(section_descriptor_ir, "validationBits"), 194 2, CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES); 195 descriptor->SectionFlags = ir_to_bitfield(json_object_object_get(section_descriptor_ir, "flags"), 196 8, CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES); 197 198 //Section type. 199 json_object* section_type = json_object_object_get(section_descriptor_ir, "sectionType"); 200 string_to_guid(&descriptor->SectionType, json_object_get_string(json_object_object_get(section_type, "data"))); 201 202 //FRU ID, if present. 203 json_object* fru_id = json_object_object_get(section_descriptor_ir, "fruID"); 204 if (fru_id != NULL) 205 string_to_guid(&descriptor->FruId, json_object_get_string(fru_id)); 206 207 //Severity code. 208 json_object* severity = json_object_object_get(section_descriptor_ir, "severity"); 209 descriptor->Severity = (UINT32)json_object_get_uint64(json_object_object_get(severity, "code")); 210 211 //FRU text, if present. 212 json_object* fru_text = json_object_object_get(section_descriptor_ir, "fruText"); 213 if (fru_text != NULL) 214 strncpy(descriptor->FruString, json_object_get_string(fru_text), 20); 215 }