]> git.proxmox.com Git - mirror_edk2.git/blob - IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.c
f181b94dfa9f2bfb950de26263dd75f1901d72a8
[mirror_edk2.git] / IntelSiliconPkg / PlatformVTdSampleDxe / PlatformVTdSampleDxe.c
1 /** @file
2 Platform VTd Sample driver.
3
4 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include <PiDxe.h>
16
17 #include <IndustryStandard/Vtd.h>
18 #include <Protocol/PlatformVtdPolicy.h>
19 #include <Protocol/PciIo.h>
20 #include <Protocol/DevicePath.h>
21
22 #include <Library/IoLib.h>
23 #include <Library/BaseLib.h>
24 #include <Library/BaseMemoryLib.h>
25 #include <Library/MemoryAllocationLib.h>
26 #include <Library/DebugLib.h>
27 #include <Library/UefiBootServicesTableLib.h>
28 #include <Library/DevicePathLib.h>
29
30 typedef struct {
31 ACPI_EXTENDED_HID_DEVICE_PATH I2cController;
32 UINT8 HidStr[8];
33 UINT8 UidStr[1];
34 UINT8 CidStr[8];
35 } PLATFORM_I2C_CONTROLLER_DEVICE_PATH;
36
37 typedef struct {
38 ACPI_EXTENDED_HID_DEVICE_PATH I2cDevice;
39 UINT8 HidStr[13];
40 UINT8 UidStr[1];
41 UINT8 CidStr[13];
42 } PLATFORM_I2C_DEVICE_DEVICE_PATH;
43
44 typedef struct {
45 PLATFORM_I2C_CONTROLLER_DEVICE_PATH I2cController;
46 PLATFORM_I2C_DEVICE_DEVICE_PATH I2cDevice;
47 EFI_DEVICE_PATH_PROTOCOL End;
48 } PLATFORM_I2C_DEVICE_PATH;
49
50 typedef struct {
51 ACPI_HID_DEVICE_PATH PciRootBridge;
52 PCI_DEVICE_PATH PciDevice;
53 EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
54 } PLATFORM_PCI_DEVICE_PATH;
55
56 typedef struct {
57 ACPI_HID_DEVICE_PATH PciRootBridge;
58 PCI_DEVICE_PATH PciBridge;
59 PCI_DEVICE_PATH PciDevice;
60 EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
61 } PLATFORM_PCI_BRIDGE_DEVICE_PATH;
62
63 typedef struct {
64 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
65 UINT16 Segment;
66 VTD_SOURCE_ID SourceId;
67 } PLATFORM_ACPI_DEVICE_MAPPING;
68
69 #define PLATFORM_PCI_ROOT_BRIDGE \
70 { \
71 { \
72 ACPI_DEVICE_PATH, \
73 ACPI_DP, \
74 { \
75 (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), \
76 (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) \
77 }, \
78 }, \
79 EISA_PNP_ID (0x0A03), \
80 0 \
81 }
82
83 #define PLATFORM_END_ENTIRE \
84 { \
85 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { END_DEVICE_PATH_LENGTH, 0 } \
86 }
87
88 #define PLATFORM_PCI(Device, Function) \
89 { \
90 { \
91 HARDWARE_DEVICE_PATH, \
92 HW_PCI_DP, \
93 { \
94 (UINT8) (sizeof (PCI_DEVICE_PATH)), \
95 (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) \
96 } \
97 }, \
98 (Function), \
99 (Device) \
100 }
101
102 #define PLATFORM_I2C(Hid, Uid, Cid, HidStr, UidStr, CidStr) \
103 { \
104 { \
105 { \
106 ACPI_DEVICE_PATH, \
107 ACPI_EXTENDED_DP, \
108 {sizeof(ACPI_EXTENDED_HID_DEVICE_PATH) + sizeof(HidStr) + sizeof(UidStr) + sizeof(CidStr), 0} \
109 }, \
110 Hid, \
111 Uid, \
112 Cid \
113 }, \
114 HidStr, \
115 UidStr, \
116 CidStr \
117 }
118
119 PLATFORM_I2C_DEVICE_PATH mPlatformI2CDevicePath = {
120 PLATFORM_I2C(0, 2, 0, "INT33C3", "", "INT33C3"),
121 PLATFORM_I2C(0, 1, 0, "I2C01\\TPANEL", "", "I2C01\\TPANEL"),
122 PLATFORM_END_ENTIRE
123 };
124
125 PLATFORM_ACPI_DEVICE_MAPPING mAcpiDeviceMapping[] = {
126 {
127 (EFI_DEVICE_PATH_PROTOCOL *)&mPlatformI2CDevicePath,
128 0x0, // Segment
129 {{0x01, 0x15, 0x00}} // Function, Device, Bus
130 }
131 };
132
133 PLATFORM_PCI_BRIDGE_DEVICE_PATH mPlatformPciBridgeDevicePath = {
134 PLATFORM_PCI_ROOT_BRIDGE,
135 PLATFORM_PCI(0x1C, 1),
136 PLATFORM_PCI(0, 0),
137 PLATFORM_END_ENTIRE
138 };
139
140 EDKII_PLATFORM_VTD_DEVICE_INFO mExceptionDeviceList[] = {
141 {
142 0x0, // Segment
143 {{0x00, 0x00, 0x02}} // Function, Device, Bus
144 },
145 };
146
147 /**
148 Compares 2 device path.
149
150 @param[in] DevicePath1 A device path with EndDevicePath node.
151 @param[in] DevicePath2 A device path with EndDevicePath node.
152
153 @retval TRUE 2 device path are identical.
154 @retval FALSE 2 device path are not identical.
155 **/
156 BOOLEAN
157 CompareDevicePath (
158 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath1,
159 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath2
160 )
161 {
162 UINTN Size1;
163 UINTN Size2;
164
165 Size1 = GetDevicePathSize (DevicePath1);
166 Size2 = GetDevicePathSize (DevicePath2);
167 if (Size1 != Size2) {
168 return FALSE;
169 }
170 if (CompareMem (DevicePath1, DevicePath2, Size1) != 0) {
171 return FALSE;
172 }
173 return TRUE;
174 }
175
176 /**
177 Get the VTD SourceId from the device handler.
178 This function is required for non PCI device handler.
179
180 Pseudo-algo in Intel VTd driver:
181 Status = PlatformGetVTdDeviceId ();
182 if (EFI_ERROR(Status)) {
183 if (DeviceHandle is PCI) {
184 Get SourceId from Bus/Device/Function
185 } else {
186 return EFI_UNSUPPORTED
187 }
188 }
189 Get VTd engine by Segment/Bus/Device/Function.
190
191 @param[in] This The protocol instance pointer.
192 @param[in] DeviceHandle Device Identifier in UEFI.
193 @param[out] DeviceInfo DeviceInfo for indentify the VTd engine in ACPI Table
194 and the VTd page entry.
195
196 @retval EFI_SUCCESS The VtdIndex and SourceId are returned.
197 @retval EFI_INVALID_PARAMETER DeviceHandle is not a valid handler.
198 @retval EFI_INVALID_PARAMETER DeviceInfo is NULL.
199 @retval EFI_NOT_FOUND The Segment or SourceId information is NOT found.
200 @retval EFI_UNSUPPORTED This function is not supported.
201
202 **/
203 EFI_STATUS
204 EFIAPI
205 PlatformVTdGetDeviceId (
206 IN EDKII_PLATFORM_VTD_POLICY_PROTOCOL *This,
207 IN EFI_HANDLE DeviceHandle,
208 OUT EDKII_PLATFORM_VTD_DEVICE_INFO *DeviceInfo
209 )
210 {
211 EFI_PCI_IO_PROTOCOL *PciIo;
212 UINTN Seg;
213 UINTN Bus;
214 UINTN Dev;
215 UINTN Func;
216 EFI_STATUS Status;
217 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
218 UINTN Index;
219
220 DEBUG ((DEBUG_VERBOSE, "PlatformVTdGetDeviceId\n"));
221
222 if (DeviceInfo == NULL) {
223 return EFI_INVALID_PARAMETER;
224 }
225
226 if (DeviceHandle == NULL) {
227 return EFI_INVALID_PARAMETER;
228 }
229
230 //
231 // Handle PCI device
232 //
233 Status = gBS->HandleProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, (VOID **)&PciIo);
234 if (!EFI_ERROR(Status)) {
235 Status = PciIo->GetLocation (PciIo, &Seg, &Bus, &Dev, &Func);
236 if (EFI_ERROR(Status)) {
237 return EFI_UNSUPPORTED;
238 }
239 DeviceInfo->Segment = (UINT16)Seg;
240 DeviceInfo->SourceId.Bits.Bus = (UINT8)Bus;
241 DeviceInfo->SourceId.Bits.Device = (UINT8)Dev;
242 DeviceInfo->SourceId.Bits.Function = (UINT8)Func;
243
244 return EFI_SUCCESS;
245 }
246
247 //
248 // Handle ACPI device
249 //
250 Status = gBS->HandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);
251 if (!EFI_ERROR(Status)) {
252 for (Index = 0; Index < ARRAY_SIZE(mAcpiDeviceMapping); Index++) {
253 if (CompareDevicePath (mAcpiDeviceMapping[Index].DevicePath, DevicePath)) {
254 DeviceInfo->Segment = mAcpiDeviceMapping[Index].Segment;
255 DeviceInfo->SourceId = mAcpiDeviceMapping[Index].SourceId;
256 return EFI_SUCCESS;
257 }
258 }
259 }
260
261 return EFI_NOT_FOUND;
262 }
263
264 /**
265 Get a list of the exception devices.
266
267 The VTd driver should always set ALLOW for the device in this list.
268
269 @param[in] This The protocol instance pointer.
270 @param[out] DeviceInfoCount The count of the list of DeviceInfo.
271 @param[out] DeviceInfo A callee allocated buffer to hold a list of DeviceInfo.
272
273 @retval EFI_SUCCESS The DeviceInfoCount and DeviceInfo are returned.
274 @retval EFI_INVALID_PARAMETER DeviceInfoCount is NULL, or DeviceInfo is NULL.
275 @retval EFI_UNSUPPORTED This function is not supported.
276
277 **/
278 EFI_STATUS
279 EFIAPI
280 PlatformVTdGetExceptionDeviceList (
281 IN EDKII_PLATFORM_VTD_POLICY_PROTOCOL *This,
282 OUT UINTN *DeviceInfoCount,
283 OUT EDKII_PLATFORM_VTD_DEVICE_INFO **DeviceInfo
284 )
285 {
286 DEBUG ((DEBUG_VERBOSE, "PlatformVTdGetExceptionDeviceList\n"));
287
288 if (DeviceInfoCount == NULL || DeviceInfo == NULL) {
289 return EFI_INVALID_PARAMETER;
290 }
291
292 *DeviceInfo = AllocateZeroPool (sizeof(mExceptionDeviceList));
293 if (*DeviceInfo == NULL) {
294 return EFI_OUT_OF_RESOURCES;
295 }
296 CopyMem (*DeviceInfo, mExceptionDeviceList, sizeof(mExceptionDeviceList));
297
298 *DeviceInfoCount = ARRAY_SIZE(mExceptionDeviceList);
299
300 return EFI_SUCCESS;
301 }
302
303 EDKII_PLATFORM_VTD_POLICY_PROTOCOL mPlatformVTdSample = {
304 EDKII_PLATFORM_VTD_POLICY_PROTOCOL_REVISION,
305 PlatformVTdGetDeviceId,
306 PlatformVTdGetExceptionDeviceList,
307 };
308
309 /**
310 Platform VTd sample driver.
311
312 @param[in] ImageHandle ImageHandle of the loaded driver
313 @param[in] SystemTable Pointer to the System Table
314
315 @retval EFI_SUCCESS The Protocol is installed.
316 @retval EFI_OUT_OF_RESOURCES Not enough resources available to initialize driver.
317 @retval EFI_DEVICE_ERROR A device error occurred attempting to initialize the driver.
318
319 **/
320 EFI_STATUS
321 EFIAPI
322 PlatformVTdSampleInitialize (
323 IN EFI_HANDLE ImageHandle,
324 IN EFI_SYSTEM_TABLE *SystemTable
325 )
326 {
327 EFI_STATUS Status;
328 EFI_HANDLE Handle;
329
330 Handle = NULL;
331 Status = gBS->InstallMultipleProtocolInterfaces (
332 &Handle,
333 &gEdkiiPlatformVTdPolicyProtocolGuid, &mPlatformVTdSample,
334 NULL
335 );
336 ASSERT_EFI_ERROR (Status);
337
338 return Status;
339 }