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