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*a7d2cdddSEd Tanous #include "base64.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.
cper_section_dmar_vtd_to_ir(void * section)16f8fc7052SJohn 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;
24f8fc7052SJohn Chung 	for (int i = 0; i < 6; i++) {
250a4b3f2dSLawrence Tang 		oem_id |= (UINT64)vtd_error->OemId[i] << (i * 8);
26f8fc7052SJohn 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*a7d2cdddSEd Tanous 	int32_t encoded_len = 0;
86*a7d2cdddSEd Tanous 
87*a7d2cdddSEd Tanous 	char *encoded =
88*a7d2cdddSEd Tanous 		base64_encode((UINT8 *)vtd_error->RootEntry, 16, &encoded_len);
89e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "rootEntry",
90f8fc7052SJohn Chung 			       json_object_new_string_len(encoded,
91f8fc7052SJohn Chung 							  encoded_len));
92ce0f82bfSLawrence Tang 	free(encoded);
93ce0f82bfSLawrence Tang 
94ce0f82bfSLawrence Tang 	//Context entry.
95f8fc7052SJohn Chung 	encoded_len = 0;
96*a7d2cdddSEd Tanous 	encoded = base64_encode((UINT8 *)vtd_error->ContextEntry, 16,
97*a7d2cdddSEd Tanous 				&encoded_len);
98*a7d2cdddSEd Tanous 	if (encoded == NULL) {
99f8fc7052SJohn Chung 		printf("Failed to allocate encode output buffer. \n");
100f8fc7052SJohn Chung 	} else {
101e407b4c8SLawrence Tang 		json_object_object_add(section_ir, "contextEntry",
102f8fc7052SJohn Chung 				       json_object_new_string_len(encoded,
103f8fc7052SJohn Chung 								  encoded_len));
104ce0f82bfSLawrence Tang 		free(encoded);
105f8fc7052SJohn Chung 	}
106db1b7ce2SLawrence Tang 
107db1b7ce2SLawrence Tang 	//PTE entry for all page levels.
108e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level6",
109e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->PteL6));
110e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level5",
111e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->PteL5));
112e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level4",
113e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->PteL4));
114e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level3",
115e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->PteL3));
116e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level2",
117e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->PteL2));
118e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "pageTableEntry_Level1",
119e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->PteL1));
120db1b7ce2SLawrence Tang 
121db1b7ce2SLawrence Tang 	return section_ir;
122db1b7ce2SLawrence Tang }
123205dd1d7SLawrence Tang 
124205dd1d7SLawrence Tang //Converts a single VT-d DMAR CPER-JSON segment into CPER binary, outputting to the given stream.
ir_section_dmar_vtd_to_cper(json_object * section,FILE * out)125205dd1d7SLawrence Tang void ir_section_dmar_vtd_to_cper(json_object *section, FILE *out)
126205dd1d7SLawrence Tang {
127205dd1d7SLawrence Tang 	EFI_DIRECTED_IO_DMAR_ERROR_DATA *section_cper =
128e407b4c8SLawrence Tang 		(EFI_DIRECTED_IO_DMAR_ERROR_DATA *)calloc(
129e407b4c8SLawrence Tang 			1, sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA));
130205dd1d7SLawrence Tang 
131205dd1d7SLawrence Tang 	//OEM ID.
132e407b4c8SLawrence Tang 	UINT64 oem_id = json_object_get_uint64(
133e407b4c8SLawrence Tang 		json_object_object_get(section, "oemID"));
134f8fc7052SJohn Chung 	for (int i = 0; i < 6; i++) {
1350a4b3f2dSLawrence Tang 		section_cper->OemId[i] = (oem_id >> (i * 8)) & 0xFF;
136f8fc7052SJohn Chung 	}
137205dd1d7SLawrence Tang 
138205dd1d7SLawrence Tang 	//Registers & basic numeric fields.
139e407b4c8SLawrence Tang 	section_cper->Version = (UINT8)json_object_get_int(
140e407b4c8SLawrence Tang 		json_object_object_get(section, "version"));
141e407b4c8SLawrence Tang 	section_cper->Revision = (UINT8)json_object_get_int(
142e407b4c8SLawrence Tang 		json_object_object_get(section, "revision"));
143e407b4c8SLawrence Tang 	section_cper->Capability = json_object_get_uint64(
144e407b4c8SLawrence Tang 		json_object_object_get(section, "capabilityRegister"));
145e407b4c8SLawrence Tang 	section_cper->CapabilityEx = json_object_get_uint64(
146e407b4c8SLawrence Tang 		json_object_object_get(section, "extendedCapabilityRegister"));
147e407b4c8SLawrence Tang 	section_cper->GlobalCommand = json_object_get_uint64(
148e407b4c8SLawrence Tang 		json_object_object_get(section, "globalCommandRegister"));
149e407b4c8SLawrence Tang 	section_cper->GlobalStatus = json_object_get_uint64(
150e407b4c8SLawrence Tang 		json_object_object_get(section, "globalStatusRegister"));
151e407b4c8SLawrence Tang 	section_cper->FaultStatus = json_object_get_uint64(
152e407b4c8SLawrence Tang 		json_object_object_get(section, "faultStatusRegister"));
153205dd1d7SLawrence Tang 
154205dd1d7SLawrence Tang 	//Fault record.
155e407b4c8SLawrence Tang 	json_object *fault_record =
156e407b4c8SLawrence Tang 		json_object_object_get(section, "faultRecord");
157e407b4c8SLawrence Tang 	EFI_VTD_FAULT_RECORD *fault_record_cper =
158e407b4c8SLawrence Tang 		(EFI_VTD_FAULT_RECORD *)section_cper->FaultRecord;
159e407b4c8SLawrence Tang 	fault_record_cper->FaultInformation = json_object_get_uint64(
160e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "faultInformation"));
161e407b4c8SLawrence Tang 	fault_record_cper->SourceIdentifier = json_object_get_uint64(
162e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "sourceIdentifier"));
163e407b4c8SLawrence Tang 	fault_record_cper->PrivelegeModeRequested = json_object_get_boolean(
164e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "privelegeModeRequested"));
165e407b4c8SLawrence Tang 	fault_record_cper->ExecutePermissionRequested = json_object_get_boolean(
166e407b4c8SLawrence Tang 		json_object_object_get(fault_record,
167e407b4c8SLawrence Tang 				       "executePermissionRequested"));
168e407b4c8SLawrence Tang 	fault_record_cper->PasidPresent = json_object_get_boolean(
169e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "pasidPresent"));
170e407b4c8SLawrence Tang 	fault_record_cper->FaultReason = json_object_get_uint64(
171e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "faultReason"));
172e407b4c8SLawrence Tang 	fault_record_cper->PasidValue = json_object_get_uint64(
173e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "pasidValue"));
174e407b4c8SLawrence Tang 	fault_record_cper->AddressType = json_object_get_uint64(
175e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "addressType"));
176e407b4c8SLawrence Tang 	fault_record_cper->Type = readable_pair_to_integer(
177e407b4c8SLawrence Tang 		json_object_object_get(fault_record, "type"));
178205dd1d7SLawrence Tang 
179205dd1d7SLawrence Tang 	//Root entry.
180205dd1d7SLawrence Tang 	json_object *encoded = json_object_object_get(section, "rootEntry");
181*a7d2cdddSEd Tanous 	int32_t decoded_len = 0;
182*a7d2cdddSEd Tanous 
183*a7d2cdddSEd Tanous 	UINT8 *decoded = base64_decode(json_object_get_string(encoded),
184*a7d2cdddSEd Tanous 				       json_object_get_string_len(encoded),
185*a7d2cdddSEd Tanous 				       &decoded_len);
186*a7d2cdddSEd Tanous 	if (decoded == NULL) {
187f8fc7052SJohn Chung 		printf("Failed to allocate decode output buffer. \n");
188f8fc7052SJohn Chung 	} else {
189f8fc7052SJohn Chung 		memcpy(section_cper->RootEntry, decoded, decoded_len);
190205dd1d7SLawrence Tang 		free(decoded);
191f8fc7052SJohn Chung 	}
192*a7d2cdddSEd Tanous 
193205dd1d7SLawrence Tang 	//Context entry.
194205dd1d7SLawrence Tang 	encoded = json_object_object_get(section, "contextEntry");
195f8fc7052SJohn Chung 	decoded_len = 0;
196*a7d2cdddSEd Tanous 
197*a7d2cdddSEd Tanous 	decoded = base64_decode(json_object_get_string(encoded),
198*a7d2cdddSEd Tanous 				json_object_get_string_len(encoded),
199*a7d2cdddSEd Tanous 				&decoded_len);
200*a7d2cdddSEd Tanous 	if (decoded == NULL) {
201f8fc7052SJohn Chung 		printf("Failed to allocate decode output buffer. \n");
202*a7d2cdddSEd Tanous 
203f8fc7052SJohn Chung 	} else {
204f8fc7052SJohn Chung 		memcpy(section_cper->ContextEntry, decoded, decoded_len);
205205dd1d7SLawrence Tang 		free(decoded);
206f8fc7052SJohn Chung 	}
207205dd1d7SLawrence Tang 
208205dd1d7SLawrence Tang 	//Page table entries.
209e407b4c8SLawrence Tang 	section_cper->PteL1 = json_object_get_uint64(
210e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level1"));
211e407b4c8SLawrence Tang 	section_cper->PteL2 = json_object_get_uint64(
212e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level2"));
213e407b4c8SLawrence Tang 	section_cper->PteL3 = json_object_get_uint64(
214e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level3"));
215e407b4c8SLawrence Tang 	section_cper->PteL4 = json_object_get_uint64(
216e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level4"));
217e407b4c8SLawrence Tang 	section_cper->PteL5 = json_object_get_uint64(
218e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level5"));
219e407b4c8SLawrence Tang 	section_cper->PteL6 = json_object_get_uint64(
220e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level6"));
221205dd1d7SLawrence Tang 
222205dd1d7SLawrence Tang 	//Write to stream, free resources.
2233ab351feSLawrence Tang 	fwrite(section_cper, sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA), 1, out);
224205dd1d7SLawrence Tang 	fflush(out);
225205dd1d7SLawrence Tang 	free(section_cper);
226205dd1d7SLawrence Tang }
227