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