xref: /openbmc/libcper/sections/cper-section-dmar-vtd.c (revision ad6c880fc739b6ca750c3ab594e270efd972c2ac)
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 #include <string.h>
16 
17 //Converts a single VT-d specific DMAr CPER section into JSON IR.
cper_section_dmar_vtd_to_ir(const UINT8 * section,UINT32 size,char ** desc_string)18 json_object *cper_section_dmar_vtd_to_ir(const UINT8 *section, UINT32 size,
19 					 char **desc_string)
20 {
21 	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 
33 	if (size < sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA)) {
34 		return NULL;
35 	}
36 
37 	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();
40 
41 	//Version, revision and OEM ID, as defined in the VT-d architecture.
42 	UINT64 oem_id = 0;
43 	for (int i = 0; i < 6; i++) {
44 		oem_id |= (UINT64)vtd_error->OemId[i] << (i * 8);
45 	}
46 	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));
52 
53 	//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));
65 
66 	//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));
95 
96 	//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);
102 
103 	//Root entry.
104 	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);
112 
113 	//Context entry.
114 	encoded_len = 0;
115 	encoded = base64_encode((UINT8 *)vtd_error->ContextEntry, 16,
116 				&encoded_len);
117 	if (encoded == NULL) {
118 		cper_print_log("Failed to allocate encode output buffer. \n");
119 	} else {
120 		json_object_object_add(section_ir, "contextEntry",
121 				       json_object_new_string_len(encoded,
122 								  encoded_len));
123 		free(encoded);
124 	}
125 
126 	//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));
139 
140 	return section_ir;
141 }
142 
143 //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)144 void ir_section_dmar_vtd_to_cper(json_object *section, FILE *out)
145 {
146 	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));
149 
150 	//OEM ID.
151 	UINT64 oem_id = json_object_get_uint64(
152 		json_object_object_get(section, "oemID"));
153 	for (int i = 0; i < 6; i++) {
154 		section_cper->OemId[i] = (oem_id >> (i * 8)) & 0xFF;
155 	}
156 
157 	//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"));
172 
173 	//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"));
197 
198 	//Root entry.
199 	json_object *encoded = json_object_object_get(section, "rootEntry");
200 	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) {
206 		cper_print_log("Failed to allocate decode output buffer. \n");
207 	} else {
208 		memcpy(section_cper->RootEntry, decoded, decoded_len);
209 		free(decoded);
210 	}
211 
212 	//Context entry.
213 	encoded = json_object_object_get(section, "contextEntry");
214 	decoded_len = 0;
215 
216 	decoded = base64_decode(json_object_get_string(encoded),
217 				json_object_get_string_len(encoded),
218 				&decoded_len);
219 	if (decoded == NULL) {
220 		cper_print_log("Failed to allocate decode output buffer. \n");
221 
222 	} else {
223 		memcpy(section_cper->ContextEntry, decoded, decoded_len);
224 		free(decoded);
225 	}
226 
227 	//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);
245 }
246