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