blob: 437dd82a7ebc1dae811867f1ed229e9ebfaa596d [file] [log] [blame]
Lawrence Tangf0f95572022-07-07 16:56:22 +01001/**
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>
Lawrence Tang0cb33792022-07-13 13:51:39 +01008#include <string.h>
Lawrence Tangf0f95572022-07-07 16:56:22 +01009#include "json.h"
Lawrence Tang0cb33792022-07-13 13:51:39 +010010#include "b64.h"
Lawrence Tangb44314c2022-07-13 11:45:22 +010011#include "edk/Cper.h"
Lawrence Tangf0f95572022-07-07 16:56:22 +010012#include "cper-parse.h"
Lawrence Tangb44314c2022-07-13 11:45:22 +010013#include "cper-utils.h"
Lawrence Tang0cb33792022-07-13 13:51:39 +010014#include "sections/cper-section-generic.h"
15#include "sections/cper-section-ia32x64.h"
16#include "sections/cper-section-arm.h"
17#include "sections/cper-section-memory.h"
18#include "sections/cper-section-pcie.h"
19#include "sections/cper-section-pci-bus.h"
20#include "sections/cper-section-pci-dev.h"
21#include "sections/cper-section-firmware.h"
22#include "sections/cper-section-dmar-generic.h"
23#include "sections/cper-section-dmar-vtd.h"
24#include "sections/cper-section-dmar-iommu.h"
25#include "sections/cper-section-ccix-per.h"
26#include "sections/cper-section-cxl-protocol.h"
27#include "sections/cper-section-ipf.h"
28#include "sections/cper-section-cxl-component.h"
Lawrence Tangb44314c2022-07-13 11:45:22 +010029
30//Private pre-declarations.
Lawrence Tange407b4c2022-07-21 13:54:01 +010031void ir_header_to_cper(json_object *header_ir,
32 EFI_COMMON_ERROR_RECORD_HEADER *header);
33void ir_section_descriptor_to_cper(json_object *section_descriptor_ir,
34 EFI_ERROR_SECTION_DESCRIPTOR *descriptor);
Lawrence Tangf0f95572022-07-07 16:56:22 +010035
36//Converts the given JSON IR CPER representation into CPER binary format, piped to the provided file stream.
Lawrence Tang0cb33792022-07-13 13:51:39 +010037//This function performs no validation of the IR against the CPER-JSON specification. To ensure a safe call,
Lawrence Tange407b4c2022-07-21 13:54:01 +010038//use validate_schema() from json-schema.h before attempting to call this function.
39void ir_to_cper(json_object *ir, FILE *out)
Lawrence Tangf0f95572022-07-07 16:56:22 +010040{
Lawrence Tange407b4c2022-07-21 13:54:01 +010041 //Create the CPER header.
42 EFI_COMMON_ERROR_RECORD_HEADER *header =
43 (EFI_COMMON_ERROR_RECORD_HEADER *)calloc(
44 1, sizeof(EFI_COMMON_ERROR_RECORD_HEADER));
45 ir_header_to_cper(json_object_object_get(ir, "header"), header);
46 fwrite(header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, out);
47 fflush(out);
Lawrence Tang0cb33792022-07-13 13:51:39 +010048
Lawrence Tange407b4c2022-07-21 13:54:01 +010049 //Create the CPER section descriptors.
50 json_object *section_descriptors =
51 json_object_object_get(ir, "sectionDescriptors");
52 int amt_descriptors = json_object_array_length(section_descriptors);
53 EFI_ERROR_SECTION_DESCRIPTOR *descriptors[amt_descriptors];
54 for (int i = 0; i < amt_descriptors; i++) {
55 descriptors[i] = (EFI_ERROR_SECTION_DESCRIPTOR *)calloc(
56 1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR));
57 ir_section_descriptor_to_cper(
58 json_object_array_get_idx(section_descriptors, i),
59 descriptors[i]);
60 fwrite(descriptors[i], sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1,
61 out);
62 fflush(out);
63 }
Lawrence Tang0cb33792022-07-13 13:51:39 +010064
Lawrence Tange407b4c2022-07-21 13:54:01 +010065 //Run through each section in turn.
66 json_object *sections = json_object_object_get(ir, "sections");
67 int amt_sections = json_object_array_length(sections);
68 for (int i = 0; i < amt_sections; i++) {
69 //Get the section itself from the IR.
70 json_object *section = json_object_array_get_idx(sections, i);
Lawrence Tang0cb33792022-07-13 13:51:39 +010071
Lawrence Tange407b4c2022-07-21 13:54:01 +010072 //Find the correct section type, and parse.
73 if (guid_equal(&descriptors[i]->SectionType,
74 &gEfiProcessorGenericErrorSectionGuid))
75 ir_section_generic_to_cper(section, out);
76 else if (guid_equal(&descriptors[i]->SectionType,
77 &gEfiIa32X64ProcessorErrorSectionGuid))
78 ir_section_ia32x64_to_cper(section, out);
79 // else if (guid_equal(&descriptors[i]->SectionType, &gEfiIpfProcessorErrorSectionGuid))
80 // ir_section_ipf_to_cper(section, out);
81 else if (guid_equal(&descriptors[i]->SectionType,
82 &gEfiArmProcessorErrorSectionGuid))
83 ir_section_arm_to_cper(section, out);
84 else if (guid_equal(&descriptors[i]->SectionType,
85 &gEfiPlatformMemoryErrorSectionGuid))
86 ir_section_memory_to_cper(section, out);
87 else if (guid_equal(&descriptors[i]->SectionType,
88 &gEfiPlatformMemoryError2SectionGuid))
89 ir_section_memory2_to_cper(section, out);
90 else if (guid_equal(&descriptors[i]->SectionType,
91 &gEfiPcieErrorSectionGuid))
92 ir_section_pcie_to_cper(section, out);
93 else if (guid_equal(&descriptors[i]->SectionType,
94 &gEfiFirmwareErrorSectionGuid))
95 ir_section_firmware_to_cper(section, out);
96 else if (guid_equal(&descriptors[i]->SectionType,
97 &gEfiPciBusErrorSectionGuid))
98 ir_section_pci_bus_to_cper(section, out);
99 else if (guid_equal(&descriptors[i]->SectionType,
100 &gEfiPciDevErrorSectionGuid))
101 ir_section_pci_dev_to_cper(section, out);
102 else if (guid_equal(&descriptors[i]->SectionType,
103 &gEfiDMArGenericErrorSectionGuid))
104 ir_section_dmar_generic_to_cper(section, out);
105 else if (guid_equal(&descriptors[i]->SectionType,
106 &gEfiDirectedIoDMArErrorSectionGuid))
107 ir_section_dmar_vtd_to_cper(section, out);
108 else if (guid_equal(&descriptors[i]->SectionType,
109 &gEfiIommuDMArErrorSectionGuid))
110 ir_section_dmar_iommu_to_cper(section, out);
111 else if (guid_equal(&descriptors[i]->SectionType,
112 &gEfiCcixPerLogErrorSectionGuid))
113 ir_section_ccix_per_to_cper(section, out);
114 else if (guid_equal(&descriptors[i]->SectionType,
115 &gEfiCxlProtocolErrorSectionGuid))
116 ir_section_cxl_protocol_to_cper(section, out);
117 else if (guid_equal(&descriptors[i]->SectionType,
118 &gEfiCxlGeneralMediaErrorSectionGuid) ||
119 guid_equal(&descriptors[i]->SectionType,
120 &gEfiCxlDramEventErrorSectionGuid) ||
121 guid_equal(&descriptors[i]->SectionType,
122 &gEfiCxlPhysicalSwitchErrorSectionGuid) ||
123 guid_equal(&descriptors[i]->SectionType,
124 &gEfiCxlVirtualSwitchErrorSectionGuid) ||
125 guid_equal(&descriptors[i]->SectionType,
126 &gEfiCxlMldPortErrorSectionGuid)) {
127 ir_section_cxl_component_to_cper(section, out);
128 } else {
129 //Unknown GUID, so read as a base64 unknown section.
130 json_object *encoded =
131 json_object_object_get(section, "data");
132 UINT8 *decoded =
133 b64_decode(json_object_get_string(encoded),
134 json_object_get_string_len(encoded));
135 fwrite(decoded, descriptors[i]->SectionLength, 1, out);
136 fflush(out);
137 free(decoded);
138 }
139 }
140
141 //Free all remaining resources.
142 free(header);
143 for (int i = 0; i < amt_descriptors; i++)
144 free(descriptors[i]);
Lawrence Tangb44314c2022-07-13 11:45:22 +0100145}
146
147//Converts a CPER-JSON IR header to a CPER header structure.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100148void ir_header_to_cper(json_object *header_ir,
149 EFI_COMMON_ERROR_RECORD_HEADER *header)
Lawrence Tangb44314c2022-07-13 11:45:22 +0100150{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100151 header->SignatureStart = 0x52455043; //CPER
Lawrence Tangb44314c2022-07-13 11:45:22 +0100152
Lawrence Tange407b4c2022-07-21 13:54:01 +0100153 //Revision.
154 json_object *revision = json_object_object_get(header_ir, "revision");
155 int minor =
156 json_object_get_int(json_object_object_get(revision, "minor"));
157 int major =
158 json_object_get_int(json_object_object_get(revision, "major"));
159 header->Revision = minor + (major << 8);
Lawrence Tangb44314c2022-07-13 11:45:22 +0100160
Lawrence Tange407b4c2022-07-21 13:54:01 +0100161 header->SignatureEnd = 0xFFFFFFFF;
Lawrence Tangb44314c2022-07-13 11:45:22 +0100162
Lawrence Tange407b4c2022-07-21 13:54:01 +0100163 //Section count.
164 int section_count = json_object_get_int(
165 json_object_object_get(header_ir, "sectionCount"));
166 header->SectionCount = (UINT16)section_count;
Lawrence Tangb44314c2022-07-13 11:45:22 +0100167
Lawrence Tange407b4c2022-07-21 13:54:01 +0100168 //Error severity.
169 json_object *severity = json_object_object_get(header_ir, "severity");
170 header->ErrorSeverity = (UINT32)json_object_get_uint64(
171 json_object_object_get(severity, "code"));
Lawrence Tangb44314c2022-07-13 11:45:22 +0100172
Lawrence Tange407b4c2022-07-21 13:54:01 +0100173 //Validation bits.
174 header->ValidationBits = ir_to_bitfield(
175 json_object_object_get(header_ir, "validationBits"), 3,
176 CPER_HEADER_VALID_BITFIELD_NAMES);
Lawrence Tangb44314c2022-07-13 11:45:22 +0100177
Lawrence Tange407b4c2022-07-21 13:54:01 +0100178 //Record length.
179 header->RecordLength = (UINT32)json_object_get_uint64(
180 json_object_object_get(header_ir, "recordLength"));
Lawrence Tangb44314c2022-07-13 11:45:22 +0100181
Lawrence Tange407b4c2022-07-21 13:54:01 +0100182 //Timestamp, if present.
183 json_object *timestamp = json_object_object_get(header_ir, "timestamp");
184 if (timestamp != NULL) {
185 string_to_timestamp(&header->TimeStamp,
186 json_object_get_string(timestamp));
187 header->TimeStamp.Flag = json_object_get_boolean(
188 json_object_object_get(header_ir,
189 "timestampIsPrecise"));
190 }
Lawrence Tangb44314c2022-07-13 11:45:22 +0100191
Lawrence Tange407b4c2022-07-21 13:54:01 +0100192 //Various GUIDs.
193 json_object *platform_id =
194 json_object_object_get(header_ir, "platformID");
195 json_object *partition_id =
196 json_object_object_get(header_ir, "partitionID");
197 if (platform_id != NULL)
198 string_to_guid(&header->PlatformID,
199 json_object_get_string(platform_id));
200 if (partition_id != NULL)
201 string_to_guid(&header->PartitionID,
202 json_object_get_string(partition_id));
203 string_to_guid(&header->CreatorID,
204 json_object_get_string(
205 json_object_object_get(header_ir, "creatorID")));
Lawrence Tangb44314c2022-07-13 11:45:22 +0100206
Lawrence Tange407b4c2022-07-21 13:54:01 +0100207 //Notification type.
208 json_object *notification_type =
209 json_object_object_get(header_ir, "notificationType");
210 string_to_guid(&header->NotificationType,
211 json_object_get_string(json_object_object_get(
212 notification_type, "guid")));
Lawrence Tangb44314c2022-07-13 11:45:22 +0100213
Lawrence Tange407b4c2022-07-21 13:54:01 +0100214 //Record ID, persistence info.
215 header->RecordID = json_object_get_uint64(
216 json_object_object_get(header_ir, "recordID"));
217 header->PersistenceInfo = json_object_get_uint64(
218 json_object_object_get(header_ir, "persistenceInfo"));
Lawrence Tangb44314c2022-07-13 11:45:22 +0100219
Lawrence Tange407b4c2022-07-21 13:54:01 +0100220 //Flags.
221 json_object *flags = json_object_object_get(header_ir, "flags");
222 header->Flags = (UINT32)json_object_get_uint64(
223 json_object_object_get(flags, "value"));
Lawrence Tang0cb33792022-07-13 13:51:39 +0100224}
225
226//Converts a single CPER-JSON IR section descriptor into a CPER structure.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100227void ir_section_descriptor_to_cper(json_object *section_descriptor_ir,
228 EFI_ERROR_SECTION_DESCRIPTOR *descriptor)
Lawrence Tang0cb33792022-07-13 13:51:39 +0100229{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100230 //Section offset, length.
231 descriptor->SectionOffset = (UINT32)json_object_get_uint64(
232 json_object_object_get(section_descriptor_ir, "sectionOffset"));
233 descriptor->SectionLength = (UINT32)json_object_get_uint64(
234 json_object_object_get(section_descriptor_ir, "sectionLength"));
Lawrence Tang0cb33792022-07-13 13:51:39 +0100235
Lawrence Tange407b4c2022-07-21 13:54:01 +0100236 //Revision.
237 json_object *revision =
238 json_object_object_get(section_descriptor_ir, "revision");
239 int minor =
240 json_object_get_int(json_object_object_get(revision, "minor"));
241 int major =
242 json_object_get_int(json_object_object_get(revision, "major"));
243 descriptor->Revision = minor + (major << 8);
Lawrence Tang0cb33792022-07-13 13:51:39 +0100244
Lawrence Tange407b4c2022-07-21 13:54:01 +0100245 //Validation bits, flags.
246 descriptor->SecValidMask = ir_to_bitfield(
247 json_object_object_get(section_descriptor_ir, "validationBits"),
248 2, CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES);
249 descriptor->SectionFlags = ir_to_bitfield(
250 json_object_object_get(section_descriptor_ir, "flags"), 8,
251 CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES);
Lawrence Tang0cb33792022-07-13 13:51:39 +0100252
Lawrence Tange407b4c2022-07-21 13:54:01 +0100253 //Section type.
254 json_object *section_type =
255 json_object_object_get(section_descriptor_ir, "sectionType");
256 string_to_guid(&descriptor->SectionType,
257 json_object_get_string(
258 json_object_object_get(section_type, "data")));
Lawrence Tang0cb33792022-07-13 13:51:39 +0100259
Lawrence Tange407b4c2022-07-21 13:54:01 +0100260 //FRU ID, if present.
261 json_object *fru_id =
262 json_object_object_get(section_descriptor_ir, "fruID");
263 if (fru_id != NULL)
264 string_to_guid(&descriptor->FruId,
265 json_object_get_string(fru_id));
Lawrence Tang0cb33792022-07-13 13:51:39 +0100266
Lawrence Tange407b4c2022-07-21 13:54:01 +0100267 //Severity code.
268 json_object *severity =
269 json_object_object_get(section_descriptor_ir, "severity");
270 descriptor->Severity = (UINT32)json_object_get_uint64(
271 json_object_object_get(severity, "code"));
Lawrence Tang0cb33792022-07-13 13:51:39 +0100272
Lawrence Tange407b4c2022-07-21 13:54:01 +0100273 //FRU text, if present.
274 json_object *fru_text =
275 json_object_object_get(section_descriptor_ir, "fruText");
276 if (fru_text != NULL)
277 strncpy(descriptor->FruString, json_object_get_string(fru_text),
278 20);
Lawrence Tangf0f95572022-07-07 16:56:22 +0100279}