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>
9*5202bbb4SLawrence 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.
16e407b4c8SLawrence Tang json_object *
17e407b4c8SLawrence Tang cper_section_dmar_vtd_to_ir(void *section,
18e407b4c8SLawrence Tang 			    EFI_ERROR_SECTION_DESCRIPTOR *descriptor)
19db1b7ce2SLawrence Tang {
20e407b4c8SLawrence Tang 	EFI_DIRECTED_IO_DMAR_ERROR_DATA *vtd_error =
21e407b4c8SLawrence 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);
28e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "version",
29e407b4c8SLawrence Tang 			       json_object_new_int(vtd_error->Version));
30e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "revision",
31e407b4c8SLawrence Tang 			       json_object_new_int(vtd_error->Revision));
32e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "oemID",
33e407b4c8SLawrence Tang 			       json_object_new_uint64(oem_id));
34db1b7ce2SLawrence Tang 
35db1b7ce2SLawrence Tang 	//Registers.
36e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "capabilityRegister",
37e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->Capability));
38e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "extendedCapabilityRegister",
39e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->CapabilityEx));
40e407b4c8SLawrence Tang 	json_object_object_add(
41e407b4c8SLawrence Tang 		section_ir, "globalCommandRegister",
42e407b4c8SLawrence Tang 		json_object_new_uint64(vtd_error->GlobalCommand));
43e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "globalStatusRegister",
44e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->GlobalStatus));
45e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "faultStatusRegister",
46e407b4c8SLawrence 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();
50e407b4c8SLawrence Tang 	EFI_VTD_FAULT_RECORD *fault_record =
51e407b4c8SLawrence Tang 		(EFI_VTD_FAULT_RECORD *)vtd_error->FaultRecord;
52e407b4c8SLawrence Tang 	json_object_object_add(
53e407b4c8SLawrence Tang 		fault_record_ir, "faultInformation",
54e407b4c8SLawrence Tang 		json_object_new_uint64(fault_record->FaultInformation));
55e407b4c8SLawrence Tang 	json_object_object_add(
56e407b4c8SLawrence Tang 		fault_record_ir, "sourceIdentifier",
57e407b4c8SLawrence Tang 		json_object_new_uint64(fault_record->SourceIdentifier));
58e407b4c8SLawrence Tang 	json_object_object_add(
59e407b4c8SLawrence Tang 		fault_record_ir, "privelegeModeRequested",
60ce0f82bfSLawrence Tang 		json_object_new_boolean(fault_record->PrivelegeModeRequested));
61e407b4c8SLawrence Tang 	json_object_object_add(
62e407b4c8SLawrence Tang 		fault_record_ir, "executePermissionRequested",
63e407b4c8SLawrence Tang 		json_object_new_boolean(
64e407b4c8SLawrence Tang 			fault_record->ExecutePermissionRequested));
65e407b4c8SLawrence Tang 	json_object_object_add(
66e407b4c8SLawrence Tang 		fault_record_ir, "pasidPresent",
67e407b4c8SLawrence Tang 		json_object_new_boolean(fault_record->PasidPresent));
68e407b4c8SLawrence Tang 	json_object_object_add(
69e407b4c8SLawrence Tang 		fault_record_ir, "faultReason",
70e407b4c8SLawrence Tang 		json_object_new_uint64(fault_record->FaultReason));
71e407b4c8SLawrence Tang 	json_object_object_add(
72e407b4c8SLawrence Tang 		fault_record_ir, "pasidValue",
73e407b4c8SLawrence Tang 		json_object_new_uint64(fault_record->PasidValue));
74e407b4c8SLawrence Tang 	json_object_object_add(
75e407b4c8SLawrence Tang 		fault_record_ir, "addressType",
76e407b4c8SLawrence Tang 		json_object_new_uint64(fault_record->AddressType));
77ce0f82bfSLawrence Tang 
78205dd1d7SLawrence Tang 	//Fault record type.
79e407b4c8SLawrence Tang 	json_object *fault_record_type = integer_to_readable_pair(
80e407b4c8SLawrence Tang 		fault_record->Type, 2, VTD_FAULT_RECORD_TYPES_KEYS,
81e407b4c8SLawrence 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);
87e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "rootEntry",
88e407b4c8SLawrence 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);
93e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "contextEntry",
94e407b4c8SLawrence Tang 			       json_object_new_string(encoded));
95ce0f82bfSLawrence Tang 	free(encoded);
96db1b7ce2SLawrence Tang 
97db1b7ce2SLawrence Tang 	//PTE entry for all page levels.
98e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level6",
99e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->PteL6));
100e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level5",
101e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->PteL5));
102e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level4",
103e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->PteL4));
104e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level3",
105e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->PteL3));
106e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level2",
107e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->PteL2));
108e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level1",
109e407b4c8SLawrence 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 =
118e407b4c8SLawrence Tang 		(EFI_DIRECTED_IO_DMAR_ERROR_DATA *)calloc(
119e407b4c8SLawrence Tang 			1, sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA));
120205dd1d7SLawrence Tang 
121205dd1d7SLawrence Tang 	//OEM ID.
122e407b4c8SLawrence Tang 	UINT64 oem_id = json_object_get_uint64(
123e407b4c8SLawrence 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.
128e407b4c8SLawrence Tang 	section_cper->Version = (UINT8)json_object_get_int(
129e407b4c8SLawrence Tang 		json_object_object_get(section, "version"));
130e407b4c8SLawrence Tang 	section_cper->Revision = (UINT8)json_object_get_int(
131e407b4c8SLawrence Tang 		json_object_object_get(section, "revision"));
132e407b4c8SLawrence Tang 	section_cper->Capability = json_object_get_uint64(
133e407b4c8SLawrence Tang 		json_object_object_get(section, "capabilityRegister"));
134e407b4c8SLawrence Tang 	section_cper->CapabilityEx = json_object_get_uint64(
135e407b4c8SLawrence Tang 		json_object_object_get(section, "extendedCapabilityRegister"));
136e407b4c8SLawrence Tang 	section_cper->GlobalCommand = json_object_get_uint64(
137e407b4c8SLawrence Tang 		json_object_object_get(section, "globalCommandRegister"));
138e407b4c8SLawrence Tang 	section_cper->GlobalStatus = json_object_get_uint64(
139e407b4c8SLawrence Tang 		json_object_object_get(section, "globalStatusRegister"));
140e407b4c8SLawrence Tang 	section_cper->FaultStatus = json_object_get_uint64(
141e407b4c8SLawrence Tang 		json_object_object_get(section, "faultStatusRegister"));
142205dd1d7SLawrence Tang 
143205dd1d7SLawrence Tang 	//Fault record.
144e407b4c8SLawrence Tang 	json_object *fault_record =
145e407b4c8SLawrence Tang 		json_object_object_get(section, "faultRecord");
146e407b4c8SLawrence Tang 	EFI_VTD_FAULT_RECORD *fault_record_cper =
147e407b4c8SLawrence Tang 		(EFI_VTD_FAULT_RECORD *)section_cper->FaultRecord;
148e407b4c8SLawrence Tang 	fault_record_cper->FaultInformation = json_object_get_uint64(
149e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "faultInformation"));
150e407b4c8SLawrence Tang 	fault_record_cper->SourceIdentifier = json_object_get_uint64(
151e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "sourceIdentifier"));
152e407b4c8SLawrence Tang 	fault_record_cper->PrivelegeModeRequested = json_object_get_boolean(
153e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "privelegeModeRequested"));
154e407b4c8SLawrence Tang 	fault_record_cper->ExecutePermissionRequested = json_object_get_boolean(
155e407b4c8SLawrence Tang 		json_object_object_get(fault_record,
156e407b4c8SLawrence Tang 				       "executePermissionRequested"));
157e407b4c8SLawrence Tang 	fault_record_cper->PasidPresent = json_object_get_boolean(
158e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "pasidPresent"));
159e407b4c8SLawrence Tang 	fault_record_cper->FaultReason = json_object_get_uint64(
160e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "faultReason"));
161e407b4c8SLawrence Tang 	fault_record_cper->PasidValue = json_object_get_uint64(
162e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "pasidValue"));
163e407b4c8SLawrence Tang 	fault_record_cper->AddressType = json_object_get_uint64(
164e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "addressType"));
165e407b4c8SLawrence Tang 	fault_record_cper->Type = readable_pair_to_integer(
166e407b4c8SLawrence 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");
170e407b4c8SLawrence Tang 	UINT8 *decoded = b64_decode(json_object_get_string(encoded),
171e407b4c8SLawrence 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");
177e407b4c8SLawrence Tang 	decoded = b64_decode(json_object_get_string(encoded),
178e407b4c8SLawrence 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.
183e407b4c8SLawrence Tang 	section_cper->PteL1 = json_object_get_uint64(
184e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level1"));
185e407b4c8SLawrence Tang 	section_cper->PteL2 = json_object_get_uint64(
186e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level2"));
187e407b4c8SLawrence Tang 	section_cper->PteL3 = json_object_get_uint64(
188e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level3"));
189e407b4c8SLawrence Tang 	section_cper->PteL4 = json_object_get_uint64(
190e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level4"));
191e407b4c8SLawrence Tang 	section_cper->PteL5 = json_object_get_uint64(
192e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level5"));
193e407b4c8SLawrence Tang 	section_cper->PteL6 = json_object_get_uint64(
194e407b4c8SLawrence 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 }