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