]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c
IntelSiliconPkg IntelVTdDxe: Fix incorrect code to clear VTd error
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdPmrPei / IntelVTdPmr.c
... / ...
CommitLineData
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 <IndustryStandard/Vtd.h>\r
21#include <Ppi/VtdInfo.h>\r
22\r
23#include "IntelVTdPmrPei.h"\r
24\r
25/**\r
26 Get protected low memory alignment.\r
27\r
28 @param HostAddressWidth The host address width.\r
29 @param VtdUnitBaseAddress The base address of the VTd engine.\r
30\r
31 @return protected low memory alignment.\r
32**/\r
33UINT32\r
34GetPlmrAlignment (\r
35 IN UINT8 HostAddressWidth,\r
36 IN UINTN VtdUnitBaseAddress\r
37 )\r
38{\r
39 UINT32 Data32;\r
40\r
41 MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG, 0xFFFFFFFF);\r
42 Data32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG);\r
43 Data32 = ~Data32 + 1;\r
44\r
45 return Data32;\r
46}\r
47\r
48/**\r
49 Get protected high memory alignment.\r
50\r
51 @param HostAddressWidth The host address width.\r
52 @param VtdUnitBaseAddress The base address of the VTd engine.\r
53\r
54 @return protected high memory alignment.\r
55**/\r
56UINT64\r
57GetPhmrAlignment (\r
58 IN UINT8 HostAddressWidth,\r
59 IN UINTN VtdUnitBaseAddress\r
60 )\r
61{\r
62 UINT64 Data64;\r
63\r
64 MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, 0xFFFFFFFFFFFFFFFF);\r
65 Data64 = MmioRead64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG);\r
66 Data64 = ~Data64 + 1;\r
67 Data64 = Data64 & (LShiftU64 (1, HostAddressWidth) - 1);\r
68\r
69 return Data64;\r
70}\r
71\r
72/**\r
73 Get protected low memory alignment.\r
74\r
75 @param VTdInfo The VTd engine context information.\r
76 @param EngineMask The mask of the VTd engine to be accessed.\r
77\r
78 @return protected low memory alignment.\r
79**/\r
80UINT32\r
81GetLowMemoryAlignment (\r
82 IN VTD_INFO *VTdInfo,\r
83 IN UINT64 EngineMask\r
84 )\r
85{\r
86 UINTN Index;\r
87 UINT32 Alignment;\r
88 UINT32 FinalAlignment;\r
89\r
90 FinalAlignment = 0;\r
91 for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {\r
92 if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
93 continue;\r
94 }\r
95 Alignment = GetPlmrAlignment (VTdInfo->HostAddressWidth, (UINTN)VTdInfo->VTdEngineAddress[Index]);\r
96 if (FinalAlignment < Alignment) {\r
97 FinalAlignment = Alignment;\r
98 }\r
99 }\r
100 return FinalAlignment;\r
101}\r
102\r
103/**\r
104 Get protected high memory alignment.\r
105\r
106 @param VTdInfo The VTd engine context information.\r
107 @param EngineMask The mask of the VTd engine to be accessed.\r
108\r
109 @return protected high memory alignment.\r
110**/\r
111UINT64\r
112GetHighMemoryAlignment (\r
113 IN VTD_INFO *VTdInfo,\r
114 IN UINT64 EngineMask\r
115 )\r
116{\r
117 UINTN Index;\r
118 UINT64 Alignment;\r
119 UINT64 FinalAlignment;\r
120\r
121 FinalAlignment = 0;\r
122 for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {\r
123 if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
124 continue;\r
125 }\r
126 Alignment = GetPhmrAlignment (VTdInfo->HostAddressWidth, (UINTN)VTdInfo->VTdEngineAddress[Index]);\r
127 if (FinalAlignment < Alignment) {\r
128 FinalAlignment = Alignment;\r
129 }\r
130 }\r
131 return FinalAlignment;\r
132}\r
133\r
134/**\r
135 Enable PMR in the VTd engine.\r
136\r
137 @param VtdUnitBaseAddress The base address of the VTd engine.\r
138\r
139 @retval EFI_SUCCESS The PMR is enabled.\r
140 @retval EFI_UNSUPPORTED The PMR is not supported.\r
141**/\r
142EFI_STATUS\r
143EnablePmr (\r
144 IN UINTN VtdUnitBaseAddress\r
145 )\r
146{\r
147 UINT32 Reg32;\r
148 VTD_CAP_REG CapReg;\r
149\r
150 DEBUG ((DEBUG_INFO, "EnablePmr - %x\n", VtdUnitBaseAddress));\r
151\r
152 CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);\r
153 if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {\r
154 return EFI_UNSUPPORTED;\r
155 }\r
156\r
157 Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);\r
158 if (Reg32 == 0xFFFFFFFF) {\r
159 DEBUG ((DEBUG_ERROR, "R_PMEN_ENABLE_REG - 0x%x\n", Reg32));\r
160 ASSERT(FALSE);\r
161 }\r
162\r
163 if ((Reg32 & BIT0) == 0) {\r
164 MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, BIT31);\r
165 do {\r
166 Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);\r
167 } while((Reg32 & BIT0) == 0);\r
168 }\r
169\r
170 DEBUG ((DEBUG_INFO, "EnablePmr - Done\n"));\r
171\r
172 return EFI_SUCCESS;\r
173}\r
174\r
175/**\r
176 Disable PMR in the VTd engine.\r
177\r
178 @param VtdUnitBaseAddress The base address of the VTd engine.\r
179\r
180 @retval EFI_SUCCESS The PMR is disabled.\r
181 @retval EFI_UNSUPPORTED The PMR is not supported.\r
182**/\r
183EFI_STATUS\r
184DisablePmr (\r
185 IN UINTN VtdUnitBaseAddress\r
186 )\r
187{\r
188 UINT32 Reg32;\r
189 VTD_CAP_REG CapReg;\r
190\r
191 CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);\r
192 if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {\r
193 return EFI_UNSUPPORTED;\r
194 }\r
195\r
196 Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);\r
197 if (Reg32 == 0xFFFFFFFF) {\r
198 DEBUG ((DEBUG_ERROR, "R_PMEN_ENABLE_REG - 0x%x\n", Reg32));\r
199 ASSERT(FALSE);\r
200 }\r
201\r
202 if ((Reg32 & BIT0) != 0) {\r
203 MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, 0x0);\r
204 do {\r
205 Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);\r
206 } while((Reg32 & BIT0) != 0);\r
207 }\r
208\r
209 return EFI_SUCCESS;\r
210}\r
211\r
212/**\r
213 Set PMR region in the VTd engine.\r
214\r
215 @param HostAddressWidth The host address width.\r
216 @param VtdUnitBaseAddress The base address of the VTd engine.\r
217 @param LowMemoryBase The protected low memory region base.\r
218 @param LowMemoryLength The protected low memory region length.\r
219 @param HighMemoryBase The protected high memory region base.\r
220 @param HighMemoryLength The protected high memory region length.\r
221\r
222 @retval EFI_SUCCESS The PMR is set to protected region.\r
223 @retval EFI_UNSUPPORTED The PMR is not supported.\r
224**/\r
225EFI_STATUS\r
226SetPmrRegion (\r
227 IN UINT8 HostAddressWidth,\r
228 IN UINTN VtdUnitBaseAddress,\r
229 IN UINT32 LowMemoryBase,\r
230 IN UINT32 LowMemoryLength,\r
231 IN UINT64 HighMemoryBase,\r
232 IN UINT64 HighMemoryLength\r
233 )\r
234{\r
235 VTD_CAP_REG CapReg;\r
236 UINT32 PlmrAlignment;\r
237 UINT64 PhmrAlignment;\r
238\r
239 DEBUG ((DEBUG_INFO, "VtdUnitBaseAddress - 0x%x\n", VtdUnitBaseAddress));\r
240\r
241 CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);\r
242 if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {\r
243 DEBUG ((DEBUG_ERROR, "PLMR/PHMR unsupported\n"));\r
244 return EFI_UNSUPPORTED;\r
245 }\r
246\r
247 PlmrAlignment = GetPlmrAlignment (HostAddressWidth, VtdUnitBaseAddress);\r
248 DEBUG ((DEBUG_INFO, "PlmrAlignment - 0x%x\n", PlmrAlignment));\r
249 PhmrAlignment = GetPhmrAlignment (HostAddressWidth, VtdUnitBaseAddress);\r
250 DEBUG ((DEBUG_INFO, "PhmrAlignment - 0x%lx\n", PhmrAlignment));\r
251\r
252 if ((LowMemoryBase != ALIGN_VALUE(LowMemoryBase, PlmrAlignment)) ||\r
253 (LowMemoryLength != ALIGN_VALUE(LowMemoryLength, PlmrAlignment)) ||\r
254 (HighMemoryBase != ALIGN_VALUE(HighMemoryBase, PhmrAlignment)) ||\r
255 (HighMemoryLength != ALIGN_VALUE(HighMemoryLength, PhmrAlignment))) {\r
256 DEBUG ((DEBUG_ERROR, "PLMR/PHMR alignment issue\n"));\r
257 return EFI_UNSUPPORTED;\r
258 }\r
259\r
260 if (LowMemoryBase == 0 && LowMemoryLength == 0) {\r
261 LowMemoryBase = 0xFFFFFFFF;\r
262 }\r
263 if (HighMemoryBase == 0 && HighMemoryLength == 0) {\r
264 HighMemoryBase = 0xFFFFFFFFFFFFFFFF;\r
265 }\r
266\r
267 MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG, LowMemoryBase);\r
268 MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_LIMITE_REG, LowMemoryBase + LowMemoryLength - 1);\r
269 DEBUG ((DEBUG_INFO, "PLMR set done\n"));\r
270 MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, HighMemoryBase);\r
271 MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_LIMITE_REG, HighMemoryBase + HighMemoryLength - 1);\r
272 DEBUG ((DEBUG_INFO, "PHMR set done\n"));\r
273\r
274 return EFI_SUCCESS;\r
275}\r
276\r
277/**\r
278 Set DMA protected region.\r
279\r
280 @param VTdInfo The VTd engine context information.\r
281 @param EngineMask The mask of the VTd engine to be accessed.\r
282 @param LowMemoryBase The protected low memory region base.\r
283 @param LowMemoryLength The protected low memory region length.\r
284 @param HighMemoryBase The protected high memory region base.\r
285 @param HighMemoryLength The protected high memory region length.\r
286\r
287 @retval EFI_SUCCESS The DMA protection is set.\r
288 @retval EFI_UNSUPPORTED The DMA protection is not set.\r
289**/\r
290EFI_STATUS\r
291SetDmaProtectedRange (\r
292 IN VTD_INFO *VTdInfo,\r
293 IN UINT64 EngineMask,\r
294 IN UINT32 LowMemoryBase,\r
295 IN UINT32 LowMemoryLength,\r
296 IN UINT64 HighMemoryBase,\r
297 IN UINT64 HighMemoryLength\r
298 )\r
299{\r
300 UINTN Index;\r
301 EFI_STATUS Status;\r
302\r
303 DEBUG ((DEBUG_INFO, "SetDmaProtectedRange(0x%lx) - [0x%x, 0x%x] [0x%lx, 0x%lx]\n", EngineMask, LowMemoryBase, LowMemoryLength, HighMemoryBase, HighMemoryLength));\r
304\r
305 for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {\r
306 if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
307 continue;\r
308 }\r
309 DisablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);\r
310 Status = SetPmrRegion (\r
311 VTdInfo->HostAddressWidth,\r
312 (UINTN)VTdInfo->VTdEngineAddress[Index],\r
313 LowMemoryBase,\r
314 LowMemoryLength,\r
315 HighMemoryBase,\r
316 HighMemoryLength\r
317 );\r
318 if (EFI_ERROR(Status)) {\r
319 return Status;\r
320 }\r
321 Status = EnablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);\r
322 if (EFI_ERROR(Status)) {\r
323 return Status;\r
324 }\r
325 }\r
326\r
327 return EFI_SUCCESS;\r
328}\r
329\r
330/**\r
331 Diable DMA protection.\r
332\r
333 @param VTdInfo The VTd engine context information.\r
334 @param EngineMask The mask of the VTd engine to be accessed.\r
335\r
336 @retval EFI_SUCCESS DMA protection is disabled.\r
337**/\r
338EFI_STATUS\r
339DisableDmaProtection (\r
340 IN VTD_INFO *VTdInfo,\r
341 IN UINT64 EngineMask\r
342 )\r
343{\r
344 UINTN Index;\r
345 EFI_STATUS Status;\r
346\r
347 DEBUG ((DEBUG_INFO, "DisableDmaProtection - 0x%lx\n", EngineMask));\r
348\r
349 for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {\r
350 DEBUG ((DEBUG_INFO, "Disabling...%d\n", Index));\r
351\r
352 if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
353 continue;\r
354 }\r
355 Status = DisablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);\r
356 if (EFI_ERROR(Status)) {\r
357 return Status;\r
358 }\r
359 }\r
360\r
361 return EFI_SUCCESS;\r
362}\r
363\r
364/**\r
365 Return if the PMR is enabled.\r
366\r
367 @param VtdUnitBaseAddress The base address of the VTd engine.\r
368\r
369 @retval TRUE PMR is enabled.\r
370 @retval FALSE PMR is disabled or unsupported.\r
371**/\r
372BOOLEAN\r
373IsPmrEnabled (\r
374 IN UINTN VtdUnitBaseAddress\r
375 )\r
376{\r
377 UINT32 Reg32;\r
378 VTD_CAP_REG CapReg;\r
379\r
380 CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);\r
381 if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {\r
382 return FALSE;\r
383 }\r
384\r
385 Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);\r
386 if ((Reg32 & BIT0) == 0) {\r
387 return FALSE;\r
388 }\r
389\r
390 return TRUE;\r
391}\r
392\r
393/**\r
394 Return the mask of the VTd engine which is enabled.\r
395\r
396 @param VTdInfo The VTd engine context information.\r
397 @param EngineMask The mask of the VTd engine to be accessed.\r
398\r
399 @return the mask of the VTd engine which is enabled.\r
400**/\r
401UINT64\r
402GetDmaProtectionEnabledEngineMask (\r
403 IN VTD_INFO *VTdInfo,\r
404 IN UINT64 EngineMask\r
405 )\r
406{\r
407 UINTN Index;\r
408 BOOLEAN Result;\r
409 UINT64 EnabledEngineMask;\r
410\r
411 DEBUG ((DEBUG_INFO, "GetDmaProtectionEnabledEngineMask - 0x%lx\n", EngineMask));\r
412\r
413 EnabledEngineMask = 0;\r
414 for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {\r
415 if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
416 continue;\r
417 }\r
418 Result = IsPmrEnabled ((UINTN)VTdInfo->VTdEngineAddress[Index]);\r
419 if (Result) {\r
420 EnabledEngineMask |= LShiftU64(1, Index);\r
421 }\r
422 }\r
423\r
424 DEBUG ((DEBUG_INFO, "EnabledEngineMask - 0x%lx\n", EnabledEngineMask));\r
425 return EnabledEngineMask;\r
426}\r