xref: /openbmc/libcper/sections/cper-section-dmar-vtd.c (revision 3f810e5b3c2b8eb217ebc47dd4b17b9ec5ccea24)
1 /**
2  * Describes functions for converting VT-d specific DMAr CPER sections from binary and JSON format
3  * into an intermediate format.
4  *
5  * Author: Lawrence.Tang@arm.com
6  **/
7 #include <stdio.h>
8 #include <string.h>
9 #include <json.h>
10 #include <libcper/base64.h>
11 #include <libcper/Cper.h>
12 #include <libcper/cper-utils.h>
13 #include <libcper/sections/cper-section-dmar-vtd.h>
14 #include <libcper/log.h>
15 #include <string.h>
16 
17 //Converts a single VT-d specific DMAr CPER section into JSON IR.
cper_section_dmar_vtd_to_ir(const UINT8 * section,UINT32 size,char ** desc_string)18 json_object *cper_section_dmar_vtd_to_ir(const UINT8 *section, UINT32 size,
19 					 char **desc_string)
20 {
21 	int outstr_len = 0;
22 	*desc_string = NULL;
23 	if (size < sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA)) {
24 		cper_print_log("Error: VT-d DMAr section too small\n");
25 		return NULL;
26 	}
27 
28 	*desc_string = calloc(1, SECTION_DESC_STRING_SIZE);
29 	if (*desc_string == NULL) {
30 		cper_print_log(
31 			"Error: Failed to allocate VT-d DMAr desc string\n");
32 		return NULL;
33 	}
34 	outstr_len = snprintf(*desc_string, SECTION_DESC_STRING_SIZE,
35 			      "A VT-d DMAr Error occurred");
36 	if (outstr_len < 0) {
37 		cper_print_log(
38 			"Error: Could not write to VT-d DMAr description string\n");
39 	} else if (outstr_len > SECTION_DESC_STRING_SIZE) {
40 		cper_print_log(
41 			"Error: VT-d DMAr description string truncated\n");
42 	}
43 
44 	EFI_DIRECTED_IO_DMAR_ERROR_DATA *vtd_error =
45 		(EFI_DIRECTED_IO_DMAR_ERROR_DATA *)section;
46 	json_object *section_ir = json_object_new_object();
47 
48 	//Version, revision and OEM ID, as defined in the VT-d architecture.
49 	UINT64 oem_id = 0;
50 	for (int i = 0; i < 6; i++) {
51 		oem_id |= (UINT64)vtd_error->OemId[i] << (i * 8);
52 	}
53 	add_int(section_ir, "version", vtd_error->Version);
54 	add_int(section_ir, "revision", vtd_error->Revision);
55 	add_uint(section_ir, "oemID", oem_id);
56 
57 	//Registers.
58 	add_uint(section_ir, "capabilityRegister", vtd_error->Capability);
59 	add_uint(section_ir, "extendedCapabilityRegister",
60 		 vtd_error->CapabilityEx);
61 	add_uint(section_ir, "globalCommandRegister", vtd_error->GlobalCommand);
62 	add_uint(section_ir, "globalStatusRegister", vtd_error->GlobalStatus);
63 	add_uint(section_ir, "faultStatusRegister", vtd_error->FaultStatus);
64 
65 	//Fault record basic fields.
66 	json_object *fault_record_ir = json_object_new_object();
67 	EFI_VTD_FAULT_RECORD *fault_record =
68 		(EFI_VTD_FAULT_RECORD *)vtd_error->FaultRecord;
69 	add_uint(fault_record_ir, "faultInformation",
70 		 fault_record->FaultInformation);
71 	add_uint(fault_record_ir, "sourceIdentifier",
72 		 fault_record->SourceIdentifier);
73 	add_bool(fault_record_ir, "privelegeModeRequested",
74 		 fault_record->PrivelegeModeRequested);
75 	add_bool(fault_record_ir, "executePermissionRequested",
76 		 fault_record->ExecutePermissionRequested);
77 	add_bool(fault_record_ir, "pasidPresent", fault_record->PasidPresent);
78 	add_uint(fault_record_ir, "faultReason", fault_record->FaultReason);
79 	add_uint(fault_record_ir, "pasidValue", fault_record->PasidValue);
80 	add_uint(fault_record_ir, "addressType", fault_record->AddressType);
81 
82 	//Fault record type.
83 	json_object *fault_record_type = integer_to_readable_pair(
84 		fault_record->Type, 2, VTD_FAULT_RECORD_TYPES_KEYS,
85 		VTD_FAULT_RECORD_TYPES_VALUES, "Unknown");
86 	json_object_object_add(fault_record_ir, "type", fault_record_type);
87 	json_object_object_add(section_ir, "faultRecord", fault_record_ir);
88 
89 	//Root entry.
90 	add_binary_base64(section_ir, "rootEntry",
91 			  (UINT8 *)vtd_error->RootEntry,
92 			  sizeof(vtd_error->RootEntry));
93 
94 	//Context entry.
95 	add_binary_base64(section_ir, "contextEntry",
96 			  (UINT8 *)vtd_error->ContextEntry,
97 			  sizeof(vtd_error->ContextEntry));
98 
99 	//PTE entry for all page levels.
100 	add_uint(section_ir, "pageTableEntry_Level6", vtd_error->PteL6);
101 	add_uint(section_ir, "pageTableEntry_Level5", vtd_error->PteL5);
102 	add_uint(section_ir, "pageTableEntry_Level4", vtd_error->PteL4);
103 	add_uint(section_ir, "pageTableEntry_Level3", vtd_error->PteL3);
104 	add_uint(section_ir, "pageTableEntry_Level2", vtd_error->PteL2);
105 	add_uint(section_ir, "pageTableEntry_Level1", vtd_error->PteL1);
106 
107 	return section_ir;
108 }
109 
110 //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)111 void ir_section_dmar_vtd_to_cper(json_object *section, FILE *out)
112 {
113 	EFI_DIRECTED_IO_DMAR_ERROR_DATA *section_cper =
114 		(EFI_DIRECTED_IO_DMAR_ERROR_DATA *)calloc(
115 			1, sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA));
116 
117 	//OEM ID.
118 	UINT64 oem_id = json_object_get_uint64(
119 		json_object_object_get(section, "oemID"));
120 	for (int i = 0; i < 6; i++) {
121 		section_cper->OemId[i] = (oem_id >> (i * 8)) & 0xFF;
122 	}
123 
124 	//Registers & basic numeric fields.
125 	section_cper->Version = (UINT8)json_object_get_int(
126 		json_object_object_get(section, "version"));
127 	section_cper->Revision = (UINT8)json_object_get_int(
128 		json_object_object_get(section, "revision"));
129 	section_cper->Capability = json_object_get_uint64(
130 		json_object_object_get(section, "capabilityRegister"));
131 	section_cper->CapabilityEx = json_object_get_uint64(
132 		json_object_object_get(section, "extendedCapabilityRegister"));
133 	section_cper->GlobalCommand = json_object_get_uint64(
134 		json_object_object_get(section, "globalCommandRegister"));
135 	section_cper->GlobalStatus = json_object_get_uint64(
136 		json_object_object_get(section, "globalStatusRegister"));
137 	section_cper->FaultStatus = json_object_get_uint64(
138 		json_object_object_get(section, "faultStatusRegister"));
139 
140 	//Fault record.
141 	json_object *fault_record =
142 		json_object_object_get(section, "faultRecord");
143 	EFI_VTD_FAULT_RECORD *fault_record_cper =
144 		(EFI_VTD_FAULT_RECORD *)section_cper->FaultRecord;
145 	fault_record_cper->FaultInformation = json_object_get_uint64(
146 		json_object_object_get(fault_record, "faultInformation"));
147 	fault_record_cper->SourceIdentifier = json_object_get_uint64(
148 		json_object_object_get(fault_record, "sourceIdentifier"));
149 	fault_record_cper->PrivelegeModeRequested = json_object_get_boolean(
150 		json_object_object_get(fault_record, "privelegeModeRequested"));
151 	fault_record_cper->ExecutePermissionRequested = json_object_get_boolean(
152 		json_object_object_get(fault_record,
153 				       "executePermissionRequested"));
154 	fault_record_cper->PasidPresent = json_object_get_boolean(
155 		json_object_object_get(fault_record, "pasidPresent"));
156 	fault_record_cper->FaultReason = json_object_get_uint64(
157 		json_object_object_get(fault_record, "faultReason"));
158 	fault_record_cper->PasidValue = json_object_get_uint64(
159 		json_object_object_get(fault_record, "pasidValue"));
160 	fault_record_cper->AddressType = json_object_get_uint64(
161 		json_object_object_get(fault_record, "addressType"));
162 	fault_record_cper->Type = readable_pair_to_integer(
163 		json_object_object_get(fault_record, "type"));
164 
165 	//Root entry.
166 	json_object *encoded = json_object_object_get(section, "rootEntry");
167 	int32_t decoded_len = 0;
168 
169 	UINT8 *decoded = base64_decode(json_object_get_string(encoded),
170 				       json_object_get_string_len(encoded),
171 				       &decoded_len);
172 	if (decoded == NULL) {
173 		cper_print_log("Failed to allocate decode output buffer. \n");
174 	} else {
175 		memcpy(section_cper->RootEntry, decoded, decoded_len);
176 		free(decoded);
177 	}
178 
179 	//Context entry.
180 	encoded = json_object_object_get(section, "contextEntry");
181 	decoded_len = 0;
182 
183 	decoded = base64_decode(json_object_get_string(encoded),
184 				json_object_get_string_len(encoded),
185 				&decoded_len);
186 	if (decoded == NULL) {
187 		cper_print_log("Failed to allocate decode output buffer. \n");
188 
189 	} else {
190 		memcpy(section_cper->ContextEntry, decoded, decoded_len);
191 		free(decoded);
192 	}
193 
194 	//Page table entries.
195 	section_cper->PteL1 = json_object_get_uint64(
196 		json_object_object_get(section, "pageTableEntry_Level1"));
197 	section_cper->PteL2 = json_object_get_uint64(
198 		json_object_object_get(section, "pageTableEntry_Level2"));
199 	section_cper->PteL3 = json_object_get_uint64(
200 		json_object_object_get(section, "pageTableEntry_Level3"));
201 	section_cper->PteL4 = json_object_get_uint64(
202 		json_object_object_get(section, "pageTableEntry_Level4"));
203 	section_cper->PteL5 = json_object_get_uint64(
204 		json_object_object_get(section, "pageTableEntry_Level5"));
205 	section_cper->PteL6 = json_object_get_uint64(
206 		json_object_object_get(section, "pageTableEntry_Level6"));
207 
208 	//Write to stream, free resources.
209 	fwrite(section_cper, sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA), 1, out);
210 	fflush(out);
211 	free(section_cper);
212 }
213