xref: /openbmc/libcper/sections/cper-section-dmar-vtd.c (revision 50b966f7afa31fe39fda70e10eb9139cce39e025)
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>
10e42fb487SThu Nguyen #include <libcper/base64.h>
11e42fb487SThu Nguyen #include <libcper/Cper.h>
12e42fb487SThu Nguyen #include <libcper/cper-utils.h>
13e42fb487SThu Nguyen #include <libcper/sections/cper-section-dmar-vtd.h>
14*50b966f7SEd Tanous #include <libcper/log.h>
15db1b7ce2SLawrence Tang 
cper_section_dmar_vtd_to_ir(void * section)16db1b7ce2SLawrence Tang //Converts a single VT-d specific DMAr CPER section into JSON IR.
1712dbd4fdSEd Tanous json_object *cper_section_dmar_vtd_to_ir(const UINT8 *section, UINT32 size)
18db1b7ce2SLawrence Tang {
1912dbd4fdSEd Tanous 	if (size < sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA)) {
2012dbd4fdSEd Tanous 		return NULL;
2112dbd4fdSEd Tanous 	}
2212dbd4fdSEd Tanous 
23e407b4c8SLawrence Tang 	EFI_DIRECTED_IO_DMAR_ERROR_DATA *vtd_error =
24e407b4c8SLawrence Tang 		(EFI_DIRECTED_IO_DMAR_ERROR_DATA *)section;
25db1b7ce2SLawrence Tang 	json_object *section_ir = json_object_new_object();
26db1b7ce2SLawrence Tang 
27db1b7ce2SLawrence Tang 	//Version, revision and OEM ID, as defined in the VT-d architecture.
280a4b3f2dSLawrence Tang 	UINT64 oem_id = 0;
29f8fc7052SJohn Chung 	for (int i = 0; i < 6; i++) {
300a4b3f2dSLawrence Tang 		oem_id |= (UINT64)vtd_error->OemId[i] << (i * 8);
31f8fc7052SJohn Chung 	}
32e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "version",
33e407b4c8SLawrence Tang 			       json_object_new_int(vtd_error->Version));
34e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "revision",
35e407b4c8SLawrence Tang 			       json_object_new_int(vtd_error->Revision));
36e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "oemID",
37e407b4c8SLawrence Tang 			       json_object_new_uint64(oem_id));
38db1b7ce2SLawrence Tang 
39db1b7ce2SLawrence Tang 	//Registers.
40e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "capabilityRegister",
41e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->Capability));
42e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "extendedCapabilityRegister",
43e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->CapabilityEx));
44e407b4c8SLawrence Tang 	json_object_object_add(
45e407b4c8SLawrence Tang 		section_ir, "globalCommandRegister",
46e407b4c8SLawrence Tang 		json_object_new_uint64(vtd_error->GlobalCommand));
47e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "globalStatusRegister",
48e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->GlobalStatus));
49e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "faultStatusRegister",
50e407b4c8SLawrence Tang 			       json_object_new_uint64(vtd_error->FaultStatus));
51db1b7ce2SLawrence Tang 
52ce0f82bfSLawrence Tang 	//Fault record basic fields.
53ce0f82bfSLawrence Tang 	json_object *fault_record_ir = json_object_new_object();
54e407b4c8SLawrence Tang 	EFI_VTD_FAULT_RECORD *fault_record =
55e407b4c8SLawrence Tang 		(EFI_VTD_FAULT_RECORD *)vtd_error->FaultRecord;
56e407b4c8SLawrence Tang 	json_object_object_add(
57e407b4c8SLawrence Tang 		fault_record_ir, "faultInformation",
58e407b4c8SLawrence Tang 		json_object_new_uint64(fault_record->FaultInformation));
59e407b4c8SLawrence Tang 	json_object_object_add(
60e407b4c8SLawrence Tang 		fault_record_ir, "sourceIdentifier",
61e407b4c8SLawrence Tang 		json_object_new_uint64(fault_record->SourceIdentifier));
62e407b4c8SLawrence Tang 	json_object_object_add(
63e407b4c8SLawrence Tang 		fault_record_ir, "privelegeModeRequested",
64ce0f82bfSLawrence Tang 		json_object_new_boolean(fault_record->PrivelegeModeRequested));
65e407b4c8SLawrence Tang 	json_object_object_add(
66e407b4c8SLawrence Tang 		fault_record_ir, "executePermissionRequested",
67e407b4c8SLawrence Tang 		json_object_new_boolean(
68e407b4c8SLawrence Tang 			fault_record->ExecutePermissionRequested));
69e407b4c8SLawrence Tang 	json_object_object_add(
70e407b4c8SLawrence Tang 		fault_record_ir, "pasidPresent",
71e407b4c8SLawrence Tang 		json_object_new_boolean(fault_record->PasidPresent));
72e407b4c8SLawrence Tang 	json_object_object_add(
73e407b4c8SLawrence Tang 		fault_record_ir, "faultReason",
74e407b4c8SLawrence Tang 		json_object_new_uint64(fault_record->FaultReason));
75e407b4c8SLawrence Tang 	json_object_object_add(
76e407b4c8SLawrence Tang 		fault_record_ir, "pasidValue",
77e407b4c8SLawrence Tang 		json_object_new_uint64(fault_record->PasidValue));
78e407b4c8SLawrence Tang 	json_object_object_add(
79e407b4c8SLawrence Tang 		fault_record_ir, "addressType",
80e407b4c8SLawrence Tang 		json_object_new_uint64(fault_record->AddressType));
81ce0f82bfSLawrence Tang 
82205dd1d7SLawrence Tang 	//Fault record type.
83e407b4c8SLawrence Tang 	json_object *fault_record_type = integer_to_readable_pair(
84e407b4c8SLawrence Tang 		fault_record->Type, 2, VTD_FAULT_RECORD_TYPES_KEYS,
85e407b4c8SLawrence Tang 		VTD_FAULT_RECORD_TYPES_VALUES, "Unknown");
86ce0f82bfSLawrence Tang 	json_object_object_add(fault_record_ir, "type", fault_record_type);
87ce0f82bfSLawrence Tang 	json_object_object_add(section_ir, "faultRecord", fault_record_ir);
88ce0f82bfSLawrence Tang 
89ce0f82bfSLawrence Tang 	//Root entry.
90a7d2cdddSEd Tanous 	int32_t encoded_len = 0;
91a7d2cdddSEd Tanous 
92a7d2cdddSEd Tanous 	char *encoded =
93a7d2cdddSEd Tanous 		base64_encode((UINT8 *)vtd_error->RootEntry, 16, &encoded_len);
94e407b4c8SLawrence Tang 	json_object_object_add(section_ir, "rootEntry",
95f8fc7052SJohn Chung 			       json_object_new_string_len(encoded,
96f8fc7052SJohn Chung 							  encoded_len));
97ce0f82bfSLawrence Tang 	free(encoded);
98ce0f82bfSLawrence Tang 
99ce0f82bfSLawrence Tang 	//Context entry.
100f8fc7052SJohn Chung 	encoded_len = 0;
101a7d2cdddSEd Tanous 	encoded = base64_encode((UINT8 *)vtd_error->ContextEntry, 16,
102a7d2cdddSEd Tanous 				&encoded_len);
103a7d2cdddSEd Tanous 	if (encoded == NULL) {
104*50b966f7SEd Tanous 		cper_print_log("Failed to allocate encode output buffer. \n");
105f8fc7052SJohn Chung 	} else {
106e407b4c8SLawrence Tang 		json_object_object_add(section_ir, "contextEntry",
107f8fc7052SJohn Chung 				       json_object_new_string_len(encoded,
108f8fc7052SJohn Chung 								  encoded_len));
109ce0f82bfSLawrence Tang 		free(encoded);
110f8fc7052SJohn 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"));
139f8fc7052SJohn Chung 	for (int i = 0; i < 6; i++) {
1400a4b3f2dSLawrence Tang 		section_cper->OemId[i] = (oem_id >> (i * 8)) & 0xFF;
141f8fc7052SJohn 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");
186a7d2cdddSEd Tanous 	int32_t decoded_len = 0;
187a7d2cdddSEd Tanous 
188a7d2cdddSEd Tanous 	UINT8 *decoded = base64_decode(json_object_get_string(encoded),
189a7d2cdddSEd Tanous 				       json_object_get_string_len(encoded),
190a7d2cdddSEd Tanous 				       &decoded_len);
191a7d2cdddSEd Tanous 	if (decoded == NULL) {
192*50b966f7SEd Tanous 		cper_print_log("Failed to allocate decode output buffer. \n");
193f8fc7052SJohn Chung 	} else {
194f8fc7052SJohn Chung 		memcpy(section_cper->RootEntry, decoded, decoded_len);
195205dd1d7SLawrence Tang 		free(decoded);
196f8fc7052SJohn Chung 	}
197a7d2cdddSEd Tanous 
198205dd1d7SLawrence Tang 	//Context entry.
199205dd1d7SLawrence Tang 	encoded = json_object_object_get(section, "contextEntry");
200f8fc7052SJohn Chung 	decoded_len = 0;
201a7d2cdddSEd Tanous 
202a7d2cdddSEd Tanous 	decoded = base64_decode(json_object_get_string(encoded),
203a7d2cdddSEd Tanous 				json_object_get_string_len(encoded),
204a7d2cdddSEd Tanous 				&decoded_len);
205a7d2cdddSEd Tanous 	if (decoded == NULL) {
206*50b966f7SEd Tanous 		cper_print_log("Failed to allocate decode output buffer. \n");
207a7d2cdddSEd Tanous 
208f8fc7052SJohn Chung 	} else {
209f8fc7052SJohn Chung 		memcpy(section_cper->ContextEntry, decoded, decoded_len);
210205dd1d7SLawrence Tang 		free(decoded);
211f8fc7052SJohn Chung 	}
212205dd1d7SLawrence Tang 
213205dd1d7SLawrence Tang 	//Page table entries.
214e407b4c8SLawrence Tang 	section_cper->PteL1 = json_object_get_uint64(
215e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level1"));
216e407b4c8SLawrence Tang 	section_cper->PteL2 = json_object_get_uint64(
217e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level2"));
218e407b4c8SLawrence Tang 	section_cper->PteL3 = json_object_get_uint64(
219e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level3"));
220e407b4c8SLawrence Tang 	section_cper->PteL4 = json_object_get_uint64(
221e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level4"));
222e407b4c8SLawrence Tang 	section_cper->PteL5 = json_object_get_uint64(
223e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level5"));
224e407b4c8SLawrence Tang 	section_cper->PteL6 = json_object_get_uint64(
225e407b4c8SLawrence Tang 		json_object_object_get(section, "pageTableEntry_Level6"));
226205dd1d7SLawrence Tang 
227205dd1d7SLawrence Tang 	//Write to stream, free resources.
2283ab351feSLawrence Tang 	fwrite(section_cper, sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA), 1, out);
229205dd1d7SLawrence Tang 	fflush(out);
230205dd1d7SLawrence Tang 	free(section_cper);
231205dd1d7SLawrence Tang }
232