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