IntelSiliconPkg/VtdPmrPei: Add premem support.
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdPmrPei / IntelVTdPmr.c
CommitLineData
3f5ed3fa
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 <IndustryStandard/Vtd.h>\r
4084ccfa 21#include <Ppi/VtdInfo.h>\r
3f5ed3fa
JY
22\r
23#include "IntelVTdPmrPei.h"\r
24\r
3f5ed3fa
JY
25/**\r
26 Get protected low memory alignment.\r
27\r
a1e7cd0b 28 @param HostAddressWidth The host address width.\r
3f5ed3fa
JY
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
a1e7cd0b 35 IN UINT8 HostAddressWidth,\r
3f5ed3fa
JY
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
a1e7cd0b 51 @param HostAddressWidth The host address width.\r
3f5ed3fa
JY
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
a1e7cd0b 58 IN UINT8 HostAddressWidth,\r
3f5ed3fa
JY
59 IN UINTN VtdUnitBaseAddress\r
60 )\r
61{\r
62 UINT64 Data64;\r
3f5ed3fa
JY
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
a1e7cd0b 75 @param VTdInfo The VTd engine context information.\r
8e9da4ba
JY
76 @param EngineMask The mask of the VTd engine to be accessed.\r
77\r
3f5ed3fa
JY
78 @return protected low memory alignment.\r
79**/\r
80UINT32\r
81GetLowMemoryAlignment (\r
a1e7cd0b 82 IN VTD_INFO *VTdInfo,\r
8e9da4ba 83 IN UINT64 EngineMask\r
3f5ed3fa
JY
84 )\r
85{\r
86 UINTN Index;\r
87 UINT32 Alignment;\r
88 UINT32 FinalAlignment;\r
89\r
90 FinalAlignment = 0;\r
a1e7cd0b 91 for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {\r
8e9da4ba
JY
92 if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
93 continue;\r
94 }\r
a1e7cd0b 95 Alignment = GetPlmrAlignment (VTdInfo->HostAddressWidth, (UINTN)VTdInfo->VTdEngineAddress[Index]);\r
3f5ed3fa
JY
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
a1e7cd0b 106 @param VTdInfo The VTd engine context information.\r
8e9da4ba
JY
107 @param EngineMask The mask of the VTd engine to be accessed.\r
108\r
3f5ed3fa
JY
109 @return protected high memory alignment.\r
110**/\r
111UINT64\r
112GetHighMemoryAlignment (\r
a1e7cd0b 113 IN VTD_INFO *VTdInfo,\r
8e9da4ba 114 IN UINT64 EngineMask\r
3f5ed3fa
JY
115 )\r
116{\r
117 UINTN Index;\r
118 UINT64 Alignment;\r
119 UINT64 FinalAlignment;\r
120\r
121 FinalAlignment = 0;\r
a1e7cd0b 122 for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {\r
8e9da4ba
JY
123 if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
124 continue;\r
125 }\r
a1e7cd0b 126 Alignment = GetPhmrAlignment (VTdInfo->HostAddressWidth, (UINTN)VTdInfo->VTdEngineAddress[Index]);\r
3f5ed3fa
JY
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
a1e7cd0b
JY
150 DEBUG ((DEBUG_INFO, "EnablePmr - %x\n", VtdUnitBaseAddress));\r
151\r
3f5ed3fa
JY
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
a1e7cd0b
JY
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
3f5ed3fa
JY
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
a1e7cd0b
JY
170 DEBUG ((DEBUG_INFO, "EnablePmr - Done\n"));\r
171\r
3f5ed3fa
JY
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
a1e7cd0b
JY
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
3f5ed3fa
JY
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
a1e7cd0b 215 @param HostAddressWidth The host address width.\r
3f5ed3fa
JY
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
a1e7cd0b 227 IN UINT8 HostAddressWidth,\r
3f5ed3fa
JY
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
a1e7cd0b 247 PlmrAlignment = GetPlmrAlignment (HostAddressWidth, VtdUnitBaseAddress);\r
3f5ed3fa 248 DEBUG ((DEBUG_INFO, "PlmrAlignment - 0x%x\n", PlmrAlignment));\r
a1e7cd0b 249 PhmrAlignment = GetPhmrAlignment (HostAddressWidth, VtdUnitBaseAddress);\r
3f5ed3fa
JY
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
a1e7cd0b 269 DEBUG ((DEBUG_INFO, "PLMR set done\n"));\r
3f5ed3fa
JY
270 MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, HighMemoryBase);\r
271 MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_LIMITE_REG, HighMemoryBase + HighMemoryLength - 1);\r
a1e7cd0b 272 DEBUG ((DEBUG_INFO, "PHMR set done\n"));\r
3f5ed3fa
JY
273\r
274 return EFI_SUCCESS;\r
275}\r
276\r
277/**\r
278 Set DMA protected region.\r
279\r
a1e7cd0b 280 @param VTdInfo The VTd engine context information.\r
8e9da4ba 281 @param EngineMask The mask of the VTd engine to be accessed.\r
3f5ed3fa
JY
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
a1e7cd0b 292 IN VTD_INFO *VTdInfo,\r
8e9da4ba 293 IN UINT64 EngineMask,\r
3f5ed3fa
JY
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
8e9da4ba 303 DEBUG ((DEBUG_INFO, "SetDmaProtectedRange(0x%lx) - [0x%x, 0x%x] [0x%lx, 0x%lx]\n", EngineMask, LowMemoryBase, LowMemoryLength, HighMemoryBase, HighMemoryLength));\r
3f5ed3fa 304\r
a1e7cd0b 305 for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {\r
8e9da4ba
JY
306 if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
307 continue;\r
308 }\r
a1e7cd0b 309 DisablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);\r
3f5ed3fa 310 Status = SetPmrRegion (\r
a1e7cd0b
JY
311 VTdInfo->HostAddressWidth,\r
312 (UINTN)VTdInfo->VTdEngineAddress[Index],\r
3f5ed3fa
JY
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
a1e7cd0b 321 Status = EnablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);\r
3f5ed3fa
JY
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
a1e7cd0b 333 @param VTdInfo The VTd engine context information.\r
8e9da4ba
JY
334 @param EngineMask The mask of the VTd engine to be accessed.\r
335\r
a1e7cd0b 336 @retval EFI_SUCCESS DMA protection is disabled.\r
3f5ed3fa
JY
337**/\r
338EFI_STATUS\r
339DisableDmaProtection (\r
a1e7cd0b 340 IN VTD_INFO *VTdInfo,\r
8e9da4ba 341 IN UINT64 EngineMask\r
3f5ed3fa
JY
342 )\r
343{\r
344 UINTN Index;\r
345 EFI_STATUS Status;\r
346\r
a1e7cd0b
JY
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
3f5ed3fa 351\r
8e9da4ba
JY
352 if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
353 continue;\r
354 }\r
a1e7cd0b 355 Status = DisablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);\r
3f5ed3fa
JY
356 if (EFI_ERROR(Status)) {\r
357 return Status;\r
358 }\r
359 }\r
360\r
361 return EFI_SUCCESS;\r
362}\r
a1e7cd0b
JY
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