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