IntelSiliconPkg IntelVTdDxe: Use TPL to protect list/engine operation
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdDxe / DmaProtection.h
CommitLineData
c049fc99
JY
1/** @file\r
2\r
3 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
4 This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution. The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php.\r
8\r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12**/\r
13\r
14#ifndef _DMAR_PROTECTION_H_\r
15#define _DMAR_PROTECTION_H_\r
16\r
17#include <Uefi.h>\r
18#include <PiDxe.h>\r
19\r
20#include <Library/BaseLib.h>\r
21#include <Library/BaseMemoryLib.h>\r
22#include <Library/MemoryAllocationLib.h>\r
23#include <Library/UefiBootServicesTableLib.h>\r
24#include <Library/IoLib.h>\r
25#include <Library/PciSegmentLib.h>\r
26#include <Library/DebugLib.h>\r
27#include <Library/UefiLib.h>\r
4ad5f597
JY
28#include <Library/CacheMaintenanceLib.h>\r
29#include <Library/PerformanceLib.h>\r
30#include <Library/PrintLib.h>\r
c049fc99
JY
31\r
32#include <Guid/EventGroup.h>\r
33#include <Guid/Acpi.h>\r
34\r
35#include <Protocol/DxeSmmReadyToLock.h>\r
36#include <Protocol/PciRootBridgeIo.h>\r
37#include <Protocol/PciIo.h>\r
38#include <Protocol/PciEnumerationComplete.h>\r
c049fc99
JY
39#include <Protocol/PlatformVtdPolicy.h>\r
40#include <Protocol/IoMmu.h>\r
41\r
42#include <IndustryStandard/Pci.h>\r
43#include <IndustryStandard/DmaRemappingReportingTable.h>\r
44#include <IndustryStandard/Vtd.h>\r
45\r
76c6f69c
SZ
46#define VTD_64BITS_ADDRESS(Lo, Hi) (LShiftU64 (Lo, 12) | LShiftU64 (Hi, 32))\r
47\r
c049fc99
JY
48#define ALIGN_VALUE_UP(Value, Alignment) (((Value) + (Alignment) - 1) & (~((Alignment) - 1)))\r
49#define ALIGN_VALUE_LOW(Value, Alignment) ((Value) & (~((Alignment) - 1)))\r
50\r
3a716706
SZ
51#define VTD_TPL_LEVEL TPL_NOTIFY\r
52\r
c049fc99 53//\r
f77d35c7 54// This is the initial max PCI DATA number.\r
c049fc99
JY
55// The number may be enlarged later.\r
56//\r
f77d35c7 57#define MAX_VTD_PCI_DATA_NUMBER 0x100\r
c049fc99
JY
58\r
59typedef struct {\r
f77d35c7
JY
60 UINT8 DeviceType;\r
61 VTD_SOURCE_ID PciSourceId;\r
62 EDKII_PLATFORM_VTD_PCI_DEVICE_ID PciDeviceId;\r
4ad5f597 63 // for statistic analysis\r
f77d35c7
JY
64 UINTN AccessCount;\r
65} PCI_DEVICE_DATA;\r
66\r
67typedef struct {\r
68 BOOLEAN IncludeAllFlag;\r
69 UINTN PciDeviceDataNumber;\r
70 UINTN PciDeviceDataMaxNumber;\r
71 PCI_DEVICE_DATA *PciDeviceData;\r
c049fc99
JY
72} PCI_DEVICE_INFORMATION;\r
73\r
74typedef struct {\r
75 UINTN VtdUnitBaseAddress;\r
76 UINT16 Segment;\r
77 VTD_CAP_REG CapReg;\r
78 VTD_ECAP_REG ECapReg;\r
79 VTD_ROOT_ENTRY *RootEntryTable;\r
80 VTD_EXT_ROOT_ENTRY *ExtRootEntryTable;\r
81 VTD_SECOND_LEVEL_PAGING_ENTRY *FixedSecondLevelPagingEntry;\r
4ad5f597 82 BOOLEAN HasDirtyContext;\r
c049fc99
JY
83 BOOLEAN HasDirtyPages;\r
84 PCI_DEVICE_INFORMATION PciDeviceInfo;\r
85} VTD_UNIT_INFORMATION;\r
86\r
f77d35c7
JY
87/**\r
88 The scan bus callback function.\r
89\r
90 It is called in PCI bus scan for each PCI device under the bus.\r
91\r
92 @param[in] Context The context of the callback.\r
93 @param[in] Segment The segment of the source.\r
94 @param[in] Bus The bus of the source.\r
95 @param[in] Device The device of the source.\r
96 @param[in] Function The function of the source.\r
97\r
98 @retval EFI_SUCCESS The specific PCI device is processed in the callback.\r
99**/\r
100typedef\r
101EFI_STATUS\r
102(EFIAPI *SCAN_BUS_FUNC_CALLBACK_FUNC) (\r
103 IN VOID *Context,\r
104 IN UINT16 Segment,\r
105 IN UINT8 Bus,\r
106 IN UINT8 Device,\r
107 IN UINT8 Function\r
108 );\r
109\r
c049fc99
JY
110extern EFI_ACPI_DMAR_HEADER *mAcpiDmarTable;\r
111\r
112extern UINT64 mVtdHostAddressWidthMask;\r
113extern UINTN mVtdUnitNumber;\r
114extern VTD_UNIT_INFORMATION *mVtdUnitInformation;\r
115\r
116extern UINT64 mBelow4GMemoryLimit;\r
117extern UINT64 mAbove4GMemoryLimit;\r
118\r
119extern EDKII_PLATFORM_VTD_POLICY_PROTOCOL *mPlatformVTdPolicy;\r
120\r
121/**\r
122 Prepare VTD configuration.\r
123**/\r
124VOID\r
125PrepareVtdConfig (\r
126 VOID\r
127 );\r
128\r
129/**\r
130 Setup VTd translation table.\r
131\r
132 @retval EFI_SUCCESS Setup translation table successfully.\r
133 @retval EFI_OUT_OF_RESOURCE Setup translation table fail.\r
134**/\r
135EFI_STATUS\r
136SetupTranslationTable (\r
137 VOID\r
138 );\r
139\r
140/**\r
141 Enable DMAR translation.\r
142\r
143 @retval EFI_SUCCESS DMAR translation is enabled.\r
144 @retval EFI_DEVICE_ERROR DMAR translation is not enabled.\r
145**/\r
146EFI_STATUS\r
147EnableDmar (\r
148 VOID\r
149 );\r
150\r
151/**\r
152 Disable DMAR translation.\r
153\r
154 @retval EFI_SUCCESS DMAR translation is disabled.\r
155 @retval EFI_DEVICE_ERROR DMAR translation is not disabled.\r
156**/\r
157EFI_STATUS\r
158DisableDmar (\r
159 VOID\r
160 );\r
161\r
c049fc99
JY
162/**\r
163 Invalid VTd global IOTLB.\r
164\r
165 @param[in] VtdIndex The index of VTd engine.\r
166\r
167 @retval EFI_SUCCESS VTd global IOTLB is invalidated.\r
168 @retval EFI_DEVICE_ERROR VTd global IOTLB is not invalidated.\r
169**/\r
170EFI_STATUS\r
171InvalidateVtdIOTLBGlobal (\r
172 IN UINTN VtdIndex\r
173 );\r
174\r
175/**\r
176 Dump VTd registers.\r
177\r
178 @param[in] VtdIndex The index of VTd engine.\r
179**/\r
180VOID\r
181DumpVtdRegs (\r
182 IN UINTN VtdIndex\r
183 );\r
184\r
185/**\r
186 Dump VTd registers for all VTd engine.\r
187**/\r
188VOID\r
189DumpVtdRegsAll (\r
190 VOID\r
191 );\r
192\r
193/**\r
194 Dump VTd capability registers.\r
195\r
196 @param[in] CapReg The capability register.\r
197**/\r
198VOID\r
199DumpVtdCapRegs (\r
200 IN VTD_CAP_REG *CapReg\r
201 );\r
202\r
203/**\r
204 Dump VTd extended capability registers.\r
205\r
206 @param[in] ECapReg The extended capability register.\r
207**/\r
208VOID\r
209DumpVtdECapRegs (\r
210 IN VTD_ECAP_REG *ECapReg\r
211 );\r
212\r
213/**\r
f77d35c7 214 Register PCI device to VTd engine.\r
c049fc99
JY
215\r
216 @param[in] VtdIndex The index of VTd engine.\r
217 @param[in] Segment The segment of the source.\r
218 @param[in] SourceId The SourceId of the source.\r
f77d35c7 219 @param[in] DeviceType The DMAR device scope type.\r
c049fc99
JY
220 @param[in] CheckExist TRUE: ERROR will be returned if the PCI device is already registered.\r
221 FALSE: SUCCESS will be returned if the PCI device is registered.\r
222\r
223 @retval EFI_SUCCESS The PCI device is registered.\r
224 @retval EFI_OUT_OF_RESOURCES No enough resource to register a new PCI device.\r
225 @retval EFI_ALREADY_STARTED The device is already registered.\r
226**/\r
227EFI_STATUS\r
228RegisterPciDevice (\r
229 IN UINTN VtdIndex,\r
230 IN UINT16 Segment,\r
231 IN VTD_SOURCE_ID SourceId,\r
f77d35c7 232 IN UINT8 DeviceType,\r
c049fc99
JY
233 IN BOOLEAN CheckExist\r
234 );\r
235\r
236/**\r
f77d35c7 237 The scan bus callback function to always enable page attribute.\r
c049fc99 238\r
f77d35c7 239 @param[in] Context The context of the callback.\r
c049fc99
JY
240 @param[in] Segment The segment of the source.\r
241 @param[in] Bus The bus of the source.\r
f77d35c7
JY
242 @param[in] Device The device of the source.\r
243 @param[in] Function The function of the source.\r
c049fc99 244\r
f77d35c7 245 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device.\r
c049fc99
JY
246**/\r
247EFI_STATUS\r
f77d35c7
JY
248EFIAPI\r
249ScanBusCallbackRegisterPciDevice (\r
250 IN VOID *Context,\r
c049fc99 251 IN UINT16 Segment,\r
f77d35c7
JY
252 IN UINT8 Bus,\r
253 IN UINT8 Device,\r
254 IN UINT8 Function\r
255 );\r
256\r
257/**\r
258 Scan PCI bus and invoke callback function for each PCI devices under the bus.\r
259\r
260 @param[in] Context The context of the callback function.\r
261 @param[in] Segment The segment of the source.\r
262 @param[in] Bus The bus of the source.\r
263 @param[in] Callback The callback function in PCI scan.\r
264\r
265 @retval EFI_SUCCESS The PCI devices under the bus are scaned.\r
266**/\r
267EFI_STATUS\r
268ScanPciBus (\r
269 IN VOID *Context,\r
270 IN UINT16 Segment,\r
271 IN UINT8 Bus,\r
272 IN SCAN_BUS_FUNC_CALLBACK_FUNC Callback\r
c049fc99
JY
273 );\r
274\r
275/**\r
276 Dump the PCI device information managed by this VTd engine.\r
277\r
278 @param[in] VtdIndex The index of VTd engine.\r
279**/\r
280VOID\r
281DumpPciDeviceInfo (\r
282 IN UINTN VtdIndex\r
283 );\r
284\r
285/**\r
286 Find the VTd index by the Segment and SourceId.\r
287\r
288 @param[in] Segment The segment of the source.\r
289 @param[in] SourceId The SourceId of the source.\r
290 @param[out] ExtContextEntry The ExtContextEntry of the source.\r
291 @param[out] ContextEntry The ContextEntry of the source.\r
292\r
f77d35c7
JY
293 @return The index of the VTd engine.\r
294 @retval (UINTN)-1 The VTd engine is not found.\r
c049fc99
JY
295**/\r
296UINTN\r
297FindVtdIndexByPciDevice (\r
298 IN UINT16 Segment,\r
299 IN VTD_SOURCE_ID SourceId,\r
300 OUT VTD_EXT_CONTEXT_ENTRY **ExtContextEntry,\r
301 OUT VTD_CONTEXT_ENTRY **ContextEntry\r
302 );\r
303\r
304/**\r
305 Get the DMAR ACPI table.\r
306\r
7729e3c4
SZ
307 @retval EFI_SUCCESS The DMAR ACPI table is got.\r
308 @retval EFI_ALREADY_STARTED The DMAR ACPI table has been got previously.\r
309 @retval EFI_NOT_FOUND The DMAR ACPI table is not found.\r
c049fc99
JY
310**/\r
311EFI_STATUS\r
312GetDmarAcpiTable (\r
313 VOID\r
314 );\r
315\r
316/**\r
317 Parse DMAR DRHD table.\r
318\r
319 @return EFI_SUCCESS The DMAR DRHD table is parsed.\r
320**/\r
321EFI_STATUS\r
322ParseDmarAcpiTableDrhd (\r
323 VOID\r
324 );\r
325\r
326/**\r
327 Parse DMAR RMRR table.\r
328\r
329 @return EFI_SUCCESS The DMAR RMRR table is parsed.\r
330**/\r
331EFI_STATUS\r
332ParseDmarAcpiTableRmrr (\r
333 VOID\r
334 );\r
335\r
336/**\r
337 Dump DMAR context entry table.\r
338\r
339 @param[in] RootEntry DMAR root entry.\r
340**/\r
341VOID\r
342DumpDmarContextEntryTable (\r
343 IN VTD_ROOT_ENTRY *RootEntry\r
344 );\r
345\r
346/**\r
347 Dump DMAR extended context entry table.\r
348\r
349 @param[in] ExtRootEntry DMAR extended root entry.\r
350**/\r
351VOID\r
352DumpDmarExtContextEntryTable (\r
353 IN VTD_EXT_ROOT_ENTRY *ExtRootEntry\r
354 );\r
355\r
356/**\r
357 Dump DMAR second level paging entry.\r
358\r
359 @param[in] SecondLevelPagingEntry The second level paging entry.\r
360**/\r
361VOID\r
362DumpSecondLevelPagingEntry (\r
363 IN VOID *SecondLevelPagingEntry\r
364 );\r
365\r
366/**\r
367 Set VTd attribute for a system memory.\r
368\r
369 @param[in] VtdIndex The index used to identify a VTd engine.\r
d654bf85 370 @param[in] DomainIdentifier The domain ID of the source.\r
c049fc99
JY
371 @param[in] SecondLevelPagingEntry The second level paging entry in VTd table for the device.\r
372 @param[in] BaseAddress The base of device memory address to be used as the DMA memory.\r
373 @param[in] Length The length of device memory address to be used as the DMA memory.\r
374 @param[in] IoMmuAccess The IOMMU access.\r
375\r
376 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by BaseAddress and Length.\r
377 @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.\r
378 @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.\r
379 @retval EFI_INVALID_PARAMETER Length is 0.\r
380 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.\r
381 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.\r
382 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by BaseAddress and Length.\r
383 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.\r
384 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.\r
385**/\r
386EFI_STATUS\r
387SetPageAttribute (\r
388 IN UINTN VtdIndex,\r
4ad5f597 389 IN UINT16 DomainIdentifier,\r
c049fc99
JY
390 IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,\r
391 IN UINT64 BaseAddress,\r
392 IN UINT64 Length,\r
393 IN UINT64 IoMmuAccess\r
394 );\r
395\r
396/**\r
397 Set VTd attribute for a system memory.\r
398\r
399 @param[in] Segment The Segment used to identify a VTd engine.\r
400 @param[in] SourceId The SourceId used to identify a VTd engine and table entry.\r
401 @param[in] BaseAddress The base of device memory address to be used as the DMA memory.\r
402 @param[in] Length The length of device memory address to be used as the DMA memory.\r
403 @param[in] IoMmuAccess The IOMMU access.\r
404\r
405 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by BaseAddress and Length.\r
406 @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.\r
407 @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.\r
408 @retval EFI_INVALID_PARAMETER Length is 0.\r
409 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.\r
410 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.\r
411 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by BaseAddress and Length.\r
412 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.\r
413 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.\r
414**/\r
415EFI_STATUS\r
416SetAccessAttribute (\r
417 IN UINT16 Segment,\r
418 IN VTD_SOURCE_ID SourceId,\r
419 IN UINT64 BaseAddress,\r
420 IN UINT64 Length,\r
421 IN UINT64 IoMmuAccess\r
422 );\r
423\r
424/**\r
f77d35c7 425 Return the index of PCI data.\r
c049fc99
JY
426\r
427 @param[in] VtdIndex The index used to identify a VTd engine.\r
428 @param[in] Segment The Segment used to identify a VTd engine.\r
429 @param[in] SourceId The SourceId used to identify a VTd engine and table entry.\r
430\r
f77d35c7
JY
431 @return The index of the PCI data.\r
432 @retval (UINTN)-1 The PCI data is not found.\r
c049fc99
JY
433**/\r
434UINTN\r
f77d35c7 435GetPciDataIndex (\r
c049fc99
JY
436 IN UINTN VtdIndex,\r
437 IN UINT16 Segment,\r
438 IN VTD_SOURCE_ID SourceId\r
439 );\r
440\r
441/**\r
442 Dump VTd registers if there is error.\r
443**/\r
444VOID\r
445DumpVtdIfError (\r
446 VOID\r
447 );\r
448\r
449/**\r
450 Initialize platform VTd policy.\r
451**/\r
452VOID\r
453InitializePlatformVTdPolicy (\r
454 VOID\r
455 );\r
456\r
457/**\r
458 Always enable the VTd page attribute for the device.\r
459\r
460 @param[in] Segment The Segment used to identify a VTd engine.\r
461 @param[in] SourceId The SourceId used to identify a VTd engine and table entry.\r
462\r
463 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device.\r
464**/\r
465EFI_STATUS\r
466AlwaysEnablePageAttribute (\r
467 IN UINT16 Segment,\r
468 IN VTD_SOURCE_ID SourceId\r
469 );\r
470\r
471/**\r
472 Convert the DeviceHandle to SourceId and Segment.\r
473\r
474 @param[in] DeviceHandle The device who initiates the DMA access request.\r
475 @param[out] Segment The Segment used to identify a VTd engine.\r
476 @param[out] SourceId The SourceId used to identify a VTd engine and table entry.\r
477\r
478 @retval EFI_SUCCESS The Segment and SourceId are returned.\r
479 @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle.\r
480 @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU.\r
481**/\r
482EFI_STATUS\r
483DeviceHandleToSourceId (\r
484 IN EFI_HANDLE DeviceHandle,\r
485 OUT UINT16 *Segment,\r
486 OUT VTD_SOURCE_ID *SourceId\r
487 );\r
488\r
489/**\r
490 Get device information from mapping.\r
491\r
492 @param[in] Mapping The mapping.\r
493 @param[out] DeviceAddress The device address of the mapping.\r
494 @param[out] NumberOfPages The number of pages of the mapping.\r
495\r
496 @retval EFI_SUCCESS The device information is returned.\r
497 @retval EFI_INVALID_PARAMETER The mapping is invalid.\r
498**/\r
499EFI_STATUS\r
500GetDeviceInfoFromMapping (\r
501 IN VOID *Mapping,\r
502 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
503 OUT UINTN *NumberOfPages\r
504 );\r
505\r
506/**\r
507 Initialize DMA protection.\r
508**/\r
509VOID\r
510InitializeDmaProtection (\r
511 VOID\r
512 );\r
513\r
514/**\r
515 Allocate zero pages.\r
516\r
517 @param[in] Pages the number of pages.\r
518\r
519 @return the page address.\r
520 @retval NULL No resource to allocate pages.\r
521**/\r
522VOID *\r
523EFIAPI\r
524AllocateZeroPages (\r
525 IN UINTN Pages\r
526 );\r
527\r
4ad5f597
JY
528/**\r
529 Flush VTD page table and context table memory.\r
530\r
531 This action is to make sure the IOMMU engine can get final data in memory.\r
532\r
533 @param[in] VtdIndex The index used to identify a VTd engine.\r
534 @param[in] Base The base address of memory to be flushed.\r
535 @param[in] Size The size of memory in bytes to be flushed.\r
536**/\r
537VOID\r
538FlushPageTableMemory (\r
539 IN UINTN VtdIndex,\r
540 IN UINTN Base,\r
541 IN UINTN Size\r
542 );\r
543\r
f77d35c7
JY
544/**\r
545 Get PCI device information from DMAR DevScopeEntry.\r
546\r
547 @param[in] Segment The segment number.\r
548 @param[in] DmarDevScopeEntry DMAR DevScopeEntry\r
549 @param[out] Bus The bus number.\r
550 @param[out] Device The device number.\r
551 @param[out] Function The function number.\r
552\r
553 @retval EFI_SUCCESS The PCI device information is returned.\r
554**/\r
555EFI_STATUS\r
556GetPciBusDeviceFunction (\r
557 IN UINT16 Segment,\r
558 IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry,\r
559 OUT UINT8 *Bus,\r
560 OUT UINT8 *Device,\r
561 OUT UINT8 *Function\r
562 );\r
563\r
c049fc99 564#endif\r