]> git.proxmox.com Git - mirror_edk2.git/blob - IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/VtdReg.c
IntelSiliconPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdPmrPei / VtdReg.c
1 /** @file
2
3 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
4
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <PiPei.h>
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>
18
19 #include "IntelVTdPmrPei.h"
20
21 /**
22 Flush VTD page table and context table memory.
23
24 This action is to make sure the IOMMU engine can get final data in memory.
25
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.
28 **/
29 VOID
30 FlushPageTableMemory (
31 IN UINTN Base,
32 IN UINTN Size
33 )
34 {
35 WriteBackDataCacheRange ((VOID *)Base, Size);
36 }
37
38 /**
39 Flush VTd engine write buffer.
40
41 @param VtdUnitBaseAddress The base address of the VTd engine.
42 **/
43 VOID
44 FlushWriteBuffer (
45 IN UINTN VtdUnitBaseAddress
46 )
47 {
48 UINT32 Reg32;
49 VTD_CAP_REG CapReg;
50
51 CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
52
53 if (CapReg.Bits.RWBF != 0) {
54 Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
55 MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_WBF);
56 do {
57 Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
58 } while ((Reg32 & B_GSTS_REG_WBF) != 0);
59 }
60 }
61
62 /**
63 Invalidate VTd context cache.
64
65 @param VtdUnitBaseAddress The base address of the VTd engine.
66 **/
67 EFI_STATUS
68 InvalidateContextCache (
69 IN UINTN VtdUnitBaseAddress
70 )
71 {
72 UINT64 Reg64;
73
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;
78 }
79
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);
83
84 do {
85 Reg64 = MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG);
86 } while ((Reg64 & B_CCMD_REG_ICC) != 0);
87
88 return EFI_SUCCESS;
89 }
90
91 /**
92 Invalidate VTd IOTLB.
93
94 @param VtdUnitBaseAddress The base address of the VTd engine.
95 **/
96 EFI_STATUS
97 InvalidateIOTLB (
98 IN UINTN VtdUnitBaseAddress
99 )
100 {
101 UINT64 Reg64;
102 VTD_ECAP_REG ECapReg;
103
104 ECapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_ECAP_REG);
105
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;
110 }
111
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);
115
116 do {
117 Reg64 = MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
118 } while ((Reg64 & B_IOTLB_REG_IVT) != 0);
119
120 return EFI_SUCCESS;
121 }
122
123 /**
124 Enable DMAR translation.
125
126 @param VtdUnitBaseAddress The base address of the VTd engine.
127 @param RootEntryTable The address of the VTd RootEntryTable.
128
129 @retval EFI_SUCCESS DMAR translation is enabled.
130 @retval EFI_DEVICE_ERROR DMAR translation is not enabled.
131 **/
132 EFI_STATUS
133 EnableDmar (
134 IN UINTN VtdUnitBaseAddress,
135 IN UINTN RootEntryTable
136 )
137 {
138 UINT32 Reg32;
139
140 DEBUG((DEBUG_INFO, ">>>>>>EnableDmar() for engine [%x] \n", VtdUnitBaseAddress));
141
142 DEBUG((DEBUG_INFO, "RootEntryTable 0x%x \n", RootEntryTable));
143 MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, (UINT64)(UINTN)RootEntryTable);
144
145 MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
146
147 DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
148 do {
149 Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
150 } while((Reg32 & B_GSTS_REG_RTPS) == 0);
151
152 //
153 // Init DMAr Fault Event and Data registers
154 //
155 Reg32 = MmioRead32 (VtdUnitBaseAddress + R_FEDATA_REG);
156
157 //
158 // Write Buffer Flush before invalidation
159 //
160 FlushWriteBuffer (VtdUnitBaseAddress);
161
162 //
163 // Invalidate the context cache
164 //
165 InvalidateContextCache (VtdUnitBaseAddress);
166
167 //
168 // Invalidate the IOTLB cache
169 //
170 InvalidateIOTLB (VtdUnitBaseAddress);
171
172 //
173 // Enable VTd
174 //
175 MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_TE);
176 DEBUG((DEBUG_INFO, "EnableDmar: Waiting B_GSTS_REG_TE ...\n"));
177 do {
178 Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
179 } while ((Reg32 & B_GSTS_REG_TE) == 0);
180
181 DEBUG ((DEBUG_INFO,"VTD () enabled!<<<<<<\n"));
182
183 return EFI_SUCCESS;
184 }
185
186 /**
187 Disable DMAR translation.
188
189 @param VtdUnitBaseAddress The base address of the VTd engine.
190
191 @retval EFI_SUCCESS DMAR translation is disabled.
192 @retval EFI_DEVICE_ERROR DMAR translation is not disabled.
193 **/
194 EFI_STATUS
195 DisableDmar (
196 IN UINTN VtdUnitBaseAddress
197 )
198 {
199 UINT32 Reg32;
200
201 DEBUG((DEBUG_INFO, ">>>>>>DisableDmar() for engine [%x] \n", VtdUnitBaseAddress));
202
203 //
204 // Write Buffer Flush before invalidation
205 //
206 FlushWriteBuffer (VtdUnitBaseAddress);
207
208 //
209 // Disable VTd
210 //
211 MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
212 do {
213 Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
214 } while((Reg32 & B_GSTS_REG_RTPS) == 0);
215
216 Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
217 DEBUG((DEBUG_INFO, "DisableDmar: GSTS_REG - 0x%08x\n", Reg32));
218
219 MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, 0);
220
221 DEBUG ((DEBUG_INFO,"VTD () Disabled!<<<<<<\n"));
222
223 return EFI_SUCCESS;
224 }
225
226 /**
227 Enable VTd translation table protection.
228
229 @param VTdInfo The VTd engine context information.
230 @param EngineMask The mask of the VTd engine to be accessed.
231 **/
232 VOID
233 EnableVTdTranslationProtection (
234 IN VTD_INFO *VTdInfo,
235 IN UINT64 EngineMask
236 )
237 {
238 UINTN Index;
239 VOID *RootEntryTable;
240
241 DEBUG ((DEBUG_INFO, "EnableVTdTranslationProtection - 0x%lx\n", EngineMask));
242
243 RootEntryTable = AllocatePages (1);
244 ASSERT (RootEntryTable != NULL);
245 if (RootEntryTable == NULL) {
246 DEBUG ((DEBUG_INFO, " EnableVTdTranslationProtection : OutOfResource\n"));
247 return ;
248 }
249
250 ZeroMem (RootEntryTable, EFI_PAGES_TO_SIZE(1));
251 FlushPageTableMemory ((UINTN)RootEntryTable, EFI_PAGES_TO_SIZE(1));
252
253 for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
254 if ((EngineMask & LShiftU64(1, Index)) == 0) {
255 continue;
256 }
257 EnableDmar ((UINTN)VTdInfo->VTdEngineAddress[Index], (UINTN)RootEntryTable);
258 }
259
260 return ;
261 }
262
263 /**
264 Disable VTd translation table protection.
265
266 @param VTdInfo The VTd engine context information.
267 @param EngineMask The mask of the VTd engine to be accessed.
268 **/
269 VOID
270 DisableVTdTranslationProtection (
271 IN VTD_INFO *VTdInfo,
272 IN UINT64 EngineMask
273 )
274 {
275 UINTN Index;
276
277 DEBUG ((DEBUG_INFO, "DisableVTdTranslationProtection - 0x%lx\n", EngineMask));
278
279 for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
280 if ((EngineMask & LShiftU64(1, Index)) == 0) {
281 continue;
282 }
283 DisableDmar ((UINTN)VTdInfo->VTdEngineAddress[Index]);
284 }
285
286 return ;
287 }