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, 32 EFI_COMMON_ERROR_RECORD_HEADER *header); 33 void ir_section_descriptor_to_cper(json_object *section_descriptor_ir, 34 EFI_ERROR_SECTION_DESCRIPTOR *descriptor); 35 36 //Converts the given JSON IR CPER representation into CPER binary format, piped to the provided file stream. 37 //This function performs no validation of the IR against the CPER-JSON specification. To ensure a safe call, 38 //use validate_schema() from json-schema.h before attempting to call this function. 39 void ir_to_cper(json_object *ir, FILE *out) 40 { 41 //Create the CPER header. 42 EFI_COMMON_ERROR_RECORD_HEADER *header = 43 (EFI_COMMON_ERROR_RECORD_HEADER *)calloc( 44 1, sizeof(EFI_COMMON_ERROR_RECORD_HEADER)); 45 ir_header_to_cper(json_object_object_get(ir, "header"), header); 46 fwrite(header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, out); 47 fflush(out); 48 49 //Create the CPER section descriptors. 50 json_object *section_descriptors = 51 json_object_object_get(ir, "sectionDescriptors"); 52 int amt_descriptors = json_object_array_length(section_descriptors); 53 EFI_ERROR_SECTION_DESCRIPTOR *descriptors[amt_descriptors]; 54 for (int i = 0; i < amt_descriptors; i++) { 55 descriptors[i] = (EFI_ERROR_SECTION_DESCRIPTOR *)calloc( 56 1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR)); 57 ir_section_descriptor_to_cper( 58 json_object_array_get_idx(section_descriptors, i), 59 descriptors[i]); 60 fwrite(descriptors[i], sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1, 61 out); 62 fflush(out); 63 } 64 65 //Run through each section in turn. 66 json_object *sections = json_object_object_get(ir, "sections"); 67 int amt_sections = json_object_array_length(sections); 68 for (int i = 0; i < amt_sections; i++) { 69 //Get the section itself from the IR. 70 json_object *section = json_object_array_get_idx(sections, i); 71 72 //Find the correct section type, and parse. 73 if (guid_equal(&descriptors[i]->SectionType, 74 &gEfiProcessorGenericErrorSectionGuid)) 75 ir_section_generic_to_cper(section, out); 76 else if (guid_equal(&descriptors[i]->SectionType, 77 &gEfiIa32X64ProcessorErrorSectionGuid)) 78 ir_section_ia32x64_to_cper(section, out); 79 // else if (guid_equal(&descriptors[i]->SectionType, &gEfiIpfProcessorErrorSectionGuid)) 80 // ir_section_ipf_to_cper(section, out); 81 else if (guid_equal(&descriptors[i]->SectionType, 82 &gEfiArmProcessorErrorSectionGuid)) 83 ir_section_arm_to_cper(section, out); 84 else if (guid_equal(&descriptors[i]->SectionType, 85 &gEfiPlatformMemoryErrorSectionGuid)) 86 ir_section_memory_to_cper(section, out); 87 else if (guid_equal(&descriptors[i]->SectionType, 88 &gEfiPlatformMemoryError2SectionGuid)) 89 ir_section_memory2_to_cper(section, out); 90 else if (guid_equal(&descriptors[i]->SectionType, 91 &gEfiPcieErrorSectionGuid)) 92 ir_section_pcie_to_cper(section, out); 93 else if (guid_equal(&descriptors[i]->SectionType, 94 &gEfiFirmwareErrorSectionGuid)) 95 ir_section_firmware_to_cper(section, out); 96 else if (guid_equal(&descriptors[i]->SectionType, 97 &gEfiPciBusErrorSectionGuid)) 98 ir_section_pci_bus_to_cper(section, out); 99 else if (guid_equal(&descriptors[i]->SectionType, 100 &gEfiPciDevErrorSectionGuid)) 101 ir_section_pci_dev_to_cper(section, out); 102 else if (guid_equal(&descriptors[i]->SectionType, 103 &gEfiDMArGenericErrorSectionGuid)) 104 ir_section_dmar_generic_to_cper(section, out); 105 else if (guid_equal(&descriptors[i]->SectionType, 106 &gEfiDirectedIoDMArErrorSectionGuid)) 107 ir_section_dmar_vtd_to_cper(section, out); 108 else if (guid_equal(&descriptors[i]->SectionType, 109 &gEfiIommuDMArErrorSectionGuid)) 110 ir_section_dmar_iommu_to_cper(section, out); 111 else if (guid_equal(&descriptors[i]->SectionType, 112 &gEfiCcixPerLogErrorSectionGuid)) 113 ir_section_ccix_per_to_cper(section, out); 114 else if (guid_equal(&descriptors[i]->SectionType, 115 &gEfiCxlProtocolErrorSectionGuid)) 116 ir_section_cxl_protocol_to_cper(section, out); 117 else if (guid_equal(&descriptors[i]->SectionType, 118 &gEfiCxlGeneralMediaErrorSectionGuid) || 119 guid_equal(&descriptors[i]->SectionType, 120 &gEfiCxlDramEventErrorSectionGuid) || 121 guid_equal(&descriptors[i]->SectionType, 122 &gEfiCxlPhysicalSwitchErrorSectionGuid) || 123 guid_equal(&descriptors[i]->SectionType, 124 &gEfiCxlVirtualSwitchErrorSectionGuid) || 125 guid_equal(&descriptors[i]->SectionType, 126 &gEfiCxlMldPortErrorSectionGuid)) { 127 ir_section_cxl_component_to_cper(section, out); 128 } else { 129 //Unknown GUID, so read as a base64 unknown section. 130 json_object *encoded = 131 json_object_object_get(section, "data"); 132 UINT8 *decoded = 133 b64_decode(json_object_get_string(encoded), 134 json_object_get_string_len(encoded)); 135 fwrite(decoded, descriptors[i]->SectionLength, 1, out); 136 fflush(out); 137 free(decoded); 138 } 139 } 140 141 //Free all remaining resources. 142 free(header); 143 for (int i = 0; i < amt_descriptors; i++) 144 free(descriptors[i]); 145 } 146 147 //Converts a CPER-JSON IR header to a CPER header structure. 148 void ir_header_to_cper(json_object *header_ir, 149 EFI_COMMON_ERROR_RECORD_HEADER *header) 150 { 151 header->SignatureStart = 0x52455043; //CPER 152 153 //Revision. 154 json_object *revision = json_object_object_get(header_ir, "revision"); 155 int minor = 156 json_object_get_int(json_object_object_get(revision, "minor")); 157 int major = 158 json_object_get_int(json_object_object_get(revision, "major")); 159 header->Revision = minor + (major << 8); 160 161 header->SignatureEnd = 0xFFFFFFFF; 162 163 //Section count. 164 int section_count = json_object_get_int( 165 json_object_object_get(header_ir, "sectionCount")); 166 header->SectionCount = (UINT16)section_count; 167 168 //Error severity. 169 json_object *severity = json_object_object_get(header_ir, "severity"); 170 header->ErrorSeverity = (UINT32)json_object_get_uint64( 171 json_object_object_get(severity, "code")); 172 173 //Validation bits. 174 header->ValidationBits = ir_to_bitfield( 175 json_object_object_get(header_ir, "validationBits"), 3, 176 CPER_HEADER_VALID_BITFIELD_NAMES); 177 178 //Record length. 179 header->RecordLength = (UINT32)json_object_get_uint64( 180 json_object_object_get(header_ir, "recordLength")); 181 182 //Timestamp, if present. 183 json_object *timestamp = json_object_object_get(header_ir, "timestamp"); 184 if (timestamp != NULL) { 185 string_to_timestamp(&header->TimeStamp, 186 json_object_get_string(timestamp)); 187 header->TimeStamp.Flag = json_object_get_boolean( 188 json_object_object_get(header_ir, 189 "timestampIsPrecise")); 190 } 191 192 //Various GUIDs. 193 json_object *platform_id = 194 json_object_object_get(header_ir, "platformID"); 195 json_object *partition_id = 196 json_object_object_get(header_ir, "partitionID"); 197 if (platform_id != NULL) 198 string_to_guid(&header->PlatformID, 199 json_object_get_string(platform_id)); 200 if (partition_id != NULL) 201 string_to_guid(&header->PartitionID, 202 json_object_get_string(partition_id)); 203 string_to_guid(&header->CreatorID, 204 json_object_get_string( 205 json_object_object_get(header_ir, "creatorID"))); 206 207 //Notification type. 208 json_object *notification_type = 209 json_object_object_get(header_ir, "notificationType"); 210 string_to_guid(&header->NotificationType, 211 json_object_get_string(json_object_object_get( 212 notification_type, "guid"))); 213 214 //Record ID, persistence info. 215 header->RecordID = json_object_get_uint64( 216 json_object_object_get(header_ir, "recordID")); 217 header->PersistenceInfo = json_object_get_uint64( 218 json_object_object_get(header_ir, "persistenceInfo")); 219 220 //Flags. 221 json_object *flags = json_object_object_get(header_ir, "flags"); 222 header->Flags = (UINT32)json_object_get_uint64( 223 json_object_object_get(flags, "value")); 224 } 225 226 //Converts a single CPER-JSON IR section descriptor into a CPER structure. 227 void ir_section_descriptor_to_cper(json_object *section_descriptor_ir, 228 EFI_ERROR_SECTION_DESCRIPTOR *descriptor) 229 { 230 //Section offset, length. 231 descriptor->SectionOffset = (UINT32)json_object_get_uint64( 232 json_object_object_get(section_descriptor_ir, "sectionOffset")); 233 descriptor->SectionLength = (UINT32)json_object_get_uint64( 234 json_object_object_get(section_descriptor_ir, "sectionLength")); 235 236 //Revision. 237 json_object *revision = 238 json_object_object_get(section_descriptor_ir, "revision"); 239 int minor = 240 json_object_get_int(json_object_object_get(revision, "minor")); 241 int major = 242 json_object_get_int(json_object_object_get(revision, "major")); 243 descriptor->Revision = minor + (major << 8); 244 245 //Validation bits, flags. 246 descriptor->SecValidMask = ir_to_bitfield( 247 json_object_object_get(section_descriptor_ir, "validationBits"), 248 2, CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES); 249 descriptor->SectionFlags = ir_to_bitfield( 250 json_object_object_get(section_descriptor_ir, "flags"), 8, 251 CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES); 252 253 //Section type. 254 json_object *section_type = 255 json_object_object_get(section_descriptor_ir, "sectionType"); 256 string_to_guid(&descriptor->SectionType, 257 json_object_get_string( 258 json_object_object_get(section_type, "data"))); 259 260 //FRU ID, if present. 261 json_object *fru_id = 262 json_object_object_get(section_descriptor_ir, "fruID"); 263 if (fru_id != NULL) 264 string_to_guid(&descriptor->FruId, 265 json_object_get_string(fru_id)); 266 267 //Severity code. 268 json_object *severity = 269 json_object_object_get(section_descriptor_ir, "severity"); 270 descriptor->Severity = (UINT32)json_object_get_uint64( 271 json_object_object_get(severity, "code")); 272 273 //FRU text, if present. 274 json_object *fru_text = 275 json_object_object_get(section_descriptor_ir, "fruText"); 276 if (fru_text != NULL) 277 strncpy(descriptor->FruString, json_object_get_string(fru_text), 278 20); 279 }