xref: /openbmc/libcper/ir-parse.c (revision d34f2b11)
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-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"
29 
30 //Private pre-declarations.
31 void ir_header_to_cper(json_object* header_ir, EFI_COMMON_ERROR_RECORD_HEADER* header);
32 void ir_section_descriptor_to_cper(json_object* section_descriptor_ir, EFI_ERROR_SECTION_DESCRIPTOR* descriptor);
33 
34 //Converts the given JSON IR CPER representation into CPER binary format, piped to the provided file stream.
35 //This function performs no validation of the IR against the CPER-JSON specification. To ensure a safe call,
36 //use validate_schema() from json-schema.h before attempting to call this function.
37 void ir_to_cper(json_object* ir, FILE* out)
38 {
39     //Create the CPER header.
40     EFI_COMMON_ERROR_RECORD_HEADER* header = (EFI_COMMON_ERROR_RECORD_HEADER*)calloc(1, sizeof(EFI_COMMON_ERROR_RECORD_HEADER));
41     ir_header_to_cper(json_object_object_get(ir, "header"), header);
42     fwrite(header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, out);
43     fflush(out);
44 
45     //Create the CPER section descriptors.
46     json_object* section_descriptors = json_object_object_get(ir, "sectionDescriptors");
47     int amt_descriptors = json_object_array_length(section_descriptors);
48     EFI_ERROR_SECTION_DESCRIPTOR* descriptors[amt_descriptors];
49     for (int i=0; i<amt_descriptors; i++)
50     {
51         descriptors[i] = (EFI_ERROR_SECTION_DESCRIPTOR*)calloc(1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR));
52         ir_section_descriptor_to_cper(json_object_array_get_idx(section_descriptors, i), descriptors[i]);
53         fwrite(descriptors[i], sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1, out);
54         fflush(out);
55     }
56 
57     //Run through each section in turn.
58     json_object* sections = json_object_object_get(ir, "sections");
59     int amt_sections = json_object_array_length(sections);
60     for (int i=0; i<amt_sections; i++)
61     {
62         //Get the section itself from the IR.
63         json_object* section = json_object_array_get_idx(sections, i);
64 
65         //Find the correct section type, and parse.
66         if (guid_equal(&descriptors[i]->SectionType, &gEfiProcessorGenericErrorSectionGuid))
67             ir_section_generic_to_cper(section, out);
68         else if (guid_equal(&descriptors[i]->SectionType, &gEfiIa32X64ProcessorErrorSectionGuid))
69             ir_section_ia32x64_to_cper(section, out);
70         // else if (guid_equal(&descriptors[i]->SectionType, &gEfiIpfProcessorErrorSectionGuid))
71         //     ir_section_ipf_to_cper(section, out);
72         else if (guid_equal(&descriptors[i]->SectionType, &gEfiArmProcessorErrorSectionGuid))
73             ir_section_arm_to_cper(section, out);
74         else if (guid_equal(&descriptors[i]->SectionType, &gEfiPlatformMemoryErrorSectionGuid))
75             ir_section_memory_to_cper(section, out);
76         else if (guid_equal(&descriptors[i]->SectionType, &gEfiPlatformMemoryError2SectionGuid))
77             ir_section_memory2_to_cper(section, out);
78         else if (guid_equal(&descriptors[i]->SectionType, &gEfiPcieErrorSectionGuid))
79             ir_section_pcie_to_cper(section, out);
80         else if (guid_equal(&descriptors[i]->SectionType, &gEfiFirmwareErrorSectionGuid))
81             ir_section_firmware_to_cper(section, out);
82         else if (guid_equal(&descriptors[i]->SectionType, &gEfiPciBusErrorSectionGuid))
83             ir_section_pci_bus_to_cper(section, out);
84         else if (guid_equal(&descriptors[i]->SectionType, &gEfiPciDevErrorSectionGuid))
85             ir_section_pci_dev_to_cper(section, out);
86         else if (guid_equal(&descriptors[i]->SectionType, &gEfiDMArGenericErrorSectionGuid))
87             ir_section_dmar_generic_to_cper(section, out);
88         else if (guid_equal(&descriptors[i]->SectionType, &gEfiDirectedIoDMArErrorSectionGuid))
89             ir_section_dmar_vtd_to_cper(section, out);
90         else if (guid_equal(&descriptors[i]->SectionType, &gEfiIommuDMArErrorSectionGuid))
91             ir_section_dmar_iommu_to_cper(section, out);
92         else if (guid_equal(&descriptors[i]->SectionType, &gEfiCcixPerLogErrorSectionGuid))
93             ir_section_ccix_per_to_cper(section, out);
94         else if (guid_equal(&descriptors[i]->SectionType, &gEfiCxlProtocolErrorSectionGuid))
95             ir_section_cxl_protocol_to_cper(section, out);
96         else if (guid_equal(&descriptors[i]->SectionType, &gEfiCxlGeneralMediaErrorSectionGuid)
97             || guid_equal(&descriptors[i]->SectionType, &gEfiCxlDramEventErrorSectionGuid)
98             || guid_equal(&descriptors[i]->SectionType, &gEfiCxlPhysicalSwitchErrorSectionGuid)
99             || guid_equal(&descriptors[i]->SectionType, &gEfiCxlVirtualSwitchErrorSectionGuid)
100             || guid_equal(&descriptors[i]->SectionType, &gEfiCxlMldPortErrorSectionGuid))
101         {
102             ir_section_cxl_component_to_cper(section, out);
103         }
104         else
105         {
106             //Unknown GUID, so read as a base64 unknown section.
107             json_object* encoded = json_object_object_get(section, "data");
108             UINT8* decoded = b64_decode(json_object_get_string(encoded), json_object_get_string_len(encoded));
109             fwrite(decoded, descriptors[i]->SectionLength, 1, out);
110             fflush(out);
111             free(decoded);
112         }
113     }
114 
115     //Free all remaining resources.
116     free(header);
117     for (int i=0; i<amt_descriptors; i++)
118         free(descriptors[i]);
119 }
120 
121 //Converts a CPER-JSON IR header to a CPER header structure.
122 void ir_header_to_cper(json_object* header_ir, EFI_COMMON_ERROR_RECORD_HEADER* header)
123 {
124     header->SignatureStart = 0x52455043; //CPER
125 
126     //Revision.
127     json_object* revision = json_object_object_get(header_ir, "revision");
128     int minor = json_object_get_int(json_object_object_get(revision, "minor"));
129     int major = json_object_get_int(json_object_object_get(revision, "major"));
130     header->Revision = minor + (major << 8);
131 
132     header->SignatureEnd = 0xFFFFFFFF;
133 
134     //Section count.
135     int section_count = json_object_get_int(json_object_object_get(header_ir, "sectionCount"));
136     header->SectionCount = (UINT16)section_count;
137 
138     //Error severity.
139     json_object* severity = json_object_object_get(header_ir, "severity");
140     header->ErrorSeverity = (UINT32)json_object_get_uint64(json_object_object_get(severity, "code"));
141 
142     //Validation bits.
143     header->ValidationBits = ir_to_bitfield(json_object_object_get(header_ir, "validationBits"),
144         3, CPER_HEADER_VALID_BITFIELD_NAMES);
145 
146     //Record length.
147     header->RecordLength = (UINT32)json_object_get_uint64(json_object_object_get(header_ir, "recordLength"));
148 
149     //Timestamp, if present.
150     json_object* timestamp = json_object_object_get(header_ir, "timestamp");
151     if (timestamp != NULL)
152     {
153         string_to_timestamp(&header->TimeStamp, json_object_get_string(timestamp));
154         header->TimeStamp.Flag = json_object_get_boolean(json_object_object_get(header_ir, "timestampIsPrecise"));
155     }
156 
157     //Various GUIDs.
158     json_object* platform_id = json_object_object_get(header_ir, "platformID");
159     json_object* partition_id = json_object_object_get(header_ir, "partitionID");
160     if (platform_id != NULL)
161         string_to_guid(&header->PlatformID, json_object_get_string(platform_id));
162     if (partition_id != NULL)
163         string_to_guid(&header->PartitionID, json_object_get_string(partition_id));
164     string_to_guid(&header->CreatorID, json_object_get_string(json_object_object_get(header_ir, "creatorID")));
165 
166     //Notification type.
167     json_object* notification_type = json_object_object_get(header_ir, "notificationType");
168     string_to_guid(&header->NotificationType, json_object_get_string(json_object_object_get(notification_type, "guid")));
169 
170     //Record ID, persistence info.
171     header->RecordID = json_object_get_uint64(json_object_object_get(header_ir, "recordID"));
172     header->PersistenceInfo = json_object_get_uint64(json_object_object_get(header_ir, "persistenceInfo"));
173 
174     //Flags.
175     json_object* flags = json_object_object_get(header_ir, "flags");
176     header->Flags = (UINT32)json_object_get_uint64(json_object_object_get(flags, "value"));
177 }
178 
179 //Converts a single CPER-JSON IR section descriptor into a CPER structure.
180 void ir_section_descriptor_to_cper(json_object* section_descriptor_ir, EFI_ERROR_SECTION_DESCRIPTOR* descriptor)
181 {
182     //Section offset, length.
183     descriptor->SectionOffset = (UINT32)json_object_get_uint64(json_object_object_get(section_descriptor_ir, "sectionOffset"));
184     descriptor->SectionLength = (UINT32)json_object_get_uint64(json_object_object_get(section_descriptor_ir, "sectionLength"));
185 
186     //Revision.
187     json_object* revision = json_object_object_get(section_descriptor_ir, "revision");
188     int minor = json_object_get_int(json_object_object_get(revision, "minor"));
189     int major = json_object_get_int(json_object_object_get(revision, "major"));
190     descriptor->Revision = minor + (major << 8);
191 
192     //Validation bits, flags.
193     descriptor->SecValidMask = ir_to_bitfield(json_object_object_get(section_descriptor_ir, "validationBits"),
194         2, CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES);
195     descriptor->SectionFlags = ir_to_bitfield(json_object_object_get(section_descriptor_ir, "flags"),
196         8, CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES);
197 
198     //Section type.
199     json_object* section_type = json_object_object_get(section_descriptor_ir, "sectionType");
200     string_to_guid(&descriptor->SectionType, json_object_get_string(json_object_object_get(section_type, "data")));
201 
202     //FRU ID, if present.
203     json_object* fru_id = json_object_object_get(section_descriptor_ir, "fruID");
204     if (fru_id != NULL)
205         string_to_guid(&descriptor->FruId, json_object_get_string(fru_id));
206 
207     //Severity code.
208     json_object* severity = json_object_object_get(section_descriptor_ir, "severity");
209     descriptor->Severity = (UINT32)json_object_get_uint64(json_object_object_get(severity, "code"));
210 
211     //FRU text, if present.
212     json_object* fru_text = json_object_object_get(section_descriptor_ir, "fruText");
213     if (fru_text != NULL)
214         strncpy(descriptor->FruString, json_object_get_string(fru_text), 20);
215 }