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