]> git.proxmox.com Git - mirror_edk2.git/blame - IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
IntelSiliconPkg IntelVTdPmrPei: Install IOMMU PPI for pre-memory phase
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdPmrPei / IntelVTdPmrPei.c
CommitLineData
3f5ed3fa
JY
1/** @file\r
2\r
e8097a74 3 Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>\r
3f5ed3fa
JY
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 <Uefi.h>\r
16#include <PiPei.h>\r
17#include <Library/BaseLib.h>\r
18#include <Library/BaseMemoryLib.h>\r
19#include <Library/MemoryAllocationLib.h>\r
20#include <Library/IoLib.h>\r
21#include <Library/DebugLib.h>\r
22#include <Library/PeiServicesLib.h>\r
23#include <Library/HobLib.h>\r
24#include <IndustryStandard/Vtd.h>\r
25#include <Ppi/IoMmu.h>\r
4084ccfa 26#include <Ppi/VtdInfo.h>\r
a1e7cd0b 27#include <Ppi/MemoryDiscovered.h>\r
fc8be1ad 28#include <Ppi/EndOfPeiPhase.h>\r
3f5ed3fa
JY
29\r
30#include "IntelVTdPmrPei.h"\r
31\r
32#define TOTAL_DMA_BUFFER_SIZE SIZE_4MB\r
fc8be1ad 33#define TOTAL_DMA_BUFFER_SIZE_S3 SIZE_1MB\r
3f5ed3fa 34\r
a1e7cd0b
JY
35EFI_GUID mVTdInfoGuid = {\r
36 0x222f5e30, 0x5cd, 0x49c6, { 0x8a, 0xc, 0x36, 0xd6, 0x58, 0x41, 0xe0, 0x82 }\r
37};\r
38\r
39EFI_GUID mDmaBufferInfoGuid = {\r
40 0x7b624ec7, 0xfb67, 0x4f9c, { 0xb6, 0xb0, 0x4d, 0xfa, 0x9c, 0x88, 0x20, 0x39 }\r
41};\r
42\r
43typedef struct {\r
44 UINTN DmaBufferBase;\r
45 UINTN DmaBufferSize;\r
46 UINTN DmaBufferCurrentTop;\r
47 UINTN DmaBufferCurrentBottom;\r
48} DMA_BUFFER_INFO;\r
3f5ed3fa
JY
49\r
50#define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P')\r
51typedef struct {\r
52 UINT32 Signature;\r
53 EDKII_IOMMU_OPERATION Operation;\r
54 UINTN NumberOfBytes;\r
55 EFI_PHYSICAL_ADDRESS HostAddress;\r
56 EFI_PHYSICAL_ADDRESS DeviceAddress;\r
57} MAP_INFO;\r
58\r
59/**\r
60\r
61 PEI Memory Layout:\r
62\r
b2725f57 63 +------------------+ <=============== PHMR.Limit (+ alignment) (1 << (HostAddressWidth + 1))\r
8e9da4ba
JY
64 | Mem Resource |\r
65 | |\r
66\r
3f5ed3fa
JY
67 +------------------+ <------- EfiMemoryTop\r
68 | PEI allocated |\r
8e9da4ba 69 =========== +==================+ <=============== PHMR.Base\r
3f5ed3fa
JY
70 ^ | Commom Buf |\r
71 | | -------------- |\r
72 DMA Buffer | * DMA FREE * |\r
73 | | -------------- |\r
74 V | Read/Write Buf |\r
e8097a74 75 =========== +==================+ <=============== PLMR.Limit (+ alignment)\r
3f5ed3fa
JY
76 | PEI allocated |\r
77 | -------------- | <------- EfiFreeMemoryTop\r
78 | * PEI FREE * |\r
79 | -------------- | <------- EfiFreeMemoryBottom\r
80 | hob |\r
81 | -------------- |\r
82 | Stack |\r
83 +------------------+ <------- EfiMemoryBottom / Stack Bottom\r
84\r
85 +------------------+\r
86 | Mem Alloc Hob |\r
87 +------------------+\r
88\r
8e9da4ba
JY
89 | |\r
90 | Mem Resource |\r
91 +------------------+ <=============== PLMR.Base (0)\r
3f5ed3fa
JY
92**/\r
93\r
3f5ed3fa
JY
94/**\r
95 Set IOMMU attribute for a system memory.\r
96\r
97 If the IOMMU PPI exists, the system memory cannot be used\r
98 for DMA by default.\r
99\r
100 When a device requests a DMA access for a system memory,\r
101 the device driver need use SetAttribute() to update the IOMMU\r
102 attribute to request DMA access (read and/or write).\r
103\r
104 @param[in] This The PPI instance pointer.\r
105 @param[in] Mapping The mapping value returned from Map().\r
106 @param[in] IoMmuAccess The IOMMU access.\r
107\r
108 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by DeviceAddress and Length.\r
109 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().\r
110 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.\r
111 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.\r
112 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by Mapping.\r
113 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.\r
114 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.\r
940dbd07
SZ
115 @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are\r
116 not available to be allocated yet.\r
3f5ed3fa
JY
117\r
118**/\r
119EFI_STATUS\r
120EFIAPI\r
121PeiIoMmuSetAttribute (\r
122 IN EDKII_IOMMU_PPI *This,\r
123 IN VOID *Mapping,\r
124 IN UINT64 IoMmuAccess\r
125 )\r
126{\r
940dbd07
SZ
127 VOID *Hob;\r
128 DMA_BUFFER_INFO *DmaBufferInfo;\r
129\r
130 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
131 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
132\r
133 if (DmaBufferInfo->DmaBufferCurrentTop == 0) {\r
134 return EFI_NOT_AVAILABLE_YET;\r
135 }\r
136\r
3f5ed3fa
JY
137 return EFI_SUCCESS;\r
138}\r
139\r
140/**\r
141 Provides the controller-specific addresses required to access system memory from a\r
142 DMA bus master.\r
143\r
144 @param This The PPI instance pointer.\r
145 @param Operation Indicates if the bus master is going to read or write to system memory.\r
146 @param HostAddress The system memory address to map to the PCI controller.\r
147 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes\r
148 that were mapped.\r
149 @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
150 access the hosts HostAddress.\r
151 @param Mapping A resulting value to pass to Unmap().\r
152\r
153 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
154 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.\r
155 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
156 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
157 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
940dbd07
SZ
158 @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are\r
159 not available to be allocated yet.\r
3f5ed3fa
JY
160\r
161**/\r
162EFI_STATUS\r
163EFIAPI\r
164PeiIoMmuMap (\r
165 IN EDKII_IOMMU_PPI *This,\r
166 IN EDKII_IOMMU_OPERATION Operation,\r
167 IN VOID *HostAddress,\r
168 IN OUT UINTN *NumberOfBytes,\r
169 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
170 OUT VOID **Mapping\r
171 )\r
172{\r
a1e7cd0b
JY
173 MAP_INFO *MapInfo;\r
174 UINTN Length;\r
175 VOID *Hob;\r
176 DMA_BUFFER_INFO *DmaBufferInfo;\r
177\r
178 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
179 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
3f5ed3fa 180\r
940dbd07
SZ
181 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuMap - HostAddress - 0x%x, NumberOfBytes - %x\n", HostAddress, *NumberOfBytes));\r
182 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
183 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
184\r
185 if (DmaBufferInfo->DmaBufferCurrentTop == 0) {\r
186 return EFI_NOT_AVAILABLE_YET;\r
187 }\r
188\r
3f5ed3fa
JY
189 if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||\r
190 Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {\r
191 *DeviceAddress = (UINTN)HostAddress;\r
192 *Mapping = 0;\r
193 return EFI_SUCCESS;\r
194 }\r
195\r
3f5ed3fa 196 Length = *NumberOfBytes + sizeof(MAP_INFO);\r
a1e7cd0b 197 if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {\r
3f5ed3fa
JY
198 DEBUG ((DEBUG_ERROR, "PeiIoMmuMap - OUT_OF_RESOURCE\n"));\r
199 ASSERT (FALSE);\r
200 return EFI_OUT_OF_RESOURCES;\r
201 }\r
202\r
a1e7cd0b
JY
203 *DeviceAddress = DmaBufferInfo->DmaBufferCurrentBottom;\r
204 DmaBufferInfo->DmaBufferCurrentBottom += Length;\r
3f5ed3fa
JY
205\r
206 MapInfo = (VOID *)(UINTN)(*DeviceAddress + *NumberOfBytes);\r
207 MapInfo->Signature = MAP_INFO_SIGNATURE;\r
208 MapInfo->Operation = Operation;\r
209 MapInfo->NumberOfBytes = *NumberOfBytes;\r
210 MapInfo->HostAddress = (UINTN)HostAddress;\r
211 MapInfo->DeviceAddress = *DeviceAddress;\r
212 *Mapping = MapInfo;\r
213 DEBUG ((DEBUG_VERBOSE, " Op(%x):DeviceAddress - %x, Mapping - %x\n", Operation, (UINTN)*DeviceAddress, MapInfo));\r
214\r
215 //\r
216 // If this is a read operation from the Bus Master's point of view,\r
217 // then copy the contents of the real buffer into the mapped buffer\r
218 // so the Bus Master can read the contents of the real buffer.\r
219 //\r
220 if (Operation == EdkiiIoMmuOperationBusMasterRead ||\r
221 Operation == EdkiiIoMmuOperationBusMasterRead64) {\r
222 CopyMem (\r
223 (VOID *) (UINTN) MapInfo->DeviceAddress,\r
224 (VOID *) (UINTN) MapInfo->HostAddress,\r
225 MapInfo->NumberOfBytes\r
226 );\r
227 }\r
228\r
229 return EFI_SUCCESS;\r
230}\r
231\r
232/**\r
233 Completes the Map() operation and releases any corresponding resources.\r
234\r
235 @param This The PPI instance pointer.\r
236 @param Mapping The mapping value returned from Map().\r
237\r
238 @retval EFI_SUCCESS The range was unmapped.\r
239 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().\r
240 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.\r
940dbd07
SZ
241 @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are\r
242 not available to be allocated yet.\r
243\r
3f5ed3fa
JY
244**/\r
245EFI_STATUS\r
246EFIAPI\r
247PeiIoMmuUnmap (\r
248 IN EDKII_IOMMU_PPI *This,\r
249 IN VOID *Mapping\r
250 )\r
251{\r
a1e7cd0b
JY
252 MAP_INFO *MapInfo;\r
253 UINTN Length;\r
254 VOID *Hob;\r
255 DMA_BUFFER_INFO *DmaBufferInfo;\r
256\r
257 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
258 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
3f5ed3fa 259\r
3f5ed3fa 260 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuUnmap - Mapping - %x\n", Mapping));\r
a1e7cd0b
JY
261 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
262 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
3f5ed3fa 263\r
940dbd07
SZ
264 if (DmaBufferInfo->DmaBufferCurrentTop == 0) {\r
265 return EFI_NOT_AVAILABLE_YET;\r
266 }\r
267\r
268 if (Mapping == NULL) {\r
269 return EFI_INVALID_PARAMETER;\r
270 }\r
271\r
3f5ed3fa
JY
272 MapInfo = Mapping;\r
273 ASSERT (MapInfo->Signature == MAP_INFO_SIGNATURE);\r
274 DEBUG ((DEBUG_VERBOSE, " Op(%x):DeviceAddress - %x, NumberOfBytes - %x\n", MapInfo->Operation, (UINTN)MapInfo->DeviceAddress, MapInfo->NumberOfBytes));\r
275\r
276 //\r
277 // If this is a write operation from the Bus Master's point of view,\r
278 // then copy the contents of the mapped buffer into the real buffer\r
279 // so the processor can read the contents of the real buffer.\r
280 //\r
281 if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite ||\r
282 MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite64) {\r
283 CopyMem (\r
284 (VOID *) (UINTN) MapInfo->HostAddress,\r
285 (VOID *) (UINTN) MapInfo->DeviceAddress,\r
286 MapInfo->NumberOfBytes\r
287 );\r
288 }\r
289\r
290 Length = MapInfo->NumberOfBytes + sizeof(MAP_INFO);\r
a1e7cd0b
JY
291 if (DmaBufferInfo->DmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) {\r
292 DmaBufferInfo->DmaBufferCurrentBottom -= Length;\r
3f5ed3fa
JY
293 }\r
294\r
295 return EFI_SUCCESS;\r
296}\r
297\r
298/**\r
299 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
300 OperationBusMasterCommonBuffer64 mapping.\r
301\r
302 @param This The PPI instance pointer.\r
303 @param MemoryType The type of memory to allocate, EfiBootServicesData or\r
304 EfiRuntimeServicesData.\r
305 @param Pages The number of pages to allocate.\r
306 @param HostAddress A pointer to store the base system memory address of the\r
307 allocated range.\r
308 @param Attributes The requested bit mask of attributes for the allocated range.\r
309\r
310 @retval EFI_SUCCESS The requested memory pages were allocated.\r
311 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
34e18d17 312 MEMORY_WRITE_COMBINE, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.\r
3f5ed3fa
JY
313 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
314 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
940dbd07
SZ
315 @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are\r
316 not available to be allocated yet.\r
3f5ed3fa
JY
317\r
318**/\r
319EFI_STATUS\r
320EFIAPI\r
321PeiIoMmuAllocateBuffer (\r
322 IN EDKII_IOMMU_PPI *This,\r
323 IN EFI_MEMORY_TYPE MemoryType,\r
324 IN UINTN Pages,\r
325 IN OUT VOID **HostAddress,\r
326 IN UINT64 Attributes\r
327 )\r
328{\r
a1e7cd0b
JY
329 UINTN Length;\r
330 VOID *Hob;\r
331 DMA_BUFFER_INFO *DmaBufferInfo;\r
332\r
333 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
334 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
3f5ed3fa
JY
335\r
336 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - page - %x\n", Pages));\r
a1e7cd0b
JY
337 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
338 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
3f5ed3fa 339\r
940dbd07
SZ
340 if (DmaBufferInfo->DmaBufferCurrentTop == 0) {\r
341 return EFI_NOT_AVAILABLE_YET;\r
342 }\r
343\r
3f5ed3fa 344 Length = EFI_PAGES_TO_SIZE(Pages);\r
a1e7cd0b 345 if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {\r
3f5ed3fa
JY
346 DEBUG ((DEBUG_ERROR, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n"));\r
347 ASSERT (FALSE);\r
348 return EFI_OUT_OF_RESOURCES;\r
349 }\r
a1e7cd0b
JY
350 *HostAddress = (VOID *)(UINTN)(DmaBufferInfo->DmaBufferCurrentTop - Length);\r
351 DmaBufferInfo->DmaBufferCurrentTop -= Length;\r
3f5ed3fa
JY
352\r
353 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - allocate - %x\n", *HostAddress));\r
354 return EFI_SUCCESS;\r
355}\r
356\r
357/**\r
358 Frees memory that was allocated with AllocateBuffer().\r
359\r
360 @param This The PPI instance pointer.\r
361 @param Pages The number of pages to free.\r
362 @param HostAddress The base system memory address of the allocated range.\r
363\r
364 @retval EFI_SUCCESS The requested memory pages were freed.\r
365 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
366 was not allocated with AllocateBuffer().\r
940dbd07
SZ
367 @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are\r
368 not available to be allocated yet.\r
3f5ed3fa
JY
369\r
370**/\r
371EFI_STATUS\r
372EFIAPI\r
373PeiIoMmuFreeBuffer (\r
374 IN EDKII_IOMMU_PPI *This,\r
375 IN UINTN Pages,\r
376 IN VOID *HostAddress\r
377 )\r
378{\r
a1e7cd0b
JY
379 UINTN Length;\r
380 VOID *Hob;\r
381 DMA_BUFFER_INFO *DmaBufferInfo;\r
382\r
383 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
384 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
3f5ed3fa
JY
385\r
386 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n", Pages, HostAddress));\r
a1e7cd0b
JY
387 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
388 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
3f5ed3fa 389\r
940dbd07
SZ
390 if (DmaBufferInfo->DmaBufferCurrentTop == 0) {\r
391 return EFI_NOT_AVAILABLE_YET;\r
392 }\r
393\r
3f5ed3fa 394 Length = EFI_PAGES_TO_SIZE(Pages);\r
a1e7cd0b
JY
395 if ((UINTN)HostAddress == DmaBufferInfo->DmaBufferCurrentTop) {\r
396 DmaBufferInfo->DmaBufferCurrentTop += Length;\r
3f5ed3fa
JY
397 }\r
398\r
399 return EFI_SUCCESS;\r
400}\r
401\r
402EDKII_IOMMU_PPI mIoMmuPpi = {\r
403 EDKII_IOMMU_PPI_REVISION,\r
404 PeiIoMmuSetAttribute,\r
405 PeiIoMmuMap,\r
406 PeiIoMmuUnmap,\r
407 PeiIoMmuAllocateBuffer,\r
408 PeiIoMmuFreeBuffer,\r
409};\r
410\r
411CONST EFI_PEI_PPI_DESCRIPTOR mIoMmuPpiList = {\r
412 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
413 &gEdkiiIoMmuPpiGuid,\r
414 (VOID *) &mIoMmuPpi\r
415};\r
416\r
3f5ed3fa
JY
417/**\r
418 Initialize DMA protection.\r
419\r
a1e7cd0b 420 @param VTdInfo The VTd engine context information.\r
3f5ed3fa
JY
421\r
422 @retval EFI_SUCCESS the DMA protection is initialized.\r
423 @retval EFI_OUT_OF_RESOURCES no enough resource to initialize DMA protection.\r
424**/\r
425EFI_STATUS\r
426InitDmaProtection (\r
ed0e52fc 427 IN VTD_INFO *VTdInfo\r
3f5ed3fa
JY
428 )\r
429{\r
430 EFI_STATUS Status;\r
3f5ed3fa
JY
431 UINT32 LowMemoryAlignment;\r
432 UINT64 HighMemoryAlignment;\r
433 UINTN MemoryAlignment;\r
434 UINTN LowBottom;\r
435 UINTN LowTop;\r
436 UINTN HighBottom;\r
437 UINT64 HighTop;\r
ed0e52fc
SZ
438 DMA_BUFFER_INFO *DmaBufferInfo;\r
439 VOID *Hob;\r
940dbd07
SZ
440 EFI_PEI_PPI_DESCRIPTOR *OldDescriptor;\r
441 EDKII_IOMMU_PPI *OldIoMmuPpi;\r
ed0e52fc
SZ
442\r
443 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
444 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
445\r
446 DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", DmaBufferInfo->DmaBufferSize));\r
3f5ed3fa 447\r
a1e7cd0b
JY
448 LowMemoryAlignment = GetLowMemoryAlignment (VTdInfo, VTdInfo->EngineMask);\r
449 HighMemoryAlignment = GetHighMemoryAlignment (VTdInfo, VTdInfo->EngineMask);\r
3f5ed3fa
JY
450 if (LowMemoryAlignment < HighMemoryAlignment) {\r
451 MemoryAlignment = (UINTN)HighMemoryAlignment;\r
452 } else {\r
453 MemoryAlignment = LowMemoryAlignment;\r
454 }\r
ed0e52fc
SZ
455 ASSERT (DmaBufferInfo->DmaBufferSize == ALIGN_VALUE(DmaBufferInfo->DmaBufferSize, MemoryAlignment));\r
456 DmaBufferInfo->DmaBufferBase = (UINTN)AllocateAlignedPages (EFI_SIZE_TO_PAGES(DmaBufferInfo->DmaBufferSize), MemoryAlignment);\r
457 ASSERT (DmaBufferInfo->DmaBufferBase != 0);\r
458 if (DmaBufferInfo->DmaBufferBase == 0) {\r
3f5ed3fa
JY
459 DEBUG ((DEBUG_INFO, " InitDmaProtection : OutOfResource\n"));\r
460 return EFI_OUT_OF_RESOURCES;\r
461 }\r
462\r
ed0e52fc
SZ
463 DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", DmaBufferInfo->DmaBufferBase));\r
464\r
465 DmaBufferInfo->DmaBufferCurrentTop = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;\r
466 DmaBufferInfo->DmaBufferCurrentBottom = DmaBufferInfo->DmaBufferBase;\r
467\r
468 //\r
940dbd07 469 // (Re)Install PPI.\r
ed0e52fc 470 //\r
940dbd07
SZ
471 Status = PeiServicesLocatePpi (\r
472 &gEdkiiIoMmuPpiGuid,\r
473 0,\r
474 &OldDescriptor,\r
475 (VOID **) &OldIoMmuPpi\r
476 );\r
477 if (!EFI_ERROR (Status)) {\r
478 Status = PeiServicesReInstallPpi (OldDescriptor, &mIoMmuPpiList);\r
479 } else {\r
480 Status = PeiServicesInstallPpi (&mIoMmuPpiList);\r
481 }\r
482 ASSERT_EFI_ERROR (Status);\r
ed0e52fc 483\r
3f5ed3fa 484 LowBottom = 0;\r
ed0e52fc
SZ
485 LowTop = DmaBufferInfo->DmaBufferBase;\r
486 HighBottom = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;\r
b2725f57 487 HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth + 1);\r
3f5ed3fa
JY
488\r
489 Status = SetDmaProtectedRange (\r
a1e7cd0b
JY
490 VTdInfo,\r
491 VTdInfo->EngineMask,\r
492 (UINT32)LowBottom,\r
493 (UINT32)(LowTop - LowBottom),\r
494 HighBottom,\r
495 HighTop - HighBottom\r
496 );\r
3f5ed3fa
JY
497\r
498 if (EFI_ERROR(Status)) {\r
ed0e52fc 499 FreePages ((VOID *)DmaBufferInfo->DmaBufferBase, EFI_SIZE_TO_PAGES(DmaBufferInfo->DmaBufferSize));\r
3f5ed3fa
JY
500 }\r
501\r
502 return Status;\r
503}\r
504\r
8e9da4ba 505/**\r
a1e7cd0b
JY
506 Initializes the Intel VTd Info.\r
507\r
508 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
509 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
8e9da4ba 510\r
8e9da4ba 511**/\r
a1e7cd0b
JY
512EFI_STATUS\r
513InitVTdInfo (\r
514 VOID\r
8e9da4ba
JY
515 )\r
516{\r
a1e7cd0b
JY
517 EFI_STATUS Status;\r
518 EFI_ACPI_DMAR_HEADER *AcpiDmarTable;\r
519 VOID *Hob;\r
8e9da4ba 520\r
a1e7cd0b
JY
521 Status = PeiServicesLocatePpi (\r
522 &gEdkiiVTdInfoPpiGuid,\r
523 0,\r
524 NULL,\r
525 (VOID **)&AcpiDmarTable\r
526 );\r
527 ASSERT_EFI_ERROR(Status);\r
8e9da4ba 528\r
a1e7cd0b 529 DumpAcpiDMAR (AcpiDmarTable);\r
8e9da4ba 530\r
a1e7cd0b
JY
531 //\r
532 // Clear old VTdInfo Hob.\r
533 //\r
534 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
535 if (Hob != NULL) {\r
536 ZeroMem (&((EFI_HOB_GUID_TYPE *)Hob)->Name, sizeof(EFI_GUID));\r
8e9da4ba
JY
537 }\r
538\r
a1e7cd0b
JY
539 //\r
540 // Get DMAR information to local VTdInfo\r
541 //\r
542 Status = ParseDmarAcpiTableDrhd (AcpiDmarTable);\r
543 if (EFI_ERROR(Status)) {\r
544 return Status;\r
8e9da4ba
JY
545 }\r
546\r
a1e7cd0b
JY
547 //\r
548 // NOTE: Do not parse RMRR here, because RMRR may cause PMR programming.\r
549 //\r
8e9da4ba 550\r
a1e7cd0b 551 return EFI_SUCCESS;\r
8e9da4ba
JY
552}\r
553\r
554/**\r
a1e7cd0b
JY
555 Initializes the Intel VTd PMR for all memory.\r
556\r
557 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
558 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
8e9da4ba 559\r
8e9da4ba 560**/\r
a1e7cd0b
JY
561EFI_STATUS\r
562InitVTdPmrForAll (\r
563 VOID\r
8e9da4ba
JY
564 )\r
565{\r
a1e7cd0b
JY
566 EFI_STATUS Status;\r
567 VOID *Hob;\r
568 VTD_INFO *VTdInfo;\r
569 UINTN LowBottom;\r
570 UINTN LowTop;\r
571 UINTN HighBottom;\r
572 UINT64 HighTop;\r
8e9da4ba 573\r
a1e7cd0b
JY
574 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
575 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
8e9da4ba 576\r
a1e7cd0b
JY
577 LowBottom = 0;\r
578 LowTop = 0;\r
579 HighBottom = 0;\r
9dd8b190 580 HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth + 1);\r
8e9da4ba 581\r
a1e7cd0b
JY
582 Status = SetDmaProtectedRange (\r
583 VTdInfo,\r
584 VTdInfo->EngineMask,\r
585 (UINT32)LowBottom,\r
586 (UINT32)(LowTop - LowBottom),\r
587 HighBottom,\r
588 HighTop - HighBottom\r
589 );\r
8e9da4ba 590\r
a1e7cd0b 591 return Status;\r
8e9da4ba
JY
592}\r
593\r
594/**\r
a1e7cd0b
JY
595 Initializes the Intel VTd PMR for DMA buffer.\r
596\r
597 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
598 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
8e9da4ba 599\r
8e9da4ba 600**/\r
a1e7cd0b
JY
601EFI_STATUS\r
602InitVTdPmrForDma (\r
603 VOID\r
8e9da4ba
JY
604 )\r
605{\r
a1e7cd0b
JY
606 EFI_STATUS Status;\r
607 VOID *Hob;\r
608 VTD_INFO *VTdInfo;\r
8e9da4ba 609\r
a1e7cd0b
JY
610 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
611 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
8e9da4ba
JY
612\r
613 //\r
a1e7cd0b 614 // If there is RMRR memory, parse it here.\r
8e9da4ba 615 //\r
a1e7cd0b 616 ParseDmarAcpiTableRmrr (VTdInfo);\r
8e9da4ba 617\r
8e9da4ba 618 //\r
ed0e52fc
SZ
619 // Allocate a range in PEI memory as DMA buffer\r
620 // Mark others to be DMA protected.\r
8e9da4ba 621 //\r
ed0e52fc 622 Status = InitDmaProtection (VTdInfo);\r
8e9da4ba 623\r
a1e7cd0b 624 return Status;\r
8e9da4ba
JY
625}\r
626\r
627/**\r
a1e7cd0b 628 This function handles S3 resume task at the end of PEI\r
8e9da4ba 629\r
a1e7cd0b
JY
630 @param[in] PeiServices Pointer to PEI Services Table.\r
631 @param[in] NotifyDesc Pointer to the descriptor for the Notification event that\r
632 caused this function to execute.\r
633 @param[in] Ppi Pointer to the PPI data associated with this function.\r
8e9da4ba 634\r
a1e7cd0b 635 @retval EFI_STATUS Always return EFI_SUCCESS\r
8e9da4ba 636**/\r
a1e7cd0b
JY
637EFI_STATUS\r
638EFIAPI\r
639S3EndOfPeiNotify(\r
640 IN EFI_PEI_SERVICES **PeiServices,\r
641 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
642 IN VOID *Ppi\r
8e9da4ba
JY
643 )\r
644{\r
a1e7cd0b
JY
645 VOID *Hob;\r
646 VTD_INFO *VTdInfo;\r
647 UINT64 EngineMask;\r
8e9da4ba 648\r
a1e7cd0b 649 DEBUG((DEBUG_INFO, "VTdPmr S3EndOfPeiNotify\n"));\r
8e9da4ba 650\r
a1e7cd0b
JY
651 if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {\r
652 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
653 if (Hob == NULL) {\r
654 return EFI_SUCCESS;\r
8e9da4ba 655 }\r
a1e7cd0b 656 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
8e9da4ba 657\r
a1e7cd0b
JY
658 EngineMask = LShiftU64 (1, VTdInfo->VTdEngineCount) - 1;\r
659 DisableDmaProtection (VTdInfo, EngineMask);\r
8e9da4ba 660 }\r
a1e7cd0b 661 return EFI_SUCCESS;\r
8e9da4ba
JY
662}\r
663\r
a1e7cd0b
JY
664EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc = {\r
665 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
666 &gEfiEndOfPeiSignalPpiGuid,\r
667 S3EndOfPeiNotify\r
668};\r
8e9da4ba 669\r
fc8be1ad 670/**\r
a1e7cd0b 671 This function handles VTd engine setup\r
fc8be1ad
JY
672\r
673 @param[in] PeiServices Pointer to PEI Services Table.\r
674 @param[in] NotifyDesc Pointer to the descriptor for the Notification event that\r
675 caused this function to execute.\r
676 @param[in] Ppi Pointer to the PPI data associated with this function.\r
677\r
678 @retval EFI_STATUS Always return EFI_SUCCESS\r
679**/\r
680EFI_STATUS\r
681EFIAPI\r
a1e7cd0b 682VTdInfoNotify (\r
fc8be1ad
JY
683 IN EFI_PEI_SERVICES **PeiServices,\r
684 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
685 IN VOID *Ppi\r
686 )\r
687{\r
a1e7cd0b
JY
688 EFI_STATUS Status;\r
689 VOID *MemoryDiscovered;\r
690 UINT64 EnabledEngineMask;\r
691 VOID *Hob;\r
692 VTD_INFO *VTdInfo;\r
693 BOOLEAN MemoryInitialized;\r
fc8be1ad 694\r
a1e7cd0b
JY
695 DEBUG ((DEBUG_INFO, "VTdInfoNotify\n"));\r
696\r
697 //\r
698 // Check if memory is initialized.\r
699 //\r
700 MemoryInitialized = FALSE;\r
701 Status = PeiServicesLocatePpi (\r
702 &gEfiPeiMemoryDiscoveredPpiGuid,\r
703 0,\r
704 NULL,\r
705 &MemoryDiscovered\r
706 );\r
707 if (!EFI_ERROR(Status)) {\r
708 MemoryInitialized = TRUE;\r
709 }\r
710\r
711 DEBUG ((DEBUG_INFO, "MemoryInitialized - %x\n", MemoryInitialized));\r
712\r
713 if (!MemoryInitialized) {\r
714 //\r
715 // If the memory is not initialized,\r
716 // Protect all system memory\r
717 //\r
718 InitVTdInfo ();\r
719 InitVTdPmrForAll ();\r
940dbd07
SZ
720\r
721 //\r
722 // Install PPI.\r
723 //\r
724 Status = PeiServicesInstallPpi (&mIoMmuPpiList);\r
725 ASSERT_EFI_ERROR(Status);\r
a1e7cd0b
JY
726 } else {\r
727 //\r
728 // If the memory is initialized,\r
729 // Allocate DMA buffer and protect rest system memory\r
730 //\r
731\r
732 //\r
733 // NOTE: We need reinit VTdInfo because previous information might be overriden.\r
734 //\r
735 InitVTdInfo ();\r
736\r
737 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
738 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
739\r
740 //\r
741 // NOTE: We need check if PMR is enabled or not.\r
742 //\r
743 EnabledEngineMask = GetDmaProtectionEnabledEngineMask (VTdInfo, VTdInfo->EngineMask);\r
744 if (EnabledEngineMask != 0) {\r
745 EnableVTdTranslationProtection (VTdInfo, EnabledEngineMask);\r
746 DisableDmaProtection (VTdInfo, EnabledEngineMask);\r
747 }\r
748 InitVTdPmrForDma ();\r
749 if (EnabledEngineMask != 0) {\r
750 DisableVTdTranslationProtection (VTdInfo, EnabledEngineMask);\r
751 }\r
fc8be1ad 752\r
fc8be1ad 753 }\r
a1e7cd0b 754\r
fc8be1ad
JY
755 return EFI_SUCCESS;\r
756}\r
757\r
a1e7cd0b 758EFI_PEI_NOTIFY_DESCRIPTOR mVTdInfoNotifyDesc = {\r
fc8be1ad 759 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
a1e7cd0b
JY
760 &gEdkiiVTdInfoPpiGuid,\r
761 VTdInfoNotify\r
fc8be1ad
JY
762};\r
763\r
3f5ed3fa
JY
764/**\r
765 Initializes the Intel VTd PMR PEIM.\r
766\r
767 @param FileHandle Handle of the file being invoked.\r
768 @param PeiServices Describes the list of possible PEI Services.\r
769\r
770 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
771 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
772\r
773**/\r
774EFI_STATUS\r
775EFIAPI\r
776IntelVTdPmrInitialize (\r
777 IN EFI_PEI_FILE_HANDLE FileHandle,\r
778 IN CONST EFI_PEI_SERVICES **PeiServices\r
779 )\r
780{\r
781 EFI_STATUS Status;\r
fc8be1ad 782 EFI_BOOT_MODE BootMode;\r
a1e7cd0b
JY
783 DMA_BUFFER_INFO *DmaBufferInfo;\r
784\r
785 DEBUG ((DEBUG_INFO, "IntelVTdPmrInitialize\n"));\r
3f5ed3fa
JY
786\r
787 if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) == 0) {\r
788 return EFI_UNSUPPORTED;\r
789 }\r
790\r
a1e7cd0b
JY
791 DmaBufferInfo = BuildGuidHob (&mDmaBufferInfoGuid, sizeof(DMA_BUFFER_INFO));\r
792 ASSERT(DmaBufferInfo != NULL);\r
793 if (DmaBufferInfo == NULL) {\r
794 return EFI_OUT_OF_RESOURCES;\r
8e9da4ba 795 }\r
a1e7cd0b 796 ZeroMem (DmaBufferInfo, sizeof(DMA_BUFFER_INFO));\r
8e9da4ba 797\r
a1e7cd0b 798 PeiServicesGetBootMode (&BootMode);\r
8e9da4ba 799\r
fc8be1ad 800 if (BootMode == BOOT_ON_S3_RESUME) {\r
a1e7cd0b 801 DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE_S3;\r
fc8be1ad 802 } else {\r
a1e7cd0b 803 DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE;\r
3f5ed3fa
JY
804 }\r
805\r
a1e7cd0b
JY
806 Status = PeiServicesNotifyPpi (&mVTdInfoNotifyDesc);\r
807 ASSERT_EFI_ERROR (Status);\r
3f5ed3fa 808\r
fc8be1ad 809 //\r
a1e7cd0b 810 // Register EndOfPei Notify for S3\r
fc8be1ad
JY
811 //\r
812 if (BootMode == BOOT_ON_S3_RESUME) {\r
813 Status = PeiServicesNotifyPpi (&mS3EndOfPeiNotifyDesc);\r
814 ASSERT_EFI_ERROR (Status);\r
815 }\r
816\r
a1e7cd0b 817 return EFI_SUCCESS;\r
3f5ed3fa
JY
818}\r
819\r