xref: /openbmc/libcper/ir-parse.c (revision f1f3b839)
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>
95202bbb4SLawrence 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"
14580423feSLawrence Tang #include "sections/cper-section.h"
15b44314c7SLawrence Tang 
16b44314c7SLawrence Tang //Private pre-declarations.
17e407b4c8SLawrence Tang void ir_header_to_cper(json_object *header_ir,
18e407b4c8SLawrence Tang 		       EFI_COMMON_ERROR_RECORD_HEADER *header);
19e407b4c8SLawrence Tang void ir_section_descriptor_to_cper(json_object *section_descriptor_ir,
20e407b4c8SLawrence Tang 				   EFI_ERROR_SECTION_DESCRIPTOR *descriptor);
21617949e4SLawrence Tang void ir_section_to_cper(json_object *section,
22617949e4SLawrence Tang 			EFI_ERROR_SECTION_DESCRIPTOR *descriptor, FILE *out);
23f0f95574SLawrence Tang 
24f0f95574SLawrence Tang //Converts the given JSON IR CPER representation into CPER binary format, piped to the provided file stream.
250cb33793SLawrence Tang //This function performs no validation of the IR against the CPER-JSON specification. To ensure a safe call,
260cb33793SLawrence Tang //use validate_schema() from json-schema.h before attempting to call this function.
27f0f95574SLawrence Tang void ir_to_cper(json_object *ir, FILE *out)
28f0f95574SLawrence Tang {
29b44314c7SLawrence Tang 	//Create the CPER header.
30e407b4c8SLawrence Tang 	EFI_COMMON_ERROR_RECORD_HEADER *header =
31e407b4c8SLawrence Tang 		(EFI_COMMON_ERROR_RECORD_HEADER *)calloc(
32e407b4c8SLawrence Tang 			1, sizeof(EFI_COMMON_ERROR_RECORD_HEADER));
33b44314c7SLawrence Tang 	ir_header_to_cper(json_object_object_get(ir, "header"), header);
34b44314c7SLawrence Tang 	fwrite(header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, out);
35b44314c7SLawrence Tang 	fflush(out);
360cb33793SLawrence Tang 
370cb33793SLawrence Tang 	//Create the CPER section descriptors.
38e407b4c8SLawrence Tang 	json_object *section_descriptors =
39e407b4c8SLawrence Tang 		json_object_object_get(ir, "sectionDescriptors");
400cb33793SLawrence Tang 	int amt_descriptors = json_object_array_length(section_descriptors);
410cb33793SLawrence Tang 	EFI_ERROR_SECTION_DESCRIPTOR *descriptors[amt_descriptors];
42e407b4c8SLawrence Tang 	for (int i = 0; i < amt_descriptors; i++) {
43e407b4c8SLawrence Tang 		descriptors[i] = (EFI_ERROR_SECTION_DESCRIPTOR *)calloc(
44e407b4c8SLawrence Tang 			1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR));
45e407b4c8SLawrence Tang 		ir_section_descriptor_to_cper(
46e407b4c8SLawrence Tang 			json_object_array_get_idx(section_descriptors, i),
47e407b4c8SLawrence Tang 			descriptors[i]);
48e407b4c8SLawrence Tang 		fwrite(descriptors[i], sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1,
49e407b4c8SLawrence Tang 		       out);
500cb33793SLawrence Tang 		fflush(out);
510cb33793SLawrence Tang 	}
520cb33793SLawrence Tang 
530cb33793SLawrence Tang 	//Run through each section in turn.
540cb33793SLawrence Tang 	json_object *sections = json_object_object_get(ir, "sections");
550cb33793SLawrence Tang 	int amt_sections = json_object_array_length(sections);
56e407b4c8SLawrence Tang 	for (int i = 0; i < amt_sections; i++) {
570cb33793SLawrence Tang 		//Get the section itself from the IR.
580cb33793SLawrence Tang 		json_object *section = json_object_array_get_idx(sections, i);
590cb33793SLawrence Tang 
60617949e4SLawrence Tang 		//Convert.
61617949e4SLawrence Tang 		ir_section_to_cper(section, descriptors[i], out);
620cb33793SLawrence Tang 	}
630cb33793SLawrence Tang 
640cb33793SLawrence Tang 	//Free all remaining resources.
65b44314c7SLawrence Tang 	free(header);
660cb33793SLawrence Tang 	for (int i = 0; i < amt_descriptors; i++)
670cb33793SLawrence Tang 		free(descriptors[i]);
68b44314c7SLawrence Tang }
69b44314c7SLawrence Tang 
70b44314c7SLawrence Tang //Converts a CPER-JSON IR header to a CPER header structure.
71e407b4c8SLawrence Tang void ir_header_to_cper(json_object *header_ir,
72e407b4c8SLawrence Tang 		       EFI_COMMON_ERROR_RECORD_HEADER *header)
73b44314c7SLawrence Tang {
74b44314c7SLawrence Tang 	header->SignatureStart = 0x52455043; //CPER
75b44314c7SLawrence Tang 
76b44314c7SLawrence Tang 	//Revision.
77b44314c7SLawrence Tang 	json_object *revision = json_object_object_get(header_ir, "revision");
78e407b4c8SLawrence Tang 	int minor =
79e407b4c8SLawrence Tang 		json_object_get_int(json_object_object_get(revision, "minor"));
80e407b4c8SLawrence Tang 	int major =
81e407b4c8SLawrence Tang 		json_object_get_int(json_object_object_get(revision, "major"));
82b44314c7SLawrence Tang 	header->Revision = minor + (major << 8);
83b44314c7SLawrence Tang 
84b44314c7SLawrence Tang 	header->SignatureEnd = 0xFFFFFFFF;
85b44314c7SLawrence Tang 
86b44314c7SLawrence Tang 	//Section count.
87e407b4c8SLawrence Tang 	int section_count = json_object_get_int(
88e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "sectionCount"));
89b44314c7SLawrence Tang 	header->SectionCount = (UINT16)section_count;
90b44314c7SLawrence Tang 
91b44314c7SLawrence Tang 	//Error severity.
92b44314c7SLawrence Tang 	json_object *severity = json_object_object_get(header_ir, "severity");
93e407b4c8SLawrence Tang 	header->ErrorSeverity = (UINT32)json_object_get_uint64(
94e407b4c8SLawrence Tang 		json_object_object_get(severity, "code"));
95b44314c7SLawrence Tang 
96b44314c7SLawrence Tang 	//Validation bits.
97e407b4c8SLawrence Tang 	header->ValidationBits = ir_to_bitfield(
98e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "validationBits"), 3,
99e407b4c8SLawrence Tang 		CPER_HEADER_VALID_BITFIELD_NAMES);
100b44314c7SLawrence Tang 
101b44314c7SLawrence Tang 	//Record length.
102e407b4c8SLawrence Tang 	header->RecordLength = (UINT32)json_object_get_uint64(
103e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "recordLength"));
104b44314c7SLawrence Tang 
105b44314c7SLawrence Tang 	//Timestamp, if present.
106b44314c7SLawrence Tang 	json_object *timestamp = json_object_object_get(header_ir, "timestamp");
107e407b4c8SLawrence Tang 	if (timestamp != NULL) {
108e407b4c8SLawrence Tang 		string_to_timestamp(&header->TimeStamp,
109e407b4c8SLawrence Tang 				    json_object_get_string(timestamp));
110e407b4c8SLawrence Tang 		header->TimeStamp.Flag = json_object_get_boolean(
111e407b4c8SLawrence Tang 			json_object_object_get(header_ir,
112e407b4c8SLawrence Tang 					       "timestampIsPrecise"));
113b44314c7SLawrence Tang 	}
114b44314c7SLawrence Tang 
115b44314c7SLawrence Tang 	//Various GUIDs.
116e407b4c8SLawrence Tang 	json_object *platform_id =
117e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "platformID");
118e407b4c8SLawrence Tang 	json_object *partition_id =
119e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "partitionID");
120b44314c7SLawrence Tang 	if (platform_id != NULL)
121e407b4c8SLawrence Tang 		string_to_guid(&header->PlatformID,
122e407b4c8SLawrence Tang 			       json_object_get_string(platform_id));
123b44314c7SLawrence Tang 	if (partition_id != NULL)
124e407b4c8SLawrence Tang 		string_to_guid(&header->PartitionID,
125e407b4c8SLawrence Tang 			       json_object_get_string(partition_id));
126e407b4c8SLawrence Tang 	string_to_guid(&header->CreatorID,
127e407b4c8SLawrence Tang 		       json_object_get_string(
128e407b4c8SLawrence Tang 			       json_object_object_get(header_ir, "creatorID")));
129b44314c7SLawrence Tang 
130b44314c7SLawrence Tang 	//Notification type.
131e407b4c8SLawrence Tang 	json_object *notification_type =
132e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "notificationType");
133e407b4c8SLawrence Tang 	string_to_guid(&header->NotificationType,
134e407b4c8SLawrence Tang 		       json_object_get_string(json_object_object_get(
135e407b4c8SLawrence Tang 			       notification_type, "guid")));
136b44314c7SLawrence Tang 
137b44314c7SLawrence Tang 	//Record ID, persistence info.
138e407b4c8SLawrence Tang 	header->RecordID = json_object_get_uint64(
139e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "recordID"));
140e407b4c8SLawrence Tang 	header->PersistenceInfo = json_object_get_uint64(
141e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "persistenceInfo"));
142b44314c7SLawrence Tang 
143b44314c7SLawrence Tang 	//Flags.
144b44314c7SLawrence Tang 	json_object *flags = json_object_object_get(header_ir, "flags");
145e407b4c8SLawrence Tang 	header->Flags = (UINT32)json_object_get_uint64(
146e407b4c8SLawrence Tang 		json_object_object_get(flags, "value"));
147f0f95574SLawrence Tang }
1480cb33793SLawrence Tang 
149617949e4SLawrence Tang //Converts a single given IR section into CPER, outputting to the given stream.
150617949e4SLawrence Tang void ir_section_to_cper(json_object *section,
151617949e4SLawrence Tang 			EFI_ERROR_SECTION_DESCRIPTOR *descriptor, FILE *out)
152617949e4SLawrence Tang {
153617949e4SLawrence Tang 	//Find the correct section type, and parse.
154580423feSLawrence Tang 	int section_converted = 0;
155*f1f3b839SLawrence Tang 	for (int i = 0; i < section_definitions_len; i++) {
156*f1f3b839SLawrence Tang 		if (guid_equal(section_definitions[i].Guid,
157*f1f3b839SLawrence Tang 			       &descriptor->SectionType) &&
158*f1f3b839SLawrence Tang 		    section_definitions[i].ToCPER != NULL) {
159580423feSLawrence Tang 			section_definitions[i].ToCPER(section, out);
160580423feSLawrence Tang 			section_converted = 1;
161580423feSLawrence Tang 			break;
162580423feSLawrence Tang 		}
163580423feSLawrence Tang 	}
164580423feSLawrence Tang 
165580423feSLawrence Tang 	//If unknown GUID, so read as a base64 unknown section.
166580423feSLawrence Tang 	if (!section_converted) {
167617949e4SLawrence Tang 		json_object *encoded = json_object_object_get(section, "data");
168617949e4SLawrence Tang 		UINT8 *decoded =
169617949e4SLawrence Tang 			b64_decode(json_object_get_string(encoded),
170617949e4SLawrence Tang 				   json_object_get_string_len(encoded));
171617949e4SLawrence Tang 		fwrite(decoded, descriptor->SectionLength, 1, out);
172617949e4SLawrence Tang 		fflush(out);
173617949e4SLawrence Tang 		free(decoded);
174617949e4SLawrence Tang 	}
175617949e4SLawrence Tang }
176617949e4SLawrence Tang 
1770cb33793SLawrence Tang //Converts a single CPER-JSON IR section descriptor into a CPER structure.
178e407b4c8SLawrence Tang void ir_section_descriptor_to_cper(json_object *section_descriptor_ir,
179e407b4c8SLawrence Tang 				   EFI_ERROR_SECTION_DESCRIPTOR *descriptor)
1800cb33793SLawrence Tang {
1810cb33793SLawrence Tang 	//Section offset, length.
182e407b4c8SLawrence Tang 	descriptor->SectionOffset = (UINT32)json_object_get_uint64(
183e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "sectionOffset"));
184e407b4c8SLawrence Tang 	descriptor->SectionLength = (UINT32)json_object_get_uint64(
185e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "sectionLength"));
1860cb33793SLawrence Tang 
1870cb33793SLawrence Tang 	//Revision.
188e407b4c8SLawrence Tang 	json_object *revision =
189e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "revision");
190e407b4c8SLawrence Tang 	int minor =
191e407b4c8SLawrence Tang 		json_object_get_int(json_object_object_get(revision, "minor"));
192e407b4c8SLawrence Tang 	int major =
193e407b4c8SLawrence Tang 		json_object_get_int(json_object_object_get(revision, "major"));
1940cb33793SLawrence Tang 	descriptor->Revision = minor + (major << 8);
1950cb33793SLawrence Tang 
1960cb33793SLawrence Tang 	//Validation bits, flags.
197e407b4c8SLawrence Tang 	descriptor->SecValidMask = ir_to_bitfield(
198e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "validationBits"),
1990cb33793SLawrence Tang 		2, CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES);
200e407b4c8SLawrence Tang 	descriptor->SectionFlags = ir_to_bitfield(
201e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "flags"), 8,
202e407b4c8SLawrence Tang 		CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES);
2030cb33793SLawrence Tang 
2040cb33793SLawrence Tang 	//Section type.
205e407b4c8SLawrence Tang 	json_object *section_type =
206e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "sectionType");
207e407b4c8SLawrence Tang 	string_to_guid(&descriptor->SectionType,
208e407b4c8SLawrence Tang 		       json_object_get_string(
209e407b4c8SLawrence Tang 			       json_object_object_get(section_type, "data")));
2100cb33793SLawrence Tang 
2110cb33793SLawrence Tang 	//FRU ID, if present.
212e407b4c8SLawrence Tang 	json_object *fru_id =
213e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "fruID");
2140cb33793SLawrence Tang 	if (fru_id != NULL)
215e407b4c8SLawrence Tang 		string_to_guid(&descriptor->FruId,
216e407b4c8SLawrence Tang 			       json_object_get_string(fru_id));
2170cb33793SLawrence Tang 
2180cb33793SLawrence Tang 	//Severity code.
219e407b4c8SLawrence Tang 	json_object *severity =
220e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "severity");
221e407b4c8SLawrence Tang 	descriptor->Severity = (UINT32)json_object_get_uint64(
222e407b4c8SLawrence Tang 		json_object_object_get(severity, "code"));
2230cb33793SLawrence Tang 
2240cb33793SLawrence Tang 	//FRU text, if present.
225e407b4c8SLawrence Tang 	json_object *fru_text =
226e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "fruText");
2270cb33793SLawrence Tang 	if (fru_text != NULL)
228e407b4c8SLawrence Tang 		strncpy(descriptor->FruString, json_object_get_string(fru_text),
229e407b4c8SLawrence Tang 			20);
2300cb33793SLawrence Tang }
231617949e4SLawrence Tang 
232617949e4SLawrence Tang //Converts IR for a given single section format CPER record into CPER binary.
233617949e4SLawrence Tang void ir_single_section_to_cper(json_object *ir, FILE *out)
234617949e4SLawrence Tang {
235617949e4SLawrence Tang 	//Create & write a section descriptor to file.
236617949e4SLawrence Tang 	EFI_ERROR_SECTION_DESCRIPTOR *section_descriptor =
237617949e4SLawrence Tang 		(EFI_ERROR_SECTION_DESCRIPTOR *)calloc(
238617949e4SLawrence Tang 			1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR));
239617949e4SLawrence Tang 	ir_section_descriptor_to_cper(
240617949e4SLawrence Tang 		json_object_object_get(ir, "sectionDescriptor"),
241617949e4SLawrence Tang 		section_descriptor);
242617949e4SLawrence Tang 	fwrite(section_descriptor, sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1,
243617949e4SLawrence Tang 	       out);
244617949e4SLawrence Tang 	fflush(out);
245617949e4SLawrence Tang 
246617949e4SLawrence Tang 	//Write section to file.
247617949e4SLawrence Tang 	ir_section_to_cper(json_object_object_get(ir, "section"),
248617949e4SLawrence Tang 			   section_descriptor, out);
249617949e4SLawrence Tang 
250617949e4SLawrence Tang 	//Free remaining resources.
251617949e4SLawrence Tang 	free(section_descriptor);
252617949e4SLawrence Tang }