xref: /openbmc/libcper/ir-parse.c (revision 379e492a)
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>
10a7d2cdddSEd Tanous #include "base64.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.
ir_to_cper(json_object * ir,FILE * out)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);
56f8fc7052SJohn Chung 	if (amt_sections == amt_descriptors) {
57e407b4c8SLawrence Tang 		for (int i = 0; i < amt_sections; i++) {
580cb33793SLawrence Tang 			//Get the section itself from the IR.
59f8fc7052SJohn Chung 			json_object *section =
60f8fc7052SJohn Chung 				json_object_array_get_idx(sections, i);
610cb33793SLawrence Tang 
62617949e4SLawrence Tang 			//Convert.
63617949e4SLawrence Tang 			ir_section_to_cper(section, descriptors[i], out);
640cb33793SLawrence Tang 		}
65f8fc7052SJohn Chung 	}
660cb33793SLawrence Tang 
670cb33793SLawrence Tang 	//Free all remaining resources.
68b44314c7SLawrence Tang 	free(header);
69f8fc7052SJohn Chung 	for (int i = 0; i < amt_descriptors; i++) {
700cb33793SLawrence Tang 		free(descriptors[i]);
71b44314c7SLawrence Tang 	}
72f8fc7052SJohn Chung }
73b44314c7SLawrence Tang 
74b44314c7SLawrence Tang //Converts a CPER-JSON IR header to a CPER header structure.
ir_header_to_cper(json_object * header_ir,EFI_COMMON_ERROR_RECORD_HEADER * header)75e407b4c8SLawrence Tang void ir_header_to_cper(json_object *header_ir,
76e407b4c8SLawrence Tang 		       EFI_COMMON_ERROR_RECORD_HEADER *header)
77b44314c7SLawrence Tang {
78b44314c7SLawrence Tang 	header->SignatureStart = 0x52455043; //CPER
79b44314c7SLawrence Tang 
80b44314c7SLawrence Tang 	//Revision.
81b44314c7SLawrence Tang 	json_object *revision = json_object_object_get(header_ir, "revision");
82e407b4c8SLawrence Tang 	int minor =
83e407b4c8SLawrence Tang 		json_object_get_int(json_object_object_get(revision, "minor"));
84e407b4c8SLawrence Tang 	int major =
85e407b4c8SLawrence Tang 		json_object_get_int(json_object_object_get(revision, "major"));
86b44314c7SLawrence Tang 	header->Revision = minor + (major << 8);
87b44314c7SLawrence Tang 
88b44314c7SLawrence Tang 	header->SignatureEnd = 0xFFFFFFFF;
89b44314c7SLawrence Tang 
90b44314c7SLawrence Tang 	//Section count.
91e407b4c8SLawrence Tang 	int section_count = json_object_get_int(
92e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "sectionCount"));
93b44314c7SLawrence Tang 	header->SectionCount = (UINT16)section_count;
94b44314c7SLawrence Tang 
95b44314c7SLawrence Tang 	//Error severity.
96b44314c7SLawrence Tang 	json_object *severity = json_object_object_get(header_ir, "severity");
97e407b4c8SLawrence Tang 	header->ErrorSeverity = (UINT32)json_object_get_uint64(
98e407b4c8SLawrence Tang 		json_object_object_get(severity, "code"));
99b44314c7SLawrence Tang 
100b44314c7SLawrence Tang 	//Validation bits.
101e407b4c8SLawrence Tang 	header->ValidationBits = ir_to_bitfield(
102e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "validationBits"), 3,
103e407b4c8SLawrence Tang 		CPER_HEADER_VALID_BITFIELD_NAMES);
104b44314c7SLawrence Tang 
105b44314c7SLawrence Tang 	//Record length.
106e407b4c8SLawrence Tang 	header->RecordLength = (UINT32)json_object_get_uint64(
107e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "recordLength"));
108b44314c7SLawrence Tang 
109b44314c7SLawrence Tang 	//Timestamp, if present.
110b44314c7SLawrence Tang 	json_object *timestamp = json_object_object_get(header_ir, "timestamp");
111e407b4c8SLawrence Tang 	if (timestamp != NULL) {
112e407b4c8SLawrence Tang 		string_to_timestamp(&header->TimeStamp,
113e407b4c8SLawrence Tang 				    json_object_get_string(timestamp));
114e407b4c8SLawrence Tang 		header->TimeStamp.Flag = json_object_get_boolean(
115e407b4c8SLawrence Tang 			json_object_object_get(header_ir,
116e407b4c8SLawrence Tang 					       "timestampIsPrecise"));
117b44314c7SLawrence Tang 	}
118b44314c7SLawrence Tang 
119b44314c7SLawrence Tang 	//Various GUIDs.
120e407b4c8SLawrence Tang 	json_object *platform_id =
121e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "platformID");
122e407b4c8SLawrence Tang 	json_object *partition_id =
123e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "partitionID");
124f8fc7052SJohn Chung 	if (platform_id != NULL) {
125e407b4c8SLawrence Tang 		string_to_guid(&header->PlatformID,
126e407b4c8SLawrence Tang 			       json_object_get_string(platform_id));
127f8fc7052SJohn Chung 	}
128f8fc7052SJohn Chung 	if (partition_id != NULL) {
129e407b4c8SLawrence Tang 		string_to_guid(&header->PartitionID,
130e407b4c8SLawrence Tang 			       json_object_get_string(partition_id));
131f8fc7052SJohn Chung 	}
132e407b4c8SLawrence Tang 	string_to_guid(&header->CreatorID,
133e407b4c8SLawrence Tang 		       json_object_get_string(
134e407b4c8SLawrence Tang 			       json_object_object_get(header_ir, "creatorID")));
135b44314c7SLawrence Tang 
136b44314c7SLawrence Tang 	//Notification type.
137e407b4c8SLawrence Tang 	json_object *notification_type =
138e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "notificationType");
139e407b4c8SLawrence Tang 	string_to_guid(&header->NotificationType,
140e407b4c8SLawrence Tang 		       json_object_get_string(json_object_object_get(
141e407b4c8SLawrence Tang 			       notification_type, "guid")));
142b44314c7SLawrence Tang 
143b44314c7SLawrence Tang 	//Record ID, persistence info.
144e407b4c8SLawrence Tang 	header->RecordID = json_object_get_uint64(
145e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "recordID"));
146e407b4c8SLawrence Tang 	header->PersistenceInfo = json_object_get_uint64(
147e407b4c8SLawrence Tang 		json_object_object_get(header_ir, "persistenceInfo"));
148b44314c7SLawrence Tang 
149b44314c7SLawrence Tang 	//Flags.
150b44314c7SLawrence Tang 	json_object *flags = json_object_object_get(header_ir, "flags");
151e407b4c8SLawrence Tang 	header->Flags = (UINT32)json_object_get_uint64(
152e407b4c8SLawrence Tang 		json_object_object_get(flags, "value"));
153f0f95574SLawrence Tang }
1540cb33793SLawrence Tang 
155617949e4SLawrence Tang //Converts a single given IR section into CPER, outputting to the given stream.
ir_section_to_cper(json_object * section,EFI_ERROR_SECTION_DESCRIPTOR * descriptor,FILE * out)156617949e4SLawrence Tang void ir_section_to_cper(json_object *section,
157617949e4SLawrence Tang 			EFI_ERROR_SECTION_DESCRIPTOR *descriptor, FILE *out)
158617949e4SLawrence Tang {
159617949e4SLawrence Tang 	//Find the correct section type, and parse.
160580423feSLawrence Tang 	int section_converted = 0;
161f8fc7052SJohn Chung 	for (size_t i = 0; i < section_definitions_len; i++) {
162f1f3b839SLawrence Tang 		if (guid_equal(section_definitions[i].Guid,
163f1f3b839SLawrence Tang 			       &descriptor->SectionType) &&
164f1f3b839SLawrence Tang 		    section_definitions[i].ToCPER != NULL) {
165580423feSLawrence Tang 			section_definitions[i].ToCPER(section, out);
166580423feSLawrence Tang 			section_converted = 1;
167580423feSLawrence Tang 			break;
168580423feSLawrence Tang 		}
169580423feSLawrence Tang 	}
170580423feSLawrence Tang 
171580423feSLawrence Tang 	//If unknown GUID, so read as a base64 unknown section.
172580423feSLawrence Tang 	if (!section_converted) {
173617949e4SLawrence Tang 		json_object *encoded = json_object_object_get(section, "data");
174a7d2cdddSEd Tanous 
175a7d2cdddSEd Tanous 		int32_t decoded_len = 0;
176a7d2cdddSEd Tanous 
177a7d2cdddSEd Tanous 		UINT8 *decoded = base64_decode(
178a7d2cdddSEd Tanous 			json_object_get_string(encoded),
179a7d2cdddSEd Tanous 			json_object_get_string_len(encoded), &decoded_len);
180a7d2cdddSEd Tanous 		if (decoded == NULL) {
181f8fc7052SJohn Chung 			printf("Failed to allocate decode output buffer. \n");
182f8fc7052SJohn Chung 		} else {
183f8fc7052SJohn Chung 			fwrite(decoded, decoded_len, 1, out);
184617949e4SLawrence Tang 			fflush(out);
185617949e4SLawrence Tang 			free(decoded);
186617949e4SLawrence Tang 		}
187617949e4SLawrence Tang 	}
188f8fc7052SJohn Chung }
189617949e4SLawrence Tang 
1900cb33793SLawrence Tang //Converts a single CPER-JSON IR section descriptor into a CPER structure.
ir_section_descriptor_to_cper(json_object * section_descriptor_ir,EFI_ERROR_SECTION_DESCRIPTOR * descriptor)191e407b4c8SLawrence Tang void ir_section_descriptor_to_cper(json_object *section_descriptor_ir,
192e407b4c8SLawrence Tang 				   EFI_ERROR_SECTION_DESCRIPTOR *descriptor)
1930cb33793SLawrence Tang {
1940cb33793SLawrence Tang 	//Section offset, length.
195e407b4c8SLawrence Tang 	descriptor->SectionOffset = (UINT32)json_object_get_uint64(
196e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "sectionOffset"));
197e407b4c8SLawrence Tang 	descriptor->SectionLength = (UINT32)json_object_get_uint64(
198e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "sectionLength"));
1990cb33793SLawrence Tang 
2000cb33793SLawrence Tang 	//Revision.
201e407b4c8SLawrence Tang 	json_object *revision =
202e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "revision");
203e407b4c8SLawrence Tang 	int minor =
204e407b4c8SLawrence Tang 		json_object_get_int(json_object_object_get(revision, "minor"));
205e407b4c8SLawrence Tang 	int major =
206e407b4c8SLawrence Tang 		json_object_get_int(json_object_object_get(revision, "major"));
2070cb33793SLawrence Tang 	descriptor->Revision = minor + (major << 8);
2080cb33793SLawrence Tang 
2090cb33793SLawrence Tang 	//Validation bits, flags.
210e407b4c8SLawrence Tang 	descriptor->SecValidMask = ir_to_bitfield(
211e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "validationBits"),
2120cb33793SLawrence Tang 		2, CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES);
213e407b4c8SLawrence Tang 	descriptor->SectionFlags = ir_to_bitfield(
214e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "flags"), 8,
215e407b4c8SLawrence Tang 		CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES);
2160cb33793SLawrence Tang 
2170cb33793SLawrence Tang 	//Section type.
218e407b4c8SLawrence Tang 	json_object *section_type =
219e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "sectionType");
220e407b4c8SLawrence Tang 	string_to_guid(&descriptor->SectionType,
221e407b4c8SLawrence Tang 		       json_object_get_string(
222e407b4c8SLawrence Tang 			       json_object_object_get(section_type, "data")));
2230cb33793SLawrence Tang 
2240cb33793SLawrence Tang 	//FRU ID, if present.
225e407b4c8SLawrence Tang 	json_object *fru_id =
226e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "fruID");
227f8fc7052SJohn Chung 	if (fru_id != NULL) {
228e407b4c8SLawrence Tang 		string_to_guid(&descriptor->FruId,
229e407b4c8SLawrence Tang 			       json_object_get_string(fru_id));
230f8fc7052SJohn Chung 	}
2310cb33793SLawrence Tang 
2320cb33793SLawrence Tang 	//Severity code.
233e407b4c8SLawrence Tang 	json_object *severity =
234e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "severity");
235e407b4c8SLawrence Tang 	descriptor->Severity = (UINT32)json_object_get_uint64(
236e407b4c8SLawrence Tang 		json_object_object_get(severity, "code"));
2370cb33793SLawrence Tang 
2380cb33793SLawrence Tang 	//FRU text, if present.
239e407b4c8SLawrence Tang 	json_object *fru_text =
240e407b4c8SLawrence Tang 		json_object_object_get(section_descriptor_ir, "fruText");
241f8fc7052SJohn Chung 	if (fru_text != NULL) {
242e407b4c8SLawrence Tang 		strncpy(descriptor->FruString, json_object_get_string(fru_text),
243*379e492aSPatrick Williams 			sizeof(descriptor->FruString) - 1);
244*379e492aSPatrick Williams 		descriptor->FruString[sizeof(descriptor->FruString) - 1] = '\0';
2450cb33793SLawrence Tang 	}
246f8fc7052SJohn Chung }
247617949e4SLawrence Tang 
248617949e4SLawrence Tang //Converts IR for a given single section format CPER record into CPER binary.
ir_single_section_to_cper(json_object * ir,FILE * out)249617949e4SLawrence Tang void ir_single_section_to_cper(json_object *ir, FILE *out)
250617949e4SLawrence Tang {
251617949e4SLawrence Tang 	//Create & write a section descriptor to file.
252617949e4SLawrence Tang 	EFI_ERROR_SECTION_DESCRIPTOR *section_descriptor =
253617949e4SLawrence Tang 		(EFI_ERROR_SECTION_DESCRIPTOR *)calloc(
254617949e4SLawrence Tang 			1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR));
255617949e4SLawrence Tang 	ir_section_descriptor_to_cper(
256617949e4SLawrence Tang 		json_object_object_get(ir, "sectionDescriptor"),
257617949e4SLawrence Tang 		section_descriptor);
258617949e4SLawrence Tang 	fwrite(section_descriptor, sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1,
259617949e4SLawrence Tang 	       out);
260617949e4SLawrence Tang 	fflush(out);
261617949e4SLawrence Tang 
262617949e4SLawrence Tang 	//Write section to file.
263617949e4SLawrence Tang 	ir_section_to_cper(json_object_object_get(ir, "section"),
264617949e4SLawrence Tang 			   section_descriptor, out);
265617949e4SLawrence Tang 
266617949e4SLawrence Tang 	//Free remaining resources.
267617949e4SLawrence Tang 	free(section_descriptor);
268617949e4SLawrence Tang }
269