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