3 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
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
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.
17 #include <Library/BaseLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/IoLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/PeiServicesLib.h>
23 #include <Library/HobLib.h>
24 #include <IndustryStandard/Vtd.h>
25 #include <Ppi/IoMmu.h>
26 #include <Ppi/VTdInfo.h>
28 #include "IntelVTdPmrPei.h"
30 #define TOTAL_DMA_BUFFER_SIZE SIZE_4MB
32 EDKII_VTD_INFO_PPI
*mVTdInfoPpi
;
34 UINTN mDmaBufferSize
= TOTAL_DMA_BUFFER_SIZE
;
35 UINTN mDmaBufferCurrentTop
;
36 UINTN mDmaBufferCurrentBottom
;
38 #define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P')
41 EDKII_IOMMU_OPERATION Operation
;
43 EFI_PHYSICAL_ADDRESS HostAddress
;
44 EFI_PHYSICAL_ADDRESS DeviceAddress
;
51 +------------------+ <------- EfiMemoryTop
53 =========== +==================+
56 DMA Buffer | * DMA FREE * |
59 =========== +==================+
61 | -------------- | <------- EfiFreeMemoryTop
63 | -------------- | <------- EfiFreeMemoryBottom
67 +------------------+ <------- EfiMemoryBottom / Stack Bottom
77 Set IOMMU attribute for a system memory.
79 If the IOMMU PPI exists, the system memory cannot be used
82 When a device requests a DMA access for a system memory,
83 the device driver need use SetAttribute() to update the IOMMU
84 attribute to request DMA access (read and/or write).
86 @param[in] This The PPI instance pointer.
87 @param[in] Mapping The mapping value returned from Map().
88 @param[in] IoMmuAccess The IOMMU access.
90 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by DeviceAddress and Length.
91 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
92 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.
93 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.
94 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by Mapping.
95 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.
96 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.
101 PeiIoMmuSetAttribute (
102 IN EDKII_IOMMU_PPI
*This
,
104 IN UINT64 IoMmuAccess
111 Provides the controller-specific addresses required to access system memory from a
114 @param This The PPI instance pointer.
115 @param Operation Indicates if the bus master is going to read or write to system memory.
116 @param HostAddress The system memory address to map to the PCI controller.
117 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
119 @param DeviceAddress The resulting map address for the bus master PCI controller to use to
120 access the hosts HostAddress.
121 @param Mapping A resulting value to pass to Unmap().
123 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
124 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
125 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
126 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
127 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
133 IN EDKII_IOMMU_PPI
*This
,
134 IN EDKII_IOMMU_OPERATION Operation
,
135 IN VOID
*HostAddress
,
136 IN OUT UINTN
*NumberOfBytes
,
137 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
144 if (Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer
||
145 Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer64
) {
146 *DeviceAddress
= (UINTN
)HostAddress
;
151 DEBUG ((DEBUG_VERBOSE
, "PeiIoMmuMap - HostAddress - 0x%x, NumberOfBytes - %x\n", HostAddress
, *NumberOfBytes
));
152 DEBUG ((DEBUG_VERBOSE
, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop
));
153 DEBUG ((DEBUG_VERBOSE
, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom
));
155 Length
= *NumberOfBytes
+ sizeof(MAP_INFO
);
156 if (Length
> mDmaBufferCurrentTop
- mDmaBufferCurrentBottom
) {
157 DEBUG ((DEBUG_ERROR
, "PeiIoMmuMap - OUT_OF_RESOURCE\n"));
159 return EFI_OUT_OF_RESOURCES
;
162 *DeviceAddress
= mDmaBufferCurrentBottom
;
163 mDmaBufferCurrentBottom
+= Length
;
165 MapInfo
= (VOID
*)(UINTN
)(*DeviceAddress
+ *NumberOfBytes
);
166 MapInfo
->Signature
= MAP_INFO_SIGNATURE
;
167 MapInfo
->Operation
= Operation
;
168 MapInfo
->NumberOfBytes
= *NumberOfBytes
;
169 MapInfo
->HostAddress
= (UINTN
)HostAddress
;
170 MapInfo
->DeviceAddress
= *DeviceAddress
;
172 DEBUG ((DEBUG_VERBOSE
, " Op(%x):DeviceAddress - %x, Mapping - %x\n", Operation
, (UINTN
)*DeviceAddress
, MapInfo
));
175 // If this is a read operation from the Bus Master's point of view,
176 // then copy the contents of the real buffer into the mapped buffer
177 // so the Bus Master can read the contents of the real buffer.
179 if (Operation
== EdkiiIoMmuOperationBusMasterRead
||
180 Operation
== EdkiiIoMmuOperationBusMasterRead64
) {
182 (VOID
*) (UINTN
) MapInfo
->DeviceAddress
,
183 (VOID
*) (UINTN
) MapInfo
->HostAddress
,
184 MapInfo
->NumberOfBytes
192 Completes the Map() operation and releases any corresponding resources.
194 @param This The PPI instance pointer.
195 @param Mapping The mapping value returned from Map().
197 @retval EFI_SUCCESS The range was unmapped.
198 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
199 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
204 IN EDKII_IOMMU_PPI
*This
,
211 if (Mapping
== NULL
) {
215 DEBUG ((DEBUG_VERBOSE
, "PeiIoMmuUnmap - Mapping - %x\n", Mapping
));
216 DEBUG ((DEBUG_VERBOSE
, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop
));
217 DEBUG ((DEBUG_VERBOSE
, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom
));
220 ASSERT (MapInfo
->Signature
== MAP_INFO_SIGNATURE
);
221 DEBUG ((DEBUG_VERBOSE
, " Op(%x):DeviceAddress - %x, NumberOfBytes - %x\n", MapInfo
->Operation
, (UINTN
)MapInfo
->DeviceAddress
, MapInfo
->NumberOfBytes
));
224 // If this is a write operation from the Bus Master's point of view,
225 // then copy the contents of the mapped buffer into the real buffer
226 // so the processor can read the contents of the real buffer.
228 if (MapInfo
->Operation
== EdkiiIoMmuOperationBusMasterWrite
||
229 MapInfo
->Operation
== EdkiiIoMmuOperationBusMasterWrite64
) {
231 (VOID
*) (UINTN
) MapInfo
->HostAddress
,
232 (VOID
*) (UINTN
) MapInfo
->DeviceAddress
,
233 MapInfo
->NumberOfBytes
237 Length
= MapInfo
->NumberOfBytes
+ sizeof(MAP_INFO
);
238 if (mDmaBufferCurrentBottom
== MapInfo
->DeviceAddress
+ Length
) {
239 mDmaBufferCurrentBottom
-= Length
;
246 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
247 OperationBusMasterCommonBuffer64 mapping.
249 @param This The PPI instance pointer.
250 @param MemoryType The type of memory to allocate, EfiBootServicesData or
251 EfiRuntimeServicesData.
252 @param Pages The number of pages to allocate.
253 @param HostAddress A pointer to store the base system memory address of the
255 @param Attributes The requested bit mask of attributes for the allocated range.
257 @retval EFI_SUCCESS The requested memory pages were allocated.
258 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
259 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
260 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
261 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
266 PeiIoMmuAllocateBuffer (
267 IN EDKII_IOMMU_PPI
*This
,
268 IN EFI_MEMORY_TYPE MemoryType
,
270 IN OUT VOID
**HostAddress
,
276 DEBUG ((DEBUG_VERBOSE
, "PeiIoMmuAllocateBuffer - page - %x\n", Pages
));
277 DEBUG ((DEBUG_VERBOSE
, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop
));
278 DEBUG ((DEBUG_VERBOSE
, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom
));
280 Length
= EFI_PAGES_TO_SIZE(Pages
);
281 if (Length
> mDmaBufferCurrentTop
- mDmaBufferCurrentBottom
) {
282 DEBUG ((DEBUG_ERROR
, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n"));
284 return EFI_OUT_OF_RESOURCES
;
286 *HostAddress
= (VOID
*)(UINTN
)(mDmaBufferCurrentTop
- Length
);
287 mDmaBufferCurrentTop
-= Length
;
289 DEBUG ((DEBUG_VERBOSE
, "PeiIoMmuAllocateBuffer - allocate - %x\n", *HostAddress
));
294 Frees memory that was allocated with AllocateBuffer().
296 @param This The PPI instance pointer.
297 @param Pages The number of pages to free.
298 @param HostAddress The base system memory address of the allocated range.
300 @retval EFI_SUCCESS The requested memory pages were freed.
301 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
302 was not allocated with AllocateBuffer().
308 IN EDKII_IOMMU_PPI
*This
,
315 DEBUG ((DEBUG_VERBOSE
, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n", Pages
, HostAddress
));
316 DEBUG ((DEBUG_VERBOSE
, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop
));
317 DEBUG ((DEBUG_VERBOSE
, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom
));
319 Length
= EFI_PAGES_TO_SIZE(Pages
);
320 if ((UINTN
)HostAddress
== mDmaBufferCurrentTop
) {
321 mDmaBufferCurrentTop
+= Length
;
327 EDKII_IOMMU_PPI mIoMmuPpi
= {
328 EDKII_IOMMU_PPI_REVISION
,
329 PeiIoMmuSetAttribute
,
332 PeiIoMmuAllocateBuffer
,
336 CONST EFI_PEI_PPI_DESCRIPTOR mIoMmuPpiList
= {
337 EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
342 #define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
343 EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
344 EFI_RESOURCE_ATTRIBUTE_TESTED | \
345 EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \
346 EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \
347 EFI_RESOURCE_ATTRIBUTE_64_BIT_IO \
350 #define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED)
352 #define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED)
354 #define PRESENT_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT)
356 GLOBAL_REMOVE_IF_UNREFERENCED CHAR8
*mResourceTypeShortName
[] = {
367 Return the short name of resource type.
369 @param Type resource type.
371 @return the short name of resource type.
374 ShortNameOfResourceType (
378 if (Type
< sizeof(mResourceTypeShortName
) / sizeof(mResourceTypeShortName
[0])) {
379 return mResourceTypeShortName
[Type
];
388 @param HobList the HOB list.
395 EFI_PEI_HOB_POINTERS Hob
;
396 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
398 DEBUG ((DEBUG_VERBOSE
, "Resource Descriptor HOBs\n"));
399 for (Hob
.Raw
= HobList
; !END_OF_HOB_LIST (Hob
); Hob
.Raw
= GET_NEXT_HOB (Hob
)) {
400 if (GET_HOB_TYPE (Hob
) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
401 ResourceHob
= Hob
.ResourceDescriptor
;
402 DEBUG ((DEBUG_VERBOSE
,
403 " BA=%016lx L=%016lx Attr=%08x ",
404 ResourceHob
->PhysicalStart
,
405 ResourceHob
->ResourceLength
,
406 ResourceHob
->ResourceAttribute
408 DEBUG ((DEBUG_VERBOSE
, ShortNameOfResourceType(ResourceHob
->ResourceType
)));
409 switch (ResourceHob
->ResourceType
) {
410 case EFI_RESOURCE_SYSTEM_MEMORY
:
411 if ((ResourceHob
->ResourceAttribute
& EFI_RESOURCE_ATTRIBUTE_PERSISTENT
) != 0) {
412 DEBUG ((DEBUG_VERBOSE
, " (Persistent)"));
413 } else if ((ResourceHob
->ResourceAttribute
& EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE
) != 0) {
414 DEBUG ((DEBUG_VERBOSE
, " (MoreReliable)"));
415 } else if ((ResourceHob
->ResourceAttribute
& MEMORY_ATTRIBUTE_MASK
) == TESTED_MEMORY_ATTRIBUTES
) {
416 DEBUG ((DEBUG_VERBOSE
, " (Tested)"));
417 } else if ((ResourceHob
->ResourceAttribute
& MEMORY_ATTRIBUTE_MASK
) == INITIALIZED_MEMORY_ATTRIBUTES
) {
418 DEBUG ((DEBUG_VERBOSE
, " (Init)"));
419 } else if ((ResourceHob
->ResourceAttribute
& MEMORY_ATTRIBUTE_MASK
) == PRESENT_MEMORY_ATTRIBUTES
) {
420 DEBUG ((DEBUG_VERBOSE
, " (Present)"));
422 DEBUG ((DEBUG_VERBOSE
, " (Unknown)"));
428 DEBUG ((DEBUG_VERBOSE
, "\n"));
436 @param HobList the HOB list.
443 EFI_HOB_HANDOFF_INFO_TABLE
*PhitHob
;
446 ASSERT(GET_HOB_TYPE(HobList
) == EFI_HOB_TYPE_HANDOFF
);
447 DEBUG ((DEBUG_VERBOSE
, "PHIT HOB\n"));
448 DEBUG ((DEBUG_VERBOSE
, " PhitHob - 0x%x\n", PhitHob
));
449 DEBUG ((DEBUG_VERBOSE
, " BootMode - 0x%x\n", PhitHob
->BootMode
));
450 DEBUG ((DEBUG_VERBOSE
, " EfiMemoryTop - 0x%016lx\n", PhitHob
->EfiMemoryTop
));
451 DEBUG ((DEBUG_VERBOSE
, " EfiMemoryBottom - 0x%016lx\n", PhitHob
->EfiMemoryBottom
));
452 DEBUG ((DEBUG_VERBOSE
, " EfiFreeMemoryTop - 0x%016lx\n", PhitHob
->EfiFreeMemoryTop
));
453 DEBUG ((DEBUG_VERBOSE
, " EfiFreeMemoryBottom - 0x%016lx\n", PhitHob
->EfiFreeMemoryBottom
));
454 DEBUG ((DEBUG_VERBOSE
, " EfiEndOfHobList - 0x%lx\n", PhitHob
->EfiEndOfHobList
));
458 Get the highest memory.
460 @param HobList the HOB list.
462 @return the highest memory.
469 EFI_PEI_HOB_POINTERS Hob
;
470 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
475 for (Hob
.Raw
= HobList
; !END_OF_HOB_LIST (Hob
); Hob
.Raw
= GET_NEXT_HOB (Hob
)) {
476 if (GET_HOB_TYPE (Hob
) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
477 ResourceHob
= Hob
.ResourceDescriptor
;
478 switch (ResourceHob
->ResourceType
) {
479 case EFI_RESOURCE_SYSTEM_MEMORY
:
480 ResourceTop
= ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
;
481 if (TopMemory
< ResourceTop
) {
482 TopMemory
= ResourceTop
;
488 DEBUG ((DEBUG_VERBOSE
, "\n"));
495 Initialize DMA protection.
497 @param DmaBufferSize the DMA buffer size
498 @param DmaBufferBase the DMA buffer base
500 @retval EFI_SUCCESS the DMA protection is initialized.
501 @retval EFI_OUT_OF_RESOURCES no enough resource to initialize DMA protection.
505 IN UINTN DmaBufferSize
,
506 OUT UINTN
*DmaBufferBase
511 EFI_HOB_HANDOFF_INFO_TABLE
*PhitHob
;
512 UINT32 LowMemoryAlignment
;
513 UINT64 HighMemoryAlignment
;
514 UINTN MemoryAlignment
;
520 HobList
= GetHobList ();
521 DumpPhitHob (HobList
);
522 DumpResourceHob (HobList
);
526 ASSERT (PhitHob
->EfiMemoryBottom
< PhitHob
->EfiMemoryTop
);
528 LowMemoryAlignment
= GetLowMemoryAlignment ();
529 HighMemoryAlignment
= GetHighMemoryAlignment ();
530 if (LowMemoryAlignment
< HighMemoryAlignment
) {
531 MemoryAlignment
= (UINTN
)HighMemoryAlignment
;
533 MemoryAlignment
= LowMemoryAlignment
;
535 ASSERT (DmaBufferSize
== ALIGN_VALUE(DmaBufferSize
, MemoryAlignment
));
536 *DmaBufferBase
= (UINTN
)AllocateAlignedPages (EFI_SIZE_TO_PAGES(DmaBufferSize
), MemoryAlignment
);
537 if (*DmaBufferBase
== 0) {
538 DEBUG ((DEBUG_INFO
, " InitDmaProtection : OutOfResource\n"));
539 return EFI_OUT_OF_RESOURCES
;
543 LowTop
= *DmaBufferBase
;
544 HighBottom
= *DmaBufferBase
+ DmaBufferSize
;
545 HighTop
= GetTopMemory (HobList
);
547 Status
= SetDmaProtectedRange (
549 (UINT32
)(LowTop
- LowBottom
),
554 if (EFI_ERROR(Status
)) {
555 FreePages ((VOID
*)*DmaBufferBase
, EFI_SIZE_TO_PAGES(DmaBufferSize
));
562 Initializes the Intel VTd PMR PEIM.
564 @param FileHandle Handle of the file being invoked.
565 @param PeiServices Describes the list of possible PEI Services.
567 @retval EFI_SUCCESS Usb bot driver is successfully initialized.
568 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.
573 IntelVTdPmrInitialize (
574 IN EFI_PEI_FILE_HANDLE FileHandle
,
575 IN CONST EFI_PEI_SERVICES
**PeiServices
580 if ((PcdGet8(PcdVTdPolicyPropertyMask
) & BIT0
) == 0) {
581 return EFI_UNSUPPORTED
;
584 Status
= PeiServicesLocatePpi (
585 &gEdkiiVTdInfoPpiGuid
,
588 (VOID
**)&mVTdInfoPpi
590 ASSERT_EFI_ERROR(Status
);
593 // Find a pre-memory in resource hob as DMA buffer
594 // Mark PEI memory to be DMA protected.
596 Status
= InitDmaProtection (mDmaBufferSize
, &mDmaBufferBase
);
597 if (EFI_ERROR(Status
)) {
601 DEBUG ((DEBUG_INFO
, " DmaBufferBase : 0x%x\n", mDmaBufferBase
));
602 DEBUG ((DEBUG_INFO
, " DmaBufferSize : 0x%x\n", mDmaBufferSize
));
604 mDmaBufferCurrentTop
= mDmaBufferBase
+ mDmaBufferSize
;
605 mDmaBufferCurrentBottom
= mDmaBufferBase
;
610 Status
= PeiServicesInstallPpi (&mIoMmuPpiList
);
611 ASSERT_EFI_ERROR(Status
);