2 Platform VTd Sample driver.
4 Note: This module should only be used for dev/debug purposes.
5 It MUST never be used for production builds.
7 Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 #include <IndustryStandard/Vtd.h>
21 #include <Protocol/PlatformVtdPolicy.h>
22 #include <Protocol/PciIo.h>
23 #include <Protocol/DevicePath.h>
25 #include <Library/IoLib.h>
26 #include <Library/BaseLib.h>
27 #include <Library/BaseMemoryLib.h>
28 #include <Library/MemoryAllocationLib.h>
29 #include <Library/DebugLib.h>
30 #include <Library/UefiBootServicesTableLib.h>
31 #include <Library/DevicePathLib.h>
33 #include <IndustryStandard/DmaRemappingReportingTable.h>
36 ACPI_EXTENDED_HID_DEVICE_PATH I2cController
;
40 } PLATFORM_I2C_CONTROLLER_DEVICE_PATH
;
43 ACPI_EXTENDED_HID_DEVICE_PATH I2cDevice
;
47 } PLATFORM_I2C_DEVICE_DEVICE_PATH
;
50 PLATFORM_I2C_CONTROLLER_DEVICE_PATH I2cController
;
51 PLATFORM_I2C_DEVICE_DEVICE_PATH I2cDevice
;
52 EFI_DEVICE_PATH_PROTOCOL End
;
53 } PLATFORM_I2C_DEVICE_PATH
;
56 ACPI_HID_DEVICE_PATH PciRootBridge
;
57 PCI_DEVICE_PATH PciDevice
;
58 EFI_DEVICE_PATH_PROTOCOL EndDevicePath
;
59 } PLATFORM_PCI_DEVICE_PATH
;
62 ACPI_HID_DEVICE_PATH PciRootBridge
;
63 PCI_DEVICE_PATH PciBridge
;
64 PCI_DEVICE_PATH PciDevice
;
65 EFI_DEVICE_PATH_PROTOCOL EndDevicePath
;
66 } PLATFORM_PCI_BRIDGE_DEVICE_PATH
;
69 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
71 VTD_SOURCE_ID SourceId
;
72 } PLATFORM_ACPI_DEVICE_MAPPING
;
74 #define PLATFORM_PCI_ROOT_BRIDGE \
80 (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), \
81 (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) \
84 EISA_PNP_ID (0x0A03), \
88 #define PLATFORM_END_ENTIRE \
90 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { END_DEVICE_PATH_LENGTH, 0 } \
93 #define PLATFORM_PCI(Device, Function) \
96 HARDWARE_DEVICE_PATH, \
99 (UINT8) (sizeof (PCI_DEVICE_PATH)), \
100 (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) \
107 #define PLATFORM_I2C(Hid, Uid, Cid, HidStr, UidStr, CidStr) \
113 {sizeof(ACPI_EXTENDED_HID_DEVICE_PATH) + sizeof(HidStr) + sizeof(UidStr) + sizeof(CidStr), 0} \
124 PLATFORM_I2C_DEVICE_PATH mPlatformI2CDevicePath
= {
125 PLATFORM_I2C(0, 2, 0, "INT33C3", "", "INT33C3"),
126 PLATFORM_I2C(0, 1, 0, "I2C01\\TPANEL", "", "I2C01\\TPANEL"),
130 PLATFORM_ACPI_DEVICE_MAPPING mAcpiDeviceMapping
[] = {
132 (EFI_DEVICE_PATH_PROTOCOL
*)&mPlatformI2CDevicePath
,
134 {{0x01, 0x15, 0x00}} // Function, Device, Bus
138 PLATFORM_PCI_BRIDGE_DEVICE_PATH mPlatformPciBridgeDevicePath
= {
139 PLATFORM_PCI_ROOT_BRIDGE
,
140 PLATFORM_PCI(0x1C, 1),
148 EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO ExceptionDeviceInfo
;
149 EDKII_PLATFORM_VTD_DEVICE_SCOPE DeviceScope
;
150 EFI_ACPI_DMAR_PCI_PATH PciBridge
;
151 EFI_ACPI_DMAR_PCI_PATH PciDevice
;
152 } PLATFORM_EXCEPTION_DEVICE_SCOPE_STRUCT
;
155 EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO ExceptionDeviceInfo
;
156 EDKII_PLATFORM_VTD_PCI_DEVICE_ID PciDeviceId
;
157 } PLATFORM_EXCEPTION_PCI_DEVICE_ID_STRUCT
;
161 PLATFORM_EXCEPTION_DEVICE_SCOPE_STRUCT mExceptionDeviceScopeList
[] = {
164 EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_DEVICE_SCOPE
,
165 sizeof(PLATFORM_EXCEPTION_DEVICE_SCOPE_STRUCT
)
166 }, // ExceptionDeviceInfo
170 EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT
, // Type
171 sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
) +
172 2 * sizeof(EFI_ACPI_DMAR_PCI_PATH
), // Length
178 { 0x1C, 1 }, // PciBridge
179 { 0x0, 0 }, // PciDevice
183 PLATFORM_EXCEPTION_PCI_DEVICE_ID_STRUCT mExceptionPciDeviceIdList
[] = {
186 EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_PCI_DEVICE_ID
,
187 sizeof(PLATFORM_EXCEPTION_PCI_DEVICE_ID_STRUCT
)
188 }, // ExceptionDeviceInfo
193 0x8086, // SubsystemVendorId
194 0x7270, // SubsystemDeviceId
200 Compares 2 device path.
202 @param[in] DevicePath1 A device path with EndDevicePath node.
203 @param[in] DevicePath2 A device path with EndDevicePath node.
205 @retval TRUE 2 device path are identical.
206 @retval FALSE 2 device path are not identical.
210 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath1
,
211 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath2
217 Size1
= GetDevicePathSize (DevicePath1
);
218 Size2
= GetDevicePathSize (DevicePath2
);
219 if (Size1
!= Size2
) {
222 if (CompareMem (DevicePath1
, DevicePath2
, Size1
) != 0) {
229 Get the VTD SourceId from the device handler.
230 This function is required for non PCI device handler.
232 Pseudo-algo in Intel VTd driver:
233 Status = PlatformGetVTdDeviceId ();
234 if (EFI_ERROR(Status)) {
235 if (DeviceHandle is PCI) {
236 Get SourceId from Bus/Device/Function
238 return EFI_UNSUPPORTED
241 Get VTd engine by Segment/Bus/Device/Function.
243 @param[in] This The protocol instance pointer.
244 @param[in] DeviceHandle Device Identifier in UEFI.
245 @param[out] DeviceInfo DeviceInfo for indentify the VTd engine in ACPI Table
246 and the VTd page entry.
248 @retval EFI_SUCCESS The VtdIndex and SourceId are returned.
249 @retval EFI_INVALID_PARAMETER DeviceHandle is not a valid handler.
250 @retval EFI_INVALID_PARAMETER DeviceInfo is NULL.
251 @retval EFI_NOT_FOUND The Segment or SourceId information is NOT found.
252 @retval EFI_UNSUPPORTED This function is not supported.
257 PlatformVTdGetDeviceId (
258 IN EDKII_PLATFORM_VTD_POLICY_PROTOCOL
*This
,
259 IN EFI_HANDLE DeviceHandle
,
260 OUT EDKII_PLATFORM_VTD_DEVICE_INFO
*DeviceInfo
263 EFI_PCI_IO_PROTOCOL
*PciIo
;
269 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
272 DEBUG ((DEBUG_VERBOSE
, "PlatformVTdGetDeviceId\n"));
274 if (DeviceInfo
== NULL
) {
275 return EFI_INVALID_PARAMETER
;
278 if (DeviceHandle
== NULL
) {
279 return EFI_INVALID_PARAMETER
;
285 Status
= gBS
->HandleProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
, (VOID
**)&PciIo
);
286 if (!EFI_ERROR(Status
)) {
287 Status
= PciIo
->GetLocation (PciIo
, &Seg
, &Bus
, &Dev
, &Func
);
288 if (EFI_ERROR(Status
)) {
289 return EFI_UNSUPPORTED
;
291 DeviceInfo
->Segment
= (UINT16
)Seg
;
292 DeviceInfo
->SourceId
.Bits
.Bus
= (UINT8
)Bus
;
293 DeviceInfo
->SourceId
.Bits
.Device
= (UINT8
)Dev
;
294 DeviceInfo
->SourceId
.Bits
.Function
= (UINT8
)Func
;
300 // Handle ACPI device
302 Status
= gBS
->HandleProtocol (DeviceHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePath
);
303 if (!EFI_ERROR(Status
)) {
304 for (Index
= 0; Index
< ARRAY_SIZE(mAcpiDeviceMapping
); Index
++) {
305 if (CompareDevicePath (mAcpiDeviceMapping
[Index
].DevicePath
, DevicePath
)) {
306 DeviceInfo
->Segment
= mAcpiDeviceMapping
[Index
].Segment
;
307 DeviceInfo
->SourceId
= mAcpiDeviceMapping
[Index
].SourceId
;
313 return EFI_NOT_FOUND
;
317 Get a list of the exception devices.
319 The VTd driver should always set ALLOW for the device in this list.
321 @param[in] This The protocol instance pointer.
322 @param[out] DeviceInfoCount The count of the list of DeviceInfo.
323 @param[out] DeviceInfo A callee allocated buffer to hold a list of DeviceInfo.
324 Each DeviceInfo pointer points to EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO.
326 @retval EFI_SUCCESS The DeviceInfoCount and DeviceInfo are returned.
327 @retval EFI_INVALID_PARAMETER DeviceInfoCount is NULL, or DeviceInfo is NULL.
328 @retval EFI_UNSUPPORTED This function is not supported.
333 PlatformVTdGetExceptionDeviceList (
334 IN EDKII_PLATFORM_VTD_POLICY_PROTOCOL
*This
,
335 OUT UINTN
*DeviceInfoCount
,
336 OUT VOID
**DeviceInfo
339 DEBUG ((DEBUG_VERBOSE
, "PlatformVTdGetExceptionDeviceList\n"));
341 if (DeviceInfoCount
== NULL
|| DeviceInfo
== NULL
) {
342 return EFI_INVALID_PARAMETER
;
346 // Sample codes for device scope based exception list.
347 // Uncomment to take affect and comment the sample codes for PCI vendor id
348 // based exception list.
351 *DeviceInfo = AllocateZeroPool (sizeof(mExceptionDeviceScopeList));
352 if (*DeviceInfo == NULL) {
353 return EFI_OUT_OF_RESOURCES;
355 CopyMem (*DeviceInfo, mExceptionDeviceScopeList, sizeof(mExceptionDeviceScopeList));
357 *DeviceInfoCount = ARRAY_SIZE(mExceptionDeviceScopeList);
361 // Sample codes for PCI vendor id based exception list.
362 // Uncomment to take affect and comment the sample codes for device scope
363 // based exception list.
366 *DeviceInfo = AllocateZeroPool (sizeof(mExceptionPciDeviceIdList));
367 if (*DeviceInfo == NULL) {
368 return EFI_OUT_OF_RESOURCES;
370 CopyMem (*DeviceInfo, mExceptionPciDeviceIdList, sizeof(mExceptionPciDeviceIdList));
372 *DeviceInfoCount = ARRAY_SIZE(mExceptionPciDeviceIdList);
374 return EFI_UNSUPPORTED
;
377 EDKII_PLATFORM_VTD_POLICY_PROTOCOL mPlatformVTdSample
= {
378 EDKII_PLATFORM_VTD_POLICY_PROTOCOL_REVISION
,
379 PlatformVTdGetDeviceId
,
380 PlatformVTdGetExceptionDeviceList
,
384 Platform VTd sample driver.
386 @param[in] ImageHandle ImageHandle of the loaded driver
387 @param[in] SystemTable Pointer to the System Table
389 @retval EFI_SUCCESS The Protocol is installed.
390 @retval EFI_OUT_OF_RESOURCES Not enough resources available to initialize driver.
391 @retval EFI_DEVICE_ERROR A device error occurred attempting to initialize the driver.
396 PlatformVTdSampleInitialize (
397 IN EFI_HANDLE ImageHandle
,
398 IN EFI_SYSTEM_TABLE
*SystemTable
405 Status
= gBS
->InstallMultipleProtocolInterfaces (
407 &gEdkiiPlatformVTdPolicyProtocolGuid
, &mPlatformVTdSample
,
410 ASSERT_EFI_ERROR (Status
);