IntelSiliconPkg/IntelVTdPmrPei: Parse RMRR table.
[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 extern VTD_INFO *mVTdInfo;
26
27 /**
28 Get protected low memory alignment.
29
30 @param VtdUnitBaseAddress The base address of the VTd engine.
31
32 @return protected low memory alignment.
33 **/
34 UINT32
35 GetPlmrAlignment (
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 VtdUnitBaseAddress The base address of the VTd engine.
52
53 @return protected high memory alignment.
54 **/
55 UINT64
56 GetPhmrAlignment (
57 IN UINTN VtdUnitBaseAddress
58 )
59 {
60 UINT64 Data64;
61 UINT8 HostAddressWidth;
62
63 HostAddressWidth = mVTdInfo->HostAddressWidth;
64
65 MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, 0xFFFFFFFFFFFFFFFF);
66 Data64 = MmioRead64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG);
67 Data64 = ~Data64 + 1;
68 Data64 = Data64 & (LShiftU64 (1, HostAddressWidth) - 1);
69
70 return Data64;
71 }
72
73 /**
74 Get protected low memory alignment.
75
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 UINT64 EngineMask
83 )
84 {
85 UINTN Index;
86 UINT32 Alignment;
87 UINT32 FinalAlignment;
88
89 FinalAlignment = 0;
90 for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
91 if ((EngineMask & LShiftU64(1, Index)) == 0) {
92 continue;
93 }
94 Alignment = GetPlmrAlignment ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
95 if (FinalAlignment < Alignment) {
96 FinalAlignment = Alignment;
97 }
98 }
99 return FinalAlignment;
100 }
101
102 /**
103 Get protected high memory alignment.
104
105 @param EngineMask The mask of the VTd engine to be accessed.
106
107 @return protected high memory alignment.
108 **/
109 UINT64
110 GetHighMemoryAlignment (
111 IN UINT64 EngineMask
112 )
113 {
114 UINTN Index;
115 UINT64 Alignment;
116 UINT64 FinalAlignment;
117
118 FinalAlignment = 0;
119 for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
120 if ((EngineMask & LShiftU64(1, Index)) == 0) {
121 continue;
122 }
123 Alignment = GetPhmrAlignment ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
124 if (FinalAlignment < Alignment) {
125 FinalAlignment = Alignment;
126 }
127 }
128 return FinalAlignment;
129 }
130
131 /**
132 Enable PMR in the VTd engine.
133
134 @param VtdUnitBaseAddress The base address of the VTd engine.
135
136 @retval EFI_SUCCESS The PMR is enabled.
137 @retval EFI_UNSUPPORTED The PMR is not supported.
138 **/
139 EFI_STATUS
140 EnablePmr (
141 IN UINTN VtdUnitBaseAddress
142 )
143 {
144 UINT32 Reg32;
145 VTD_CAP_REG CapReg;
146
147 CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
148 if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {
149 return EFI_UNSUPPORTED;
150 }
151
152 Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
153 if ((Reg32 & BIT0) == 0) {
154 MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, BIT31);
155 do {
156 Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
157 } while((Reg32 & BIT0) == 0);
158 }
159
160 return EFI_SUCCESS;
161 }
162
163 /**
164 Disable PMR in the VTd engine.
165
166 @param VtdUnitBaseAddress The base address of the VTd engine.
167
168 @retval EFI_SUCCESS The PMR is disabled.
169 @retval EFI_UNSUPPORTED The PMR is not supported.
170 **/
171 EFI_STATUS
172 DisablePmr (
173 IN UINTN VtdUnitBaseAddress
174 )
175 {
176 UINT32 Reg32;
177 VTD_CAP_REG CapReg;
178
179 CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
180 if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {
181 return EFI_UNSUPPORTED;
182 }
183
184 Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
185 if ((Reg32 & BIT0) != 0) {
186 MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, 0x0);
187 do {
188 Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
189 } while((Reg32 & BIT0) != 0);
190 }
191
192 return EFI_SUCCESS;
193 }
194
195 /**
196 Set PMR region in the VTd engine.
197
198 @param VtdUnitBaseAddress The base address of the VTd engine.
199 @param LowMemoryBase The protected low memory region base.
200 @param LowMemoryLength The protected low memory region length.
201 @param HighMemoryBase The protected high memory region base.
202 @param HighMemoryLength The protected high memory region length.
203
204 @retval EFI_SUCCESS The PMR is set to protected region.
205 @retval EFI_UNSUPPORTED The PMR is not supported.
206 **/
207 EFI_STATUS
208 SetPmrRegion (
209 IN UINTN VtdUnitBaseAddress,
210 IN UINT32 LowMemoryBase,
211 IN UINT32 LowMemoryLength,
212 IN UINT64 HighMemoryBase,
213 IN UINT64 HighMemoryLength
214 )
215 {
216 VTD_CAP_REG CapReg;
217 UINT32 PlmrAlignment;
218 UINT64 PhmrAlignment;
219
220 DEBUG ((DEBUG_INFO, "VtdUnitBaseAddress - 0x%x\n", VtdUnitBaseAddress));
221
222 CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
223 if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {
224 DEBUG ((DEBUG_ERROR, "PLMR/PHMR unsupported\n"));
225 return EFI_UNSUPPORTED;
226 }
227
228 PlmrAlignment = GetPlmrAlignment (VtdUnitBaseAddress);
229 DEBUG ((DEBUG_INFO, "PlmrAlignment - 0x%x\n", PlmrAlignment));
230 PhmrAlignment = GetPhmrAlignment (VtdUnitBaseAddress);
231 DEBUG ((DEBUG_INFO, "PhmrAlignment - 0x%lx\n", PhmrAlignment));
232
233 if ((LowMemoryBase != ALIGN_VALUE(LowMemoryBase, PlmrAlignment)) ||
234 (LowMemoryLength != ALIGN_VALUE(LowMemoryLength, PlmrAlignment)) ||
235 (HighMemoryBase != ALIGN_VALUE(HighMemoryBase, PhmrAlignment)) ||
236 (HighMemoryLength != ALIGN_VALUE(HighMemoryLength, PhmrAlignment))) {
237 DEBUG ((DEBUG_ERROR, "PLMR/PHMR alignment issue\n"));
238 return EFI_UNSUPPORTED;
239 }
240
241 if (LowMemoryBase == 0 && LowMemoryLength == 0) {
242 LowMemoryBase = 0xFFFFFFFF;
243 }
244 if (HighMemoryBase == 0 && HighMemoryLength == 0) {
245 HighMemoryBase = 0xFFFFFFFFFFFFFFFF;
246 }
247
248 MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG, LowMemoryBase);
249 MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_LIMITE_REG, LowMemoryBase + LowMemoryLength - 1);
250 MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, HighMemoryBase);
251 MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_LIMITE_REG, HighMemoryBase + HighMemoryLength - 1);
252
253 return EFI_SUCCESS;
254 }
255
256 /**
257 Set DMA protected region.
258
259 @param EngineMask The mask of the VTd engine to be accessed.
260 @param LowMemoryBase The protected low memory region base.
261 @param LowMemoryLength The protected low memory region length.
262 @param HighMemoryBase The protected high memory region base.
263 @param HighMemoryLength The protected high memory region length.
264
265 @retval EFI_SUCCESS The DMA protection is set.
266 @retval EFI_UNSUPPORTED The DMA protection is not set.
267 **/
268 EFI_STATUS
269 SetDmaProtectedRange (
270 IN UINT64 EngineMask,
271 IN UINT32 LowMemoryBase,
272 IN UINT32 LowMemoryLength,
273 IN UINT64 HighMemoryBase,
274 IN UINT64 HighMemoryLength
275 )
276 {
277 UINTN Index;
278 EFI_STATUS Status;
279
280 DEBUG ((DEBUG_INFO, "SetDmaProtectedRange(0x%lx) - [0x%x, 0x%x] [0x%lx, 0x%lx]\n", EngineMask, LowMemoryBase, LowMemoryLength, HighMemoryBase, HighMemoryLength));
281
282 for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
283 if ((EngineMask & LShiftU64(1, Index)) == 0) {
284 continue;
285 }
286 DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
287 Status = SetPmrRegion (
288 (UINTN)mVTdInfo->VTdEngineAddress[Index],
289 LowMemoryBase,
290 LowMemoryLength,
291 HighMemoryBase,
292 HighMemoryLength
293 );
294 if (EFI_ERROR(Status)) {
295 return Status;
296 }
297 Status = EnablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
298 if (EFI_ERROR(Status)) {
299 return Status;
300 }
301 }
302
303 return EFI_SUCCESS;
304 }
305
306 /**
307 Diable DMA protection.
308
309 @param EngineMask The mask of the VTd engine to be accessed.
310
311 @retval DMA protection is disabled.
312 **/
313 EFI_STATUS
314 DisableDmaProtection (
315 IN UINT64 EngineMask
316 )
317 {
318 UINTN Index;
319 EFI_STATUS Status;
320
321 DEBUG ((DEBUG_INFO, "DisableDmaProtection\n"));
322
323 for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
324 if ((EngineMask & LShiftU64(1, Index)) == 0) {
325 continue;
326 }
327 Status = DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
328 if (EFI_ERROR(Status)) {
329 return Status;
330 }
331 }
332
333 return EFI_SUCCESS;
334 }