blob: 0b82bf66e0fef6b13e81d2d8c8de056597adaa3b [file] [log] [blame]
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +01001/**
2 * Describes functions for converting VT-d specific DMAr CPER sections from binary and JSON format
3 * into an intermediate format.
Ed Tanousfedd4572024-07-12 13:56:00 -07004 *
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +01005 * Author: Lawrence.Tang@arm.com
6 **/
7#include <stdio.h>
Lawrence Tang205dd1d2022-07-14 16:23:38 +01008#include <string.h>
Lawrence Tang5202bbb2022-08-12 14:54:36 +01009#include <json.h>
Thu Nguyene42fb482024-10-15 14:43:11 +000010#include <libcper/base64.h>
11#include <libcper/Cper.h>
12#include <libcper/cper-utils.h>
13#include <libcper/sections/cper-section-dmar-vtd.h>
Ed Tanous50b966f2025-03-11 09:06:19 -070014#include <libcper/log.h>
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070015#include <string.h>
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010016
17//Converts a single VT-d specific DMAr CPER section into JSON IR.
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070018json_object *cper_section_dmar_vtd_to_ir(const UINT8 *section, UINT32 size,
19 char **desc_string)
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010020{
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070021 int outstr_len = 0;
22 *desc_string = malloc(SECTION_DESC_STRING_SIZE);
23 outstr_len = snprintf(*desc_string, SECTION_DESC_STRING_SIZE,
24 "A VT-d DMAr Error occurred");
25 if (outstr_len < 0) {
26 cper_print_log(
27 "Error: Could not write to VT-d DMAr description string\n");
28 } else if (outstr_len > SECTION_DESC_STRING_SIZE) {
29 cper_print_log(
30 "Error: VT-d DMAr description string truncated\n");
31 }
32
Ed Tanous12dbd4f2025-03-08 19:05:01 -080033 if (size < sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA)) {
34 return NULL;
35 }
36
Lawrence Tange407b4c2022-07-21 13:54:01 +010037 EFI_DIRECTED_IO_DMAR_ERROR_DATA *vtd_error =
38 (EFI_DIRECTED_IO_DMAR_ERROR_DATA *)section;
39 json_object *section_ir = json_object_new_object();
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010040
Lawrence Tange407b4c2022-07-21 13:54:01 +010041 //Version, revision and OEM ID, as defined in the VT-d architecture.
42 UINT64 oem_id = 0;
John Chungf8fc7052024-05-03 20:05:29 +080043 for (int i = 0; i < 6; i++) {
Lawrence Tange407b4c2022-07-21 13:54:01 +010044 oem_id |= (UINT64)vtd_error->OemId[i] << (i * 8);
John Chungf8fc7052024-05-03 20:05:29 +080045 }
Lawrence Tange407b4c2022-07-21 13:54:01 +010046 json_object_object_add(section_ir, "version",
47 json_object_new_int(vtd_error->Version));
48 json_object_object_add(section_ir, "revision",
49 json_object_new_int(vtd_error->Revision));
50 json_object_object_add(section_ir, "oemID",
51 json_object_new_uint64(oem_id));
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010052
Lawrence Tange407b4c2022-07-21 13:54:01 +010053 //Registers.
54 json_object_object_add(section_ir, "capabilityRegister",
55 json_object_new_uint64(vtd_error->Capability));
56 json_object_object_add(section_ir, "extendedCapabilityRegister",
57 json_object_new_uint64(vtd_error->CapabilityEx));
58 json_object_object_add(
59 section_ir, "globalCommandRegister",
60 json_object_new_uint64(vtd_error->GlobalCommand));
61 json_object_object_add(section_ir, "globalStatusRegister",
62 json_object_new_uint64(vtd_error->GlobalStatus));
63 json_object_object_add(section_ir, "faultStatusRegister",
64 json_object_new_uint64(vtd_error->FaultStatus));
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010065
Lawrence Tange407b4c2022-07-21 13:54:01 +010066 //Fault record basic fields.
67 json_object *fault_record_ir = json_object_new_object();
68 EFI_VTD_FAULT_RECORD *fault_record =
69 (EFI_VTD_FAULT_RECORD *)vtd_error->FaultRecord;
70 json_object_object_add(
71 fault_record_ir, "faultInformation",
72 json_object_new_uint64(fault_record->FaultInformation));
73 json_object_object_add(
74 fault_record_ir, "sourceIdentifier",
75 json_object_new_uint64(fault_record->SourceIdentifier));
76 json_object_object_add(
77 fault_record_ir, "privelegeModeRequested",
78 json_object_new_boolean(fault_record->PrivelegeModeRequested));
79 json_object_object_add(
80 fault_record_ir, "executePermissionRequested",
81 json_object_new_boolean(
82 fault_record->ExecutePermissionRequested));
83 json_object_object_add(
84 fault_record_ir, "pasidPresent",
85 json_object_new_boolean(fault_record->PasidPresent));
86 json_object_object_add(
87 fault_record_ir, "faultReason",
88 json_object_new_uint64(fault_record->FaultReason));
89 json_object_object_add(
90 fault_record_ir, "pasidValue",
91 json_object_new_uint64(fault_record->PasidValue));
92 json_object_object_add(
93 fault_record_ir, "addressType",
94 json_object_new_uint64(fault_record->AddressType));
Lawrence Tangce0f82b2022-07-07 16:14:28 +010095
Lawrence Tange407b4c2022-07-21 13:54:01 +010096 //Fault record type.
97 json_object *fault_record_type = integer_to_readable_pair(
98 fault_record->Type, 2, VTD_FAULT_RECORD_TYPES_KEYS,
99 VTD_FAULT_RECORD_TYPES_VALUES, "Unknown");
100 json_object_object_add(fault_record_ir, "type", fault_record_type);
101 json_object_object_add(section_ir, "faultRecord", fault_record_ir);
Lawrence Tangce0f82b2022-07-07 16:14:28 +0100102
Lawrence Tange407b4c2022-07-21 13:54:01 +0100103 //Root entry.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700104 int32_t encoded_len = 0;
105
106 char *encoded =
107 base64_encode((UINT8 *)vtd_error->RootEntry, 16, &encoded_len);
108 json_object_object_add(section_ir, "rootEntry",
109 json_object_new_string_len(encoded,
110 encoded_len));
111 free(encoded);
Lawrence Tangce0f82b2022-07-07 16:14:28 +0100112
Lawrence Tange407b4c2022-07-21 13:54:01 +0100113 //Context entry.
John Chungf8fc7052024-05-03 20:05:29 +0800114 encoded_len = 0;
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700115 encoded = base64_encode((UINT8 *)vtd_error->ContextEntry, 16,
116 &encoded_len);
117 if (encoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700118 cper_print_log("Failed to allocate encode output buffer. \n");
John Chungf8fc7052024-05-03 20:05:29 +0800119 } else {
John Chungf8fc7052024-05-03 20:05:29 +0800120 json_object_object_add(section_ir, "contextEntry",
121 json_object_new_string_len(encoded,
122 encoded_len));
123 free(encoded);
124 }
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +0100125
Lawrence Tange407b4c2022-07-21 13:54:01 +0100126 //PTE entry for all page levels.
127 json_object_object_add(section_ir, "pageTableEntry_Level6",
128 json_object_new_uint64(vtd_error->PteL6));
129 json_object_object_add(section_ir, "pageTableEntry_Level5",
130 json_object_new_uint64(vtd_error->PteL5));
131 json_object_object_add(section_ir, "pageTableEntry_Level4",
132 json_object_new_uint64(vtd_error->PteL4));
133 json_object_object_add(section_ir, "pageTableEntry_Level3",
134 json_object_new_uint64(vtd_error->PteL3));
135 json_object_object_add(section_ir, "pageTableEntry_Level2",
136 json_object_new_uint64(vtd_error->PteL2));
137 json_object_object_add(section_ir, "pageTableEntry_Level1",
138 json_object_new_uint64(vtd_error->PteL1));
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +0100139
Lawrence Tange407b4c2022-07-21 13:54:01 +0100140 return section_ir;
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100141}
142
143//Converts a single VT-d DMAR CPER-JSON segment into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100144void ir_section_dmar_vtd_to_cper(json_object *section, FILE *out)
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100145{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100146 EFI_DIRECTED_IO_DMAR_ERROR_DATA *section_cper =
147 (EFI_DIRECTED_IO_DMAR_ERROR_DATA *)calloc(
148 1, sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA));
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100149
Lawrence Tange407b4c2022-07-21 13:54:01 +0100150 //OEM ID.
151 UINT64 oem_id = json_object_get_uint64(
152 json_object_object_get(section, "oemID"));
John Chungf8fc7052024-05-03 20:05:29 +0800153 for (int i = 0; i < 6; i++) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100154 section_cper->OemId[i] = (oem_id >> (i * 8)) & 0xFF;
John Chungf8fc7052024-05-03 20:05:29 +0800155 }
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100156
Lawrence Tange407b4c2022-07-21 13:54:01 +0100157 //Registers & basic numeric fields.
158 section_cper->Version = (UINT8)json_object_get_int(
159 json_object_object_get(section, "version"));
160 section_cper->Revision = (UINT8)json_object_get_int(
161 json_object_object_get(section, "revision"));
162 section_cper->Capability = json_object_get_uint64(
163 json_object_object_get(section, "capabilityRegister"));
164 section_cper->CapabilityEx = json_object_get_uint64(
165 json_object_object_get(section, "extendedCapabilityRegister"));
166 section_cper->GlobalCommand = json_object_get_uint64(
167 json_object_object_get(section, "globalCommandRegister"));
168 section_cper->GlobalStatus = json_object_get_uint64(
169 json_object_object_get(section, "globalStatusRegister"));
170 section_cper->FaultStatus = json_object_get_uint64(
171 json_object_object_get(section, "faultStatusRegister"));
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100172
Lawrence Tange407b4c2022-07-21 13:54:01 +0100173 //Fault record.
174 json_object *fault_record =
175 json_object_object_get(section, "faultRecord");
176 EFI_VTD_FAULT_RECORD *fault_record_cper =
177 (EFI_VTD_FAULT_RECORD *)section_cper->FaultRecord;
178 fault_record_cper->FaultInformation = json_object_get_uint64(
179 json_object_object_get(fault_record, "faultInformation"));
180 fault_record_cper->SourceIdentifier = json_object_get_uint64(
181 json_object_object_get(fault_record, "sourceIdentifier"));
182 fault_record_cper->PrivelegeModeRequested = json_object_get_boolean(
183 json_object_object_get(fault_record, "privelegeModeRequested"));
184 fault_record_cper->ExecutePermissionRequested = json_object_get_boolean(
185 json_object_object_get(fault_record,
186 "executePermissionRequested"));
187 fault_record_cper->PasidPresent = json_object_get_boolean(
188 json_object_object_get(fault_record, "pasidPresent"));
189 fault_record_cper->FaultReason = json_object_get_uint64(
190 json_object_object_get(fault_record, "faultReason"));
191 fault_record_cper->PasidValue = json_object_get_uint64(
192 json_object_object_get(fault_record, "pasidValue"));
193 fault_record_cper->AddressType = json_object_get_uint64(
194 json_object_object_get(fault_record, "addressType"));
195 fault_record_cper->Type = readable_pair_to_integer(
196 json_object_object_get(fault_record, "type"));
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100197
Lawrence Tange407b4c2022-07-21 13:54:01 +0100198 //Root entry.
199 json_object *encoded = json_object_object_get(section, "rootEntry");
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700200 int32_t decoded_len = 0;
201
202 UINT8 *decoded = base64_decode(json_object_get_string(encoded),
203 json_object_get_string_len(encoded),
204 &decoded_len);
205 if (decoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700206 cper_print_log("Failed to allocate decode output buffer. \n");
John Chungf8fc7052024-05-03 20:05:29 +0800207 } else {
John Chungf8fc7052024-05-03 20:05:29 +0800208 memcpy(section_cper->RootEntry, decoded, decoded_len);
209 free(decoded);
210 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700211
Lawrence Tange407b4c2022-07-21 13:54:01 +0100212 //Context entry.
213 encoded = json_object_object_get(section, "contextEntry");
John Chungf8fc7052024-05-03 20:05:29 +0800214 decoded_len = 0;
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700215
216 decoded = base64_decode(json_object_get_string(encoded),
217 json_object_get_string_len(encoded),
218 &decoded_len);
219 if (decoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700220 cper_print_log("Failed to allocate decode output buffer. \n");
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700221
John Chungf8fc7052024-05-03 20:05:29 +0800222 } else {
John Chungf8fc7052024-05-03 20:05:29 +0800223 memcpy(section_cper->ContextEntry, decoded, decoded_len);
224 free(decoded);
225 }
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100226
Lawrence Tange407b4c2022-07-21 13:54:01 +0100227 //Page table entries.
228 section_cper->PteL1 = json_object_get_uint64(
229 json_object_object_get(section, "pageTableEntry_Level1"));
230 section_cper->PteL2 = json_object_get_uint64(
231 json_object_object_get(section, "pageTableEntry_Level2"));
232 section_cper->PteL3 = json_object_get_uint64(
233 json_object_object_get(section, "pageTableEntry_Level3"));
234 section_cper->PteL4 = json_object_get_uint64(
235 json_object_object_get(section, "pageTableEntry_Level4"));
236 section_cper->PteL5 = json_object_get_uint64(
237 json_object_object_get(section, "pageTableEntry_Level5"));
238 section_cper->PteL6 = json_object_get_uint64(
239 json_object_object_get(section, "pageTableEntry_Level6"));
240
241 //Write to stream, free resources.
242 fwrite(section_cper, sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA), 1, out);
243 fflush(out);
244 free(section_cper);
John Chungf8fc7052024-05-03 20:05:29 +0800245}