3 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Library/BaseLib.h>
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/IoLib.h>
13 #include <Library/DebugLib.h>
14 #include <Library/MemoryAllocationLib.h>
15 #include <Library/CacheMaintenanceLib.h>
16 #include <IndustryStandard/Vtd.h>
17 #include <Ppi/VtdInfo.h>
19 #include "IntelVTdPmrPei.h"
22 Flush VTD page table and context table memory.
24 This action is to make sure the IOMMU engine can get final data in memory.
26 @param[in] Base The base address of memory to be flushed.
27 @param[in] Size The size of memory in bytes to be flushed.
30 FlushPageTableMemory (
35 WriteBackDataCacheRange ((VOID
*)Base
, Size
);
39 Flush VTd engine write buffer.
41 @param VtdUnitBaseAddress The base address of the VTd engine.
45 IN UINTN VtdUnitBaseAddress
51 CapReg
.Uint64
= MmioRead64 (VtdUnitBaseAddress
+ R_CAP_REG
);
53 if (CapReg
.Bits
.RWBF
!= 0) {
54 Reg32
= MmioRead32 (VtdUnitBaseAddress
+ R_GSTS_REG
);
55 MmioWrite32 (VtdUnitBaseAddress
+ R_GCMD_REG
, Reg32
| B_GMCD_REG_WBF
);
57 Reg32
= MmioRead32 (VtdUnitBaseAddress
+ R_GSTS_REG
);
58 } while ((Reg32
& B_GSTS_REG_WBF
) != 0);
63 Invalidate VTd context cache.
65 @param VtdUnitBaseAddress The base address of the VTd engine.
68 InvalidateContextCache (
69 IN UINTN VtdUnitBaseAddress
74 Reg64
= MmioRead64 (VtdUnitBaseAddress
+ R_CCMD_REG
);
75 if ((Reg64
& B_CCMD_REG_ICC
) != 0) {
76 DEBUG ((DEBUG_ERROR
,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC is set for VTD(%x)\n",VtdUnitBaseAddress
));
77 return EFI_DEVICE_ERROR
;
80 Reg64
&= ((~B_CCMD_REG_ICC
) & (~B_CCMD_REG_CIRG_MASK
));
81 Reg64
|= (B_CCMD_REG_ICC
| V_CCMD_REG_CIRG_GLOBAL
);
82 MmioWrite64 (VtdUnitBaseAddress
+ R_CCMD_REG
, Reg64
);
85 Reg64
= MmioRead64 (VtdUnitBaseAddress
+ R_CCMD_REG
);
86 } while ((Reg64
& B_CCMD_REG_ICC
) != 0);
94 @param VtdUnitBaseAddress The base address of the VTd engine.
98 IN UINTN VtdUnitBaseAddress
102 VTD_ECAP_REG ECapReg
;
104 ECapReg
.Uint64
= MmioRead64 (VtdUnitBaseAddress
+ R_ECAP_REG
);
106 Reg64
= MmioRead64 (VtdUnitBaseAddress
+ (ECapReg
.Bits
.IRO
* 16) + R_IOTLB_REG
);
107 if ((Reg64
& B_IOTLB_REG_IVT
) != 0) {
108 DEBUG ((DEBUG_ERROR
,"ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set for VTD(%x)\n", VtdUnitBaseAddress
));
109 return EFI_DEVICE_ERROR
;
112 Reg64
&= ((~B_IOTLB_REG_IVT
) & (~B_IOTLB_REG_IIRG_MASK
));
113 Reg64
|= (B_IOTLB_REG_IVT
| V_IOTLB_REG_IIRG_GLOBAL
);
114 MmioWrite64 (VtdUnitBaseAddress
+ (ECapReg
.Bits
.IRO
* 16) + R_IOTLB_REG
, Reg64
);
117 Reg64
= MmioRead64 (VtdUnitBaseAddress
+ (ECapReg
.Bits
.IRO
* 16) + R_IOTLB_REG
);
118 } while ((Reg64
& B_IOTLB_REG_IVT
) != 0);
124 Enable DMAR translation.
126 @param VtdUnitBaseAddress The base address of the VTd engine.
127 @param RootEntryTable The address of the VTd RootEntryTable.
129 @retval EFI_SUCCESS DMAR translation is enabled.
130 @retval EFI_DEVICE_ERROR DMAR translation is not enabled.
134 IN UINTN VtdUnitBaseAddress
,
135 IN UINTN RootEntryTable
140 DEBUG((DEBUG_INFO
, ">>>>>>EnableDmar() for engine [%x] \n", VtdUnitBaseAddress
));
142 DEBUG((DEBUG_INFO
, "RootEntryTable 0x%x \n", RootEntryTable
));
143 MmioWrite64 (VtdUnitBaseAddress
+ R_RTADDR_REG
, (UINT64
)(UINTN
)RootEntryTable
);
145 MmioWrite32 (VtdUnitBaseAddress
+ R_GCMD_REG
, B_GMCD_REG_SRTP
);
147 DEBUG((DEBUG_INFO
, "EnableDmar: waiting for RTPS bit to be set... \n"));
149 Reg32
= MmioRead32 (VtdUnitBaseAddress
+ R_GSTS_REG
);
150 } while((Reg32
& B_GSTS_REG_RTPS
) == 0);
153 // Init DMAr Fault Event and Data registers
155 Reg32
= MmioRead32 (VtdUnitBaseAddress
+ R_FEDATA_REG
);
158 // Write Buffer Flush before invalidation
160 FlushWriteBuffer (VtdUnitBaseAddress
);
163 // Invalidate the context cache
165 InvalidateContextCache (VtdUnitBaseAddress
);
168 // Invalidate the IOTLB cache
170 InvalidateIOTLB (VtdUnitBaseAddress
);
175 MmioWrite32 (VtdUnitBaseAddress
+ R_GCMD_REG
, B_GMCD_REG_TE
);
176 DEBUG((DEBUG_INFO
, "EnableDmar: Waiting B_GSTS_REG_TE ...\n"));
178 Reg32
= MmioRead32 (VtdUnitBaseAddress
+ R_GSTS_REG
);
179 } while ((Reg32
& B_GSTS_REG_TE
) == 0);
181 DEBUG ((DEBUG_INFO
,"VTD () enabled!<<<<<<\n"));
187 Disable DMAR translation.
189 @param VtdUnitBaseAddress The base address of the VTd engine.
191 @retval EFI_SUCCESS DMAR translation is disabled.
192 @retval EFI_DEVICE_ERROR DMAR translation is not disabled.
196 IN UINTN VtdUnitBaseAddress
201 DEBUG((DEBUG_INFO
, ">>>>>>DisableDmar() for engine [%x] \n", VtdUnitBaseAddress
));
204 // Write Buffer Flush before invalidation
206 FlushWriteBuffer (VtdUnitBaseAddress
);
211 MmioWrite32 (VtdUnitBaseAddress
+ R_GCMD_REG
, B_GMCD_REG_SRTP
);
213 Reg32
= MmioRead32 (VtdUnitBaseAddress
+ R_GSTS_REG
);
214 } while((Reg32
& B_GSTS_REG_RTPS
) == 0);
216 Reg32
= MmioRead32 (VtdUnitBaseAddress
+ R_GSTS_REG
);
217 DEBUG((DEBUG_INFO
, "DisableDmar: GSTS_REG - 0x%08x\n", Reg32
));
219 MmioWrite64 (VtdUnitBaseAddress
+ R_RTADDR_REG
, 0);
221 DEBUG ((DEBUG_INFO
,"VTD () Disabled!<<<<<<\n"));
227 Enable VTd translation table protection.
229 @param VTdInfo The VTd engine context information.
230 @param EngineMask The mask of the VTd engine to be accessed.
233 EnableVTdTranslationProtection (
234 IN VTD_INFO
*VTdInfo
,
239 VOID
*RootEntryTable
;
241 DEBUG ((DEBUG_INFO
, "EnableVTdTranslationProtection - 0x%lx\n", EngineMask
));
243 RootEntryTable
= AllocatePages (1);
244 ASSERT (RootEntryTable
!= NULL
);
245 if (RootEntryTable
== NULL
) {
246 DEBUG ((DEBUG_INFO
, " EnableVTdTranslationProtection : OutOfResource\n"));
250 ZeroMem (RootEntryTable
, EFI_PAGES_TO_SIZE(1));
251 FlushPageTableMemory ((UINTN
)RootEntryTable
, EFI_PAGES_TO_SIZE(1));
253 for (Index
= 0; Index
< VTdInfo
->VTdEngineCount
; Index
++) {
254 if ((EngineMask
& LShiftU64(1, Index
)) == 0) {
257 EnableDmar ((UINTN
)VTdInfo
->VTdEngineAddress
[Index
], (UINTN
)RootEntryTable
);
264 Disable VTd translation table protection.
266 @param VTdInfo The VTd engine context information.
267 @param EngineMask The mask of the VTd engine to be accessed.
270 DisableVTdTranslationProtection (
271 IN VTD_INFO
*VTdInfo
,
277 DEBUG ((DEBUG_INFO
, "DisableVTdTranslationProtection - 0x%lx\n", EngineMask
));
279 for (Index
= 0; Index
< VTdInfo
->VTdEngineCount
; Index
++) {
280 if ((EngineMask
& LShiftU64(1, Index
)) == 0) {
283 DisableDmar ((UINTN
)VTdInfo
->VTdEngineAddress
[Index
]);