1db1b7ce2SLawrence Tang /**
2db1b7ce2SLawrence Tang  * Describes functions for converting VT-d specific DMAr CPER sections from binary and JSON format
3db1b7ce2SLawrence Tang  * into an intermediate format.
4db1b7ce2SLawrence Tang  *
5db1b7ce2SLawrence Tang  * Author: Lawrence.Tang@arm.com
6db1b7ce2SLawrence Tang  **/
7db1b7ce2SLawrence Tang #include <stdio.h>
8205dd1d7SLawrence Tang #include <string.h>
9db1b7ce2SLawrence Tang #include "json.h"
10ce0f82bfSLawrence Tang #include "b64.h"
11db1b7ce2SLawrence Tang #include "../edk/Cper.h"
12db1b7ce2SLawrence Tang #include "../cper-utils.h"
13db1b7ce2SLawrence Tang #include "cper-section-dmar-vtd.h"
14db1b7ce2SLawrence Tang 
15db1b7ce2SLawrence Tang //Converts a single VT-d specific DMAr CPER section into JSON IR.
16*e407b4c8SLawrence Tang json_object *
17*e407b4c8SLawrence Tang cper_section_dmar_vtd_to_ir(void *section,
18*e407b4c8SLawrence Tang 			    EFI_ERROR_SECTION_DESCRIPTOR *descriptor)
19db1b7ce2SLawrence Tang {
20*e407b4c8SLawrence Tang 	EFI_DIRECTED_IO_DMAR_ERROR_DATA *vtd_error =
21*e407b4c8SLawrence Tang 		(EFI_DIRECTED_IO_DMAR_ERROR_DATA *)section;
22db1b7ce2SLawrence Tang 	json_object *section_ir = json_object_new_object();
23db1b7ce2SLawrence Tang 
24db1b7ce2SLawrence Tang 	//Version, revision and OEM ID, as defined in the VT-d architecture.
250a4b3f2dSLawrence Tang 	UINT64 oem_id = 0;
260a4b3f2dSLawrence Tang 	for (int i = 0; i < 6; i++)
270a4b3f2dSLawrence Tang 		oem_id |= (UINT64)vtd_error->OemId[i] << (i * 8);
28*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "version",
29*e407b4c8SLawrence Tang 			       json_object_new_int(vtd_error->Version));
30*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "revision",
31*e407b4c8SLawrence Tang 			       json_object_new_int(vtd_error->Revision));
32*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "oemID",
33*e407b4c8SLawrence Tang 			       json_object_new_uint64(oem_id));
34db1b7ce2SLawrence Tang 
35db1b7ce2SLawrence Tang 	//Registers.
36*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "capabilityRegister",
37*e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->Capability));
38*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "extendedCapabilityRegister",
39*e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->CapabilityEx));
40*e407b4c8SLawrence Tang 	json_object_object_add(
41*e407b4c8SLawrence Tang 		section_ir, "globalCommandRegister",
42*e407b4c8SLawrence Tang 		json_object_new_uint64(vtd_error->GlobalCommand));
43*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "globalStatusRegister",
44*e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->GlobalStatus));
45*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "faultStatusRegister",
46*e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->FaultStatus));
47db1b7ce2SLawrence Tang 
48ce0f82bfSLawrence Tang 	//Fault record basic fields.
49ce0f82bfSLawrence Tang 	json_object *fault_record_ir = json_object_new_object();
50*e407b4c8SLawrence Tang 	EFI_VTD_FAULT_RECORD *fault_record =
51*e407b4c8SLawrence Tang 		(EFI_VTD_FAULT_RECORD *)vtd_error->FaultRecord;
52*e407b4c8SLawrence Tang 	json_object_object_add(
53*e407b4c8SLawrence Tang 		fault_record_ir, "faultInformation",
54*e407b4c8SLawrence Tang 		json_object_new_uint64(fault_record->FaultInformation));
55*e407b4c8SLawrence Tang 	json_object_object_add(
56*e407b4c8SLawrence Tang 		fault_record_ir, "sourceIdentifier",
57*e407b4c8SLawrence Tang 		json_object_new_uint64(fault_record->SourceIdentifier));
58*e407b4c8SLawrence Tang 	json_object_object_add(
59*e407b4c8SLawrence Tang 		fault_record_ir, "privelegeModeRequested",
60ce0f82bfSLawrence Tang 		json_object_new_boolean(fault_record->PrivelegeModeRequested));
61*e407b4c8SLawrence Tang 	json_object_object_add(
62*e407b4c8SLawrence Tang 		fault_record_ir, "executePermissionRequested",
63*e407b4c8SLawrence Tang 		json_object_new_boolean(
64*e407b4c8SLawrence Tang 			fault_record->ExecutePermissionRequested));
65*e407b4c8SLawrence Tang 	json_object_object_add(
66*e407b4c8SLawrence Tang 		fault_record_ir, "pasidPresent",
67*e407b4c8SLawrence Tang 		json_object_new_boolean(fault_record->PasidPresent));
68*e407b4c8SLawrence Tang 	json_object_object_add(
69*e407b4c8SLawrence Tang 		fault_record_ir, "faultReason",
70*e407b4c8SLawrence Tang 		json_object_new_uint64(fault_record->FaultReason));
71*e407b4c8SLawrence Tang 	json_object_object_add(
72*e407b4c8SLawrence Tang 		fault_record_ir, "pasidValue",
73*e407b4c8SLawrence Tang 		json_object_new_uint64(fault_record->PasidValue));
74*e407b4c8SLawrence Tang 	json_object_object_add(
75*e407b4c8SLawrence Tang 		fault_record_ir, "addressType",
76*e407b4c8SLawrence Tang 		json_object_new_uint64(fault_record->AddressType));
77ce0f82bfSLawrence Tang 
78205dd1d7SLawrence Tang 	//Fault record type.
79*e407b4c8SLawrence Tang 	json_object *fault_record_type = integer_to_readable_pair(
80*e407b4c8SLawrence Tang 		fault_record->Type, 2, VTD_FAULT_RECORD_TYPES_KEYS,
81*e407b4c8SLawrence Tang 		VTD_FAULT_RECORD_TYPES_VALUES, "Unknown");
82ce0f82bfSLawrence Tang 	json_object_object_add(fault_record_ir, "type", fault_record_type);
83ce0f82bfSLawrence Tang 	json_object_object_add(section_ir, "faultRecord", fault_record_ir);
84ce0f82bfSLawrence Tang 
85ce0f82bfSLawrence Tang 	//Root entry.
86ce0f82bfSLawrence Tang 	char *encoded = b64_encode((unsigned char *)vtd_error->RootEntry, 16);
87*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "rootEntry",
88*e407b4c8SLawrence Tang 			       json_object_new_string(encoded));
89ce0f82bfSLawrence Tang 	free(encoded);
90ce0f82bfSLawrence Tang 
91ce0f82bfSLawrence Tang 	//Context entry.
92ce0f82bfSLawrence Tang 	encoded = b64_encode((unsigned char *)vtd_error->ContextEntry, 16);
93*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "contextEntry",
94*e407b4c8SLawrence Tang 			       json_object_new_string(encoded));
95ce0f82bfSLawrence Tang 	free(encoded);
96db1b7ce2SLawrence Tang 
97db1b7ce2SLawrence Tang 	//PTE entry for all page levels.
98*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level6",
99*e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->PteL6));
100*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level5",
101*e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->PteL5));
102*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level4",
103*e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->PteL4));
104*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level3",
105*e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->PteL3));
106*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level2",
107*e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->PteL2));
108*e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level1",
109*e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->PteL1));
110db1b7ce2SLawrence Tang 
111db1b7ce2SLawrence Tang 	return section_ir;
112db1b7ce2SLawrence Tang }
113205dd1d7SLawrence Tang 
114205dd1d7SLawrence Tang //Converts a single VT-d DMAR CPER-JSON segment into CPER binary, outputting to the given stream.
115205dd1d7SLawrence Tang void ir_section_dmar_vtd_to_cper(json_object *section, FILE *out)
116205dd1d7SLawrence Tang {
117205dd1d7SLawrence Tang 	EFI_DIRECTED_IO_DMAR_ERROR_DATA *section_cper =
118*e407b4c8SLawrence Tang 		(EFI_DIRECTED_IO_DMAR_ERROR_DATA *)calloc(
119*e407b4c8SLawrence Tang 			1, sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA));
120205dd1d7SLawrence Tang 
121205dd1d7SLawrence Tang 	//OEM ID.
122*e407b4c8SLawrence Tang 	UINT64 oem_id = json_object_get_uint64(
123*e407b4c8SLawrence Tang 		json_object_object_get(section, "oemID"));
1240a4b3f2dSLawrence Tang 	for (int i = 0; i < 6; i++)
1250a4b3f2dSLawrence Tang 		section_cper->OemId[i] = (oem_id >> (i * 8)) & 0xFF;
126205dd1d7SLawrence Tang 
127205dd1d7SLawrence Tang 	//Registers & basic numeric fields.
128*e407b4c8SLawrence Tang 	section_cper->Version = (UINT8)json_object_get_int(
129*e407b4c8SLawrence Tang 		json_object_object_get(section, "version"));
130*e407b4c8SLawrence Tang 	section_cper->Revision = (UINT8)json_object_get_int(
131*e407b4c8SLawrence Tang 		json_object_object_get(section, "revision"));
132*e407b4c8SLawrence Tang 	section_cper->Capability = json_object_get_uint64(
133*e407b4c8SLawrence Tang 		json_object_object_get(section, "capabilityRegister"));
134*e407b4c8SLawrence Tang 	section_cper->CapabilityEx = json_object_get_uint64(
135*e407b4c8SLawrence Tang 		json_object_object_get(section, "extendedCapabilityRegister"));
136*e407b4c8SLawrence Tang 	section_cper->GlobalCommand = json_object_get_uint64(
137*e407b4c8SLawrence Tang 		json_object_object_get(section, "globalCommandRegister"));
138*e407b4c8SLawrence Tang 	section_cper->GlobalStatus = json_object_get_uint64(
139*e407b4c8SLawrence Tang 		json_object_object_get(section, "globalStatusRegister"));
140*e407b4c8SLawrence Tang 	section_cper->FaultStatus = json_object_get_uint64(
141*e407b4c8SLawrence Tang 		json_object_object_get(section, "faultStatusRegister"));
142205dd1d7SLawrence Tang 
143205dd1d7SLawrence Tang 	//Fault record.
144*e407b4c8SLawrence Tang 	json_object *fault_record =
145*e407b4c8SLawrence Tang 		json_object_object_get(section, "faultRecord");
146*e407b4c8SLawrence Tang 	EFI_VTD_FAULT_RECORD *fault_record_cper =
147*e407b4c8SLawrence Tang 		(EFI_VTD_FAULT_RECORD *)section_cper->FaultRecord;
148*e407b4c8SLawrence Tang 	fault_record_cper->FaultInformation = json_object_get_uint64(
149*e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "faultInformation"));
150*e407b4c8SLawrence Tang 	fault_record_cper->SourceIdentifier = json_object_get_uint64(
151*e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "sourceIdentifier"));
152*e407b4c8SLawrence Tang 	fault_record_cper->PrivelegeModeRequested = json_object_get_boolean(
153*e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "privelegeModeRequested"));
154*e407b4c8SLawrence Tang 	fault_record_cper->ExecutePermissionRequested = json_object_get_boolean(
155*e407b4c8SLawrence Tang 		json_object_object_get(fault_record,
156*e407b4c8SLawrence Tang 				       "executePermissionRequested"));
157*e407b4c8SLawrence Tang 	fault_record_cper->PasidPresent = json_object_get_boolean(
158*e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "pasidPresent"));
159*e407b4c8SLawrence Tang 	fault_record_cper->FaultReason = json_object_get_uint64(
160*e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "faultReason"));
161*e407b4c8SLawrence Tang 	fault_record_cper->PasidValue = json_object_get_uint64(
162*e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "pasidValue"));
163*e407b4c8SLawrence Tang 	fault_record_cper->AddressType = json_object_get_uint64(
164*e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "addressType"));
165*e407b4c8SLawrence Tang 	fault_record_cper->Type = readable_pair_to_integer(
166*e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "type"));
167205dd1d7SLawrence Tang 
168205dd1d7SLawrence Tang 	//Root entry.
169205dd1d7SLawrence Tang 	json_object *encoded = json_object_object_get(section, "rootEntry");
170*e407b4c8SLawrence Tang 	UINT8 *decoded = b64_decode(json_object_get_string(encoded),
171*e407b4c8SLawrence Tang 				    json_object_get_string_len(encoded));
172205dd1d7SLawrence Tang 	memcpy(section_cper->RootEntry, decoded, 16);
173205dd1d7SLawrence Tang 	free(decoded);
174205dd1d7SLawrence Tang 
175205dd1d7SLawrence Tang 	//Context entry.
176205dd1d7SLawrence Tang 	encoded = json_object_object_get(section, "contextEntry");
177*e407b4c8SLawrence Tang 	decoded = b64_decode(json_object_get_string(encoded),
178*e407b4c8SLawrence Tang 			     json_object_get_string_len(encoded));
179205dd1d7SLawrence Tang 	memcpy(section_cper->ContextEntry, decoded, 16);
180205dd1d7SLawrence Tang 	free(decoded);
181205dd1d7SLawrence Tang 
182205dd1d7SLawrence Tang 	//Page table entries.
183*e407b4c8SLawrence Tang 	section_cper->PteL1 = json_object_get_uint64(
184*e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level1"));
185*e407b4c8SLawrence Tang 	section_cper->PteL2 = json_object_get_uint64(
186*e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level2"));
187*e407b4c8SLawrence Tang 	section_cper->PteL3 = json_object_get_uint64(
188*e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level3"));
189*e407b4c8SLawrence Tang 	section_cper->PteL4 = json_object_get_uint64(
190*e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level4"));
191*e407b4c8SLawrence Tang 	section_cper->PteL5 = json_object_get_uint64(
192*e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level5"));
193*e407b4c8SLawrence Tang 	section_cper->PteL6 = json_object_get_uint64(
194*e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level6"));
195205dd1d7SLawrence Tang 
196205dd1d7SLawrence Tang 	//Write to stream, free resources.
1973ab351feSLawrence Tang 	fwrite(section_cper, sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA), 1, out);
198205dd1d7SLawrence Tang 	fflush(out);
199205dd1d7SLawrence Tang 	free(section_cper);
200205dd1d7SLawrence Tang }