xref: /openbmc/libcper/cper-parse.c (revision 5202bbb4)
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>
9*5202bbb4SLawrence 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);
32e407b4c8SLawrence Tang json_object *
33e407b4c8SLawrence Tang cper_section_descriptor_to_ir(EFI_ERROR_SECTION_DESCRIPTOR *section_descriptor);
34e407b4c8SLawrence Tang json_object *cper_section_to_ir(FILE *handle,
35e407b4c8SLawrence 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);
44e407b4c8SLawrence Tang 	if (fread(&header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1,
45e407b4c8SLawrence 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();
62e407b4c8SLawrence Tang 	for (int i = 0; i < header.SectionCount; i++) {
631b0b00e3SLawrence Tang 		//Create the section descriptor.
641b0b00e3SLawrence Tang 		EFI_ERROR_SECTION_DESCRIPTOR section_descriptor;
65e407b4c8SLawrence Tang 		if (fread(&section_descriptor,
66e407b4c8SLawrence Tang 			  sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1,
67e407b4c8SLawrence Tang 			  cper_file) != 1) {
68e407b4c8SLawrence Tang 			printf("Invalid number of section headers: Header states %d sections, could not read section %d.\n",
69e407b4c8SLawrence Tang 			       header.SectionCount, i + 1);
701b0b00e3SLawrence Tang 			return NULL;
711b0b00e3SLawrence Tang 		}
72e407b4c8SLawrence Tang 		json_object_array_add(
73e407b4c8SLawrence Tang 			section_descriptors_ir,
74e407b4c8SLawrence Tang 			cper_section_descriptor_to_ir(&section_descriptor));
751b0b00e3SLawrence Tang 
761b0b00e3SLawrence Tang 		//Read the section itself.
77e407b4c8SLawrence Tang 		json_object_array_add(sections_ir,
78e407b4c8SLawrence Tang 				      cper_section_to_ir(cper_file,
79e407b4c8SLawrence 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);
85e407b4c8SLawrence Tang 	json_object_object_add(parent, "sectionDescriptors",
86e407b4c8SLawrence 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.
98e407b4c8SLawrence Tang 	json_object_object_add(header_ir, "revision",
99e407b4c8SLawrence Tang 			       revision_to_ir(header->Revision));
1001b0b00e3SLawrence Tang 
1011b0b00e3SLawrence Tang 	//Section count.
102e407b4c8SLawrence Tang 	json_object_object_add(header_ir, "sectionCount",
103e407b4c8SLawrence 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();
107e407b4c8SLawrence Tang 	json_object_object_add(error_severity, "code",
108e407b4c8SLawrence Tang 			       json_object_new_uint64(header->ErrorSeverity));
109e407b4c8SLawrence Tang 	json_object_object_add(error_severity, "name",
110e407b4c8SLawrence Tang 			       json_object_new_string(severity_to_string(
111e407b4c8SLawrence Tang 				       header->ErrorSeverity)));
1121b0b00e3SLawrence Tang 	json_object_object_add(header_ir, "severity", error_severity);
1131b0b00e3SLawrence Tang 
1141b0b00e3SLawrence Tang 	//The validation bits for each section.
115e407b4c8SLawrence Tang 	json_object *validation_bits = bitfield_to_ir(
116e407b4c8SLawrence 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.
120e407b4c8SLawrence Tang 	json_object_object_add(header_ir, "recordLength",
121e407b4c8SLawrence Tang 			       json_object_new_uint64(header->RecordLength));
1221b0b00e3SLawrence Tang 
1231b0b00e3SLawrence Tang 	//If a timestamp exists according to validation bits, then add it.
124e407b4c8SLawrence Tang 	if (header->ValidationBits & 0b10) {
1251b0b00e3SLawrence Tang 		char timestamp_string[TIMESTAMP_LENGTH];
126aacf0e26SLawrence Tang 		timestamp_to_string(timestamp_string, &header->TimeStamp);
1271b0b00e3SLawrence Tang 
128e407b4c8SLawrence Tang 		json_object_object_add(
129e407b4c8SLawrence Tang 			header_ir, "timestamp",
130e407b4c8SLawrence Tang 			json_object_new_string(timestamp_string));
131e407b4c8SLawrence Tang 		json_object_object_add(
132e407b4c8SLawrence Tang 			header_ir, "timestampIsPrecise",
133e407b4c8SLawrence 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.
137e407b4c8SLawrence Tang 	if (header->ValidationBits & 0b1) {
1381b0b00e3SLawrence Tang 		char platform_string[GUID_STRING_LENGTH];
1391b0b00e3SLawrence Tang 		guid_to_string(platform_string, &header->PlatformID);
140e407b4c8SLawrence Tang 		json_object_object_add(header_ir, "platformID",
141e407b4c8SLawrence 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.
145e407b4c8SLawrence Tang 	if (header->ValidationBits & 0b100) {
1461b0b00e3SLawrence Tang 		char partition_string[GUID_STRING_LENGTH];
1471b0b00e3SLawrence Tang 		guid_to_string(partition_string, &header->PartitionID);
148e407b4c8SLawrence Tang 		json_object_object_add(
149e407b4c8SLawrence Tang 			header_ir, "partitionID",
150e407b4c8SLawrence 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);
156e407b4c8SLawrence Tang 	json_object_object_add(header_ir, "creatorID",
157e407b4c8SLawrence 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);
163e407b4c8SLawrence Tang 	json_object_object_add(
164e407b4c8SLawrence Tang 		notification_type, "guid",
165e407b4c8SLawrence 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";
169e407b4c8SLawrence Tang 	if (guid_equal(&header->NotificationType,
170e407b4c8SLawrence Tang 		       &gEfiEventNotificationTypeCmcGuid))
1711b0b00e3SLawrence Tang 		notification_type_readable = "CMC";
172e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
173e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeCpeGuid))
1741b0b00e3SLawrence Tang 		notification_type_readable = "CPE";
175e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
176e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeMceGuid))
1771b0b00e3SLawrence Tang 		notification_type_readable = "MCE";
178e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
179e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypePcieGuid))
1801b0b00e3SLawrence Tang 		notification_type_readable = "PCIe";
181e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
182e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeInitGuid))
1831b0b00e3SLawrence Tang 		notification_type_readable = "INIT";
184e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
185e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeNmiGuid))
1861b0b00e3SLawrence Tang 		notification_type_readable = "NMI";
187e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
188e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeBootGuid))
1891b0b00e3SLawrence Tang 		notification_type_readable = "Boot";
190e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
191e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeDmarGuid))
1921b0b00e3SLawrence Tang 		notification_type_readable = "DMAr";
193e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
194e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeSeaGuid))
1951b0b00e3SLawrence Tang 		notification_type_readable = "SEA";
196e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
197e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeSeiGuid))
1981b0b00e3SLawrence Tang 		notification_type_readable = "SEI";
199e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
200e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypePeiGuid))
2011b0b00e3SLawrence Tang 		notification_type_readable = "PEI";
202e407b4c8SLawrence Tang 	else if (guid_equal(&header->NotificationType,
203e407b4c8SLawrence Tang 			    &gEfiEventNotificationTypeCxlGuid))
2041b0b00e3SLawrence Tang 		notification_type_readable = "CXL Component";
205e407b4c8SLawrence Tang 	json_object_object_add(
206e407b4c8SLawrence Tang 		notification_type, "type",
207e407b4c8SLawrence Tang 		json_object_new_string(notification_type_readable));
208e407b4c8SLawrence Tang 	json_object_object_add(header_ir, "notificationType",
209e407b4c8SLawrence Tang 			       notification_type);
2101b0b00e3SLawrence Tang 
2111b0b00e3SLawrence Tang 	//The record ID for this record, unique on a given system.
212e407b4c8SLawrence Tang 	json_object_object_add(header_ir, "recordID",
213e407b4c8SLawrence Tang 			       json_object_new_uint64(header->RecordID));
2141b0b00e3SLawrence Tang 
2151b0b00e3SLawrence Tang 	//Flag for the record, and a human readable form.
216e407b4c8SLawrence Tang 	json_object *flags = integer_to_readable_pair(
217e407b4c8SLawrence Tang 		header->Flags,
2183c43f743SLawrence Tang 		sizeof(CPER_HEADER_FLAG_TYPES_KEYS) / sizeof(int),
219e407b4c8SLawrence 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.
224e407b4c8SLawrence Tang 	json_object_object_add(header_ir, "persistenceInfo",
225e407b4c8SLawrence 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.
230e407b4c8SLawrence Tang json_object *
231e407b4c8SLawrence 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.
236e407b4c8SLawrence Tang 	json_object_object_add(
237e407b4c8SLawrence Tang 		section_descriptor_ir, "sectionOffset",
238e407b4c8SLawrence Tang 		json_object_new_uint64(section_descriptor->SectionOffset));
239e407b4c8SLawrence Tang 	json_object_object_add(
240e407b4c8SLawrence Tang 		section_descriptor_ir, "sectionLength",
241e407b4c8SLawrence Tang 		json_object_new_uint64(section_descriptor->SectionLength));
2421b0b00e3SLawrence Tang 
2431b0b00e3SLawrence Tang 	//Revision.
244e407b4c8SLawrence Tang 	json_object_object_add(section_descriptor_ir, "revision",
245e407b4c8SLawrence Tang 			       revision_to_ir(section_descriptor->Revision));
2461b0b00e3SLawrence Tang 
2471b0b00e3SLawrence Tang 	//Validation bits.
248e407b4c8SLawrence Tang 	json_object *validation_bits =
249e407b4c8SLawrence Tang 		bitfield_to_ir(section_descriptor->SecValidMask, 2,
250e407b4c8SLawrence Tang 			       CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES);
251e407b4c8SLawrence Tang 	json_object_object_add(section_descriptor_ir, "validationBits",
252e407b4c8SLawrence Tang 			       validation_bits);
2531b0b00e3SLawrence Tang 
2541b0b00e3SLawrence Tang 	//Flag bits.
255e407b4c8SLawrence Tang 	json_object *flags =
256e407b4c8SLawrence Tang 		bitfield_to_ir(section_descriptor->SectionFlags, 8,
257e407b4c8SLawrence 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);
264e407b4c8SLawrence Tang 	json_object_object_add(section_type, "data",
265e407b4c8SLawrence Tang 			       json_object_new_string(section_type_string));
2661b0b00e3SLawrence Tang 
2671b0b00e3SLawrence Tang 	//Readable section type, if possible.
2681b0b00e3SLawrence Tang 	char *section_type_readable = "Unknown";
269e407b4c8SLawrence Tang 	if (guid_equal(&section_descriptor->SectionType,
270e407b4c8SLawrence Tang 		       &gEfiProcessorGenericErrorSectionGuid))
2711b0b00e3SLawrence Tang 		section_type_readable = "Processor Generic";
272e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
273e407b4c8SLawrence Tang 			    &gEfiIa32X64ProcessorErrorSectionGuid))
2741b0b00e3SLawrence Tang 		section_type_readable = "IA32/X64";
275e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
276e407b4c8SLawrence Tang 			    &gEfiIpfProcessorErrorSectionGuid))
277cc0f5f38SLawrence Tang 		section_type_readable = "IPF";
278e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
279e407b4c8SLawrence Tang 			    &gEfiArmProcessorErrorSectionGuid))
2801b0b00e3SLawrence Tang 		section_type_readable = "ARM";
281e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
282e407b4c8SLawrence Tang 			    &gEfiPlatformMemoryErrorSectionGuid) ||
283e407b4c8SLawrence Tang 		 guid_equal(&section_descriptor->SectionType,
284e407b4c8SLawrence Tang 			    &gEfiPlatformMemoryError2SectionGuid))
2851b0b00e3SLawrence Tang 		section_type_readable = "Platform Memory";
286e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
287e407b4c8SLawrence Tang 			    &gEfiPcieErrorSectionGuid))
2881b0b00e3SLawrence Tang 		section_type_readable = "PCIe";
289e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
290e407b4c8SLawrence Tang 			    &gEfiFirmwareErrorSectionGuid))
2911b0b00e3SLawrence Tang 		section_type_readable = "Firmware Error Record Reference";
292e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
293e407b4c8SLawrence Tang 			    &gEfiPciBusErrorSectionGuid))
2941b0b00e3SLawrence Tang 		section_type_readable = "PCI/PCI-X Bus";
295e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
296e407b4c8SLawrence Tang 			    &gEfiPciDevErrorSectionGuid))
2971b0b00e3SLawrence Tang 		section_type_readable = "PCI Component/Device";
298e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
299e407b4c8SLawrence Tang 			    &gEfiDMArGenericErrorSectionGuid))
3001b0b00e3SLawrence Tang 		section_type_readable = "DMAr Generic";
301e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
302e407b4c8SLawrence Tang 			    &gEfiDirectedIoDMArErrorSectionGuid))
303e407b4c8SLawrence Tang 		section_type_readable =
304e407b4c8SLawrence Tang 			"Intel VT for Directed I/O specific DMAr section";
305e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
306e407b4c8SLawrence Tang 			    &gEfiIommuDMArErrorSectionGuid))
3071b0b00e3SLawrence Tang 		section_type_readable = "IOMMU specific DMAr section";
308e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
309e407b4c8SLawrence Tang 			    &gEfiCcixPerLogErrorSectionGuid))
310864c0da9SLawrence Tang 		section_type_readable = "CCIX PER Log Error";
311e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
312e407b4c8SLawrence Tang 			    &gEfiCxlProtocolErrorSectionGuid))
313b98ec66cSLawrence Tang 		section_type_readable = "CXL Protocol Error";
314e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
315e407b4c8SLawrence Tang 			    &gEfiCxlGeneralMediaErrorSectionGuid))
316d7e8ca34SLawrence Tang 		section_type_readable = "CXL General Media Component Error";
317e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
318e407b4c8SLawrence Tang 			    &gEfiCxlDramEventErrorSectionGuid))
319d7e8ca34SLawrence Tang 		section_type_readable = "CXL DRAM Component Error";
320e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
321e407b4c8SLawrence Tang 			    &gEfiCxlPhysicalSwitchErrorSectionGuid))
322d7e8ca34SLawrence Tang 		section_type_readable = "CXL Physical Switch Component Error";
323e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
324e407b4c8SLawrence Tang 			    &gEfiCxlVirtualSwitchErrorSectionGuid))
325d7e8ca34SLawrence Tang 		section_type_readable = "CXL Virtual Switch Component Error";
326e407b4c8SLawrence Tang 	else if (guid_equal(&section_descriptor->SectionType,
327e407b4c8SLawrence Tang 			    &gEfiCxlMldPortErrorSectionGuid))
328d7e8ca34SLawrence Tang 		section_type_readable = "CXL MLD Port Component Error";
3291b0b00e3SLawrence Tang 
330e407b4c8SLawrence Tang 	json_object_object_add(section_type, "type",
331e407b4c8SLawrence Tang 			       json_object_new_string(section_type_readable));
332e407b4c8SLawrence Tang 	json_object_object_add(section_descriptor_ir, "sectionType",
333e407b4c8SLawrence Tang 			       section_type);
3341b0b00e3SLawrence Tang 
3351b0b00e3SLawrence Tang 	//If validation bits indicate it exists, add FRU ID.
336e407b4c8SLawrence 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);
339e407b4c8SLawrence Tang 		json_object_object_add(section_descriptor_ir, "fruID",
340e407b4c8SLawrence 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)
345e407b4c8SLawrence Tang 		json_object_object_add(
346e407b4c8SLawrence Tang 			section_descriptor_ir, "fruText",
347e407b4c8SLawrence Tang 			json_object_new_string(section_descriptor->FruString));
3481b0b00e3SLawrence Tang 
3491b0b00e3SLawrence Tang 	//Section severity.
3501b0b00e3SLawrence Tang 	json_object *section_severity = json_object_new_object();
351e407b4c8SLawrence Tang 	json_object_object_add(
352e407b4c8SLawrence Tang 		section_severity, "code",
353e407b4c8SLawrence Tang 		json_object_new_uint64(section_descriptor->Severity));
354e407b4c8SLawrence Tang 	json_object_object_add(section_severity, "name",
355e407b4c8SLawrence Tang 			       json_object_new_string(severity_to_string(
356e407b4c8SLawrence Tang 				       section_descriptor->Severity)));
357e407b4c8SLawrence Tang 	json_object_object_add(section_descriptor_ir, "severity",
358e407b4c8SLawrence 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.
364e407b4c8SLawrence Tang json_object *cper_section_to_ir(FILE *handle,
365e407b4c8SLawrence 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);
373e407b4c8SLawrence 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",
375e407b4c8SLawrence 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;
385e407b4c8SLawrence Tang 	if (guid_equal(&descriptor->SectionType,
386e407b4c8SLawrence Tang 		       &gEfiProcessorGenericErrorSectionGuid))
3872800cd8eSLawrence Tang 		result = cper_section_generic_to_ir(section, descriptor);
388e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
389e407b4c8SLawrence Tang 			    &gEfiIa32X64ProcessorErrorSectionGuid))
3902800cd8eSLawrence Tang 		result = cper_section_ia32x64_to_ir(section, descriptor);
391e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
392e407b4c8SLawrence Tang 			    &gEfiIpfProcessorErrorSectionGuid))
393cc0f5f38SLawrence Tang 		result = cper_section_ipf_to_ir(section, descriptor);
394e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
395e407b4c8SLawrence Tang 			    &gEfiArmProcessorErrorSectionGuid))
3962800cd8eSLawrence Tang 		result = cper_section_arm_to_ir(section, descriptor);
397e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
398e407b4c8SLawrence Tang 			    &gEfiPlatformMemoryErrorSectionGuid))
399e407b4c8SLawrence Tang 		result =
400e407b4c8SLawrence Tang 			cper_section_platform_memory_to_ir(section, descriptor);
401e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
402e407b4c8SLawrence Tang 			    &gEfiPlatformMemoryError2SectionGuid))
403e407b4c8SLawrence Tang 		result = cper_section_platform_memory2_to_ir(section,
404e407b4c8SLawrence Tang 							     descriptor);
405e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
406e407b4c8SLawrence Tang 			    &gEfiPcieErrorSectionGuid))
4074dbe3d72SLawrence Tang 		result = cper_section_pcie_to_ir(section, descriptor);
408e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
409e407b4c8SLawrence Tang 			    &gEfiFirmwareErrorSectionGuid))
410c60a243eSLawrence Tang 		result = cper_section_firmware_to_ir(section, descriptor);
411e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
412e407b4c8SLawrence Tang 			    &gEfiPciBusErrorSectionGuid))
413214a1542SLawrence Tang 		result = cper_section_pci_bus_to_ir(section, descriptor);
414e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
415e407b4c8SLawrence Tang 			    &gEfiPciDevErrorSectionGuid))
416a416ec93SLawrence Tang 		result = cper_section_pci_dev_to_ir(section, descriptor);
417e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
418e407b4c8SLawrence Tang 			    &gEfiDMArGenericErrorSectionGuid))
4194795d4aeSLawrence Tang 		result = cper_section_dmar_generic_to_ir(section, descriptor);
420e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
421e407b4c8SLawrence Tang 			    &gEfiDirectedIoDMArErrorSectionGuid))
422db1b7ce2SLawrence Tang 		result = cper_section_dmar_vtd_to_ir(section, descriptor);
423e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
424e407b4c8SLawrence Tang 			    &gEfiIommuDMArErrorSectionGuid))
425db1b7ce2SLawrence Tang 		result = cper_section_dmar_iommu_to_ir(section, descriptor);
426e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
427e407b4c8SLawrence Tang 			    &gEfiCcixPerLogErrorSectionGuid))
428864c0da9SLawrence Tang 		result = cper_section_ccix_per_to_ir(section, descriptor);
429e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
430e407b4c8SLawrence Tang 			    &gEfiCxlProtocolErrorSectionGuid))
431b98ec66cSLawrence Tang 		result = cper_section_cxl_protocol_to_ir(section, descriptor);
432e407b4c8SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
433e407b4c8SLawrence Tang 			    &gEfiCxlGeneralMediaErrorSectionGuid) ||
434e407b4c8SLawrence Tang 		 guid_equal(&descriptor->SectionType,
435e407b4c8SLawrence Tang 			    &gEfiCxlDramEventErrorSectionGuid) ||
436e407b4c8SLawrence Tang 		 guid_equal(&descriptor->SectionType,
437e407b4c8SLawrence Tang 			    &gEfiCxlPhysicalSwitchErrorSectionGuid) ||
438e407b4c8SLawrence Tang 		 guid_equal(&descriptor->SectionType,
439e407b4c8SLawrence Tang 			    &gEfiCxlVirtualSwitchErrorSectionGuid) ||
440e407b4c8SLawrence Tang 		 guid_equal(&descriptor->SectionType,
441e407b4c8SLawrence Tang 			    &gEfiCxlMldPortErrorSectionGuid)) {
442d7e8ca34SLawrence Tang 		result = cper_section_cxl_component_to_ir(section, descriptor);
443e407b4c8SLawrence Tang 	} else {
444db1b7ce2SLawrence Tang 		//Failed read, unknown GUID.
445d7e8ca34SLawrence Tang 		//Output the data as formatted base64.
446d7e8ca34SLawrence Tang 		result = json_object_new_object();
447e407b4c8SLawrence Tang 		char *encoded = b64_encode((unsigned char *)section,
448e407b4c8SLawrence Tang 					   descriptor->SectionLength);
449e407b4c8SLawrence Tang 		json_object_object_add(result, "data",
450e407b4c8SLawrence 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 }
458617949e4SLawrence Tang 
459617949e4SLawrence Tang //Converts a single CPER section, without a header but with a section descriptor, to JSON.
460617949e4SLawrence Tang json_object *cper_single_section_to_ir(FILE *cper_section_file)
461617949e4SLawrence Tang {
462617949e4SLawrence Tang 	json_object *ir = json_object_new_object();
463617949e4SLawrence Tang 
464617949e4SLawrence Tang 	//Read the section descriptor out.
465617949e4SLawrence Tang 	EFI_ERROR_SECTION_DESCRIPTOR section_descriptor;
466617949e4SLawrence Tang 	if (fread(&section_descriptor, sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1,
467617949e4SLawrence Tang 		  cper_section_file) != 1) {
468617949e4SLawrence Tang 		printf("Failed to read section descriptor for CPER single section (fread() returned an unexpected value).\n");
469617949e4SLawrence Tang 		return NULL;
470617949e4SLawrence Tang 	}
471617949e4SLawrence Tang 
472617949e4SLawrence Tang 	//Convert the section descriptor to IR.
473617949e4SLawrence Tang 	json_object *section_descriptor_ir =
474617949e4SLawrence Tang 		cper_section_descriptor_to_ir(&section_descriptor);
475617949e4SLawrence Tang 	json_object_object_add(ir, "sectionDescriptor", section_descriptor_ir);
476617949e4SLawrence Tang 
477617949e4SLawrence Tang 	//Parse the single section.
478617949e4SLawrence Tang 	json_object *section_ir =
479617949e4SLawrence Tang 		cper_section_to_ir(cper_section_file, &section_descriptor);
480617949e4SLawrence Tang 	json_object_object_add(ir, "section", section_ir);
481617949e4SLawrence Tang 
482617949e4SLawrence Tang 	return ir;
483617949e4SLawrence Tang }