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