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