blob: ad86293f16f11d96aa23dd6082cb1fe17bd5c212 [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>
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010014
15//Converts a single VT-d specific DMAr CPER section into JSON IR.
Ed Tanous12dbd4f2025-03-08 19:05:01 -080016json_object *cper_section_dmar_vtd_to_ir(const UINT8 *section, UINT32 size)
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010017{
Ed Tanous12dbd4f2025-03-08 19:05:01 -080018 if (size < sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA)) {
19 return NULL;
20 }
21
Lawrence Tange407b4c2022-07-21 13:54:01 +010022 EFI_DIRECTED_IO_DMAR_ERROR_DATA *vtd_error =
23 (EFI_DIRECTED_IO_DMAR_ERROR_DATA *)section;
24 json_object *section_ir = json_object_new_object();
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010025
Lawrence Tange407b4c2022-07-21 13:54:01 +010026 //Version, revision and OEM ID, as defined in the VT-d architecture.
27 UINT64 oem_id = 0;
John Chungf8fc7052024-05-03 20:05:29 +080028 for (int i = 0; i < 6; i++) {
Lawrence Tange407b4c2022-07-21 13:54:01 +010029 oem_id |= (UINT64)vtd_error->OemId[i] << (i * 8);
John Chungf8fc7052024-05-03 20:05:29 +080030 }
Lawrence Tange407b4c2022-07-21 13:54:01 +010031 json_object_object_add(section_ir, "version",
32 json_object_new_int(vtd_error->Version));
33 json_object_object_add(section_ir, "revision",
34 json_object_new_int(vtd_error->Revision));
35 json_object_object_add(section_ir, "oemID",
36 json_object_new_uint64(oem_id));
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010037
Lawrence Tange407b4c2022-07-21 13:54:01 +010038 //Registers.
39 json_object_object_add(section_ir, "capabilityRegister",
40 json_object_new_uint64(vtd_error->Capability));
41 json_object_object_add(section_ir, "extendedCapabilityRegister",
42 json_object_new_uint64(vtd_error->CapabilityEx));
43 json_object_object_add(
44 section_ir, "globalCommandRegister",
45 json_object_new_uint64(vtd_error->GlobalCommand));
46 json_object_object_add(section_ir, "globalStatusRegister",
47 json_object_new_uint64(vtd_error->GlobalStatus));
48 json_object_object_add(section_ir, "faultStatusRegister",
49 json_object_new_uint64(vtd_error->FaultStatus));
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +010050
Lawrence Tange407b4c2022-07-21 13:54:01 +010051 //Fault record basic fields.
52 json_object *fault_record_ir = json_object_new_object();
53 EFI_VTD_FAULT_RECORD *fault_record =
54 (EFI_VTD_FAULT_RECORD *)vtd_error->FaultRecord;
55 json_object_object_add(
56 fault_record_ir, "faultInformation",
57 json_object_new_uint64(fault_record->FaultInformation));
58 json_object_object_add(
59 fault_record_ir, "sourceIdentifier",
60 json_object_new_uint64(fault_record->SourceIdentifier));
61 json_object_object_add(
62 fault_record_ir, "privelegeModeRequested",
63 json_object_new_boolean(fault_record->PrivelegeModeRequested));
64 json_object_object_add(
65 fault_record_ir, "executePermissionRequested",
66 json_object_new_boolean(
67 fault_record->ExecutePermissionRequested));
68 json_object_object_add(
69 fault_record_ir, "pasidPresent",
70 json_object_new_boolean(fault_record->PasidPresent));
71 json_object_object_add(
72 fault_record_ir, "faultReason",
73 json_object_new_uint64(fault_record->FaultReason));
74 json_object_object_add(
75 fault_record_ir, "pasidValue",
76 json_object_new_uint64(fault_record->PasidValue));
77 json_object_object_add(
78 fault_record_ir, "addressType",
79 json_object_new_uint64(fault_record->AddressType));
Lawrence Tangce0f82b2022-07-07 16:14:28 +010080
Lawrence Tange407b4c2022-07-21 13:54:01 +010081 //Fault record type.
82 json_object *fault_record_type = integer_to_readable_pair(
83 fault_record->Type, 2, VTD_FAULT_RECORD_TYPES_KEYS,
84 VTD_FAULT_RECORD_TYPES_VALUES, "Unknown");
85 json_object_object_add(fault_record_ir, "type", fault_record_type);
86 json_object_object_add(section_ir, "faultRecord", fault_record_ir);
Lawrence Tangce0f82b2022-07-07 16:14:28 +010087
Lawrence Tange407b4c2022-07-21 13:54:01 +010088 //Root entry.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -070089 int32_t encoded_len = 0;
90
91 char *encoded =
92 base64_encode((UINT8 *)vtd_error->RootEntry, 16, &encoded_len);
93 json_object_object_add(section_ir, "rootEntry",
94 json_object_new_string_len(encoded,
95 encoded_len));
96 free(encoded);
Lawrence Tangce0f82b2022-07-07 16:14:28 +010097
Lawrence Tange407b4c2022-07-21 13:54:01 +010098 //Context entry.
John Chungf8fc7052024-05-03 20:05:29 +080099 encoded_len = 0;
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700100 encoded = base64_encode((UINT8 *)vtd_error->ContextEntry, 16,
101 &encoded_len);
102 if (encoded == NULL) {
John Chungf8fc7052024-05-03 20:05:29 +0800103 printf("Failed to allocate encode output buffer. \n");
104 } else {
John Chungf8fc7052024-05-03 20:05:29 +0800105 json_object_object_add(section_ir, "contextEntry",
106 json_object_new_string_len(encoded,
107 encoded_len));
108 free(encoded);
109 }
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +0100110
Lawrence Tange407b4c2022-07-21 13:54:01 +0100111 //PTE entry for all page levels.
112 json_object_object_add(section_ir, "pageTableEntry_Level6",
113 json_object_new_uint64(vtd_error->PteL6));
114 json_object_object_add(section_ir, "pageTableEntry_Level5",
115 json_object_new_uint64(vtd_error->PteL5));
116 json_object_object_add(section_ir, "pageTableEntry_Level4",
117 json_object_new_uint64(vtd_error->PteL4));
118 json_object_object_add(section_ir, "pageTableEntry_Level3",
119 json_object_new_uint64(vtd_error->PteL3));
120 json_object_object_add(section_ir, "pageTableEntry_Level2",
121 json_object_new_uint64(vtd_error->PteL2));
122 json_object_object_add(section_ir, "pageTableEntry_Level1",
123 json_object_new_uint64(vtd_error->PteL1));
Lawrence Tangdb1b7ce2022-07-06 15:40:26 +0100124
Lawrence Tange407b4c2022-07-21 13:54:01 +0100125 return section_ir;
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100126}
127
128//Converts a single VT-d DMAR CPER-JSON segment into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100129void ir_section_dmar_vtd_to_cper(json_object *section, FILE *out)
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100130{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100131 EFI_DIRECTED_IO_DMAR_ERROR_DATA *section_cper =
132 (EFI_DIRECTED_IO_DMAR_ERROR_DATA *)calloc(
133 1, sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA));
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100134
Lawrence Tange407b4c2022-07-21 13:54:01 +0100135 //OEM ID.
136 UINT64 oem_id = json_object_get_uint64(
137 json_object_object_get(section, "oemID"));
John Chungf8fc7052024-05-03 20:05:29 +0800138 for (int i = 0; i < 6; i++) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100139 section_cper->OemId[i] = (oem_id >> (i * 8)) & 0xFF;
John Chungf8fc7052024-05-03 20:05:29 +0800140 }
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100141
Lawrence Tange407b4c2022-07-21 13:54:01 +0100142 //Registers & basic numeric fields.
143 section_cper->Version = (UINT8)json_object_get_int(
144 json_object_object_get(section, "version"));
145 section_cper->Revision = (UINT8)json_object_get_int(
146 json_object_object_get(section, "revision"));
147 section_cper->Capability = json_object_get_uint64(
148 json_object_object_get(section, "capabilityRegister"));
149 section_cper->CapabilityEx = json_object_get_uint64(
150 json_object_object_get(section, "extendedCapabilityRegister"));
151 section_cper->GlobalCommand = json_object_get_uint64(
152 json_object_object_get(section, "globalCommandRegister"));
153 section_cper->GlobalStatus = json_object_get_uint64(
154 json_object_object_get(section, "globalStatusRegister"));
155 section_cper->FaultStatus = json_object_get_uint64(
156 json_object_object_get(section, "faultStatusRegister"));
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100157
Lawrence Tange407b4c2022-07-21 13:54:01 +0100158 //Fault record.
159 json_object *fault_record =
160 json_object_object_get(section, "faultRecord");
161 EFI_VTD_FAULT_RECORD *fault_record_cper =
162 (EFI_VTD_FAULT_RECORD *)section_cper->FaultRecord;
163 fault_record_cper->FaultInformation = json_object_get_uint64(
164 json_object_object_get(fault_record, "faultInformation"));
165 fault_record_cper->SourceIdentifier = json_object_get_uint64(
166 json_object_object_get(fault_record, "sourceIdentifier"));
167 fault_record_cper->PrivelegeModeRequested = json_object_get_boolean(
168 json_object_object_get(fault_record, "privelegeModeRequested"));
169 fault_record_cper->ExecutePermissionRequested = json_object_get_boolean(
170 json_object_object_get(fault_record,
171 "executePermissionRequested"));
172 fault_record_cper->PasidPresent = json_object_get_boolean(
173 json_object_object_get(fault_record, "pasidPresent"));
174 fault_record_cper->FaultReason = json_object_get_uint64(
175 json_object_object_get(fault_record, "faultReason"));
176 fault_record_cper->PasidValue = json_object_get_uint64(
177 json_object_object_get(fault_record, "pasidValue"));
178 fault_record_cper->AddressType = json_object_get_uint64(
179 json_object_object_get(fault_record, "addressType"));
180 fault_record_cper->Type = readable_pair_to_integer(
181 json_object_object_get(fault_record, "type"));
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100182
Lawrence Tange407b4c2022-07-21 13:54:01 +0100183 //Root entry.
184 json_object *encoded = json_object_object_get(section, "rootEntry");
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700185 int32_t decoded_len = 0;
186
187 UINT8 *decoded = base64_decode(json_object_get_string(encoded),
188 json_object_get_string_len(encoded),
189 &decoded_len);
190 if (decoded == NULL) {
John Chungf8fc7052024-05-03 20:05:29 +0800191 printf("Failed to allocate decode output buffer. \n");
192 } else {
John Chungf8fc7052024-05-03 20:05:29 +0800193 memcpy(section_cper->RootEntry, decoded, decoded_len);
194 free(decoded);
195 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700196
Lawrence Tange407b4c2022-07-21 13:54:01 +0100197 //Context entry.
198 encoded = json_object_object_get(section, "contextEntry");
John Chungf8fc7052024-05-03 20:05:29 +0800199 decoded_len = 0;
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700200
201 decoded = base64_decode(json_object_get_string(encoded),
202 json_object_get_string_len(encoded),
203 &decoded_len);
204 if (decoded == NULL) {
John Chungf8fc7052024-05-03 20:05:29 +0800205 printf("Failed to allocate decode output buffer. \n");
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700206
John Chungf8fc7052024-05-03 20:05:29 +0800207 } else {
John Chungf8fc7052024-05-03 20:05:29 +0800208 memcpy(section_cper->ContextEntry, decoded, decoded_len);
209 free(decoded);
210 }
Lawrence Tang205dd1d2022-07-14 16:23:38 +0100211
Lawrence Tange407b4c2022-07-21 13:54:01 +0100212 //Page table entries.
213 section_cper->PteL1 = json_object_get_uint64(
214 json_object_object_get(section, "pageTableEntry_Level1"));
215 section_cper->PteL2 = json_object_get_uint64(
216 json_object_object_get(section, "pageTableEntry_Level2"));
217 section_cper->PteL3 = json_object_get_uint64(
218 json_object_object_get(section, "pageTableEntry_Level3"));
219 section_cper->PteL4 = json_object_get_uint64(
220 json_object_object_get(section, "pageTableEntry_Level4"));
221 section_cper->PteL5 = json_object_get_uint64(
222 json_object_object_get(section, "pageTableEntry_Level5"));
223 section_cper->PteL6 = json_object_get_uint64(
224 json_object_object_get(section, "pageTableEntry_Level6"));
225
226 //Write to stream, free resources.
227 fwrite(section_cper, sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA), 1, out);
228 fflush(out);
229 free(section_cper);
John Chungf8fc7052024-05-03 20:05:29 +0800230}