]> git.proxmox.com Git - mirror_edk2.git/blame - IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
IntelSiliconPkg IntelVTdPmrPei: Install IoMmu PPI before enabling PMR
[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
115\r
116**/\r
117EFI_STATUS\r
118EFIAPI\r
119PeiIoMmuSetAttribute (\r
120 IN EDKII_IOMMU_PPI *This,\r
121 IN VOID *Mapping,\r
122 IN UINT64 IoMmuAccess\r
123 )\r
124{\r
125 return EFI_SUCCESS;\r
126}\r
127\r
128/**\r
129 Provides the controller-specific addresses required to access system memory from a\r
130 DMA bus master.\r
131\r
132 @param This The PPI instance pointer.\r
133 @param Operation Indicates if the bus master is going to read or write to system memory.\r
134 @param HostAddress The system memory address to map to the PCI controller.\r
135 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes\r
136 that were mapped.\r
137 @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
138 access the hosts HostAddress.\r
139 @param Mapping A resulting value to pass to Unmap().\r
140\r
141 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
142 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.\r
143 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
144 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
145 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
146\r
147**/\r
148EFI_STATUS\r
149EFIAPI\r
150PeiIoMmuMap (\r
151 IN EDKII_IOMMU_PPI *This,\r
152 IN EDKII_IOMMU_OPERATION Operation,\r
153 IN VOID *HostAddress,\r
154 IN OUT UINTN *NumberOfBytes,\r
155 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
156 OUT VOID **Mapping\r
157 )\r
158{\r
a1e7cd0b
JY
159 MAP_INFO *MapInfo;\r
160 UINTN Length;\r
161 VOID *Hob;\r
162 DMA_BUFFER_INFO *DmaBufferInfo;\r
163\r
164 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
165 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
3f5ed3fa
JY
166\r
167 if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||\r
168 Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {\r
169 *DeviceAddress = (UINTN)HostAddress;\r
170 *Mapping = 0;\r
171 return EFI_SUCCESS;\r
172 }\r
173\r
174 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuMap - HostAddress - 0x%x, NumberOfBytes - %x\n", HostAddress, *NumberOfBytes));\r
a1e7cd0b
JY
175 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
176 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
3f5ed3fa
JY
177\r
178 Length = *NumberOfBytes + sizeof(MAP_INFO);\r
a1e7cd0b 179 if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {\r
3f5ed3fa
JY
180 DEBUG ((DEBUG_ERROR, "PeiIoMmuMap - OUT_OF_RESOURCE\n"));\r
181 ASSERT (FALSE);\r
182 return EFI_OUT_OF_RESOURCES;\r
183 }\r
184\r
a1e7cd0b
JY
185 *DeviceAddress = DmaBufferInfo->DmaBufferCurrentBottom;\r
186 DmaBufferInfo->DmaBufferCurrentBottom += Length;\r
3f5ed3fa
JY
187\r
188 MapInfo = (VOID *)(UINTN)(*DeviceAddress + *NumberOfBytes);\r
189 MapInfo->Signature = MAP_INFO_SIGNATURE;\r
190 MapInfo->Operation = Operation;\r
191 MapInfo->NumberOfBytes = *NumberOfBytes;\r
192 MapInfo->HostAddress = (UINTN)HostAddress;\r
193 MapInfo->DeviceAddress = *DeviceAddress;\r
194 *Mapping = MapInfo;\r
195 DEBUG ((DEBUG_VERBOSE, " Op(%x):DeviceAddress - %x, Mapping - %x\n", Operation, (UINTN)*DeviceAddress, MapInfo));\r
196\r
197 //\r
198 // If this is a read operation from the Bus Master's point of view,\r
199 // then copy the contents of the real buffer into the mapped buffer\r
200 // so the Bus Master can read the contents of the real buffer.\r
201 //\r
202 if (Operation == EdkiiIoMmuOperationBusMasterRead ||\r
203 Operation == EdkiiIoMmuOperationBusMasterRead64) {\r
204 CopyMem (\r
205 (VOID *) (UINTN) MapInfo->DeviceAddress,\r
206 (VOID *) (UINTN) MapInfo->HostAddress,\r
207 MapInfo->NumberOfBytes\r
208 );\r
209 }\r
210\r
211 return EFI_SUCCESS;\r
212}\r
213\r
214/**\r
215 Completes the Map() operation and releases any corresponding resources.\r
216\r
217 @param This The PPI instance pointer.\r
218 @param Mapping The mapping value returned from Map().\r
219\r
220 @retval EFI_SUCCESS The range was unmapped.\r
221 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().\r
222 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.\r
223**/\r
224EFI_STATUS\r
225EFIAPI\r
226PeiIoMmuUnmap (\r
227 IN EDKII_IOMMU_PPI *This,\r
228 IN VOID *Mapping\r
229 )\r
230{\r
a1e7cd0b
JY
231 MAP_INFO *MapInfo;\r
232 UINTN Length;\r
233 VOID *Hob;\r
234 DMA_BUFFER_INFO *DmaBufferInfo;\r
235\r
236 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
237 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
3f5ed3fa
JY
238\r
239 if (Mapping == NULL) {\r
240 return EFI_SUCCESS;\r
241 }\r
242\r
243 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuUnmap - Mapping - %x\n", Mapping));\r
a1e7cd0b
JY
244 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
245 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
3f5ed3fa
JY
246\r
247 MapInfo = Mapping;\r
248 ASSERT (MapInfo->Signature == MAP_INFO_SIGNATURE);\r
249 DEBUG ((DEBUG_VERBOSE, " Op(%x):DeviceAddress - %x, NumberOfBytes - %x\n", MapInfo->Operation, (UINTN)MapInfo->DeviceAddress, MapInfo->NumberOfBytes));\r
250\r
251 //\r
252 // If this is a write operation from the Bus Master's point of view,\r
253 // then copy the contents of the mapped buffer into the real buffer\r
254 // so the processor can read the contents of the real buffer.\r
255 //\r
256 if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite ||\r
257 MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite64) {\r
258 CopyMem (\r
259 (VOID *) (UINTN) MapInfo->HostAddress,\r
260 (VOID *) (UINTN) MapInfo->DeviceAddress,\r
261 MapInfo->NumberOfBytes\r
262 );\r
263 }\r
264\r
265 Length = MapInfo->NumberOfBytes + sizeof(MAP_INFO);\r
a1e7cd0b
JY
266 if (DmaBufferInfo->DmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) {\r
267 DmaBufferInfo->DmaBufferCurrentBottom -= Length;\r
3f5ed3fa
JY
268 }\r
269\r
270 return EFI_SUCCESS;\r
271}\r
272\r
273/**\r
274 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
275 OperationBusMasterCommonBuffer64 mapping.\r
276\r
277 @param This The PPI instance pointer.\r
278 @param MemoryType The type of memory to allocate, EfiBootServicesData or\r
279 EfiRuntimeServicesData.\r
280 @param Pages The number of pages to allocate.\r
281 @param HostAddress A pointer to store the base system memory address of the\r
282 allocated range.\r
283 @param Attributes The requested bit mask of attributes for the allocated range.\r
284\r
285 @retval EFI_SUCCESS The requested memory pages were allocated.\r
286 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
34e18d17 287 MEMORY_WRITE_COMBINE, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.\r
3f5ed3fa
JY
288 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
289 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
290\r
291**/\r
292EFI_STATUS\r
293EFIAPI\r
294PeiIoMmuAllocateBuffer (\r
295 IN EDKII_IOMMU_PPI *This,\r
296 IN EFI_MEMORY_TYPE MemoryType,\r
297 IN UINTN Pages,\r
298 IN OUT VOID **HostAddress,\r
299 IN UINT64 Attributes\r
300 )\r
301{\r
a1e7cd0b
JY
302 UINTN Length;\r
303 VOID *Hob;\r
304 DMA_BUFFER_INFO *DmaBufferInfo;\r
305\r
306 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
307 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
3f5ed3fa
JY
308\r
309 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - page - %x\n", Pages));\r
a1e7cd0b
JY
310 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
311 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
3f5ed3fa
JY
312\r
313 Length = EFI_PAGES_TO_SIZE(Pages);\r
a1e7cd0b 314 if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {\r
3f5ed3fa
JY
315 DEBUG ((DEBUG_ERROR, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n"));\r
316 ASSERT (FALSE);\r
317 return EFI_OUT_OF_RESOURCES;\r
318 }\r
a1e7cd0b
JY
319 *HostAddress = (VOID *)(UINTN)(DmaBufferInfo->DmaBufferCurrentTop - Length);\r
320 DmaBufferInfo->DmaBufferCurrentTop -= Length;\r
3f5ed3fa
JY
321\r
322 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - allocate - %x\n", *HostAddress));\r
323 return EFI_SUCCESS;\r
324}\r
325\r
326/**\r
327 Frees memory that was allocated with AllocateBuffer().\r
328\r
329 @param This The PPI instance pointer.\r
330 @param Pages The number of pages to free.\r
331 @param HostAddress The base system memory address of the allocated range.\r
332\r
333 @retval EFI_SUCCESS The requested memory pages were freed.\r
334 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
335 was not allocated with AllocateBuffer().\r
336\r
337**/\r
338EFI_STATUS\r
339EFIAPI\r
340PeiIoMmuFreeBuffer (\r
341 IN EDKII_IOMMU_PPI *This,\r
342 IN UINTN Pages,\r
343 IN VOID *HostAddress\r
344 )\r
345{\r
a1e7cd0b
JY
346 UINTN Length;\r
347 VOID *Hob;\r
348 DMA_BUFFER_INFO *DmaBufferInfo;\r
349\r
350 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
351 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
3f5ed3fa
JY
352\r
353 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n", Pages, HostAddress));\r
a1e7cd0b
JY
354 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
355 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
3f5ed3fa
JY
356\r
357 Length = EFI_PAGES_TO_SIZE(Pages);\r
a1e7cd0b
JY
358 if ((UINTN)HostAddress == DmaBufferInfo->DmaBufferCurrentTop) {\r
359 DmaBufferInfo->DmaBufferCurrentTop += Length;\r
3f5ed3fa
JY
360 }\r
361\r
362 return EFI_SUCCESS;\r
363}\r
364\r
365EDKII_IOMMU_PPI mIoMmuPpi = {\r
366 EDKII_IOMMU_PPI_REVISION,\r
367 PeiIoMmuSetAttribute,\r
368 PeiIoMmuMap,\r
369 PeiIoMmuUnmap,\r
370 PeiIoMmuAllocateBuffer,\r
371 PeiIoMmuFreeBuffer,\r
372};\r
373\r
374CONST EFI_PEI_PPI_DESCRIPTOR mIoMmuPpiList = {\r
375 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
376 &gEdkiiIoMmuPpiGuid,\r
377 (VOID *) &mIoMmuPpi\r
378};\r
379\r
3f5ed3fa
JY
380/**\r
381 Initialize DMA protection.\r
382\r
a1e7cd0b 383 @param VTdInfo The VTd engine context information.\r
3f5ed3fa
JY
384\r
385 @retval EFI_SUCCESS the DMA protection is initialized.\r
386 @retval EFI_OUT_OF_RESOURCES no enough resource to initialize DMA protection.\r
387**/\r
388EFI_STATUS\r
389InitDmaProtection (\r
ed0e52fc 390 IN VTD_INFO *VTdInfo\r
3f5ed3fa
JY
391 )\r
392{\r
393 EFI_STATUS Status;\r
3f5ed3fa
JY
394 UINT32 LowMemoryAlignment;\r
395 UINT64 HighMemoryAlignment;\r
396 UINTN MemoryAlignment;\r
397 UINTN LowBottom;\r
398 UINTN LowTop;\r
399 UINTN HighBottom;\r
400 UINT64 HighTop;\r
ed0e52fc
SZ
401 DMA_BUFFER_INFO *DmaBufferInfo;\r
402 VOID *Hob;\r
403\r
404 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
405 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
406\r
407 DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", DmaBufferInfo->DmaBufferSize));\r
3f5ed3fa 408\r
a1e7cd0b
JY
409 LowMemoryAlignment = GetLowMemoryAlignment (VTdInfo, VTdInfo->EngineMask);\r
410 HighMemoryAlignment = GetHighMemoryAlignment (VTdInfo, VTdInfo->EngineMask);\r
3f5ed3fa
JY
411 if (LowMemoryAlignment < HighMemoryAlignment) {\r
412 MemoryAlignment = (UINTN)HighMemoryAlignment;\r
413 } else {\r
414 MemoryAlignment = LowMemoryAlignment;\r
415 }\r
ed0e52fc
SZ
416 ASSERT (DmaBufferInfo->DmaBufferSize == ALIGN_VALUE(DmaBufferInfo->DmaBufferSize, MemoryAlignment));\r
417 DmaBufferInfo->DmaBufferBase = (UINTN)AllocateAlignedPages (EFI_SIZE_TO_PAGES(DmaBufferInfo->DmaBufferSize), MemoryAlignment);\r
418 ASSERT (DmaBufferInfo->DmaBufferBase != 0);\r
419 if (DmaBufferInfo->DmaBufferBase == 0) {\r
3f5ed3fa
JY
420 DEBUG ((DEBUG_INFO, " InitDmaProtection : OutOfResource\n"));\r
421 return EFI_OUT_OF_RESOURCES;\r
422 }\r
423\r
ed0e52fc
SZ
424 DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", DmaBufferInfo->DmaBufferBase));\r
425\r
426 DmaBufferInfo->DmaBufferCurrentTop = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;\r
427 DmaBufferInfo->DmaBufferCurrentBottom = DmaBufferInfo->DmaBufferBase;\r
428\r
429 //\r
430 // Install PPI.\r
431 //\r
432 Status = PeiServicesInstallPpi (&mIoMmuPpiList);\r
433 ASSERT_EFI_ERROR(Status);\r
434\r
3f5ed3fa 435 LowBottom = 0;\r
ed0e52fc
SZ
436 LowTop = DmaBufferInfo->DmaBufferBase;\r
437 HighBottom = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;\r
b2725f57 438 HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth + 1);\r
3f5ed3fa
JY
439\r
440 Status = SetDmaProtectedRange (\r
a1e7cd0b
JY
441 VTdInfo,\r
442 VTdInfo->EngineMask,\r
443 (UINT32)LowBottom,\r
444 (UINT32)(LowTop - LowBottom),\r
445 HighBottom,\r
446 HighTop - HighBottom\r
447 );\r
3f5ed3fa
JY
448\r
449 if (EFI_ERROR(Status)) {\r
ed0e52fc 450 FreePages ((VOID *)DmaBufferInfo->DmaBufferBase, EFI_SIZE_TO_PAGES(DmaBufferInfo->DmaBufferSize));\r
3f5ed3fa
JY
451 }\r
452\r
453 return Status;\r
454}\r
455\r
8e9da4ba 456/**\r
a1e7cd0b
JY
457 Initializes the Intel VTd Info.\r
458\r
459 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
460 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
8e9da4ba 461\r
8e9da4ba 462**/\r
a1e7cd0b
JY
463EFI_STATUS\r
464InitVTdInfo (\r
465 VOID\r
8e9da4ba
JY
466 )\r
467{\r
a1e7cd0b
JY
468 EFI_STATUS Status;\r
469 EFI_ACPI_DMAR_HEADER *AcpiDmarTable;\r
470 VOID *Hob;\r
8e9da4ba 471\r
a1e7cd0b
JY
472 Status = PeiServicesLocatePpi (\r
473 &gEdkiiVTdInfoPpiGuid,\r
474 0,\r
475 NULL,\r
476 (VOID **)&AcpiDmarTable\r
477 );\r
478 ASSERT_EFI_ERROR(Status);\r
8e9da4ba 479\r
a1e7cd0b 480 DumpAcpiDMAR (AcpiDmarTable);\r
8e9da4ba 481\r
a1e7cd0b
JY
482 //\r
483 // Clear old VTdInfo Hob.\r
484 //\r
485 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
486 if (Hob != NULL) {\r
487 ZeroMem (&((EFI_HOB_GUID_TYPE *)Hob)->Name, sizeof(EFI_GUID));\r
8e9da4ba
JY
488 }\r
489\r
a1e7cd0b
JY
490 //\r
491 // Get DMAR information to local VTdInfo\r
492 //\r
493 Status = ParseDmarAcpiTableDrhd (AcpiDmarTable);\r
494 if (EFI_ERROR(Status)) {\r
495 return Status;\r
8e9da4ba
JY
496 }\r
497\r
a1e7cd0b
JY
498 //\r
499 // NOTE: Do not parse RMRR here, because RMRR may cause PMR programming.\r
500 //\r
8e9da4ba 501\r
a1e7cd0b 502 return EFI_SUCCESS;\r
8e9da4ba
JY
503}\r
504\r
505/**\r
a1e7cd0b
JY
506 Initializes the Intel VTd PMR for all memory.\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
513InitVTdPmrForAll (\r
514 VOID\r
8e9da4ba
JY
515 )\r
516{\r
a1e7cd0b
JY
517 EFI_STATUS Status;\r
518 VOID *Hob;\r
519 VTD_INFO *VTdInfo;\r
520 UINTN LowBottom;\r
521 UINTN LowTop;\r
522 UINTN HighBottom;\r
523 UINT64 HighTop;\r
8e9da4ba 524\r
a1e7cd0b
JY
525 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
526 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
8e9da4ba 527\r
a1e7cd0b
JY
528 LowBottom = 0;\r
529 LowTop = 0;\r
530 HighBottom = 0;\r
9dd8b190 531 HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth + 1);\r
8e9da4ba 532\r
a1e7cd0b
JY
533 Status = SetDmaProtectedRange (\r
534 VTdInfo,\r
535 VTdInfo->EngineMask,\r
536 (UINT32)LowBottom,\r
537 (UINT32)(LowTop - LowBottom),\r
538 HighBottom,\r
539 HighTop - HighBottom\r
540 );\r
8e9da4ba 541\r
a1e7cd0b 542 return Status;\r
8e9da4ba
JY
543}\r
544\r
545/**\r
a1e7cd0b
JY
546 Initializes the Intel VTd PMR for DMA buffer.\r
547\r
548 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
549 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
8e9da4ba 550\r
8e9da4ba 551**/\r
a1e7cd0b
JY
552EFI_STATUS\r
553InitVTdPmrForDma (\r
554 VOID\r
8e9da4ba
JY
555 )\r
556{\r
a1e7cd0b
JY
557 EFI_STATUS Status;\r
558 VOID *Hob;\r
559 VTD_INFO *VTdInfo;\r
8e9da4ba 560\r
a1e7cd0b
JY
561 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
562 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
8e9da4ba
JY
563\r
564 //\r
a1e7cd0b 565 // If there is RMRR memory, parse it here.\r
8e9da4ba 566 //\r
a1e7cd0b 567 ParseDmarAcpiTableRmrr (VTdInfo);\r
8e9da4ba 568\r
8e9da4ba 569 //\r
ed0e52fc
SZ
570 // Allocate a range in PEI memory as DMA buffer\r
571 // Mark others to be DMA protected.\r
8e9da4ba 572 //\r
ed0e52fc 573 Status = InitDmaProtection (VTdInfo);\r
8e9da4ba 574\r
a1e7cd0b 575 return Status;\r
8e9da4ba
JY
576}\r
577\r
578/**\r
a1e7cd0b 579 This function handles S3 resume task at the end of PEI\r
8e9da4ba 580\r
a1e7cd0b
JY
581 @param[in] PeiServices Pointer to PEI Services Table.\r
582 @param[in] NotifyDesc Pointer to the descriptor for the Notification event that\r
583 caused this function to execute.\r
584 @param[in] Ppi Pointer to the PPI data associated with this function.\r
8e9da4ba 585\r
a1e7cd0b 586 @retval EFI_STATUS Always return EFI_SUCCESS\r
8e9da4ba 587**/\r
a1e7cd0b
JY
588EFI_STATUS\r
589EFIAPI\r
590S3EndOfPeiNotify(\r
591 IN EFI_PEI_SERVICES **PeiServices,\r
592 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
593 IN VOID *Ppi\r
8e9da4ba
JY
594 )\r
595{\r
a1e7cd0b
JY
596 VOID *Hob;\r
597 VTD_INFO *VTdInfo;\r
598 UINT64 EngineMask;\r
8e9da4ba 599\r
a1e7cd0b 600 DEBUG((DEBUG_INFO, "VTdPmr S3EndOfPeiNotify\n"));\r
8e9da4ba 601\r
a1e7cd0b
JY
602 if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {\r
603 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
604 if (Hob == NULL) {\r
605 return EFI_SUCCESS;\r
8e9da4ba 606 }\r
a1e7cd0b 607 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
8e9da4ba 608\r
a1e7cd0b
JY
609 EngineMask = LShiftU64 (1, VTdInfo->VTdEngineCount) - 1;\r
610 DisableDmaProtection (VTdInfo, EngineMask);\r
8e9da4ba 611 }\r
a1e7cd0b 612 return EFI_SUCCESS;\r
8e9da4ba
JY
613}\r
614\r
a1e7cd0b
JY
615EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc = {\r
616 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
617 &gEfiEndOfPeiSignalPpiGuid,\r
618 S3EndOfPeiNotify\r
619};\r
8e9da4ba 620\r
fc8be1ad 621/**\r
a1e7cd0b 622 This function handles VTd engine setup\r
fc8be1ad
JY
623\r
624 @param[in] PeiServices Pointer to PEI Services Table.\r
625 @param[in] NotifyDesc Pointer to the descriptor for the Notification event that\r
626 caused this function to execute.\r
627 @param[in] Ppi Pointer to the PPI data associated with this function.\r
628\r
629 @retval EFI_STATUS Always return EFI_SUCCESS\r
630**/\r
631EFI_STATUS\r
632EFIAPI\r
a1e7cd0b 633VTdInfoNotify (\r
fc8be1ad
JY
634 IN EFI_PEI_SERVICES **PeiServices,\r
635 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
636 IN VOID *Ppi\r
637 )\r
638{\r
a1e7cd0b
JY
639 EFI_STATUS Status;\r
640 VOID *MemoryDiscovered;\r
641 UINT64 EnabledEngineMask;\r
642 VOID *Hob;\r
643 VTD_INFO *VTdInfo;\r
644 BOOLEAN MemoryInitialized;\r
fc8be1ad 645\r
a1e7cd0b
JY
646 DEBUG ((DEBUG_INFO, "VTdInfoNotify\n"));\r
647\r
648 //\r
649 // Check if memory is initialized.\r
650 //\r
651 MemoryInitialized = FALSE;\r
652 Status = PeiServicesLocatePpi (\r
653 &gEfiPeiMemoryDiscoveredPpiGuid,\r
654 0,\r
655 NULL,\r
656 &MemoryDiscovered\r
657 );\r
658 if (!EFI_ERROR(Status)) {\r
659 MemoryInitialized = TRUE;\r
660 }\r
661\r
662 DEBUG ((DEBUG_INFO, "MemoryInitialized - %x\n", MemoryInitialized));\r
663\r
664 if (!MemoryInitialized) {\r
665 //\r
666 // If the memory is not initialized,\r
667 // Protect all system memory\r
668 //\r
669 InitVTdInfo ();\r
670 InitVTdPmrForAll ();\r
671 } else {\r
672 //\r
673 // If the memory is initialized,\r
674 // Allocate DMA buffer and protect rest system memory\r
675 //\r
676\r
677 //\r
678 // NOTE: We need reinit VTdInfo because previous information might be overriden.\r
679 //\r
680 InitVTdInfo ();\r
681\r
682 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
683 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
684\r
685 //\r
686 // NOTE: We need check if PMR is enabled or not.\r
687 //\r
688 EnabledEngineMask = GetDmaProtectionEnabledEngineMask (VTdInfo, VTdInfo->EngineMask);\r
689 if (EnabledEngineMask != 0) {\r
690 EnableVTdTranslationProtection (VTdInfo, EnabledEngineMask);\r
691 DisableDmaProtection (VTdInfo, EnabledEngineMask);\r
692 }\r
693 InitVTdPmrForDma ();\r
694 if (EnabledEngineMask != 0) {\r
695 DisableVTdTranslationProtection (VTdInfo, EnabledEngineMask);\r
696 }\r
fc8be1ad 697\r
fc8be1ad 698 }\r
a1e7cd0b 699\r
fc8be1ad
JY
700 return EFI_SUCCESS;\r
701}\r
702\r
a1e7cd0b 703EFI_PEI_NOTIFY_DESCRIPTOR mVTdInfoNotifyDesc = {\r
fc8be1ad 704 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
a1e7cd0b
JY
705 &gEdkiiVTdInfoPpiGuid,\r
706 VTdInfoNotify\r
fc8be1ad
JY
707};\r
708\r
3f5ed3fa
JY
709/**\r
710 Initializes the Intel VTd PMR PEIM.\r
711\r
712 @param FileHandle Handle of the file being invoked.\r
713 @param PeiServices Describes the list of possible PEI Services.\r
714\r
715 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
716 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
717\r
718**/\r
719EFI_STATUS\r
720EFIAPI\r
721IntelVTdPmrInitialize (\r
722 IN EFI_PEI_FILE_HANDLE FileHandle,\r
723 IN CONST EFI_PEI_SERVICES **PeiServices\r
724 )\r
725{\r
726 EFI_STATUS Status;\r
fc8be1ad 727 EFI_BOOT_MODE BootMode;\r
a1e7cd0b
JY
728 DMA_BUFFER_INFO *DmaBufferInfo;\r
729\r
730 DEBUG ((DEBUG_INFO, "IntelVTdPmrInitialize\n"));\r
3f5ed3fa
JY
731\r
732 if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) == 0) {\r
733 return EFI_UNSUPPORTED;\r
734 }\r
735\r
a1e7cd0b
JY
736 DmaBufferInfo = BuildGuidHob (&mDmaBufferInfoGuid, sizeof(DMA_BUFFER_INFO));\r
737 ASSERT(DmaBufferInfo != NULL);\r
738 if (DmaBufferInfo == NULL) {\r
739 return EFI_OUT_OF_RESOURCES;\r
8e9da4ba 740 }\r
a1e7cd0b 741 ZeroMem (DmaBufferInfo, sizeof(DMA_BUFFER_INFO));\r
8e9da4ba 742\r
a1e7cd0b 743 PeiServicesGetBootMode (&BootMode);\r
8e9da4ba 744\r
fc8be1ad 745 if (BootMode == BOOT_ON_S3_RESUME) {\r
a1e7cd0b 746 DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE_S3;\r
fc8be1ad 747 } else {\r
a1e7cd0b 748 DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE;\r
3f5ed3fa
JY
749 }\r
750\r
a1e7cd0b
JY
751 Status = PeiServicesNotifyPpi (&mVTdInfoNotifyDesc);\r
752 ASSERT_EFI_ERROR (Status);\r
3f5ed3fa 753\r
fc8be1ad 754 //\r
a1e7cd0b 755 // Register EndOfPei Notify for S3\r
fc8be1ad
JY
756 //\r
757 if (BootMode == BOOT_ON_S3_RESUME) {\r
758 Status = PeiServicesNotifyPpi (&mS3EndOfPeiNotifyDesc);\r
759 ASSERT_EFI_ERROR (Status);\r
760 }\r
761\r
a1e7cd0b 762 return EFI_SUCCESS;\r
3f5ed3fa
JY
763}\r
764\r