xref: /openbmc/libcper/ir-parse.c (revision 8f977457834a43e4a2b99e6c79e89e0f8438485f)
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.h"
15  
16  //Private pre-declarations.
17  void ir_header_to_cper(json_object *header_ir,
18  		       EFI_COMMON_ERROR_RECORD_HEADER *header);
19  void ir_section_descriptor_to_cper(json_object *section_descriptor_ir,
20  				   EFI_ERROR_SECTION_DESCRIPTOR *descriptor);
21  void ir_section_to_cper(json_object *section,
22  			EFI_ERROR_SECTION_DESCRIPTOR *descriptor, FILE *out);
23  
24  //Converts the given JSON IR CPER representation into CPER binary format, piped to the provided file stream.
25  //This function performs no validation of the IR against the CPER-JSON specification. To ensure a safe call,
26  //use validate_schema() from json-schema.h before attempting to call this function.
27  void ir_to_cper(json_object *ir, FILE *out)
28  {
29  	//Create the CPER header.
30  	EFI_COMMON_ERROR_RECORD_HEADER *header =
31  		(EFI_COMMON_ERROR_RECORD_HEADER *)calloc(
32  			1, sizeof(EFI_COMMON_ERROR_RECORD_HEADER));
33  	ir_header_to_cper(json_object_object_get(ir, "header"), header);
34  	fwrite(header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, out);
35  	fflush(out);
36  
37  	//Create the CPER section descriptors.
38  	json_object *section_descriptors =
39  		json_object_object_get(ir, "sectionDescriptors");
40  	int amt_descriptors = json_object_array_length(section_descriptors);
41  	EFI_ERROR_SECTION_DESCRIPTOR *descriptors[amt_descriptors];
42  	for (int i = 0; i < amt_descriptors; i++) {
43  		descriptors[i] = (EFI_ERROR_SECTION_DESCRIPTOR *)calloc(
44  			1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR));
45  		ir_section_descriptor_to_cper(
46  			json_object_array_get_idx(section_descriptors, i),
47  			descriptors[i]);
48  		fwrite(descriptors[i], sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1,
49  		       out);
50  		fflush(out);
51  	}
52  
53  	//Run through each section in turn.
54  	json_object *sections = json_object_object_get(ir, "sections");
55  	int amt_sections = json_object_array_length(sections);
56  	for (int i = 0; i < amt_sections; i++) {
57  		//Get the section itself from the IR.
58  		json_object *section = json_object_array_get_idx(sections, i);
59  
60  		//Convert.
61  		ir_section_to_cper(section, descriptors[i], out);
62  	}
63  
64  	//Free all remaining resources.
65  	free(header);
66  	for (int i = 0; i < amt_descriptors; i++)
67  		free(descriptors[i]);
68  }
69  
70  //Converts a CPER-JSON IR header to a CPER header structure.
71  void ir_header_to_cper(json_object *header_ir,
72  		       EFI_COMMON_ERROR_RECORD_HEADER *header)
73  {
74  	header->SignatureStart = 0x52455043; //CPER
75  
76  	//Revision.
77  	json_object *revision = json_object_object_get(header_ir, "revision");
78  	int minor =
79  		json_object_get_int(json_object_object_get(revision, "minor"));
80  	int major =
81  		json_object_get_int(json_object_object_get(revision, "major"));
82  	header->Revision = minor + (major << 8);
83  
84  	header->SignatureEnd = 0xFFFFFFFF;
85  
86  	//Section count.
87  	int section_count = json_object_get_int(
88  		json_object_object_get(header_ir, "sectionCount"));
89  	header->SectionCount = (UINT16)section_count;
90  
91  	//Error severity.
92  	json_object *severity = json_object_object_get(header_ir, "severity");
93  	header->ErrorSeverity = (UINT32)json_object_get_uint64(
94  		json_object_object_get(severity, "code"));
95  
96  	//Validation bits.
97  	header->ValidationBits = ir_to_bitfield(
98  		json_object_object_get(header_ir, "validationBits"), 3,
99  		CPER_HEADER_VALID_BITFIELD_NAMES);
100  
101  	//Record length.
102  	header->RecordLength = (UINT32)json_object_get_uint64(
103  		json_object_object_get(header_ir, "recordLength"));
104  
105  	//Timestamp, if present.
106  	json_object *timestamp = json_object_object_get(header_ir, "timestamp");
107  	if (timestamp != NULL) {
108  		string_to_timestamp(&header->TimeStamp,
109  				    json_object_get_string(timestamp));
110  		header->TimeStamp.Flag = json_object_get_boolean(
111  			json_object_object_get(header_ir,
112  					       "timestampIsPrecise"));
113  	}
114  
115  	//Various GUIDs.
116  	json_object *platform_id =
117  		json_object_object_get(header_ir, "platformID");
118  	json_object *partition_id =
119  		json_object_object_get(header_ir, "partitionID");
120  	if (platform_id != NULL)
121  		string_to_guid(&header->PlatformID,
122  			       json_object_get_string(platform_id));
123  	if (partition_id != NULL)
124  		string_to_guid(&header->PartitionID,
125  			       json_object_get_string(partition_id));
126  	string_to_guid(&header->CreatorID,
127  		       json_object_get_string(
128  			       json_object_object_get(header_ir, "creatorID")));
129  
130  	//Notification type.
131  	json_object *notification_type =
132  		json_object_object_get(header_ir, "notificationType");
133  	string_to_guid(&header->NotificationType,
134  		       json_object_get_string(json_object_object_get(
135  			       notification_type, "guid")));
136  
137  	//Record ID, persistence info.
138  	header->RecordID = json_object_get_uint64(
139  		json_object_object_get(header_ir, "recordID"));
140  	header->PersistenceInfo = json_object_get_uint64(
141  		json_object_object_get(header_ir, "persistenceInfo"));
142  
143  	//Flags.
144  	json_object *flags = json_object_object_get(header_ir, "flags");
145  	header->Flags = (UINT32)json_object_get_uint64(
146  		json_object_object_get(flags, "value"));
147  }
148  
149  //Converts a single given IR section into CPER, outputting to the given stream.
150  void ir_section_to_cper(json_object *section,
151  			EFI_ERROR_SECTION_DESCRIPTOR *descriptor, FILE *out)
152  {
153  	//Find the correct section type, and parse.
154  	int section_converted = 0;
155  	for (int i = 0; i < section_definitions_len; i++) {
156  		if (guid_equal(section_definitions[i].Guid,
157  			       &descriptor->SectionType) &&
158  		    section_definitions[i].ToCPER != NULL) {
159  			section_definitions[i].ToCPER(section, out);
160  			section_converted = 1;
161  			break;
162  		}
163  	}
164  
165  	//If unknown GUID, so read as a base64 unknown section.
166  	if (!section_converted) {
167  		json_object *encoded = json_object_object_get(section, "data");
168  		UINT8 *decoded =
169  			b64_decode(json_object_get_string(encoded),
170  				   json_object_get_string_len(encoded));
171  		fwrite(decoded, descriptor->SectionLength, 1, out);
172  		fflush(out);
173  		free(decoded);
174  	}
175  }
176  
177  //Converts a single CPER-JSON IR section descriptor into a CPER structure.
178  void ir_section_descriptor_to_cper(json_object *section_descriptor_ir,
179  				   EFI_ERROR_SECTION_DESCRIPTOR *descriptor)
180  {
181  	//Section offset, length.
182  	descriptor->SectionOffset = (UINT32)json_object_get_uint64(
183  		json_object_object_get(section_descriptor_ir, "sectionOffset"));
184  	descriptor->SectionLength = (UINT32)json_object_get_uint64(
185  		json_object_object_get(section_descriptor_ir, "sectionLength"));
186  
187  	//Revision.
188  	json_object *revision =
189  		json_object_object_get(section_descriptor_ir, "revision");
190  	int minor =
191  		json_object_get_int(json_object_object_get(revision, "minor"));
192  	int major =
193  		json_object_get_int(json_object_object_get(revision, "major"));
194  	descriptor->Revision = minor + (major << 8);
195  
196  	//Validation bits, flags.
197  	descriptor->SecValidMask = ir_to_bitfield(
198  		json_object_object_get(section_descriptor_ir, "validationBits"),
199  		2, CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES);
200  	descriptor->SectionFlags = ir_to_bitfield(
201  		json_object_object_get(section_descriptor_ir, "flags"), 8,
202  		CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES);
203  
204  	//Section type.
205  	json_object *section_type =
206  		json_object_object_get(section_descriptor_ir, "sectionType");
207  	string_to_guid(&descriptor->SectionType,
208  		       json_object_get_string(
209  			       json_object_object_get(section_type, "data")));
210  
211  	//FRU ID, if present.
212  	json_object *fru_id =
213  		json_object_object_get(section_descriptor_ir, "fruID");
214  	if (fru_id != NULL)
215  		string_to_guid(&descriptor->FruId,
216  			       json_object_get_string(fru_id));
217  
218  	//Severity code.
219  	json_object *severity =
220  		json_object_object_get(section_descriptor_ir, "severity");
221  	descriptor->Severity = (UINT32)json_object_get_uint64(
222  		json_object_object_get(severity, "code"));
223  
224  	//FRU text, if present.
225  	json_object *fru_text =
226  		json_object_object_get(section_descriptor_ir, "fruText");
227  	if (fru_text != NULL)
228  		strncpy(descriptor->FruString, json_object_get_string(fru_text),
229  			20);
230  }
231  
232  //Converts IR for a given single section format CPER record into CPER binary.
233  void ir_single_section_to_cper(json_object *ir, FILE *out)
234  {
235  	//Create & write a section descriptor to file.
236  	EFI_ERROR_SECTION_DESCRIPTOR *section_descriptor =
237  		(EFI_ERROR_SECTION_DESCRIPTOR *)calloc(
238  			1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR));
239  	ir_section_descriptor_to_cper(
240  		json_object_object_get(ir, "sectionDescriptor"),
241  		section_descriptor);
242  	fwrite(section_descriptor, sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1,
243  	       out);
244  	fflush(out);
245  
246  	//Write section to file.
247  	ir_section_to_cper(json_object_object_get(ir, "section"),
248  			   section_descriptor, out);
249  
250  	//Free remaining resources.
251  	free(section_descriptor);
252  }