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