xref: /openbmc/libcper/ir-parse.c (revision e407b4c8)
1f0f95574SLawrence Tang /**
2f0f95574SLawrence Tang  * Describes functions for parsing JSON IR CPER data into binary CPER format.
3f0f95574SLawrence Tang  *
4f0f95574SLawrence Tang  * Author: Lawrence.Tang@arm.com
5f0f95574SLawrence Tang  **/
6f0f95574SLawrence Tang 
7f0f95574SLawrence Tang #include <stdio.h>
80cb33793SLawrence Tang #include <string.h>
9f0f95574SLawrence Tang #include "json.h"
100cb33793SLawrence Tang #include "b64.h"
11b44314c7SLawrence Tang #include "edk/Cper.h"
12f0f95574SLawrence Tang #include "cper-parse.h"
13b44314c7SLawrence Tang #include "cper-utils.h"
140cb33793SLawrence Tang #include "sections/cper-section-generic.h"
150cb33793SLawrence Tang #include "sections/cper-section-ia32x64.h"
160cb33793SLawrence Tang #include "sections/cper-section-arm.h"
170cb33793SLawrence Tang #include "sections/cper-section-memory.h"
180cb33793SLawrence Tang #include "sections/cper-section-pcie.h"
190cb33793SLawrence Tang #include "sections/cper-section-pci-bus.h"
200cb33793SLawrence Tang #include "sections/cper-section-pci-dev.h"
210cb33793SLawrence Tang #include "sections/cper-section-firmware.h"
220cb33793SLawrence Tang #include "sections/cper-section-dmar-generic.h"
230cb33793SLawrence Tang #include "sections/cper-section-dmar-vtd.h"
240cb33793SLawrence Tang #include "sections/cper-section-dmar-iommu.h"
250cb33793SLawrence Tang #include "sections/cper-section-ccix-per.h"
260cb33793SLawrence Tang #include "sections/cper-section-cxl-protocol.h"
270cb33793SLawrence Tang #include "sections/cper-section-ipf.h"
280cb33793SLawrence Tang #include "sections/cper-section-cxl-component.h"
29b44314c7SLawrence Tang 
30b44314c7SLawrence Tang //Private pre-declarations.
31*e407b4c8SLawrence Tang void ir_header_to_cper(json_object *header_ir,
32*e407b4c8SLawrence Tang 		       EFI_COMMON_ERROR_RECORD_HEADER *header);
33*e407b4c8SLawrence Tang void ir_section_descriptor_to_cper(json_object *section_descriptor_ir,
34*e407b4c8SLawrence Tang 				   EFI_ERROR_SECTION_DESCRIPTOR *descriptor);
35f0f95574SLawrence Tang 
36f0f95574SLawrence Tang //Converts the given JSON IR CPER representation into CPER binary format, piped to the provided file stream.
370cb33793SLawrence Tang //This function performs no validation of the IR against the CPER-JSON specification. To ensure a safe call,
380cb33793SLawrence Tang //use validate_schema() from json-schema.h before attempting to call this function.
39f0f95574SLawrence Tang void ir_to_cper(json_object *ir, FILE *out)
40f0f95574SLawrence Tang {
41b44314c7SLawrence Tang 	//Create the CPER header.
42*e407b4c8SLawrence Tang 	EFI_COMMON_ERROR_RECORD_HEADER *header =
43*e407b4c8SLawrence Tang 		(EFI_COMMON_ERROR_RECORD_HEADER *)calloc(
44*e407b4c8SLawrence Tang 			1, sizeof(EFI_COMMON_ERROR_RECORD_HEADER));
45b44314c7SLawrence Tang 	ir_header_to_cper(json_object_object_get(ir, "header"), header);
46b44314c7SLawrence Tang 	fwrite(header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, out);
47b44314c7SLawrence Tang 	fflush(out);
480cb33793SLawrence Tang 
490cb33793SLawrence Tang 	//Create the CPER section descriptors.
50*e407b4c8SLawrence Tang 	json_object *section_descriptors =
51*e407b4c8SLawrence Tang 		json_object_object_get(ir, "sectionDescriptors");
520cb33793SLawrence Tang 	int amt_descriptors = json_object_array_length(section_descriptors);
530cb33793SLawrence Tang 	EFI_ERROR_SECTION_DESCRIPTOR *descriptors[amt_descriptors];
54*e407b4c8SLawrence Tang 	for (int i = 0; i < amt_descriptors; i++) {
55*e407b4c8SLawrence Tang 		descriptors[i] = (EFI_ERROR_SECTION_DESCRIPTOR *)calloc(
56*e407b4c8SLawrence Tang 			1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR));
57*e407b4c8SLawrence Tang 		ir_section_descriptor_to_cper(
58*e407b4c8SLawrence Tang 			json_object_array_get_idx(section_descriptors, i),
59*e407b4c8SLawrence Tang 			descriptors[i]);
60*e407b4c8SLawrence Tang 		fwrite(descriptors[i], sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1,
61*e407b4c8SLawrence Tang 		       out);
620cb33793SLawrence Tang 		fflush(out);
630cb33793SLawrence Tang 	}
640cb33793SLawrence Tang 
650cb33793SLawrence Tang 	//Run through each section in turn.
660cb33793SLawrence Tang 	json_object *sections = json_object_object_get(ir, "sections");
670cb33793SLawrence Tang 	int amt_sections = json_object_array_length(sections);
68*e407b4c8SLawrence Tang 	for (int i = 0; i < amt_sections; i++) {
690cb33793SLawrence Tang 		//Get the section itself from the IR.
700cb33793SLawrence Tang 		json_object *section = json_object_array_get_idx(sections, i);
710cb33793SLawrence Tang 
720cb33793SLawrence Tang 		//Find the correct section type, and parse.
73*e407b4c8SLawrence Tang 		if (guid_equal(&descriptors[i]->SectionType,
74*e407b4c8SLawrence Tang 			       &gEfiProcessorGenericErrorSectionGuid))
750cb33793SLawrence Tang 			ir_section_generic_to_cper(section, out);
76*e407b4c8SLawrence Tang 		else if (guid_equal(&descriptors[i]->SectionType,
77*e407b4c8SLawrence Tang 				    &gEfiIa32X64ProcessorErrorSectionGuid))
78d0c88849SLawrence Tang 			ir_section_ia32x64_to_cper(section, out);
790cb33793SLawrence Tang 		// else if (guid_equal(&descriptors[i]->SectionType, &gEfiIpfProcessorErrorSectionGuid))
800cb33793SLawrence Tang 		//     ir_section_ipf_to_cper(section, out);
81*e407b4c8SLawrence Tang 		else if (guid_equal(&descriptors[i]->SectionType,
82*e407b4c8SLawrence Tang 				    &gEfiArmProcessorErrorSectionGuid))
8371570a2aSLawrence Tang 			ir_section_arm_to_cper(section, out);
84*e407b4c8SLawrence Tang 		else if (guid_equal(&descriptors[i]->SectionType,
85*e407b4c8SLawrence Tang 				    &gEfiPlatformMemoryErrorSectionGuid))
863b7f45b5SLawrence Tang 			ir_section_memory_to_cper(section, out);
87*e407b4c8SLawrence Tang 		else if (guid_equal(&descriptors[i]->SectionType,
88*e407b4c8SLawrence Tang 				    &gEfiPlatformMemoryError2SectionGuid))
893b7f45b5SLawrence Tang 			ir_section_memory2_to_cper(section, out);
90*e407b4c8SLawrence Tang 		else if (guid_equal(&descriptors[i]->SectionType,
91*e407b4c8SLawrence Tang 				    &gEfiPcieErrorSectionGuid))
923b7f45b5SLawrence Tang 			ir_section_pcie_to_cper(section, out);
93*e407b4c8SLawrence Tang 		else if (guid_equal(&descriptors[i]->SectionType,
94*e407b4c8SLawrence Tang 				    &gEfiFirmwareErrorSectionGuid))
95205dd1d7SLawrence Tang 			ir_section_firmware_to_cper(section, out);
96*e407b4c8SLawrence Tang 		else if (guid_equal(&descriptors[i]->SectionType,
97*e407b4c8SLawrence Tang 				    &gEfiPciBusErrorSectionGuid))
98205dd1d7SLawrence Tang 			ir_section_pci_bus_to_cper(section, out);
99*e407b4c8SLawrence Tang 		else if (guid_equal(&descriptors[i]->SectionType,
100*e407b4c8SLawrence Tang 				    &gEfiPciDevErrorSectionGuid))
101205dd1d7SLawrence Tang 			ir_section_pci_dev_to_cper(section, out);
102*e407b4c8SLawrence Tang 		else if (guid_equal(&descriptors[i]->SectionType,
103*e407b4c8SLawrence Tang 				    &gEfiDMArGenericErrorSectionGuid))
104205dd1d7SLawrence Tang 			ir_section_dmar_generic_to_cper(section, out);
105*e407b4c8SLawrence Tang 		else if (guid_equal(&descriptors[i]->SectionType,
106*e407b4c8SLawrence Tang 				    &gEfiDirectedIoDMArErrorSectionGuid))
107205dd1d7SLawrence Tang 			ir_section_dmar_vtd_to_cper(section, out);
108*e407b4c8SLawrence Tang 		else if (guid_equal(&descriptors[i]->SectionType,
109*e407b4c8SLawrence Tang 				    &gEfiIommuDMArErrorSectionGuid))
110205dd1d7SLawrence Tang 			ir_section_dmar_iommu_to_cper(section, out);
111*e407b4c8SLawrence Tang 		else if (guid_equal(&descriptors[i]->SectionType,
112*e407b4c8SLawrence Tang 				    &gEfiCcixPerLogErrorSectionGuid))
113aec83900SLawrence Tang 			ir_section_ccix_per_to_cper(section, out);
114*e407b4c8SLawrence Tang 		else if (guid_equal(&descriptors[i]->SectionType,
115*e407b4c8SLawrence Tang 				    &gEfiCxlProtocolErrorSectionGuid))
116aec83900SLawrence Tang 			ir_section_cxl_protocol_to_cper(section, out);
117*e407b4c8SLawrence Tang 		else if (guid_equal(&descriptors[i]->SectionType,
118*e407b4c8SLawrence Tang 				    &gEfiCxlGeneralMediaErrorSectionGuid) ||
119*e407b4c8SLawrence Tang 			 guid_equal(&descriptors[i]->SectionType,
120*e407b4c8SLawrence Tang 				    &gEfiCxlDramEventErrorSectionGuid) ||
121*e407b4c8SLawrence Tang 			 guid_equal(&descriptors[i]->SectionType,
122*e407b4c8SLawrence Tang 				    &gEfiCxlPhysicalSwitchErrorSectionGuid) ||
123*e407b4c8SLawrence Tang 			 guid_equal(&descriptors[i]->SectionType,
124*e407b4c8SLawrence Tang 				    &gEfiCxlVirtualSwitchErrorSectionGuid) ||
125*e407b4c8SLawrence Tang 			 guid_equal(&descriptors[i]->SectionType,
126*e407b4c8SLawrence Tang 				    &gEfiCxlMldPortErrorSectionGuid)) {
127aec83900SLawrence Tang 			ir_section_cxl_component_to_cper(section, out);
128*e407b4c8SLawrence Tang 		} else {
1290cb33793SLawrence Tang 			//Unknown GUID, so read as a base64 unknown section.
130*e407b4c8SLawrence Tang 			json_object *encoded =
131*e407b4c8SLawrence Tang 				json_object_object_get(section, "data");
132*e407b4c8SLawrence Tang 			UINT8 *decoded =
133*e407b4c8SLawrence Tang 				b64_decode(json_object_get_string(encoded),
134*e407b4c8SLawrence Tang 					   json_object_get_string_len(encoded));
1350cb33793SLawrence Tang 			fwrite(decoded, descriptors[i]->SectionLength, 1, out);
1360cb33793SLawrence Tang 			fflush(out);
1370cb33793SLawrence Tang 			free(decoded);
1380cb33793SLawrence Tang 		}
1390cb33793SLawrence Tang 	}
1400cb33793SLawrence Tang 
1410cb33793SLawrence Tang 	//Free all remaining resources.
142b44314c7SLawrence Tang 	free(header);
1430cb33793SLawrence Tang 	for (int i = 0; i < amt_descriptors; i++)
1440cb33793SLawrence Tang 		free(descriptors[i]);
145b44314c7SLawrence Tang }
146b44314c7SLawrence Tang 
147b44314c7SLawrence Tang //Converts a CPER-JSON IR header to a CPER header structure.
148*e407b4c8SLawrence Tang void ir_header_to_cper(json_object *header_ir,
149*e407b4c8SLawrence Tang 		       EFI_COMMON_ERROR_RECORD_HEADER *header)
150b44314c7SLawrence Tang {
151b44314c7SLawrence Tang 	header->SignatureStart = 0x52455043; //CPER
152b44314c7SLawrence Tang 
153b44314c7SLawrence Tang 	//Revision.
154b44314c7SLawrence Tang 	json_object *revision = json_object_object_get(header_ir, "revision");
155*e407b4c8SLawrence Tang 	int minor =
156*e407b4c8SLawrence Tang 		json_object_get_int(json_object_object_get(revision, "minor"));
157*e407b4c8SLawrence Tang 	int major =
158*e407b4c8SLawrence Tang 		json_object_get_int(json_object_object_get(revision, "major"));
159b44314c7SLawrence Tang 	header->Revision = minor + (major << 8);
160b44314c7SLawrence Tang 
161b44314c7SLawrence Tang 	header->SignatureEnd = 0xFFFFFFFF;
162b44314c7SLawrence Tang 
163b44314c7SLawrence Tang 	//Section count.
164*e407b4c8SLawrence Tang 	int section_count = json_object_get_int(
165*e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "sectionCount"));
166b44314c7SLawrence Tang 	header->SectionCount = (UINT16)section_count;
167b44314c7SLawrence Tang 
168b44314c7SLawrence Tang 	//Error severity.
169b44314c7SLawrence Tang 	json_object *severity = json_object_object_get(header_ir, "severity");
170*e407b4c8SLawrence Tang 	header->ErrorSeverity = (UINT32)json_object_get_uint64(
171*e407b4c8SLawrence Tang 		json_object_object_get(severity, "code"));
172b44314c7SLawrence Tang 
173b44314c7SLawrence Tang 	//Validation bits.
174*e407b4c8SLawrence Tang 	header->ValidationBits = ir_to_bitfield(
175*e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "validationBits"), 3,
176*e407b4c8SLawrence Tang 		CPER_HEADER_VALID_BITFIELD_NAMES);
177b44314c7SLawrence Tang 
178b44314c7SLawrence Tang 	//Record length.
179*e407b4c8SLawrence Tang 	header->RecordLength = (UINT32)json_object_get_uint64(
180*e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "recordLength"));
181b44314c7SLawrence Tang 
182b44314c7SLawrence Tang 	//Timestamp, if present.
183b44314c7SLawrence Tang 	json_object *timestamp = json_object_object_get(header_ir, "timestamp");
184*e407b4c8SLawrence Tang 	if (timestamp != NULL) {
185*e407b4c8SLawrence Tang 		string_to_timestamp(&header->TimeStamp,
186*e407b4c8SLawrence Tang 				    json_object_get_string(timestamp));
187*e407b4c8SLawrence Tang 		header->TimeStamp.Flag = json_object_get_boolean(
188*e407b4c8SLawrence Tang 			json_object_object_get(header_ir,
189*e407b4c8SLawrence Tang 					       "timestampIsPrecise"));
190b44314c7SLawrence Tang 	}
191b44314c7SLawrence Tang 
192b44314c7SLawrence Tang 	//Various GUIDs.
193*e407b4c8SLawrence Tang 	json_object *platform_id =
194*e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "platformID");
195*e407b4c8SLawrence Tang 	json_object *partition_id =
196*e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "partitionID");
197b44314c7SLawrence Tang 	if (platform_id != NULL)
198*e407b4c8SLawrence Tang 		string_to_guid(&header->PlatformID,
199*e407b4c8SLawrence Tang 			       json_object_get_string(platform_id));
200b44314c7SLawrence Tang 	if (partition_id != NULL)
201*e407b4c8SLawrence Tang 		string_to_guid(&header->PartitionID,
202*e407b4c8SLawrence Tang 			       json_object_get_string(partition_id));
203*e407b4c8SLawrence Tang 	string_to_guid(&header->CreatorID,
204*e407b4c8SLawrence Tang 		       json_object_get_string(
205*e407b4c8SLawrence Tang 			       json_object_object_get(header_ir, "creatorID")));
206b44314c7SLawrence Tang 
207b44314c7SLawrence Tang 	//Notification type.
208*e407b4c8SLawrence Tang 	json_object *notification_type =
209*e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "notificationType");
210*e407b4c8SLawrence Tang 	string_to_guid(&header->NotificationType,
211*e407b4c8SLawrence Tang 		       json_object_get_string(json_object_object_get(
212*e407b4c8SLawrence Tang 			       notification_type, "guid")));
213b44314c7SLawrence Tang 
214b44314c7SLawrence Tang 	//Record ID, persistence info.
215*e407b4c8SLawrence Tang 	header->RecordID = json_object_get_uint64(
216*e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "recordID"));
217*e407b4c8SLawrence Tang 	header->PersistenceInfo = json_object_get_uint64(
218*e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "persistenceInfo"));
219b44314c7SLawrence Tang 
220b44314c7SLawrence Tang 	//Flags.
221b44314c7SLawrence Tang 	json_object *flags = json_object_object_get(header_ir, "flags");
222*e407b4c8SLawrence Tang 	header->Flags = (UINT32)json_object_get_uint64(
223*e407b4c8SLawrence Tang 		json_object_object_get(flags, "value"));
224f0f95574SLawrence Tang }
2250cb33793SLawrence Tang 
2260cb33793SLawrence Tang //Converts a single CPER-JSON IR section descriptor into a CPER structure.
227*e407b4c8SLawrence Tang void ir_section_descriptor_to_cper(json_object *section_descriptor_ir,
228*e407b4c8SLawrence Tang 				   EFI_ERROR_SECTION_DESCRIPTOR *descriptor)
2290cb33793SLawrence Tang {
2300cb33793SLawrence Tang 	//Section offset, length.
231*e407b4c8SLawrence Tang 	descriptor->SectionOffset = (UINT32)json_object_get_uint64(
232*e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "sectionOffset"));
233*e407b4c8SLawrence Tang 	descriptor->SectionLength = (UINT32)json_object_get_uint64(
234*e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "sectionLength"));
2350cb33793SLawrence Tang 
2360cb33793SLawrence Tang 	//Revision.
237*e407b4c8SLawrence Tang 	json_object *revision =
238*e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "revision");
239*e407b4c8SLawrence Tang 	int minor =
240*e407b4c8SLawrence Tang 		json_object_get_int(json_object_object_get(revision, "minor"));
241*e407b4c8SLawrence Tang 	int major =
242*e407b4c8SLawrence Tang 		json_object_get_int(json_object_object_get(revision, "major"));
2430cb33793SLawrence Tang 	descriptor->Revision = minor + (major << 8);
2440cb33793SLawrence Tang 
2450cb33793SLawrence Tang 	//Validation bits, flags.
246*e407b4c8SLawrence Tang 	descriptor->SecValidMask = ir_to_bitfield(
247*e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "validationBits"),
2480cb33793SLawrence Tang 		2, CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES);
249*e407b4c8SLawrence Tang 	descriptor->SectionFlags = ir_to_bitfield(
250*e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "flags"), 8,
251*e407b4c8SLawrence Tang 		CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES);
2520cb33793SLawrence Tang 
2530cb33793SLawrence Tang 	//Section type.
254*e407b4c8SLawrence Tang 	json_object *section_type =
255*e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "sectionType");
256*e407b4c8SLawrence Tang 	string_to_guid(&descriptor->SectionType,
257*e407b4c8SLawrence Tang 		       json_object_get_string(
258*e407b4c8SLawrence Tang 			       json_object_object_get(section_type, "data")));
2590cb33793SLawrence Tang 
2600cb33793SLawrence Tang 	//FRU ID, if present.
261*e407b4c8SLawrence Tang 	json_object *fru_id =
262*e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "fruID");
2630cb33793SLawrence Tang 	if (fru_id != NULL)
264*e407b4c8SLawrence Tang 		string_to_guid(&descriptor->FruId,
265*e407b4c8SLawrence Tang 			       json_object_get_string(fru_id));
2660cb33793SLawrence Tang 
2670cb33793SLawrence Tang 	//Severity code.
268*e407b4c8SLawrence Tang 	json_object *severity =
269*e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "severity");
270*e407b4c8SLawrence Tang 	descriptor->Severity = (UINT32)json_object_get_uint64(
271*e407b4c8SLawrence Tang 		json_object_object_get(severity, "code"));
2720cb33793SLawrence Tang 
2730cb33793SLawrence Tang 	//FRU text, if present.
274*e407b4c8SLawrence Tang 	json_object *fru_text =
275*e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "fruText");
2760cb33793SLawrence Tang 	if (fru_text != NULL)
277*e407b4c8SLawrence Tang 		strncpy(descriptor->FruString, json_object_get_string(fru_text),
278*e407b4c8SLawrence Tang 			20);
2790cb33793SLawrence Tang }