xref: /openbmc/libcper/ir-parse.c (revision 5202bbb4)
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>
9*5202bbb4SLawrence 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.
31e407b4c8SLawrence Tang void ir_header_to_cper(json_object *header_ir,
32e407b4c8SLawrence Tang 		       EFI_COMMON_ERROR_RECORD_HEADER *header);
33e407b4c8SLawrence Tang void ir_section_descriptor_to_cper(json_object *section_descriptor_ir,
34e407b4c8SLawrence Tang 				   EFI_ERROR_SECTION_DESCRIPTOR *descriptor);
35617949e4SLawrence Tang void ir_section_to_cper(json_object *section,
36617949e4SLawrence Tang 			EFI_ERROR_SECTION_DESCRIPTOR *descriptor, FILE *out);
37f0f95574SLawrence Tang 
38f0f95574SLawrence Tang //Converts the given JSON IR CPER representation into CPER binary format, piped to the provided file stream.
390cb33793SLawrence Tang //This function performs no validation of the IR against the CPER-JSON specification. To ensure a safe call,
400cb33793SLawrence Tang //use validate_schema() from json-schema.h before attempting to call this function.
41f0f95574SLawrence Tang void ir_to_cper(json_object *ir, FILE *out)
42f0f95574SLawrence Tang {
43b44314c7SLawrence Tang 	//Create the CPER header.
44e407b4c8SLawrence Tang 	EFI_COMMON_ERROR_RECORD_HEADER *header =
45e407b4c8SLawrence Tang 		(EFI_COMMON_ERROR_RECORD_HEADER *)calloc(
46e407b4c8SLawrence Tang 			1, sizeof(EFI_COMMON_ERROR_RECORD_HEADER));
47b44314c7SLawrence Tang 	ir_header_to_cper(json_object_object_get(ir, "header"), header);
48b44314c7SLawrence Tang 	fwrite(header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, out);
49b44314c7SLawrence Tang 	fflush(out);
500cb33793SLawrence Tang 
510cb33793SLawrence Tang 	//Create the CPER section descriptors.
52e407b4c8SLawrence Tang 	json_object *section_descriptors =
53e407b4c8SLawrence Tang 		json_object_object_get(ir, "sectionDescriptors");
540cb33793SLawrence Tang 	int amt_descriptors = json_object_array_length(section_descriptors);
550cb33793SLawrence Tang 	EFI_ERROR_SECTION_DESCRIPTOR *descriptors[amt_descriptors];
56e407b4c8SLawrence Tang 	for (int i = 0; i < amt_descriptors; i++) {
57e407b4c8SLawrence Tang 		descriptors[i] = (EFI_ERROR_SECTION_DESCRIPTOR *)calloc(
58e407b4c8SLawrence Tang 			1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR));
59e407b4c8SLawrence Tang 		ir_section_descriptor_to_cper(
60e407b4c8SLawrence Tang 			json_object_array_get_idx(section_descriptors, i),
61e407b4c8SLawrence Tang 			descriptors[i]);
62e407b4c8SLawrence Tang 		fwrite(descriptors[i], sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1,
63e407b4c8SLawrence Tang 		       out);
640cb33793SLawrence Tang 		fflush(out);
650cb33793SLawrence Tang 	}
660cb33793SLawrence Tang 
670cb33793SLawrence Tang 	//Run through each section in turn.
680cb33793SLawrence Tang 	json_object *sections = json_object_object_get(ir, "sections");
690cb33793SLawrence Tang 	int amt_sections = json_object_array_length(sections);
70e407b4c8SLawrence Tang 	for (int i = 0; i < amt_sections; i++) {
710cb33793SLawrence Tang 		//Get the section itself from the IR.
720cb33793SLawrence Tang 		json_object *section = json_object_array_get_idx(sections, i);
730cb33793SLawrence Tang 
74617949e4SLawrence Tang 		//Convert.
75617949e4SLawrence Tang 		ir_section_to_cper(section, descriptors[i], out);
760cb33793SLawrence Tang 	}
770cb33793SLawrence Tang 
780cb33793SLawrence Tang 	//Free all remaining resources.
79b44314c7SLawrence Tang 	free(header);
800cb33793SLawrence Tang 	for (int i = 0; i < amt_descriptors; i++)
810cb33793SLawrence Tang 		free(descriptors[i]);
82b44314c7SLawrence Tang }
83b44314c7SLawrence Tang 
84b44314c7SLawrence Tang //Converts a CPER-JSON IR header to a CPER header structure.
85e407b4c8SLawrence Tang void ir_header_to_cper(json_object *header_ir,
86e407b4c8SLawrence Tang 		       EFI_COMMON_ERROR_RECORD_HEADER *header)
87b44314c7SLawrence Tang {
88b44314c7SLawrence Tang 	header->SignatureStart = 0x52455043; //CPER
89b44314c7SLawrence Tang 
90b44314c7SLawrence Tang 	//Revision.
91b44314c7SLawrence Tang 	json_object *revision = json_object_object_get(header_ir, "revision");
92e407b4c8SLawrence Tang 	int minor =
93e407b4c8SLawrence Tang 		json_object_get_int(json_object_object_get(revision, "minor"));
94e407b4c8SLawrence Tang 	int major =
95e407b4c8SLawrence Tang 		json_object_get_int(json_object_object_get(revision, "major"));
96b44314c7SLawrence Tang 	header->Revision = minor + (major << 8);
97b44314c7SLawrence Tang 
98b44314c7SLawrence Tang 	header->SignatureEnd = 0xFFFFFFFF;
99b44314c7SLawrence Tang 
100b44314c7SLawrence Tang 	//Section count.
101e407b4c8SLawrence Tang 	int section_count = json_object_get_int(
102e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "sectionCount"));
103b44314c7SLawrence Tang 	header->SectionCount = (UINT16)section_count;
104b44314c7SLawrence Tang 
105b44314c7SLawrence Tang 	//Error severity.
106b44314c7SLawrence Tang 	json_object *severity = json_object_object_get(header_ir, "severity");
107e407b4c8SLawrence Tang 	header->ErrorSeverity = (UINT32)json_object_get_uint64(
108e407b4c8SLawrence Tang 		json_object_object_get(severity, "code"));
109b44314c7SLawrence Tang 
110b44314c7SLawrence Tang 	//Validation bits.
111e407b4c8SLawrence Tang 	header->ValidationBits = ir_to_bitfield(
112e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "validationBits"), 3,
113e407b4c8SLawrence Tang 		CPER_HEADER_VALID_BITFIELD_NAMES);
114b44314c7SLawrence Tang 
115b44314c7SLawrence Tang 	//Record length.
116e407b4c8SLawrence Tang 	header->RecordLength = (UINT32)json_object_get_uint64(
117e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "recordLength"));
118b44314c7SLawrence Tang 
119b44314c7SLawrence Tang 	//Timestamp, if present.
120b44314c7SLawrence Tang 	json_object *timestamp = json_object_object_get(header_ir, "timestamp");
121e407b4c8SLawrence Tang 	if (timestamp != NULL) {
122e407b4c8SLawrence Tang 		string_to_timestamp(&header->TimeStamp,
123e407b4c8SLawrence Tang 				    json_object_get_string(timestamp));
124e407b4c8SLawrence Tang 		header->TimeStamp.Flag = json_object_get_boolean(
125e407b4c8SLawrence Tang 			json_object_object_get(header_ir,
126e407b4c8SLawrence Tang 					       "timestampIsPrecise"));
127b44314c7SLawrence Tang 	}
128b44314c7SLawrence Tang 
129b44314c7SLawrence Tang 	//Various GUIDs.
130e407b4c8SLawrence Tang 	json_object *platform_id =
131e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "platformID");
132e407b4c8SLawrence Tang 	json_object *partition_id =
133e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "partitionID");
134b44314c7SLawrence Tang 	if (platform_id != NULL)
135e407b4c8SLawrence Tang 		string_to_guid(&header->PlatformID,
136e407b4c8SLawrence Tang 			       json_object_get_string(platform_id));
137b44314c7SLawrence Tang 	if (partition_id != NULL)
138e407b4c8SLawrence Tang 		string_to_guid(&header->PartitionID,
139e407b4c8SLawrence Tang 			       json_object_get_string(partition_id));
140e407b4c8SLawrence Tang 	string_to_guid(&header->CreatorID,
141e407b4c8SLawrence Tang 		       json_object_get_string(
142e407b4c8SLawrence Tang 			       json_object_object_get(header_ir, "creatorID")));
143b44314c7SLawrence Tang 
144b44314c7SLawrence Tang 	//Notification type.
145e407b4c8SLawrence Tang 	json_object *notification_type =
146e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "notificationType");
147e407b4c8SLawrence Tang 	string_to_guid(&header->NotificationType,
148e407b4c8SLawrence Tang 		       json_object_get_string(json_object_object_get(
149e407b4c8SLawrence Tang 			       notification_type, "guid")));
150b44314c7SLawrence Tang 
151b44314c7SLawrence Tang 	//Record ID, persistence info.
152e407b4c8SLawrence Tang 	header->RecordID = json_object_get_uint64(
153e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "recordID"));
154e407b4c8SLawrence Tang 	header->PersistenceInfo = json_object_get_uint64(
155e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "persistenceInfo"));
156b44314c7SLawrence Tang 
157b44314c7SLawrence Tang 	//Flags.
158b44314c7SLawrence Tang 	json_object *flags = json_object_object_get(header_ir, "flags");
159e407b4c8SLawrence Tang 	header->Flags = (UINT32)json_object_get_uint64(
160e407b4c8SLawrence Tang 		json_object_object_get(flags, "value"));
161f0f95574SLawrence Tang }
1620cb33793SLawrence Tang 
163617949e4SLawrence Tang //Converts a single given IR section into CPER, outputting to the given stream.
164617949e4SLawrence Tang void ir_section_to_cper(json_object *section,
165617949e4SLawrence Tang 			EFI_ERROR_SECTION_DESCRIPTOR *descriptor, FILE *out)
166617949e4SLawrence Tang {
167617949e4SLawrence Tang 	//Find the correct section type, and parse.
168617949e4SLawrence Tang 	if (guid_equal(&descriptor->SectionType,
169617949e4SLawrence Tang 		       &gEfiProcessorGenericErrorSectionGuid))
170617949e4SLawrence Tang 		ir_section_generic_to_cper(section, out);
171617949e4SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
172617949e4SLawrence Tang 			    &gEfiIa32X64ProcessorErrorSectionGuid))
173617949e4SLawrence Tang 		ir_section_ia32x64_to_cper(section, out);
174617949e4SLawrence Tang 	// else if (guid_equal(&descriptor->SectionType, &gEfiIpfProcessorErrorSectionGuid))
175617949e4SLawrence Tang 	//     ir_section_ipf_to_cper(section, out);
176617949e4SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
177617949e4SLawrence Tang 			    &gEfiArmProcessorErrorSectionGuid))
178617949e4SLawrence Tang 		ir_section_arm_to_cper(section, out);
179617949e4SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
180617949e4SLawrence Tang 			    &gEfiPlatformMemoryErrorSectionGuid))
181617949e4SLawrence Tang 		ir_section_memory_to_cper(section, out);
182617949e4SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
183617949e4SLawrence Tang 			    &gEfiPlatformMemoryError2SectionGuid))
184617949e4SLawrence Tang 		ir_section_memory2_to_cper(section, out);
185617949e4SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
186617949e4SLawrence Tang 			    &gEfiPcieErrorSectionGuid))
187617949e4SLawrence Tang 		ir_section_pcie_to_cper(section, out);
188617949e4SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
189617949e4SLawrence Tang 			    &gEfiFirmwareErrorSectionGuid))
190617949e4SLawrence Tang 		ir_section_firmware_to_cper(section, out);
191617949e4SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
192617949e4SLawrence Tang 			    &gEfiPciBusErrorSectionGuid))
193617949e4SLawrence Tang 		ir_section_pci_bus_to_cper(section, out);
194617949e4SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
195617949e4SLawrence Tang 			    &gEfiPciDevErrorSectionGuid))
196617949e4SLawrence Tang 		ir_section_pci_dev_to_cper(section, out);
197617949e4SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
198617949e4SLawrence Tang 			    &gEfiDMArGenericErrorSectionGuid))
199617949e4SLawrence Tang 		ir_section_dmar_generic_to_cper(section, out);
200617949e4SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
201617949e4SLawrence Tang 			    &gEfiDirectedIoDMArErrorSectionGuid))
202617949e4SLawrence Tang 		ir_section_dmar_vtd_to_cper(section, out);
203617949e4SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
204617949e4SLawrence Tang 			    &gEfiIommuDMArErrorSectionGuid))
205617949e4SLawrence Tang 		ir_section_dmar_iommu_to_cper(section, out);
206617949e4SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
207617949e4SLawrence Tang 			    &gEfiCcixPerLogErrorSectionGuid))
208617949e4SLawrence Tang 		ir_section_ccix_per_to_cper(section, out);
209617949e4SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
210617949e4SLawrence Tang 			    &gEfiCxlProtocolErrorSectionGuid))
211617949e4SLawrence Tang 		ir_section_cxl_protocol_to_cper(section, out);
212617949e4SLawrence Tang 	else if (guid_equal(&descriptor->SectionType,
213617949e4SLawrence Tang 			    &gEfiCxlGeneralMediaErrorSectionGuid) ||
214617949e4SLawrence Tang 		 guid_equal(&descriptor->SectionType,
215617949e4SLawrence Tang 			    &gEfiCxlDramEventErrorSectionGuid) ||
216617949e4SLawrence Tang 		 guid_equal(&descriptor->SectionType,
217617949e4SLawrence Tang 			    &gEfiCxlPhysicalSwitchErrorSectionGuid) ||
218617949e4SLawrence Tang 		 guid_equal(&descriptor->SectionType,
219617949e4SLawrence Tang 			    &gEfiCxlVirtualSwitchErrorSectionGuid) ||
220617949e4SLawrence Tang 		 guid_equal(&descriptor->SectionType,
221617949e4SLawrence Tang 			    &gEfiCxlMldPortErrorSectionGuid)) {
222617949e4SLawrence Tang 		ir_section_cxl_component_to_cper(section, out);
223617949e4SLawrence Tang 	} else {
224617949e4SLawrence Tang 		//Unknown GUID, so read as a base64 unknown section.
225617949e4SLawrence Tang 		json_object *encoded = json_object_object_get(section, "data");
226617949e4SLawrence Tang 		UINT8 *decoded =
227617949e4SLawrence Tang 			b64_decode(json_object_get_string(encoded),
228617949e4SLawrence Tang 				   json_object_get_string_len(encoded));
229617949e4SLawrence Tang 		fwrite(decoded, descriptor->SectionLength, 1, out);
230617949e4SLawrence Tang 		fflush(out);
231617949e4SLawrence Tang 		free(decoded);
232617949e4SLawrence Tang 	}
233617949e4SLawrence Tang }
234617949e4SLawrence Tang 
2350cb33793SLawrence Tang //Converts a single CPER-JSON IR section descriptor into a CPER structure.
236e407b4c8SLawrence Tang void ir_section_descriptor_to_cper(json_object *section_descriptor_ir,
237e407b4c8SLawrence Tang 				   EFI_ERROR_SECTION_DESCRIPTOR *descriptor)
2380cb33793SLawrence Tang {
2390cb33793SLawrence Tang 	//Section offset, length.
240e407b4c8SLawrence Tang 	descriptor->SectionOffset = (UINT32)json_object_get_uint64(
241e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "sectionOffset"));
242e407b4c8SLawrence Tang 	descriptor->SectionLength = (UINT32)json_object_get_uint64(
243e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "sectionLength"));
2440cb33793SLawrence Tang 
2450cb33793SLawrence Tang 	//Revision.
246e407b4c8SLawrence Tang 	json_object *revision =
247e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "revision");
248e407b4c8SLawrence Tang 	int minor =
249e407b4c8SLawrence Tang 		json_object_get_int(json_object_object_get(revision, "minor"));
250e407b4c8SLawrence Tang 	int major =
251e407b4c8SLawrence Tang 		json_object_get_int(json_object_object_get(revision, "major"));
2520cb33793SLawrence Tang 	descriptor->Revision = minor + (major << 8);
2530cb33793SLawrence Tang 
2540cb33793SLawrence Tang 	//Validation bits, flags.
255e407b4c8SLawrence Tang 	descriptor->SecValidMask = ir_to_bitfield(
256e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "validationBits"),
2570cb33793SLawrence Tang 		2, CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES);
258e407b4c8SLawrence Tang 	descriptor->SectionFlags = ir_to_bitfield(
259e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "flags"), 8,
260e407b4c8SLawrence Tang 		CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES);
2610cb33793SLawrence Tang 
2620cb33793SLawrence Tang 	//Section type.
263e407b4c8SLawrence Tang 	json_object *section_type =
264e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "sectionType");
265e407b4c8SLawrence Tang 	string_to_guid(&descriptor->SectionType,
266e407b4c8SLawrence Tang 		       json_object_get_string(
267e407b4c8SLawrence Tang 			       json_object_object_get(section_type, "data")));
2680cb33793SLawrence Tang 
2690cb33793SLawrence Tang 	//FRU ID, if present.
270e407b4c8SLawrence Tang 	json_object *fru_id =
271e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "fruID");
2720cb33793SLawrence Tang 	if (fru_id != NULL)
273e407b4c8SLawrence Tang 		string_to_guid(&descriptor->FruId,
274e407b4c8SLawrence Tang 			       json_object_get_string(fru_id));
2750cb33793SLawrence Tang 
2760cb33793SLawrence Tang 	//Severity code.
277e407b4c8SLawrence Tang 	json_object *severity =
278e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "severity");
279e407b4c8SLawrence Tang 	descriptor->Severity = (UINT32)json_object_get_uint64(
280e407b4c8SLawrence Tang 		json_object_object_get(severity, "code"));
2810cb33793SLawrence Tang 
2820cb33793SLawrence Tang 	//FRU text, if present.
283e407b4c8SLawrence Tang 	json_object *fru_text =
284e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "fruText");
2850cb33793SLawrence Tang 	if (fru_text != NULL)
286e407b4c8SLawrence Tang 		strncpy(descriptor->FruString, json_object_get_string(fru_text),
287e407b4c8SLawrence Tang 			20);
2880cb33793SLawrence Tang }
289617949e4SLawrence Tang 
290617949e4SLawrence Tang //Converts IR for a given single section format CPER record into CPER binary.
291617949e4SLawrence Tang void ir_single_section_to_cper(json_object *ir, FILE *out)
292617949e4SLawrence Tang {
293617949e4SLawrence Tang 	//Create & write a section descriptor to file.
294617949e4SLawrence Tang 	EFI_ERROR_SECTION_DESCRIPTOR *section_descriptor =
295617949e4SLawrence Tang 		(EFI_ERROR_SECTION_DESCRIPTOR *)calloc(
296617949e4SLawrence Tang 			1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR));
297617949e4SLawrence Tang 	ir_section_descriptor_to_cper(
298617949e4SLawrence Tang 		json_object_object_get(ir, "sectionDescriptor"),
299617949e4SLawrence Tang 		section_descriptor);
300617949e4SLawrence Tang 	fwrite(section_descriptor, sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1,
301617949e4SLawrence Tang 	       out);
302617949e4SLawrence Tang 	fflush(out);
303617949e4SLawrence Tang 
304617949e4SLawrence Tang 	//Write section to file.
305617949e4SLawrence Tang 	ir_section_to_cper(json_object_object_get(ir, "section"),
306617949e4SLawrence Tang 			   section_descriptor, out);
307617949e4SLawrence Tang 
308617949e4SLawrence Tang 	//Free remaining resources.
309617949e4SLawrence Tang 	free(section_descriptor);
310617949e4SLawrence Tang }