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