]> git.proxmox.com Git - mirror_edk2.git/blob - IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxe.c
IntelSiliconPkg PlatformVTdSampleDxe: State it is only for dev/debug
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / PlatformVTdSampleDxe / PlatformVTdSampleDxe.c
1 /** @file
2 Platform VTd Sample driver.
3
4 Note: This module should only be used for dev/debug purposes.
5 It MUST never be used for production builds.
6
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
12
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.
15
16 **/
17
18 #include <PiDxe.h>
19
20 #include <IndustryStandard/Vtd.h>
21 #include <Protocol/PlatformVtdPolicy.h>
22 #include <Protocol/PciIo.h>
23 #include <Protocol/DevicePath.h>
24
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>
32
33 #include <IndustryStandard/DmaRemappingReportingTable.h>
34
35 typedef struct {
36 ACPI_EXTENDED_HID_DEVICE_PATH I2cController;
37 UINT8 HidStr[8];
38 UINT8 UidStr[1];
39 UINT8 CidStr[8];
40 } PLATFORM_I2C_CONTROLLER_DEVICE_PATH;
41
42 typedef struct {
43 ACPI_EXTENDED_HID_DEVICE_PATH I2cDevice;
44 UINT8 HidStr[13];
45 UINT8 UidStr[1];
46 UINT8 CidStr[13];
47 } PLATFORM_I2C_DEVICE_DEVICE_PATH;
48
49 typedef struct {
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;
54
55 typedef struct {
56 ACPI_HID_DEVICE_PATH PciRootBridge;
57 PCI_DEVICE_PATH PciDevice;
58 EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
59 } PLATFORM_PCI_DEVICE_PATH;
60
61 typedef struct {
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;
67
68 typedef struct {
69 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
70 UINT16 Segment;
71 VTD_SOURCE_ID SourceId;
72 } PLATFORM_ACPI_DEVICE_MAPPING;
73
74 #define PLATFORM_PCI_ROOT_BRIDGE \
75 { \
76 { \
77 ACPI_DEVICE_PATH, \
78 ACPI_DP, \
79 { \
80 (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), \
81 (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) \
82 }, \
83 }, \
84 EISA_PNP_ID (0x0A03), \
85 0 \
86 }
87
88 #define PLATFORM_END_ENTIRE \
89 { \
90 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { END_DEVICE_PATH_LENGTH, 0 } \
91 }
92
93 #define PLATFORM_PCI(Device, Function) \
94 { \
95 { \
96 HARDWARE_DEVICE_PATH, \
97 HW_PCI_DP, \
98 { \
99 (UINT8) (sizeof (PCI_DEVICE_PATH)), \
100 (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) \
101 } \
102 }, \
103 (Function), \
104 (Device) \
105 }
106
107 #define PLATFORM_I2C(Hid, Uid, Cid, HidStr, UidStr, CidStr) \
108 { \
109 { \
110 { \
111 ACPI_DEVICE_PATH, \
112 ACPI_EXTENDED_DP, \
113 {sizeof(ACPI_EXTENDED_HID_DEVICE_PATH) + sizeof(HidStr) + sizeof(UidStr) + sizeof(CidStr), 0} \
114 }, \
115 Hid, \
116 Uid, \
117 Cid \
118 }, \
119 HidStr, \
120 UidStr, \
121 CidStr \
122 }
123
124 PLATFORM_I2C_DEVICE_PATH mPlatformI2CDevicePath = {
125 PLATFORM_I2C(0, 2, 0, "INT33C3", "", "INT33C3"),
126 PLATFORM_I2C(0, 1, 0, "I2C01\\TPANEL", "", "I2C01\\TPANEL"),
127 PLATFORM_END_ENTIRE
128 };
129
130 PLATFORM_ACPI_DEVICE_MAPPING mAcpiDeviceMapping[] = {
131 {
132 (EFI_DEVICE_PATH_PROTOCOL *)&mPlatformI2CDevicePath,
133 0x0, // Segment
134 {{0x01, 0x15, 0x00}} // Function, Device, Bus
135 }
136 };
137
138 PLATFORM_PCI_BRIDGE_DEVICE_PATH mPlatformPciBridgeDevicePath = {
139 PLATFORM_PCI_ROOT_BRIDGE,
140 PLATFORM_PCI(0x1C, 1),
141 PLATFORM_PCI(0, 0),
142 PLATFORM_END_ENTIRE
143 };
144
145 #pragma pack(1)
146
147 typedef struct {
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;
153
154 typedef struct {
155 EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO ExceptionDeviceInfo;
156 EDKII_PLATFORM_VTD_PCI_DEVICE_ID PciDeviceId;
157 } PLATFORM_EXCEPTION_PCI_DEVICE_ID_STRUCT;
158
159 #pragma pack()
160
161 PLATFORM_EXCEPTION_DEVICE_SCOPE_STRUCT mExceptionDeviceScopeList[] = {
162 {
163 {
164 EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_DEVICE_SCOPE,
165 sizeof(PLATFORM_EXCEPTION_DEVICE_SCOPE_STRUCT)
166 }, // ExceptionDeviceInfo
167 {
168 0, // SegmentNumber
169 {
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
173 0, // Reserved2
174 0, // EnumerationId
175 0, // StartBusNumber
176 },
177 }, // DeviceScope
178 { 0x1C, 1 }, // PciBridge
179 { 0x0, 0 }, // PciDevice
180 },
181 };
182
183 PLATFORM_EXCEPTION_PCI_DEVICE_ID_STRUCT mExceptionPciDeviceIdList[] = {
184 {
185 {
186 EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_PCI_DEVICE_ID,
187 sizeof(PLATFORM_EXCEPTION_PCI_DEVICE_ID_STRUCT)
188 }, // ExceptionDeviceInfo
189 {
190 0x8086, // VendorId
191 0x9D2F, // DeviceId
192 0x21, // RevisionId
193 0x8086, // SubsystemVendorId
194 0x7270, // SubsystemDeviceId
195 },
196 },
197 };
198
199 /**
200 Compares 2 device path.
201
202 @param[in] DevicePath1 A device path with EndDevicePath node.
203 @param[in] DevicePath2 A device path with EndDevicePath node.
204
205 @retval TRUE 2 device path are identical.
206 @retval FALSE 2 device path are not identical.
207 **/
208 BOOLEAN
209 CompareDevicePath (
210 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath1,
211 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath2
212 )
213 {
214 UINTN Size1;
215 UINTN Size2;
216
217 Size1 = GetDevicePathSize (DevicePath1);
218 Size2 = GetDevicePathSize (DevicePath2);
219 if (Size1 != Size2) {
220 return FALSE;
221 }
222 if (CompareMem (DevicePath1, DevicePath2, Size1) != 0) {
223 return FALSE;
224 }
225 return TRUE;
226 }
227
228 /**
229 Get the VTD SourceId from the device handler.
230 This function is required for non PCI device handler.
231
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
237 } else {
238 return EFI_UNSUPPORTED
239 }
240 }
241 Get VTd engine by Segment/Bus/Device/Function.
242
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.
247
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.
253
254 **/
255 EFI_STATUS
256 EFIAPI
257 PlatformVTdGetDeviceId (
258 IN EDKII_PLATFORM_VTD_POLICY_PROTOCOL *This,
259 IN EFI_HANDLE DeviceHandle,
260 OUT EDKII_PLATFORM_VTD_DEVICE_INFO *DeviceInfo
261 )
262 {
263 EFI_PCI_IO_PROTOCOL *PciIo;
264 UINTN Seg;
265 UINTN Bus;
266 UINTN Dev;
267 UINTN Func;
268 EFI_STATUS Status;
269 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
270 UINTN Index;
271
272 DEBUG ((DEBUG_VERBOSE, "PlatformVTdGetDeviceId\n"));
273
274 if (DeviceInfo == NULL) {
275 return EFI_INVALID_PARAMETER;
276 }
277
278 if (DeviceHandle == NULL) {
279 return EFI_INVALID_PARAMETER;
280 }
281
282 //
283 // Handle PCI device
284 //
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;
290 }
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;
295
296 return EFI_SUCCESS;
297 }
298
299 //
300 // Handle ACPI device
301 //
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;
308 return EFI_SUCCESS;
309 }
310 }
311 }
312
313 return EFI_NOT_FOUND;
314 }
315
316 /**
317 Get a list of the exception devices.
318
319 The VTd driver should always set ALLOW for the device in this list.
320
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.
325
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.
329
330 **/
331 EFI_STATUS
332 EFIAPI
333 PlatformVTdGetExceptionDeviceList (
334 IN EDKII_PLATFORM_VTD_POLICY_PROTOCOL *This,
335 OUT UINTN *DeviceInfoCount,
336 OUT VOID **DeviceInfo
337 )
338 {
339 DEBUG ((DEBUG_VERBOSE, "PlatformVTdGetExceptionDeviceList\n"));
340
341 if (DeviceInfoCount == NULL || DeviceInfo == NULL) {
342 return EFI_INVALID_PARAMETER;
343 }
344
345 //
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.
349 //
350 /*
351 *DeviceInfo = AllocateZeroPool (sizeof(mExceptionDeviceScopeList));
352 if (*DeviceInfo == NULL) {
353 return EFI_OUT_OF_RESOURCES;
354 }
355 CopyMem (*DeviceInfo, mExceptionDeviceScopeList, sizeof(mExceptionDeviceScopeList));
356
357 *DeviceInfoCount = ARRAY_SIZE(mExceptionDeviceScopeList);
358 */
359
360 //
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.
364 //
365 /*
366 *DeviceInfo = AllocateZeroPool (sizeof(mExceptionPciDeviceIdList));
367 if (*DeviceInfo == NULL) {
368 return EFI_OUT_OF_RESOURCES;
369 }
370 CopyMem (*DeviceInfo, mExceptionPciDeviceIdList, sizeof(mExceptionPciDeviceIdList));
371
372 *DeviceInfoCount = ARRAY_SIZE(mExceptionPciDeviceIdList);
373 */
374 return EFI_UNSUPPORTED;
375 }
376
377 EDKII_PLATFORM_VTD_POLICY_PROTOCOL mPlatformVTdSample = {
378 EDKII_PLATFORM_VTD_POLICY_PROTOCOL_REVISION,
379 PlatformVTdGetDeviceId,
380 PlatformVTdGetExceptionDeviceList,
381 };
382
383 /**
384 Platform VTd sample driver.
385
386 @param[in] ImageHandle ImageHandle of the loaded driver
387 @param[in] SystemTable Pointer to the System Table
388
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.
392
393 **/
394 EFI_STATUS
395 EFIAPI
396 PlatformVTdSampleInitialize (
397 IN EFI_HANDLE ImageHandle,
398 IN EFI_SYSTEM_TABLE *SystemTable
399 )
400 {
401 EFI_STATUS Status;
402 EFI_HANDLE Handle;
403
404 Handle = NULL;
405 Status = gBS->InstallMultipleProtocolInterfaces (
406 &Handle,
407 &gEdkiiPlatformVTdPolicyProtocolGuid, &mPlatformVTdSample,
408 NULL
409 );
410 ASSERT_EFI_ERROR (Status);
411
412 return Status;
413 }