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>
10e42fb487SThu Nguyen #include <libcper/base64.h>
11e42fb487SThu Nguyen #include <libcper/Cper.h>
12e42fb487SThu Nguyen #include <libcper/cper-parse.h>
13e42fb487SThu Nguyen #include <libcper/cper-utils.h>
14e42fb487SThu Nguyen #include <libcper/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.
101*ae8f6d9aSAushim Nagarkatti ValidationTypes ui32Type = { UINT_32T, .value.ui32 = 0 };
102*ae8f6d9aSAushim Nagarkatti struct json_object *obj = NULL;
103b44314c7SLawrence Tang
104b44314c7SLawrence Tang //Record length.
105e407b4c8SLawrence Tang header->RecordLength = (UINT32)json_object_get_uint64(
106e407b4c8SLawrence Tang json_object_object_get(header_ir, "recordLength"));
107b44314c7SLawrence Tang
108b44314c7SLawrence Tang //Timestamp, if present.
109*ae8f6d9aSAushim Nagarkatti if (json_object_object_get_ex(header_ir, "timestamp", &obj)) {
110*ae8f6d9aSAushim Nagarkatti json_object *timestamp = obj;
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 }
118*ae8f6d9aSAushim Nagarkatti add_to_valid_bitfield(&ui32Type, 1);
119*ae8f6d9aSAushim Nagarkatti }
120b44314c7SLawrence Tang
121b44314c7SLawrence Tang //Various GUIDs.
122*ae8f6d9aSAushim Nagarkatti json_object *platform_id;
123*ae8f6d9aSAushim Nagarkatti json_object_object_get_ex(header_ir, "platformID", &platform_id);
124*ae8f6d9aSAushim Nagarkatti json_object *partition_id;
125*ae8f6d9aSAushim Nagarkatti json_object_object_get_ex(header_ir, "partitionID", &partition_id);
126f8fc7052SJohn Chung if (platform_id != NULL) {
127e407b4c8SLawrence Tang string_to_guid(&header->PlatformID,
128e407b4c8SLawrence Tang json_object_get_string(platform_id));
129*ae8f6d9aSAushim Nagarkatti add_to_valid_bitfield(&ui32Type, 0);
130f8fc7052SJohn Chung }
131f8fc7052SJohn Chung if (partition_id != NULL) {
132e407b4c8SLawrence Tang string_to_guid(&header->PartitionID,
133e407b4c8SLawrence Tang json_object_get_string(partition_id));
134*ae8f6d9aSAushim Nagarkatti add_to_valid_bitfield(&ui32Type, 2);
135f8fc7052SJohn Chung }
136e407b4c8SLawrence Tang string_to_guid(&header->CreatorID,
137e407b4c8SLawrence Tang json_object_get_string(
138e407b4c8SLawrence Tang json_object_object_get(header_ir, "creatorID")));
139b44314c7SLawrence Tang
140b44314c7SLawrence Tang //Notification type.
141e407b4c8SLawrence Tang json_object *notification_type =
142e407b4c8SLawrence Tang json_object_object_get(header_ir, "notificationType");
143e407b4c8SLawrence Tang string_to_guid(&header->NotificationType,
144e407b4c8SLawrence Tang json_object_get_string(json_object_object_get(
145e407b4c8SLawrence Tang notification_type, "guid")));
146b44314c7SLawrence Tang
147b44314c7SLawrence Tang //Record ID, persistence info.
148e407b4c8SLawrence Tang header->RecordID = json_object_get_uint64(
149e407b4c8SLawrence Tang json_object_object_get(header_ir, "recordID"));
150e407b4c8SLawrence Tang header->PersistenceInfo = json_object_get_uint64(
151e407b4c8SLawrence Tang json_object_object_get(header_ir, "persistenceInfo"));
152b44314c7SLawrence Tang
153b44314c7SLawrence Tang //Flags.
154b44314c7SLawrence Tang json_object *flags = json_object_object_get(header_ir, "flags");
155e407b4c8SLawrence Tang header->Flags = (UINT32)json_object_get_uint64(
156e407b4c8SLawrence Tang json_object_object_get(flags, "value"));
157*ae8f6d9aSAushim Nagarkatti
158*ae8f6d9aSAushim Nagarkatti header->ValidationBits = ui32Type.value.ui32;
159f0f95574SLawrence Tang }
1600cb33793SLawrence Tang
161617949e4SLawrence 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)162617949e4SLawrence Tang void ir_section_to_cper(json_object *section,
163617949e4SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptor, FILE *out)
164617949e4SLawrence Tang {
165b07061abSEd Tanous json_object *ir = NULL;
166b07061abSEd Tanous
167617949e4SLawrence Tang //Find the correct section type, and parse.
168580423feSLawrence Tang int section_converted = 0;
169f8fc7052SJohn Chung for (size_t i = 0; i < section_definitions_len; i++) {
170f1f3b839SLawrence Tang if (guid_equal(section_definitions[i].Guid,
171f1f3b839SLawrence Tang &descriptor->SectionType) &&
172f1f3b839SLawrence Tang section_definitions[i].ToCPER != NULL) {
173b07061abSEd Tanous ir = json_object_object_get(
174b07061abSEd Tanous section, section_definitions[i].ShortName);
175b07061abSEd Tanous section_definitions[i].ToCPER(ir, out);
176580423feSLawrence Tang section_converted = 1;
177580423feSLawrence Tang break;
178580423feSLawrence Tang }
179580423feSLawrence Tang }
180580423feSLawrence Tang
181580423feSLawrence Tang //If unknown GUID, so read as a base64 unknown section.
182580423feSLawrence Tang if (!section_converted) {
183b07061abSEd Tanous ir = json_object_object_get(section, "Unknown");
184b07061abSEd Tanous json_object *encoded = json_object_object_get(ir, "data");
185a7d2cdddSEd Tanous
186a7d2cdddSEd Tanous int32_t decoded_len = 0;
187a7d2cdddSEd Tanous
188a7d2cdddSEd Tanous UINT8 *decoded = base64_decode(
189a7d2cdddSEd Tanous json_object_get_string(encoded),
190a7d2cdddSEd Tanous json_object_get_string_len(encoded), &decoded_len);
191a7d2cdddSEd Tanous if (decoded == NULL) {
192f8fc7052SJohn Chung printf("Failed to allocate decode output buffer. \n");
193f8fc7052SJohn Chung } else {
194f8fc7052SJohn Chung fwrite(decoded, decoded_len, 1, out);
195617949e4SLawrence Tang free(decoded);
196617949e4SLawrence Tang }
197617949e4SLawrence Tang }
198f8fc7052SJohn Chung }
199617949e4SLawrence Tang
2000cb33793SLawrence 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)201e407b4c8SLawrence Tang void ir_section_descriptor_to_cper(json_object *section_descriptor_ir,
202e407b4c8SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptor)
2030cb33793SLawrence Tang {
2040cb33793SLawrence Tang //Section offset, length.
205e407b4c8SLawrence Tang descriptor->SectionOffset = (UINT32)json_object_get_uint64(
206e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionOffset"));
207e407b4c8SLawrence Tang descriptor->SectionLength = (UINT32)json_object_get_uint64(
208e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionLength"));
2090cb33793SLawrence Tang
2100cb33793SLawrence Tang //Revision.
211e407b4c8SLawrence Tang json_object *revision =
212e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "revision");
213e407b4c8SLawrence Tang int minor =
214e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "minor"));
215e407b4c8SLawrence Tang int major =
216e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "major"));
2170cb33793SLawrence Tang descriptor->Revision = minor + (major << 8);
2180cb33793SLawrence Tang
2190cb33793SLawrence Tang //Validation bits, flags.
220*ae8f6d9aSAushim Nagarkatti ValidationTypes ui8Type = { UINT_8T, .value.ui8 = 0 };
221*ae8f6d9aSAushim Nagarkatti struct json_object *obj = NULL;
222*ae8f6d9aSAushim Nagarkatti
223e407b4c8SLawrence Tang descriptor->SectionFlags = ir_to_bitfield(
224e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "flags"), 8,
225e407b4c8SLawrence Tang CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES);
2260cb33793SLawrence Tang
2270cb33793SLawrence Tang //Section type.
228e407b4c8SLawrence Tang json_object *section_type =
229e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionType");
230e407b4c8SLawrence Tang string_to_guid(&descriptor->SectionType,
231e407b4c8SLawrence Tang json_object_get_string(
232e407b4c8SLawrence Tang json_object_object_get(section_type, "data")));
2330cb33793SLawrence Tang
2340cb33793SLawrence Tang //FRU ID, if present.
235*ae8f6d9aSAushim Nagarkatti if (json_object_object_get_ex(section_descriptor_ir, "fruID", &obj)) {
236*ae8f6d9aSAushim Nagarkatti json_object *fru_id = obj;
237f8fc7052SJohn Chung if (fru_id != NULL) {
238e407b4c8SLawrence Tang string_to_guid(&descriptor->FruId,
239e407b4c8SLawrence Tang json_object_get_string(fru_id));
240*ae8f6d9aSAushim Nagarkatti add_to_valid_bitfield(&ui8Type, 0);
241*ae8f6d9aSAushim Nagarkatti }
242f8fc7052SJohn Chung }
2430cb33793SLawrence Tang
2440cb33793SLawrence Tang //Severity code.
245e407b4c8SLawrence Tang json_object *severity =
246e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "severity");
247e407b4c8SLawrence Tang descriptor->Severity = (UINT32)json_object_get_uint64(
248e407b4c8SLawrence Tang json_object_object_get(severity, "code"));
2490cb33793SLawrence Tang
2500cb33793SLawrence Tang //FRU text, if present.
251*ae8f6d9aSAushim Nagarkatti if (json_object_object_get_ex(section_descriptor_ir, "fruText", &obj)) {
252*ae8f6d9aSAushim Nagarkatti json_object *fru_text = obj;
253f8fc7052SJohn Chung if (fru_text != NULL) {
254*ae8f6d9aSAushim Nagarkatti strncpy(descriptor->FruString,
255*ae8f6d9aSAushim Nagarkatti json_object_get_string(fru_text),
256379e492aSPatrick Williams sizeof(descriptor->FruString) - 1);
257*ae8f6d9aSAushim Nagarkatti descriptor
258*ae8f6d9aSAushim Nagarkatti ->FruString[sizeof(descriptor->FruString) - 1] =
259*ae8f6d9aSAushim Nagarkatti '\0';
260*ae8f6d9aSAushim Nagarkatti add_to_valid_bitfield(&ui8Type, 1);
2610cb33793SLawrence Tang }
262f8fc7052SJohn Chung }
263*ae8f6d9aSAushim Nagarkatti descriptor->SecValidMask = ui8Type.value.ui8;
264*ae8f6d9aSAushim Nagarkatti }
265617949e4SLawrence Tang
266617949e4SLawrence Tang //Converts IR for a given single section format CPER record into CPER binary.
ir_single_section_to_cper(json_object * ir,FILE * out)267617949e4SLawrence Tang void ir_single_section_to_cper(json_object *ir, FILE *out)
268617949e4SLawrence Tang {
269617949e4SLawrence Tang //Create & write a section descriptor to file.
270*ae8f6d9aSAushim Nagarkatti EFI_ERROR_SECTION_DESCRIPTOR section_descriptor;
271*ae8f6d9aSAushim Nagarkatti memset(§ion_descriptor, 0, sizeof(section_descriptor));
272*ae8f6d9aSAushim Nagarkatti
273617949e4SLawrence Tang ir_section_descriptor_to_cper(
274617949e4SLawrence Tang json_object_object_get(ir, "sectionDescriptor"),
275*ae8f6d9aSAushim Nagarkatti §ion_descriptor);
276*ae8f6d9aSAushim Nagarkatti fwrite(§ion_descriptor, sizeof(section_descriptor), 1, out);
277617949e4SLawrence Tang
278617949e4SLawrence Tang //Write section to file.
279617949e4SLawrence Tang ir_section_to_cper(json_object_object_get(ir, "section"),
280*ae8f6d9aSAushim Nagarkatti §ion_descriptor, out);
281617949e4SLawrence Tang
282*ae8f6d9aSAushim Nagarkatti fflush(out);
283617949e4SLawrence Tang }
284