]> git.proxmox.com Git - mirror_edk2.git/blob - IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.c
IntelSiliconPkg/PlatformVTdSample: Avoid using constant result 'if'
[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 #include <IndustryStandard/DmaRemappingReportingTable.h>
31
32 typedef struct {
33 ACPI_EXTENDED_HID_DEVICE_PATH I2cController;
34 UINT8 HidStr[8];
35 UINT8 UidStr[1];
36 UINT8 CidStr[8];
37 } PLATFORM_I2C_CONTROLLER_DEVICE_PATH;
38
39 typedef struct {
40 ACPI_EXTENDED_HID_DEVICE_PATH I2cDevice;
41 UINT8 HidStr[13];
42 UINT8 UidStr[1];
43 UINT8 CidStr[13];
44 } PLATFORM_I2C_DEVICE_DEVICE_PATH;
45
46 typedef struct {
47 PLATFORM_I2C_CONTROLLER_DEVICE_PATH I2cController;
48 PLATFORM_I2C_DEVICE_DEVICE_PATH I2cDevice;
49 EFI_DEVICE_PATH_PROTOCOL End;
50 } PLATFORM_I2C_DEVICE_PATH;
51
52 typedef struct {
53 ACPI_HID_DEVICE_PATH PciRootBridge;
54 PCI_DEVICE_PATH PciDevice;
55 EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
56 } PLATFORM_PCI_DEVICE_PATH;
57
58 typedef struct {
59 ACPI_HID_DEVICE_PATH PciRootBridge;
60 PCI_DEVICE_PATH PciBridge;
61 PCI_DEVICE_PATH PciDevice;
62 EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
63 } PLATFORM_PCI_BRIDGE_DEVICE_PATH;
64
65 typedef struct {
66 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
67 UINT16 Segment;
68 VTD_SOURCE_ID SourceId;
69 } PLATFORM_ACPI_DEVICE_MAPPING;
70
71 #define PLATFORM_PCI_ROOT_BRIDGE \
72 { \
73 { \
74 ACPI_DEVICE_PATH, \
75 ACPI_DP, \
76 { \
77 (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), \
78 (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) \
79 }, \
80 }, \
81 EISA_PNP_ID (0x0A03), \
82 0 \
83 }
84
85 #define PLATFORM_END_ENTIRE \
86 { \
87 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { END_DEVICE_PATH_LENGTH, 0 } \
88 }
89
90 #define PLATFORM_PCI(Device, Function) \
91 { \
92 { \
93 HARDWARE_DEVICE_PATH, \
94 HW_PCI_DP, \
95 { \
96 (UINT8) (sizeof (PCI_DEVICE_PATH)), \
97 (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) \
98 } \
99 }, \
100 (Function), \
101 (Device) \
102 }
103
104 #define PLATFORM_I2C(Hid, Uid, Cid, HidStr, UidStr, CidStr) \
105 { \
106 { \
107 { \
108 ACPI_DEVICE_PATH, \
109 ACPI_EXTENDED_DP, \
110 {sizeof(ACPI_EXTENDED_HID_DEVICE_PATH) + sizeof(HidStr) + sizeof(UidStr) + sizeof(CidStr), 0} \
111 }, \
112 Hid, \
113 Uid, \
114 Cid \
115 }, \
116 HidStr, \
117 UidStr, \
118 CidStr \
119 }
120
121 PLATFORM_I2C_DEVICE_PATH mPlatformI2CDevicePath = {
122 PLATFORM_I2C(0, 2, 0, "INT33C3", "", "INT33C3"),
123 PLATFORM_I2C(0, 1, 0, "I2C01\\TPANEL", "", "I2C01\\TPANEL"),
124 PLATFORM_END_ENTIRE
125 };
126
127 PLATFORM_ACPI_DEVICE_MAPPING mAcpiDeviceMapping[] = {
128 {
129 (EFI_DEVICE_PATH_PROTOCOL *)&mPlatformI2CDevicePath,
130 0x0, // Segment
131 {{0x01, 0x15, 0x00}} // Function, Device, Bus
132 }
133 };
134
135 PLATFORM_PCI_BRIDGE_DEVICE_PATH mPlatformPciBridgeDevicePath = {
136 PLATFORM_PCI_ROOT_BRIDGE,
137 PLATFORM_PCI(0x1C, 1),
138 PLATFORM_PCI(0, 0),
139 PLATFORM_END_ENTIRE
140 };
141
142 #pragma pack(1)
143
144 typedef struct {
145 EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO ExceptionDeviceInfo;
146 EDKII_PLATFORM_VTD_DEVICE_SCOPE DeviceScope;
147 EFI_ACPI_DMAR_PCI_PATH PciBridge;
148 EFI_ACPI_DMAR_PCI_PATH PciDevice;
149 } PLATFORM_EXCEPTION_DEVICE_SCOPE_STRUCT;
150
151 typedef struct {
152 EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO ExceptionDeviceInfo;
153 EDKII_PLATFORM_VTD_PCI_DEVICE_ID PciDeviceId;
154 } PLATFORM_EXCEPTION_PCI_DEVICE_ID_STRUCT;
155
156 #pragma pack()
157
158 PLATFORM_EXCEPTION_DEVICE_SCOPE_STRUCT mExceptionDeviceScopeList[] = {
159 {
160 {
161 EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_DEVICE_SCOPE,
162 sizeof(PLATFORM_EXCEPTION_DEVICE_SCOPE_STRUCT)
163 }, // ExceptionDeviceInfo
164 {
165 0, // SegmentNumber
166 {
167 EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT, // Type
168 sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER) +
169 2 * sizeof(EFI_ACPI_DMAR_PCI_PATH), // Length
170 0, // Reserved2
171 0, // EnumerationId
172 0, // StartBusNumber
173 },
174 }, // DeviceScope
175 { 0x1C, 1 }, // PciBridge
176 { 0x0, 0 }, // PciDevice
177 },
178 };
179
180 PLATFORM_EXCEPTION_PCI_DEVICE_ID_STRUCT mExceptionPciDeviceIdList[] = {
181 {
182 {
183 EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_PCI_DEVICE_ID,
184 sizeof(PLATFORM_EXCEPTION_PCI_DEVICE_ID_STRUCT)
185 }, // ExceptionDeviceInfo
186 {
187 0x8086, // VendorId
188 0x9D2F, // DeviceId
189 0x21, // RevisionId
190 0x8086, // SubsystemVendorId
191 0x7270, // SubsystemDeviceId
192 },
193 },
194 };
195
196 /**
197 Compares 2 device path.
198
199 @param[in] DevicePath1 A device path with EndDevicePath node.
200 @param[in] DevicePath2 A device path with EndDevicePath node.
201
202 @retval TRUE 2 device path are identical.
203 @retval FALSE 2 device path are not identical.
204 **/
205 BOOLEAN
206 CompareDevicePath (
207 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath1,
208 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath2
209 )
210 {
211 UINTN Size1;
212 UINTN Size2;
213
214 Size1 = GetDevicePathSize (DevicePath1);
215 Size2 = GetDevicePathSize (DevicePath2);
216 if (Size1 != Size2) {
217 return FALSE;
218 }
219 if (CompareMem (DevicePath1, DevicePath2, Size1) != 0) {
220 return FALSE;
221 }
222 return TRUE;
223 }
224
225 /**
226 Get the VTD SourceId from the device handler.
227 This function is required for non PCI device handler.
228
229 Pseudo-algo in Intel VTd driver:
230 Status = PlatformGetVTdDeviceId ();
231 if (EFI_ERROR(Status)) {
232 if (DeviceHandle is PCI) {
233 Get SourceId from Bus/Device/Function
234 } else {
235 return EFI_UNSUPPORTED
236 }
237 }
238 Get VTd engine by Segment/Bus/Device/Function.
239
240 @param[in] This The protocol instance pointer.
241 @param[in] DeviceHandle Device Identifier in UEFI.
242 @param[out] DeviceInfo DeviceInfo for indentify the VTd engine in ACPI Table
243 and the VTd page entry.
244
245 @retval EFI_SUCCESS The VtdIndex and SourceId are returned.
246 @retval EFI_INVALID_PARAMETER DeviceHandle is not a valid handler.
247 @retval EFI_INVALID_PARAMETER DeviceInfo is NULL.
248 @retval EFI_NOT_FOUND The Segment or SourceId information is NOT found.
249 @retval EFI_UNSUPPORTED This function is not supported.
250
251 **/
252 EFI_STATUS
253 EFIAPI
254 PlatformVTdGetDeviceId (
255 IN EDKII_PLATFORM_VTD_POLICY_PROTOCOL *This,
256 IN EFI_HANDLE DeviceHandle,
257 OUT EDKII_PLATFORM_VTD_DEVICE_INFO *DeviceInfo
258 )
259 {
260 EFI_PCI_IO_PROTOCOL *PciIo;
261 UINTN Seg;
262 UINTN Bus;
263 UINTN Dev;
264 UINTN Func;
265 EFI_STATUS Status;
266 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
267 UINTN Index;
268
269 DEBUG ((DEBUG_VERBOSE, "PlatformVTdGetDeviceId\n"));
270
271 if (DeviceInfo == NULL) {
272 return EFI_INVALID_PARAMETER;
273 }
274
275 if (DeviceHandle == NULL) {
276 return EFI_INVALID_PARAMETER;
277 }
278
279 //
280 // Handle PCI device
281 //
282 Status = gBS->HandleProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, (VOID **)&PciIo);
283 if (!EFI_ERROR(Status)) {
284 Status = PciIo->GetLocation (PciIo, &Seg, &Bus, &Dev, &Func);
285 if (EFI_ERROR(Status)) {
286 return EFI_UNSUPPORTED;
287 }
288 DeviceInfo->Segment = (UINT16)Seg;
289 DeviceInfo->SourceId.Bits.Bus = (UINT8)Bus;
290 DeviceInfo->SourceId.Bits.Device = (UINT8)Dev;
291 DeviceInfo->SourceId.Bits.Function = (UINT8)Func;
292
293 return EFI_SUCCESS;
294 }
295
296 //
297 // Handle ACPI device
298 //
299 Status = gBS->HandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);
300 if (!EFI_ERROR(Status)) {
301 for (Index = 0; Index < ARRAY_SIZE(mAcpiDeviceMapping); Index++) {
302 if (CompareDevicePath (mAcpiDeviceMapping[Index].DevicePath, DevicePath)) {
303 DeviceInfo->Segment = mAcpiDeviceMapping[Index].Segment;
304 DeviceInfo->SourceId = mAcpiDeviceMapping[Index].SourceId;
305 return EFI_SUCCESS;
306 }
307 }
308 }
309
310 return EFI_NOT_FOUND;
311 }
312
313 /**
314 Get a list of the exception devices.
315
316 The VTd driver should always set ALLOW for the device in this list.
317
318 @param[in] This The protocol instance pointer.
319 @param[out] DeviceInfoCount The count of the list of DeviceInfo.
320 @param[out] DeviceInfo A callee allocated buffer to hold a list of DeviceInfo.
321 Each DeviceInfo pointer points to EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO.
322
323 @retval EFI_SUCCESS The DeviceInfoCount and DeviceInfo are returned.
324 @retval EFI_INVALID_PARAMETER DeviceInfoCount is NULL, or DeviceInfo is NULL.
325 @retval EFI_UNSUPPORTED This function is not supported.
326
327 **/
328 EFI_STATUS
329 EFIAPI
330 PlatformVTdGetExceptionDeviceList (
331 IN EDKII_PLATFORM_VTD_POLICY_PROTOCOL *This,
332 OUT UINTN *DeviceInfoCount,
333 OUT VOID **DeviceInfo
334 )
335 {
336 DEBUG ((DEBUG_VERBOSE, "PlatformVTdGetExceptionDeviceList\n"));
337
338 if (DeviceInfoCount == NULL || DeviceInfo == NULL) {
339 return EFI_INVALID_PARAMETER;
340 }
341
342 //
343 // Sample codes for device scope based exception list.
344 // Uncomment to take affect and comment the sample codes for PCI vendor id
345 // based exception list.
346 //
347 /*
348 *DeviceInfo = AllocateZeroPool (sizeof(mExceptionDeviceScopeList));
349 if (*DeviceInfo == NULL) {
350 return EFI_OUT_OF_RESOURCES;
351 }
352 CopyMem (*DeviceInfo, mExceptionDeviceScopeList, sizeof(mExceptionDeviceScopeList));
353
354 *DeviceInfoCount = ARRAY_SIZE(mExceptionDeviceScopeList);
355 */
356
357 //
358 // Sample codes for PCI vendor id based exception list.
359 // Uncomment to take affect and comment the sample codes for device scope
360 // based exception list.
361 //
362 *DeviceInfo = AllocateZeroPool (sizeof(mExceptionPciDeviceIdList));
363 if (*DeviceInfo == NULL) {
364 return EFI_OUT_OF_RESOURCES;
365 }
366 CopyMem (*DeviceInfo, mExceptionPciDeviceIdList, sizeof(mExceptionPciDeviceIdList));
367
368 *DeviceInfoCount = ARRAY_SIZE(mExceptionPciDeviceIdList);
369
370 return EFI_SUCCESS;
371 }
372
373 EDKII_PLATFORM_VTD_POLICY_PROTOCOL mPlatformVTdSample = {
374 EDKII_PLATFORM_VTD_POLICY_PROTOCOL_REVISION,
375 PlatformVTdGetDeviceId,
376 PlatformVTdGetExceptionDeviceList,
377 };
378
379 /**
380 Platform VTd sample driver.
381
382 @param[in] ImageHandle ImageHandle of the loaded driver
383 @param[in] SystemTable Pointer to the System Table
384
385 @retval EFI_SUCCESS The Protocol is installed.
386 @retval EFI_OUT_OF_RESOURCES Not enough resources available to initialize driver.
387 @retval EFI_DEVICE_ERROR A device error occurred attempting to initialize the driver.
388
389 **/
390 EFI_STATUS
391 EFIAPI
392 PlatformVTdSampleInitialize (
393 IN EFI_HANDLE ImageHandle,
394 IN EFI_SYSTEM_TABLE *SystemTable
395 )
396 {
397 EFI_STATUS Status;
398 EFI_HANDLE Handle;
399
400 Handle = NULL;
401 Status = gBS->InstallMultipleProtocolInterfaces (
402 &Handle,
403 &gEdkiiPlatformVTdPolicyProtocolGuid, &mPlatformVTdSample,
404 NULL
405 );
406 ASSERT_EFI_ERROR (Status);
407
408 return Status;
409 }