xref: /openbmc/libcper/sections/cper-section-dmar-vtd.c (revision 50b966f7afa31fe39fda70e10eb9139cce39e025)
1 /**
2  * Describes functions for converting VT-d specific DMAr CPER sections from binary and JSON format
3  * into an intermediate format.
4  *
5  * Author: Lawrence.Tang@arm.com
6  **/
7 #include <stdio.h>
8 #include <string.h>
9 #include <json.h>
10 #include <libcper/base64.h>
11 #include <libcper/Cper.h>
12 #include <libcper/cper-utils.h>
13 #include <libcper/sections/cper-section-dmar-vtd.h>
14 #include <libcper/log.h>
15 
16 //Converts a single VT-d specific DMAr CPER section into JSON IR.
cper_section_dmar_vtd_to_ir(const UINT8 * section,UINT32 size)17 json_object *cper_section_dmar_vtd_to_ir(const UINT8 *section, UINT32 size)
18 {
19 	if (size < sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA)) {
20 		return NULL;
21 	}
22 
23 	EFI_DIRECTED_IO_DMAR_ERROR_DATA *vtd_error =
24 		(EFI_DIRECTED_IO_DMAR_ERROR_DATA *)section;
25 	json_object *section_ir = json_object_new_object();
26 
27 	//Version, revision and OEM ID, as defined in the VT-d architecture.
28 	UINT64 oem_id = 0;
29 	for (int i = 0; i < 6; i++) {
30 		oem_id |= (UINT64)vtd_error->OemId[i] << (i * 8);
31 	}
32 	json_object_object_add(section_ir, "version",
33 			       json_object_new_int(vtd_error->Version));
34 	json_object_object_add(section_ir, "revision",
35 			       json_object_new_int(vtd_error->Revision));
36 	json_object_object_add(section_ir, "oemID",
37 			       json_object_new_uint64(oem_id));
38 
39 	//Registers.
40 	json_object_object_add(section_ir, "capabilityRegister",
41 			       json_object_new_uint64(vtd_error->Capability));
42 	json_object_object_add(section_ir, "extendedCapabilityRegister",
43 			       json_object_new_uint64(vtd_error->CapabilityEx));
44 	json_object_object_add(
45 		section_ir, "globalCommandRegister",
46 		json_object_new_uint64(vtd_error->GlobalCommand));
47 	json_object_object_add(section_ir, "globalStatusRegister",
48 			       json_object_new_uint64(vtd_error->GlobalStatus));
49 	json_object_object_add(section_ir, "faultStatusRegister",
50 			       json_object_new_uint64(vtd_error->FaultStatus));
51 
52 	//Fault record basic fields.
53 	json_object *fault_record_ir = json_object_new_object();
54 	EFI_VTD_FAULT_RECORD *fault_record =
55 		(EFI_VTD_FAULT_RECORD *)vtd_error->FaultRecord;
56 	json_object_object_add(
57 		fault_record_ir, "faultInformation",
58 		json_object_new_uint64(fault_record->FaultInformation));
59 	json_object_object_add(
60 		fault_record_ir, "sourceIdentifier",
61 		json_object_new_uint64(fault_record->SourceIdentifier));
62 	json_object_object_add(
63 		fault_record_ir, "privelegeModeRequested",
64 		json_object_new_boolean(fault_record->PrivelegeModeRequested));
65 	json_object_object_add(
66 		fault_record_ir, "executePermissionRequested",
67 		json_object_new_boolean(
68 			fault_record->ExecutePermissionRequested));
69 	json_object_object_add(
70 		fault_record_ir, "pasidPresent",
71 		json_object_new_boolean(fault_record->PasidPresent));
72 	json_object_object_add(
73 		fault_record_ir, "faultReason",
74 		json_object_new_uint64(fault_record->FaultReason));
75 	json_object_object_add(
76 		fault_record_ir, "pasidValue",
77 		json_object_new_uint64(fault_record->PasidValue));
78 	json_object_object_add(
79 		fault_record_ir, "addressType",
80 		json_object_new_uint64(fault_record->AddressType));
81 
82 	//Fault record type.
83 	json_object *fault_record_type = integer_to_readable_pair(
84 		fault_record->Type, 2, VTD_FAULT_RECORD_TYPES_KEYS,
85 		VTD_FAULT_RECORD_TYPES_VALUES, "Unknown");
86 	json_object_object_add(fault_record_ir, "type", fault_record_type);
87 	json_object_object_add(section_ir, "faultRecord", fault_record_ir);
88 
89 	//Root entry.
90 	int32_t encoded_len = 0;
91 
92 	char *encoded =
93 		base64_encode((UINT8 *)vtd_error->RootEntry, 16, &encoded_len);
94 	json_object_object_add(section_ir, "rootEntry",
95 			       json_object_new_string_len(encoded,
96 							  encoded_len));
97 	free(encoded);
98 
99 	//Context entry.
100 	encoded_len = 0;
101 	encoded = base64_encode((UINT8 *)vtd_error->ContextEntry, 16,
102 				&encoded_len);
103 	if (encoded == NULL) {
104 		cper_print_log("Failed to allocate encode output buffer. \n");
105 	} else {
106 		json_object_object_add(section_ir, "contextEntry",
107 				       json_object_new_string_len(encoded,
108 								  encoded_len));
109 		free(encoded);
110 	}
111 
112 	//PTE entry for all page levels.
113 	json_object_object_add(section_ir, "pageTableEntry_Level6",
114 			       json_object_new_uint64(vtd_error->PteL6));
115 	json_object_object_add(section_ir, "pageTableEntry_Level5",
116 			       json_object_new_uint64(vtd_error->PteL5));
117 	json_object_object_add(section_ir, "pageTableEntry_Level4",
118 			       json_object_new_uint64(vtd_error->PteL4));
119 	json_object_object_add(section_ir, "pageTableEntry_Level3",
120 			       json_object_new_uint64(vtd_error->PteL3));
121 	json_object_object_add(section_ir, "pageTableEntry_Level2",
122 			       json_object_new_uint64(vtd_error->PteL2));
123 	json_object_object_add(section_ir, "pageTableEntry_Level1",
124 			       json_object_new_uint64(vtd_error->PteL1));
125 
126 	return section_ir;
127 }
128 
129 //Converts a single VT-d DMAR CPER-JSON segment into CPER binary, outputting to the given stream.
ir_section_dmar_vtd_to_cper(json_object * section,FILE * out)130 void ir_section_dmar_vtd_to_cper(json_object *section, FILE *out)
131 {
132 	EFI_DIRECTED_IO_DMAR_ERROR_DATA *section_cper =
133 		(EFI_DIRECTED_IO_DMAR_ERROR_DATA *)calloc(
134 			1, sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA));
135 
136 	//OEM ID.
137 	UINT64 oem_id = json_object_get_uint64(
138 		json_object_object_get(section, "oemID"));
139 	for (int i = 0; i < 6; i++) {
140 		section_cper->OemId[i] = (oem_id >> (i * 8)) & 0xFF;
141 	}
142 
143 	//Registers & basic numeric fields.
144 	section_cper->Version = (UINT8)json_object_get_int(
145 		json_object_object_get(section, "version"));
146 	section_cper->Revision = (UINT8)json_object_get_int(
147 		json_object_object_get(section, "revision"));
148 	section_cper->Capability = json_object_get_uint64(
149 		json_object_object_get(section, "capabilityRegister"));
150 	section_cper->CapabilityEx = json_object_get_uint64(
151 		json_object_object_get(section, "extendedCapabilityRegister"));
152 	section_cper->GlobalCommand = json_object_get_uint64(
153 		json_object_object_get(section, "globalCommandRegister"));
154 	section_cper->GlobalStatus = json_object_get_uint64(
155 		json_object_object_get(section, "globalStatusRegister"));
156 	section_cper->FaultStatus = json_object_get_uint64(
157 		json_object_object_get(section, "faultStatusRegister"));
158 
159 	//Fault record.
160 	json_object *fault_record =
161 		json_object_object_get(section, "faultRecord");
162 	EFI_VTD_FAULT_RECORD *fault_record_cper =
163 		(EFI_VTD_FAULT_RECORD *)section_cper->FaultRecord;
164 	fault_record_cper->FaultInformation = json_object_get_uint64(
165 		json_object_object_get(fault_record, "faultInformation"));
166 	fault_record_cper->SourceIdentifier = json_object_get_uint64(
167 		json_object_object_get(fault_record, "sourceIdentifier"));
168 	fault_record_cper->PrivelegeModeRequested = json_object_get_boolean(
169 		json_object_object_get(fault_record, "privelegeModeRequested"));
170 	fault_record_cper->ExecutePermissionRequested = json_object_get_boolean(
171 		json_object_object_get(fault_record,
172 				       "executePermissionRequested"));
173 	fault_record_cper->PasidPresent = json_object_get_boolean(
174 		json_object_object_get(fault_record, "pasidPresent"));
175 	fault_record_cper->FaultReason = json_object_get_uint64(
176 		json_object_object_get(fault_record, "faultReason"));
177 	fault_record_cper->PasidValue = json_object_get_uint64(
178 		json_object_object_get(fault_record, "pasidValue"));
179 	fault_record_cper->AddressType = json_object_get_uint64(
180 		json_object_object_get(fault_record, "addressType"));
181 	fault_record_cper->Type = readable_pair_to_integer(
182 		json_object_object_get(fault_record, "type"));
183 
184 	//Root entry.
185 	json_object *encoded = json_object_object_get(section, "rootEntry");
186 	int32_t decoded_len = 0;
187 
188 	UINT8 *decoded = base64_decode(json_object_get_string(encoded),
189 				       json_object_get_string_len(encoded),
190 				       &decoded_len);
191 	if (decoded == NULL) {
192 		cper_print_log("Failed to allocate decode output buffer. \n");
193 	} else {
194 		memcpy(section_cper->RootEntry, decoded, decoded_len);
195 		free(decoded);
196 	}
197 
198 	//Context entry.
199 	encoded = json_object_object_get(section, "contextEntry");
200 	decoded_len = 0;
201 
202 	decoded = base64_decode(json_object_get_string(encoded),
203 				json_object_get_string_len(encoded),
204 				&decoded_len);
205 	if (decoded == NULL) {
206 		cper_print_log("Failed to allocate decode output buffer. \n");
207 
208 	} else {
209 		memcpy(section_cper->ContextEntry, decoded, decoded_len);
210 		free(decoded);
211 	}
212 
213 	//Page table entries.
214 	section_cper->PteL1 = json_object_get_uint64(
215 		json_object_object_get(section, "pageTableEntry_Level1"));
216 	section_cper->PteL2 = json_object_get_uint64(
217 		json_object_object_get(section, "pageTableEntry_Level2"));
218 	section_cper->PteL3 = json_object_get_uint64(
219 		json_object_object_get(section, "pageTableEntry_Level3"));
220 	section_cper->PteL4 = json_object_get_uint64(
221 		json_object_object_get(section, "pageTableEntry_Level4"));
222 	section_cper->PteL5 = json_object_get_uint64(
223 		json_object_object_get(section, "pageTableEntry_Level5"));
224 	section_cper->PteL6 = json_object_get_uint64(
225 		json_object_object_get(section, "pageTableEntry_Level6"));
226 
227 	//Write to stream, free resources.
228 	fwrite(section_cper, sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA), 1, out);
229 	fflush(out);
230 	free(section_cper);
231 }
232