xref: /openbmc/libcper/cper-parse.c (revision e407b4c8)
11b0b00e3SLawrence Tang /**
22800cd8eSLawrence Tang  * Describes high level functions for converting an entire CPER log, and functions for parsing
32800cd8eSLawrence Tang  * CPER headers and section descriptions into an intermediate JSON format.
41b0b00e3SLawrence Tang  *
51b0b00e3SLawrence Tang  * Author: Lawrence.Tang@arm.com
61b0b00e3SLawrence Tang  **/
71b0b00e3SLawrence Tang 
81b0b00e3SLawrence Tang #include <stdio.h>
91b0b00e3SLawrence Tang #include "json.h"
10d7e8ca34SLawrence Tang #include "b64.h"
111b0b00e3SLawrence Tang #include "edk/Cper.h"
121b0b00e3SLawrence Tang #include "cper-parse.h"
131b0b00e3SLawrence Tang #include "cper-utils.h"
141b0b00e3SLawrence Tang #include "sections/cper-section-generic.h"
15794312c8SLawrence Tang #include "sections/cper-section-ia32x64.h"
162800cd8eSLawrence Tang #include "sections/cper-section-arm.h"
17a0865e38SLawrence Tang #include "sections/cper-section-memory.h"
184dbe3d72SLawrence Tang #include "sections/cper-section-pcie.h"
19214a1542SLawrence Tang #include "sections/cper-section-pci-bus.h"
20a416ec93SLawrence Tang #include "sections/cper-section-pci-dev.h"
21c60a243eSLawrence Tang #include "sections/cper-section-firmware.h"
224795d4aeSLawrence Tang #include "sections/cper-section-dmar-generic.h"
23db1b7ce2SLawrence Tang #include "sections/cper-section-dmar-vtd.h"
24db1b7ce2SLawrence Tang #include "sections/cper-section-dmar-iommu.h"
25864c0da9SLawrence Tang #include "sections/cper-section-ccix-per.h"
26b98ec66cSLawrence Tang #include "sections/cper-section-cxl-protocol.h"
27cc0f5f38SLawrence Tang #include "sections/cper-section-ipf.h"
28d7e8ca34SLawrence Tang #include "sections/cper-section-cxl-component.h"
291b0b00e3SLawrence Tang 
301b0b00e3SLawrence Tang //Private pre-definitions.
311b0b00e3SLawrence Tang json_object *cper_header_to_ir(EFI_COMMON_ERROR_RECORD_HEADER *header);
32*e407b4c8SLawrence Tang json_object *
33*e407b4c8SLawrence Tang cper_section_descriptor_to_ir(EFI_ERROR_SECTION_DESCRIPTOR *section_descriptor);
34*e407b4c8SLawrence Tang json_object *cper_section_to_ir(FILE *handle,
35*e407b4c8SLawrence Tang 				EFI_ERROR_SECTION_DESCRIPTOR *descriptor);
361b0b00e3SLawrence Tang 
371b0b00e3SLawrence Tang //Reads a CPER log file at the given file location, and returns an intermediate
381b0b00e3SLawrence Tang //JSON representation of this CPER record.
39f0f95574SLawrence Tang json_object *cper_to_ir(FILE *cper_file)
401b0b00e3SLawrence Tang {
411b0b00e3SLawrence Tang 	//Ensure this is really a CPER log.
421b0b00e3SLawrence Tang 	EFI_COMMON_ERROR_RECORD_HEADER header;
431b0b00e3SLawrence Tang 	fseek(cper_file, 0, SEEK_SET);
44*e407b4c8SLawrence Tang 	if (fread(&header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1,
45*e407b4c8SLawrence Tang 		  cper_file) != 1) {
4602c801a5SLawrence Tang 		printf("Invalid CPER file: Invalid length (log too short).\n");
471b0b00e3SLawrence Tang 		return NULL;
481b0b00e3SLawrence Tang 	}
491b0b00e3SLawrence Tang 
501b0b00e3SLawrence Tang 	//Check if the header contains the magic bytes ("CPER").
511b0b00e3SLawrence Tang 	if (header.SignatureStart != EFI_ERROR_RECORD_SIGNATURE_START) {
5202c801a5SLawrence Tang 		printf("Invalid CPER file: Invalid header (incorrect signature).\n");
531b0b00e3SLawrence Tang 		return NULL;
541b0b00e3SLawrence Tang 	}
551b0b00e3SLawrence Tang 
561b0b00e3SLawrence Tang 	//Create the header JSON object from the read bytes.
571b0b00e3SLawrence Tang 	json_object *header_ir = cper_header_to_ir(&header);
581b0b00e3SLawrence Tang 
591b0b00e3SLawrence Tang 	//Read the appropriate number of section descriptors & sections, and convert them into IR format.
601b0b00e3SLawrence Tang 	json_object *section_descriptors_ir = json_object_new_array();
611b0b00e3SLawrence Tang 	json_object *sections_ir = json_object_new_array();
62*e407b4c8SLawrence Tang 	for (int i = 0; i < header.SectionCount; i++) {
631b0b00e3SLawrence Tang 		//Create the section descriptor.
641b0b00e3SLawrence Tang 		EFI_ERROR_SECTION_DESCRIPTOR section_descriptor;
65*e407b4c8SLawrence Tang 		if (fread(&section_descriptor,
66*e407b4c8SLawrence Tang 			  sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1,
67*e407b4c8SLawrence Tang 			  cper_file) != 1) {
68*e407b4c8SLawrence Tang 			printf("Invalid number of section headers: Header states %d sections, could not read section %d.\n",
69*e407b4c8SLawrence Tang 			       header.SectionCount, i + 1);
701b0b00e3SLawrence Tang 			return NULL;
711b0b00e3SLawrence Tang 		}
72*e407b4c8SLawrence Tang 		json_object_array_add(
73*e407b4c8SLawrence Tang 			section_descriptors_ir,
74*e407b4c8SLawrence Tang 			cper_section_descriptor_to_ir(&section_descriptor));
751b0b00e3SLawrence Tang 
761b0b00e3SLawrence Tang 		//Read the section itself.
77*e407b4c8SLawrence Tang 		json_object_array_add(sections_ir,
78*e407b4c8SLawrence Tang 				      cper_section_to_ir(cper_file,
79*e407b4c8SLawrence Tang 							 &section_descriptor));
801b0b00e3SLawrence Tang 	}
811b0b00e3SLawrence Tang 
821b0b00e3SLawrence Tang 	//Add the header, section descriptors, and sections to a parent object.
831b0b00e3SLawrence Tang 	json_object *parent = json_object_new_object();
841b0b00e3SLawrence Tang 	json_object_object_add(parent, "header", header_ir);
85*e407b4c8SLawrence Tang 	json_object_object_add(parent, "sectionDescriptors",
86*e407b4c8SLawrence Tang 			       section_descriptors_ir);
872800cd8eSLawrence Tang 	json_object_object_add(parent, "sections", sections_ir);
881b0b00e3SLawrence Tang 
891b0b00e3SLawrence Tang 	return parent;
901b0b00e3SLawrence Tang }
911b0b00e3SLawrence Tang 
921b0b00e3SLawrence Tang //Converts a parsed CPER record header into intermediate JSON object format.
931b0b00e3SLawrence Tang json_object *cper_header_to_ir(EFI_COMMON_ERROR_RECORD_HEADER *header)
941b0b00e3SLawrence Tang {
951b0b00e3SLawrence Tang 	json_object *header_ir = json_object_new_object();
961b0b00e3SLawrence Tang 
971b0b00e3SLawrence Tang 	//Revision/version information.
98*e407b4c8SLawrence Tang 	json_object_object_add(header_ir, "revision",
99*e407b4c8SLawrence Tang 			       revision_to_ir(header->Revision));
1001b0b00e3SLawrence Tang 
1011b0b00e3SLawrence Tang 	//Section count.
102*e407b4c8SLawrence Tang 	json_object_object_add(header_ir, "sectionCount",
103*e407b4c8SLawrence Tang 			       json_object_new_int(header->SectionCount));
1041b0b00e3SLawrence Tang 
1051b0b00e3SLawrence Tang 	//Error severity (with interpreted string version).
1061b0b00e3SLawrence Tang 	json_object *error_severity = json_object_new_object();
107*e407b4c8SLawrence Tang 	json_object_object_add(error_severity, "code",
108*e407b4c8SLawrence Tang 			       json_object_new_uint64(header->ErrorSeverity));
109*e407b4c8SLawrence Tang 	json_object_object_add(error_severity, "name",
110*e407b4c8SLawrence Tang 			       json_object_new_string(severity_to_string(
111*e407b4c8SLawrence Tang 				       header->ErrorSeverity)));
1121b0b00e3SLawrence Tang 	json_object_object_add(header_ir, "severity", error_severity);
1131b0b00e3SLawrence Tang 
1141b0b00e3SLawrence Tang 	//The validation bits for each section.
115*e407b4c8SLawrence Tang 	json_object *validation_bits = bitfield_to_ir(
116*e407b4c8SLawrence Tang 		header->ValidationBits, 3, CPER_HEADER_VALID_BITFIELD_NAMES);
1171b0b00e3SLawrence Tang 	json_object_object_add(header_ir, "validationBits", validation_bits);
1181b0b00e3SLawrence Tang 
1191b0b00e3SLawrence Tang 	//Total length of the record (including headers) in bytes.
120*e407b4c8SLawrence Tang 	json_object_object_add(header_ir, "recordLength",
121*e407b4c8SLawrence Tang 			       json_object_new_uint64(header->RecordLength));
1221b0b00e3SLawrence Tang 
1231b0b00e3SLawrence Tang 	//If a timestamp exists according to validation bits, then add it.
124*e407b4c8SLawrence Tang 	if (header->ValidationBits & 0b10) {
1251b0b00e3SLawrence Tang 		char timestamp_string[TIMESTAMP_LENGTH];
126aacf0e26SLawrence Tang 		timestamp_to_string(timestamp_string, &header->TimeStamp);
1271b0b00e3SLawrence Tang 
128*e407b4c8SLawrence Tang 		json_object_object_add(
129*e407b4c8SLawrence Tang 			header_ir, "timestamp",
130*e407b4c8SLawrence Tang 			json_object_new_string(timestamp_string));
131*e407b4c8SLawrence Tang 		json_object_object_add(
132*e407b4c8SLawrence Tang 			header_ir, "timestampIsPrecise",
133*e407b4c8SLawrence Tang 			json_object_new_boolean(header->TimeStamp.Flag));
1341b0b00e3SLawrence Tang 	}
1351b0b00e3SLawrence Tang 
1361b0b00e3SLawrence Tang 	//If a platform ID exists according to the validation bits, then add it.
137*e407b4c8SLawrence Tang 	if (header->ValidationBits & 0b1) {
1381b0b00e3SLawrence Tang 		char platform_string[GUID_STRING_LENGTH];
1391b0b00e3SLawrence Tang 		guid_to_string(platform_string, &header->PlatformID);
140*e407b4c8SLawrence Tang 		json_object_object_add(header_ir, "platformID",
141*e407b4c8SLawrence Tang 				       json_object_new_string(platform_string));
1421b0b00e3SLawrence Tang 	}
1431b0b00e3SLawrence Tang 
1441b0b00e3SLawrence Tang 	//If a partition ID exists according to the validation bits, then add it.
145*e407b4c8SLawrence Tang 	if (header->ValidationBits & 0b100) {
1461b0b00e3SLawrence Tang 		char partition_string[GUID_STRING_LENGTH];
1471b0b00e3SLawrence Tang 		guid_to_string(partition_string, &header->PartitionID);
148*e407b4c8SLawrence Tang 		json_object_object_add(
149*e407b4c8SLawrence Tang 			header_ir, "partitionID",
150*e407b4c8SLawrence Tang 			json_object_new_string(partition_string));
1511b0b00e3SLawrence Tang 	}
1521b0b00e3SLawrence Tang 
1531b0b00e3SLawrence Tang 	//Creator ID of the header.
1541b0b00e3SLawrence Tang 	char creator_string[GUID_STRING_LENGTH];
1551b0b00e3SLawrence Tang 	guid_to_string(creator_string, &header->CreatorID);
156*e407b4c8SLawrence Tang 	json_object_object_add(header_ir, "creatorID",
157*e407b4c8SLawrence Tang 			       json_object_new_string(creator_string));
1581b0b00e3SLawrence Tang 
1591b0b00e3SLawrence Tang 	//Notification type for the header. Some defined types are available.
1601b0b00e3SLawrence Tang 	json_object *notification_type = json_object_new_object();
1611b0b00e3SLawrence Tang 	char notification_type_string[GUID_STRING_LENGTH];
1621b0b00e3SLawrence Tang 	guid_to_string(notification_type_string, &header->NotificationType);
163*e407b4c8SLawrence Tang 	json_object_object_add(
164*e407b4c8SLawrence Tang 		notification_type, "guid",
165*e407b4c8SLawrence Tang 		json_object_new_string(notification_type_string));
1661b0b00e3SLawrence Tang 
1671b0b00e3SLawrence Tang 	//Add the human readable notification type if possible.
1681b0b00e3SLawrence Tang 	char *notification_type_readable = "Unknown";
169*e407b4c8SLawrence Tang 	if (guid_equal(&header->NotificationType,
170*e407b4c8SLawrence Tang 		       &gEfiEventNotificationTypeCmcGuid))
1711b0b00e3SLawrence Tang 		notification_type_readable = "CMC";
172*e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
173*e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeCpeGuid))
1741b0b00e3SLawrence Tang 		notification_type_readable = "CPE";
175*e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
176*e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeMceGuid))
1771b0b00e3SLawrence Tang 		notification_type_readable = "MCE";
178*e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
179*e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypePcieGuid))
1801b0b00e3SLawrence Tang 		notification_type_readable = "PCIe";
181*e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
182*e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeInitGuid))
1831b0b00e3SLawrence Tang 		notification_type_readable = "INIT";
184*e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
185*e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeNmiGuid))
1861b0b00e3SLawrence Tang 		notification_type_readable = "NMI";
187*e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
188*e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeBootGuid))
1891b0b00e3SLawrence Tang 		notification_type_readable = "Boot";
190*e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
191*e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeDmarGuid))
1921b0b00e3SLawrence Tang 		notification_type_readable = "DMAr";
193*e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
194*e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeSeaGuid))
1951b0b00e3SLawrence Tang 		notification_type_readable = "SEA";
196*e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
197*e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeSeiGuid))
1981b0b00e3SLawrence Tang 		notification_type_readable = "SEI";
199*e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
200*e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypePeiGuid))
2011b0b00e3SLawrence Tang 		notification_type_readable = "PEI";
202*e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
203*e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeCxlGuid))
2041b0b00e3SLawrence Tang 		notification_type_readable = "CXL Component";
205*e407b4c8SLawrence Tang 	json_object_object_add(
206*e407b4c8SLawrence Tang 		notification_type, "type",
207*e407b4c8SLawrence Tang 		json_object_new_string(notification_type_readable));
208*e407b4c8SLawrence Tang 	json_object_object_add(header_ir, "notificationType",
209*e407b4c8SLawrence Tang 			       notification_type);
2101b0b00e3SLawrence Tang 
2111b0b00e3SLawrence Tang 	//The record ID for this record, unique on a given system.
212*e407b4c8SLawrence Tang 	json_object_object_add(header_ir, "recordID",
213*e407b4c8SLawrence Tang 			       json_object_new_uint64(header->RecordID));
2141b0b00e3SLawrence Tang 
2151b0b00e3SLawrence Tang 	//Flag for the record, and a human readable form.
216*e407b4c8SLawrence Tang 	json_object *flags = integer_to_readable_pair(
217*e407b4c8SLawrence Tang 		header->Flags,
2183c43f743SLawrence Tang 		sizeof(CPER_HEADER_FLAG_TYPES_KEYS) / sizeof(int),
219*e407b4c8SLawrence Tang 		CPER_HEADER_FLAG_TYPES_KEYS, CPER_HEADER_FLAG_TYPES_VALUES,
2203c43f743SLawrence Tang 		"Unknown");
2211b0b00e3SLawrence Tang 	json_object_object_add(header_ir, "flags", flags);
2221b0b00e3SLawrence Tang 
2231b0b00e3SLawrence Tang 	//Persistence information. Outside the scope of specification, so just a uint32 here.
224*e407b4c8SLawrence Tang 	json_object_object_add(header_ir, "persistenceInfo",
225*e407b4c8SLawrence Tang 			       json_object_new_uint64(header->PersistenceInfo));
2261b0b00e3SLawrence Tang 	return header_ir;
2271b0b00e3SLawrence Tang }
2281b0b00e3SLawrence Tang 
2291b0b00e3SLawrence Tang //Converts the given EFI section descriptor into JSON IR format.
230*e407b4c8SLawrence Tang json_object *
231*e407b4c8SLawrence Tang cper_section_descriptor_to_ir(EFI_ERROR_SECTION_DESCRIPTOR *section_descriptor)
2321b0b00e3SLawrence Tang {
2331b0b00e3SLawrence Tang 	json_object *section_descriptor_ir = json_object_new_object();
2341b0b00e3SLawrence Tang 
2351b0b00e3SLawrence Tang 	//The offset of the section from the base of the record header, length.
236*e407b4c8SLawrence Tang 	json_object_object_add(
237*e407b4c8SLawrence Tang 		section_descriptor_ir, "sectionOffset",
238*e407b4c8SLawrence Tang 		json_object_new_uint64(section_descriptor->SectionOffset));
239*e407b4c8SLawrence Tang 	json_object_object_add(
240*e407b4c8SLawrence Tang 		section_descriptor_ir, "sectionLength",
241*e407b4c8SLawrence Tang 		json_object_new_uint64(section_descriptor->SectionLength));
2421b0b00e3SLawrence Tang 
2431b0b00e3SLawrence Tang 	//Revision.
244*e407b4c8SLawrence Tang 	json_object_object_add(section_descriptor_ir, "revision",
245*e407b4c8SLawrence Tang 			       revision_to_ir(section_descriptor->Revision));
2461b0b00e3SLawrence Tang 
2471b0b00e3SLawrence Tang 	//Validation bits.
248*e407b4c8SLawrence Tang 	json_object *validation_bits =
249*e407b4c8SLawrence Tang 		bitfield_to_ir(section_descriptor->SecValidMask, 2,
250*e407b4c8SLawrence Tang 			       CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES);
251*e407b4c8SLawrence Tang 	json_object_object_add(section_descriptor_ir, "validationBits",
252*e407b4c8SLawrence Tang 			       validation_bits);
2531b0b00e3SLawrence Tang 
2541b0b00e3SLawrence Tang 	//Flag bits.
255*e407b4c8SLawrence Tang 	json_object *flags =
256*e407b4c8SLawrence Tang 		bitfield_to_ir(section_descriptor->SectionFlags, 8,
257*e407b4c8SLawrence Tang 			       CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES);
2581b0b00e3SLawrence Tang 	json_object_object_add(section_descriptor_ir, "flags", flags);
2591b0b00e3SLawrence Tang 
2601b0b00e3SLawrence Tang 	//Section type (GUID).
2611b0b00e3SLawrence Tang 	json_object *section_type = json_object_new_object();
2621b0b00e3SLawrence Tang 	char section_type_string[GUID_STRING_LENGTH];
2631b0b00e3SLawrence Tang 	guid_to_string(section_type_string, &section_descriptor->SectionType);
264*e407b4c8SLawrence Tang 	json_object_object_add(section_type, "data",
265*e407b4c8SLawrence Tang 			       json_object_new_string(section_type_string));
2661b0b00e3SLawrence Tang 
2671b0b00e3SLawrence Tang 	//Readable section type, if possible.
2681b0b00e3SLawrence Tang 	char *section_type_readable = "Unknown";
269*e407b4c8SLawrence Tang 	if (guid_equal(&section_descriptor->SectionType,
270*e407b4c8SLawrence Tang 		       &gEfiProcessorGenericErrorSectionGuid))
2711b0b00e3SLawrence Tang 		section_type_readable = "Processor Generic";
272*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
273*e407b4c8SLawrence Tang 			    &gEfiIa32X64ProcessorErrorSectionGuid))
2741b0b00e3SLawrence Tang 		section_type_readable = "IA32/X64";
275*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
276*e407b4c8SLawrence Tang 			    &gEfiIpfProcessorErrorSectionGuid))
277cc0f5f38SLawrence Tang 		section_type_readable = "IPF";
278*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
279*e407b4c8SLawrence Tang 			    &gEfiArmProcessorErrorSectionGuid))
2801b0b00e3SLawrence Tang 		section_type_readable = "ARM";
281*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
282*e407b4c8SLawrence Tang 			    &gEfiPlatformMemoryErrorSectionGuid) ||
283*e407b4c8SLawrence Tang 		 guid_equal(&section_descriptor->SectionType,
284*e407b4c8SLawrence Tang 			    &gEfiPlatformMemoryError2SectionGuid))
2851b0b00e3SLawrence Tang 		section_type_readable = "Platform Memory";
286*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
287*e407b4c8SLawrence Tang 			    &gEfiPcieErrorSectionGuid))
2881b0b00e3SLawrence Tang 		section_type_readable = "PCIe";
289*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
290*e407b4c8SLawrence Tang 			    &gEfiFirmwareErrorSectionGuid))
2911b0b00e3SLawrence Tang 		section_type_readable = "Firmware Error Record Reference";
292*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
293*e407b4c8SLawrence Tang 			    &gEfiPciBusErrorSectionGuid))
2941b0b00e3SLawrence Tang 		section_type_readable = "PCI/PCI-X Bus";
295*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
296*e407b4c8SLawrence Tang 			    &gEfiPciDevErrorSectionGuid))
2971b0b00e3SLawrence Tang 		section_type_readable = "PCI Component/Device";
298*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
299*e407b4c8SLawrence Tang 			    &gEfiDMArGenericErrorSectionGuid))
3001b0b00e3SLawrence Tang 		section_type_readable = "DMAr Generic";
301*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
302*e407b4c8SLawrence Tang 			    &gEfiDirectedIoDMArErrorSectionGuid))
303*e407b4c8SLawrence Tang 		section_type_readable =
304*e407b4c8SLawrence Tang 			"Intel VT for Directed I/O specific DMAr section";
305*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
306*e407b4c8SLawrence Tang 			    &gEfiIommuDMArErrorSectionGuid))
3071b0b00e3SLawrence Tang 		section_type_readable = "IOMMU specific DMAr section";
308*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
309*e407b4c8SLawrence Tang 			    &gEfiCcixPerLogErrorSectionGuid))
310864c0da9SLawrence Tang 		section_type_readable = "CCIX PER Log Error";
311*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
312*e407b4c8SLawrence Tang 			    &gEfiCxlProtocolErrorSectionGuid))
313b98ec66cSLawrence Tang 		section_type_readable = "CXL Protocol Error";
314*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
315*e407b4c8SLawrence Tang 			    &gEfiCxlGeneralMediaErrorSectionGuid))
316d7e8ca34SLawrence Tang 		section_type_readable = "CXL General Media Component Error";
317*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
318*e407b4c8SLawrence Tang 			    &gEfiCxlDramEventErrorSectionGuid))
319d7e8ca34SLawrence Tang 		section_type_readable = "CXL DRAM Component Error";
320*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
321*e407b4c8SLawrence Tang 			    &gEfiCxlPhysicalSwitchErrorSectionGuid))
322d7e8ca34SLawrence Tang 		section_type_readable = "CXL Physical Switch Component Error";
323*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
324*e407b4c8SLawrence Tang 			    &gEfiCxlVirtualSwitchErrorSectionGuid))
325d7e8ca34SLawrence Tang 		section_type_readable = "CXL Virtual Switch Component Error";
326*e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
327*e407b4c8SLawrence Tang 			    &gEfiCxlMldPortErrorSectionGuid))
328d7e8ca34SLawrence Tang 		section_type_readable = "CXL MLD Port Component Error";
3291b0b00e3SLawrence Tang 
330*e407b4c8SLawrence Tang 	json_object_object_add(section_type, "type",
331*e407b4c8SLawrence Tang 			       json_object_new_string(section_type_readable));
332*e407b4c8SLawrence Tang 	json_object_object_add(section_descriptor_ir, "sectionType",
333*e407b4c8SLawrence Tang 			       section_type);
3341b0b00e3SLawrence Tang 
3351b0b00e3SLawrence Tang 	//If validation bits indicate it exists, add FRU ID.
336*e407b4c8SLawrence Tang 	if (section_descriptor->SecValidMask & 0b1) {
3371b0b00e3SLawrence Tang 		char fru_id_string[GUID_STRING_LENGTH];
3381b0b00e3SLawrence Tang 		guid_to_string(fru_id_string, &section_descriptor->FruId);
339*e407b4c8SLawrence Tang 		json_object_object_add(section_descriptor_ir, "fruID",
340*e407b4c8SLawrence Tang 				       json_object_new_string(fru_id_string));
3411b0b00e3SLawrence Tang 	}
3421b0b00e3SLawrence Tang 
3431b0b00e3SLawrence Tang 	//If validation bits indicate it exists, add FRU text.
3441b0b00e3SLawrence Tang 	if ((section_descriptor->SecValidMask & 0b10) >> 1)
345*e407b4c8SLawrence Tang 		json_object_object_add(
346*e407b4c8SLawrence Tang 			section_descriptor_ir, "fruText",
347*e407b4c8SLawrence Tang 			json_object_new_string(section_descriptor->FruString));
3481b0b00e3SLawrence Tang 
3491b0b00e3SLawrence Tang 	//Section severity.
3501b0b00e3SLawrence Tang 	json_object *section_severity = json_object_new_object();
351*e407b4c8SLawrence Tang 	json_object_object_add(
352*e407b4c8SLawrence Tang 		section_severity, "code",
353*e407b4c8SLawrence Tang 		json_object_new_uint64(section_descriptor->Severity));
354*e407b4c8SLawrence Tang 	json_object_object_add(section_severity, "name",
355*e407b4c8SLawrence Tang 			       json_object_new_string(severity_to_string(
356*e407b4c8SLawrence Tang 				       section_descriptor->Severity)));
357*e407b4c8SLawrence Tang 	json_object_object_add(section_descriptor_ir, "severity",
358*e407b4c8SLawrence Tang 			       section_severity);
3591b0b00e3SLawrence Tang 
3601b0b00e3SLawrence Tang 	return section_descriptor_ir;
3611b0b00e3SLawrence Tang }
3621b0b00e3SLawrence Tang 
3631b0b00e3SLawrence Tang //Converts the section described by a single given section descriptor.
364*e407b4c8SLawrence Tang json_object *cper_section_to_ir(FILE *handle,
365*e407b4c8SLawrence Tang 				EFI_ERROR_SECTION_DESCRIPTOR *descriptor)
3661b0b00e3SLawrence Tang {
367de9707f9SLawrence Tang 	//Save our current position in the stream.
368de9707f9SLawrence Tang 	long position = ftell(handle);
369de9707f9SLawrence Tang 
3701b0b00e3SLawrence Tang 	//Read section as described by the section descriptor.
3711b0b00e3SLawrence Tang 	fseek(handle, descriptor->SectionOffset, SEEK_SET);
372e18aaee9SLawrence Tang 	void *section = malloc(descriptor->SectionLength);
373*e407b4c8SLawrence Tang 	if (fread(section, descriptor->SectionLength, 1, handle) != 1) {
37402c801a5SLawrence Tang 		printf("Section read failed: Could not read %d bytes from global offset %d.\n",
375*e407b4c8SLawrence Tang 		       descriptor->SectionLength, descriptor->SectionOffset);
376e18aaee9SLawrence Tang 		free(section);
377e18aaee9SLawrence Tang 		return NULL;
3781b0b00e3SLawrence Tang 	}
3791b0b00e3SLawrence Tang 
380de9707f9SLawrence Tang 	//Seek back to our original position.
381de9707f9SLawrence Tang 	fseek(handle, position, SEEK_SET);
382de9707f9SLawrence Tang 
383db1b7ce2SLawrence Tang 	//Parse section to IR based on GUID.
3841b0b00e3SLawrence Tang 	json_object *result = NULL;
385*e407b4c8SLawrence Tang 	if (guid_equal(&descriptor->SectionType,
386*e407b4c8SLawrence Tang 		       &gEfiProcessorGenericErrorSectionGuid))
3872800cd8eSLawrence Tang 		result = cper_section_generic_to_ir(section, descriptor);
388*e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
389*e407b4c8SLawrence Tang 			    &gEfiIa32X64ProcessorErrorSectionGuid))
3902800cd8eSLawrence Tang 		result = cper_section_ia32x64_to_ir(section, descriptor);
391*e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
392*e407b4c8SLawrence Tang 			    &gEfiIpfProcessorErrorSectionGuid))
393cc0f5f38SLawrence Tang 		result = cper_section_ipf_to_ir(section, descriptor);
394*e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
395*e407b4c8SLawrence Tang 			    &gEfiArmProcessorErrorSectionGuid))
3962800cd8eSLawrence Tang 		result = cper_section_arm_to_ir(section, descriptor);
397*e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
398*e407b4c8SLawrence Tang 			    &gEfiPlatformMemoryErrorSectionGuid))
399*e407b4c8SLawrence Tang 		result =
400*e407b4c8SLawrence Tang 			cper_section_platform_memory_to_ir(section, descriptor);
401*e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
402*e407b4c8SLawrence Tang 			    &gEfiPlatformMemoryError2SectionGuid))
403*e407b4c8SLawrence Tang 		result = cper_section_platform_memory2_to_ir(section,
404*e407b4c8SLawrence Tang 							     descriptor);
405*e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
406*e407b4c8SLawrence Tang 			    &gEfiPcieErrorSectionGuid))
4074dbe3d72SLawrence Tang 		result = cper_section_pcie_to_ir(section, descriptor);
408*e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
409*e407b4c8SLawrence Tang 			    &gEfiFirmwareErrorSectionGuid))
410c60a243eSLawrence Tang 		result = cper_section_firmware_to_ir(section, descriptor);
411*e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
412*e407b4c8SLawrence Tang 			    &gEfiPciBusErrorSectionGuid))
413214a1542SLawrence Tang 		result = cper_section_pci_bus_to_ir(section, descriptor);
414*e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
415*e407b4c8SLawrence Tang 			    &gEfiPciDevErrorSectionGuid))
416a416ec93SLawrence Tang 		result = cper_section_pci_dev_to_ir(section, descriptor);
417*e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
418*e407b4c8SLawrence Tang 			    &gEfiDMArGenericErrorSectionGuid))
4194795d4aeSLawrence Tang 		result = cper_section_dmar_generic_to_ir(section, descriptor);
420*e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
421*e407b4c8SLawrence Tang 			    &gEfiDirectedIoDMArErrorSectionGuid))
422db1b7ce2SLawrence Tang 		result = cper_section_dmar_vtd_to_ir(section, descriptor);
423*e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
424*e407b4c8SLawrence Tang 			    &gEfiIommuDMArErrorSectionGuid))
425db1b7ce2SLawrence Tang 		result = cper_section_dmar_iommu_to_ir(section, descriptor);
426*e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
427*e407b4c8SLawrence Tang 			    &gEfiCcixPerLogErrorSectionGuid))
428864c0da9SLawrence Tang 		result = cper_section_ccix_per_to_ir(section, descriptor);
429*e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
430*e407b4c8SLawrence Tang 			    &gEfiCxlProtocolErrorSectionGuid))
431b98ec66cSLawrence Tang 		result = cper_section_cxl_protocol_to_ir(section, descriptor);
432*e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
433*e407b4c8SLawrence Tang 			    &gEfiCxlGeneralMediaErrorSectionGuid) ||
434*e407b4c8SLawrence Tang 		 guid_equal(&descriptor->SectionType,
435*e407b4c8SLawrence Tang 			    &gEfiCxlDramEventErrorSectionGuid) ||
436*e407b4c8SLawrence Tang 		 guid_equal(&descriptor->SectionType,
437*e407b4c8SLawrence Tang 			    &gEfiCxlPhysicalSwitchErrorSectionGuid) ||
438*e407b4c8SLawrence Tang 		 guid_equal(&descriptor->SectionType,
439*e407b4c8SLawrence Tang 			    &gEfiCxlVirtualSwitchErrorSectionGuid) ||
440*e407b4c8SLawrence Tang 		 guid_equal(&descriptor->SectionType,
441*e407b4c8SLawrence Tang 			    &gEfiCxlMldPortErrorSectionGuid)) {
442d7e8ca34SLawrence Tang 		result = cper_section_cxl_component_to_ir(section, descriptor);
443*e407b4c8SLawrence Tang 	} else {
444db1b7ce2SLawrence Tang 		//Failed read, unknown GUID.
445d7e8ca34SLawrence Tang 		//Output the data as formatted base64.
446d7e8ca34SLawrence Tang 		result = json_object_new_object();
447*e407b4c8SLawrence Tang 		char *encoded = b64_encode((unsigned char *)section,
448*e407b4c8SLawrence Tang 					   descriptor->SectionLength);
449*e407b4c8SLawrence Tang 		json_object_object_add(result, "data",
450*e407b4c8SLawrence Tang 				       json_object_new_string(encoded));
451d7e8ca34SLawrence Tang 		free(encoded);
452db1b7ce2SLawrence Tang 	}
4531b0b00e3SLawrence Tang 
4541b0b00e3SLawrence Tang 	//Free section memory, return result.
4551b0b00e3SLawrence Tang 	free(section);
4561b0b00e3SLawrence Tang 	return result;
4571b0b00e3SLawrence Tang }