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>
27 #include <Ppi/EndOfPeiPhase.h>
29 #include "IntelVTdPmrPei.h"
31 #define TOTAL_DMA_BUFFER_SIZE SIZE_4MB
32 #define TOTAL_DMA_BUFFER_SIZE_S3 SIZE_1MB
34 EFI_ACPI_DMAR_HEADER
*mAcpiDmarTable
;
39 UINTN mDmaBufferCurrentTop
;
40 UINTN mDmaBufferCurrentBottom
;
42 #define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P')
45 EDKII_IOMMU_OPERATION Operation
;
47 EFI_PHYSICAL_ADDRESS HostAddress
;
48 EFI_PHYSICAL_ADDRESS DeviceAddress
;
55 +------------------+ <=============== PHMR.Limit (Top of memory)
59 +------------------+ <------- EfiMemoryTop
61 =========== +==================+ <=============== PHMR.Base
64 DMA Buffer | * DMA FREE * |
67 =========== +==================+ <=============== PLMR.Limit
69 | -------------- | <------- EfiFreeMemoryTop
71 | -------------- | <------- EfiFreeMemoryBottom
75 +------------------+ <------- EfiMemoryBottom / Stack Bottom
83 +------------------+ <=============== PLMR.Base (0)
88 Set IOMMU attribute for a system memory.
90 If the IOMMU PPI exists, the system memory cannot be used
93 When a device requests a DMA access for a system memory,
94 the device driver need use SetAttribute() to update the IOMMU
95 attribute to request DMA access (read and/or write).
97 @param[in] This The PPI instance pointer.
98 @param[in] Mapping The mapping value returned from Map().
99 @param[in] IoMmuAccess The IOMMU access.
101 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by DeviceAddress and Length.
102 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
103 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.
104 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.
105 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by Mapping.
106 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.
107 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.
112 PeiIoMmuSetAttribute (
113 IN EDKII_IOMMU_PPI
*This
,
115 IN UINT64 IoMmuAccess
122 Provides the controller-specific addresses required to access system memory from a
125 @param This The PPI instance pointer.
126 @param Operation Indicates if the bus master is going to read or write to system memory.
127 @param HostAddress The system memory address to map to the PCI controller.
128 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
130 @param DeviceAddress The resulting map address for the bus master PCI controller to use to
131 access the hosts HostAddress.
132 @param Mapping A resulting value to pass to Unmap().
134 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
135 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
136 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
137 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
138 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
144 IN EDKII_IOMMU_PPI
*This
,
145 IN EDKII_IOMMU_OPERATION Operation
,
146 IN VOID
*HostAddress
,
147 IN OUT UINTN
*NumberOfBytes
,
148 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
155 if (Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer
||
156 Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer64
) {
157 *DeviceAddress
= (UINTN
)HostAddress
;
162 DEBUG ((DEBUG_VERBOSE
, "PeiIoMmuMap - HostAddress - 0x%x, NumberOfBytes - %x\n", HostAddress
, *NumberOfBytes
));
163 DEBUG ((DEBUG_VERBOSE
, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop
));
164 DEBUG ((DEBUG_VERBOSE
, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom
));
166 Length
= *NumberOfBytes
+ sizeof(MAP_INFO
);
167 if (Length
> mDmaBufferCurrentTop
- mDmaBufferCurrentBottom
) {
168 DEBUG ((DEBUG_ERROR
, "PeiIoMmuMap - OUT_OF_RESOURCE\n"));
170 return EFI_OUT_OF_RESOURCES
;
173 *DeviceAddress
= mDmaBufferCurrentBottom
;
174 mDmaBufferCurrentBottom
+= Length
;
176 MapInfo
= (VOID
*)(UINTN
)(*DeviceAddress
+ *NumberOfBytes
);
177 MapInfo
->Signature
= MAP_INFO_SIGNATURE
;
178 MapInfo
->Operation
= Operation
;
179 MapInfo
->NumberOfBytes
= *NumberOfBytes
;
180 MapInfo
->HostAddress
= (UINTN
)HostAddress
;
181 MapInfo
->DeviceAddress
= *DeviceAddress
;
183 DEBUG ((DEBUG_VERBOSE
, " Op(%x):DeviceAddress - %x, Mapping - %x\n", Operation
, (UINTN
)*DeviceAddress
, MapInfo
));
186 // If this is a read operation from the Bus Master's point of view,
187 // then copy the contents of the real buffer into the mapped buffer
188 // so the Bus Master can read the contents of the real buffer.
190 if (Operation
== EdkiiIoMmuOperationBusMasterRead
||
191 Operation
== EdkiiIoMmuOperationBusMasterRead64
) {
193 (VOID
*) (UINTN
) MapInfo
->DeviceAddress
,
194 (VOID
*) (UINTN
) MapInfo
->HostAddress
,
195 MapInfo
->NumberOfBytes
203 Completes the Map() operation and releases any corresponding resources.
205 @param This The PPI instance pointer.
206 @param Mapping The mapping value returned from Map().
208 @retval EFI_SUCCESS The range was unmapped.
209 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
210 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
215 IN EDKII_IOMMU_PPI
*This
,
222 if (Mapping
== NULL
) {
226 DEBUG ((DEBUG_VERBOSE
, "PeiIoMmuUnmap - Mapping - %x\n", Mapping
));
227 DEBUG ((DEBUG_VERBOSE
, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop
));
228 DEBUG ((DEBUG_VERBOSE
, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom
));
231 ASSERT (MapInfo
->Signature
== MAP_INFO_SIGNATURE
);
232 DEBUG ((DEBUG_VERBOSE
, " Op(%x):DeviceAddress - %x, NumberOfBytes - %x\n", MapInfo
->Operation
, (UINTN
)MapInfo
->DeviceAddress
, MapInfo
->NumberOfBytes
));
235 // If this is a write operation from the Bus Master's point of view,
236 // then copy the contents of the mapped buffer into the real buffer
237 // so the processor can read the contents of the real buffer.
239 if (MapInfo
->Operation
== EdkiiIoMmuOperationBusMasterWrite
||
240 MapInfo
->Operation
== EdkiiIoMmuOperationBusMasterWrite64
) {
242 (VOID
*) (UINTN
) MapInfo
->HostAddress
,
243 (VOID
*) (UINTN
) MapInfo
->DeviceAddress
,
244 MapInfo
->NumberOfBytes
248 Length
= MapInfo
->NumberOfBytes
+ sizeof(MAP_INFO
);
249 if (mDmaBufferCurrentBottom
== MapInfo
->DeviceAddress
+ Length
) {
250 mDmaBufferCurrentBottom
-= Length
;
257 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
258 OperationBusMasterCommonBuffer64 mapping.
260 @param This The PPI instance pointer.
261 @param MemoryType The type of memory to allocate, EfiBootServicesData or
262 EfiRuntimeServicesData.
263 @param Pages The number of pages to allocate.
264 @param HostAddress A pointer to store the base system memory address of the
266 @param Attributes The requested bit mask of attributes for the allocated range.
268 @retval EFI_SUCCESS The requested memory pages were allocated.
269 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
270 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
271 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
272 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
277 PeiIoMmuAllocateBuffer (
278 IN EDKII_IOMMU_PPI
*This
,
279 IN EFI_MEMORY_TYPE MemoryType
,
281 IN OUT VOID
**HostAddress
,
287 DEBUG ((DEBUG_VERBOSE
, "PeiIoMmuAllocateBuffer - page - %x\n", Pages
));
288 DEBUG ((DEBUG_VERBOSE
, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop
));
289 DEBUG ((DEBUG_VERBOSE
, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom
));
291 Length
= EFI_PAGES_TO_SIZE(Pages
);
292 if (Length
> mDmaBufferCurrentTop
- mDmaBufferCurrentBottom
) {
293 DEBUG ((DEBUG_ERROR
, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n"));
295 return EFI_OUT_OF_RESOURCES
;
297 *HostAddress
= (VOID
*)(UINTN
)(mDmaBufferCurrentTop
- Length
);
298 mDmaBufferCurrentTop
-= Length
;
300 DEBUG ((DEBUG_VERBOSE
, "PeiIoMmuAllocateBuffer - allocate - %x\n", *HostAddress
));
305 Frees memory that was allocated with AllocateBuffer().
307 @param This The PPI instance pointer.
308 @param Pages The number of pages to free.
309 @param HostAddress The base system memory address of the allocated range.
311 @retval EFI_SUCCESS The requested memory pages were freed.
312 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
313 was not allocated with AllocateBuffer().
319 IN EDKII_IOMMU_PPI
*This
,
326 DEBUG ((DEBUG_VERBOSE
, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n", Pages
, HostAddress
));
327 DEBUG ((DEBUG_VERBOSE
, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop
));
328 DEBUG ((DEBUG_VERBOSE
, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom
));
330 Length
= EFI_PAGES_TO_SIZE(Pages
);
331 if ((UINTN
)HostAddress
== mDmaBufferCurrentTop
) {
332 mDmaBufferCurrentTop
+= Length
;
338 EDKII_IOMMU_PPI mIoMmuPpi
= {
339 EDKII_IOMMU_PPI_REVISION
,
340 PeiIoMmuSetAttribute
,
343 PeiIoMmuAllocateBuffer
,
347 CONST EFI_PEI_PPI_DESCRIPTOR mIoMmuPpiList
= {
348 EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
353 #define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
354 EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
355 EFI_RESOURCE_ATTRIBUTE_TESTED | \
356 EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \
357 EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \
358 EFI_RESOURCE_ATTRIBUTE_64_BIT_IO \
361 #define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED)
363 #define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED)
365 #define PRESENT_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT)
367 GLOBAL_REMOVE_IF_UNREFERENCED CHAR8
*mResourceTypeShortName
[] = {
378 Return the short name of resource type.
380 @param Type resource type.
382 @return the short name of resource type.
385 ShortNameOfResourceType (
389 if (Type
< sizeof(mResourceTypeShortName
) / sizeof(mResourceTypeShortName
[0])) {
390 return mResourceTypeShortName
[Type
];
399 @param HobList the HOB list.
406 EFI_PEI_HOB_POINTERS Hob
;
407 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
409 DEBUG ((DEBUG_VERBOSE
, "Resource Descriptor HOBs\n"));
410 for (Hob
.Raw
= HobList
; !END_OF_HOB_LIST (Hob
); Hob
.Raw
= GET_NEXT_HOB (Hob
)) {
411 if (GET_HOB_TYPE (Hob
) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
412 ResourceHob
= Hob
.ResourceDescriptor
;
413 DEBUG ((DEBUG_VERBOSE
,
414 " BA=%016lx L=%016lx Attr=%08x ",
415 ResourceHob
->PhysicalStart
,
416 ResourceHob
->ResourceLength
,
417 ResourceHob
->ResourceAttribute
419 DEBUG ((DEBUG_VERBOSE
, ShortNameOfResourceType(ResourceHob
->ResourceType
)));
420 switch (ResourceHob
->ResourceType
) {
421 case EFI_RESOURCE_SYSTEM_MEMORY
:
422 if ((ResourceHob
->ResourceAttribute
& EFI_RESOURCE_ATTRIBUTE_PERSISTENT
) != 0) {
423 DEBUG ((DEBUG_VERBOSE
, " (Persistent)"));
424 } else if ((ResourceHob
->ResourceAttribute
& EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE
) != 0) {
425 DEBUG ((DEBUG_VERBOSE
, " (MoreReliable)"));
426 } else if ((ResourceHob
->ResourceAttribute
& MEMORY_ATTRIBUTE_MASK
) == TESTED_MEMORY_ATTRIBUTES
) {
427 DEBUG ((DEBUG_VERBOSE
, " (Tested)"));
428 } else if ((ResourceHob
->ResourceAttribute
& MEMORY_ATTRIBUTE_MASK
) == INITIALIZED_MEMORY_ATTRIBUTES
) {
429 DEBUG ((DEBUG_VERBOSE
, " (Init)"));
430 } else if ((ResourceHob
->ResourceAttribute
& MEMORY_ATTRIBUTE_MASK
) == PRESENT_MEMORY_ATTRIBUTES
) {
431 DEBUG ((DEBUG_VERBOSE
, " (Present)"));
433 DEBUG ((DEBUG_VERBOSE
, " (Unknown)"));
439 DEBUG ((DEBUG_VERBOSE
, "\n"));
447 @param HobList the HOB list.
454 EFI_HOB_HANDOFF_INFO_TABLE
*PhitHob
;
457 ASSERT(GET_HOB_TYPE(HobList
) == EFI_HOB_TYPE_HANDOFF
);
458 DEBUG ((DEBUG_VERBOSE
, "PHIT HOB\n"));
459 DEBUG ((DEBUG_VERBOSE
, " PhitHob - 0x%x\n", PhitHob
));
460 DEBUG ((DEBUG_VERBOSE
, " BootMode - 0x%x\n", PhitHob
->BootMode
));
461 DEBUG ((DEBUG_VERBOSE
, " EfiMemoryTop - 0x%016lx\n", PhitHob
->EfiMemoryTop
));
462 DEBUG ((DEBUG_VERBOSE
, " EfiMemoryBottom - 0x%016lx\n", PhitHob
->EfiMemoryBottom
));
463 DEBUG ((DEBUG_VERBOSE
, " EfiFreeMemoryTop - 0x%016lx\n", PhitHob
->EfiFreeMemoryTop
));
464 DEBUG ((DEBUG_VERBOSE
, " EfiFreeMemoryBottom - 0x%016lx\n", PhitHob
->EfiFreeMemoryBottom
));
465 DEBUG ((DEBUG_VERBOSE
, " EfiEndOfHobList - 0x%lx\n", PhitHob
->EfiEndOfHobList
));
469 Get the highest memory.
471 @return the highest memory.
479 EFI_PEI_HOB_POINTERS Hob
;
480 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
484 HobList
= GetHobList ();
487 for (Hob
.Raw
= HobList
; !END_OF_HOB_LIST (Hob
); Hob
.Raw
= GET_NEXT_HOB (Hob
)) {
488 if (GET_HOB_TYPE (Hob
) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
489 ResourceHob
= Hob
.ResourceDescriptor
;
490 switch (ResourceHob
->ResourceType
) {
491 case EFI_RESOURCE_SYSTEM_MEMORY
:
492 ResourceTop
= ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
;
493 if (TopMemory
< ResourceTop
) {
494 TopMemory
= ResourceTop
;
500 DEBUG ((DEBUG_VERBOSE
, "\n"));
507 Initialize DMA protection.
509 @param DmaBufferSize the DMA buffer size
510 @param DmaBufferBase the DMA buffer base
512 @retval EFI_SUCCESS the DMA protection is initialized.
513 @retval EFI_OUT_OF_RESOURCES no enough resource to initialize DMA protection.
517 IN UINTN DmaBufferSize
,
518 OUT UINTN
*DmaBufferBase
523 EFI_HOB_HANDOFF_INFO_TABLE
*PhitHob
;
524 UINT32 LowMemoryAlignment
;
525 UINT64 HighMemoryAlignment
;
526 UINTN MemoryAlignment
;
532 HobList
= GetHobList ();
533 DumpPhitHob (HobList
);
534 DumpResourceHob (HobList
);
538 ASSERT (PhitHob
->EfiMemoryBottom
< PhitHob
->EfiMemoryTop
);
540 LowMemoryAlignment
= GetLowMemoryAlignment (mEngineMask
);
541 HighMemoryAlignment
= GetHighMemoryAlignment (mEngineMask
);
542 if (LowMemoryAlignment
< HighMemoryAlignment
) {
543 MemoryAlignment
= (UINTN
)HighMemoryAlignment
;
545 MemoryAlignment
= LowMemoryAlignment
;
547 ASSERT (DmaBufferSize
== ALIGN_VALUE(DmaBufferSize
, MemoryAlignment
));
548 *DmaBufferBase
= (UINTN
)AllocateAlignedPages (EFI_SIZE_TO_PAGES(DmaBufferSize
), MemoryAlignment
);
549 ASSERT (*DmaBufferBase
!= 0);
550 if (*DmaBufferBase
== 0) {
551 DEBUG ((DEBUG_INFO
, " InitDmaProtection : OutOfResource\n"));
552 return EFI_OUT_OF_RESOURCES
;
556 LowTop
= *DmaBufferBase
;
557 HighBottom
= *DmaBufferBase
+ DmaBufferSize
;
558 HighTop
= GetTopMemory ();
560 Status
= SetDmaProtectedRange (
563 (UINT32
)(LowTop
- LowBottom
),
568 if (EFI_ERROR(Status
)) {
569 FreePages ((VOID
*)*DmaBufferBase
, EFI_SIZE_TO_PAGES(DmaBufferSize
));
576 Dump DMAR DeviceScopeEntry.
578 @param[in] DmarDeviceScopeEntry DMAR DeviceScopeEntry
581 DumpDmarDeviceScopeEntry (
582 IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*DmarDeviceScopeEntry
587 EFI_ACPI_DMAR_PCI_PATH
*PciPath
;
589 if (DmarDeviceScopeEntry
== NULL
) {
594 " *************************************************************************\n"
597 " * DMA-Remapping Device Scope Entry Structure *\n"
600 " *************************************************************************\n"
603 (sizeof(UINTN
) == sizeof(UINT64
)) ?
604 " DMAR Device Scope Entry address ...................... 0x%016lx\n" :
605 " DMAR Device Scope Entry address ...................... 0x%08x\n",
609 " Device Scope Entry Type ............................ 0x%02x\n",
610 DmarDeviceScopeEntry
->Type
612 switch (DmarDeviceScopeEntry
->Type
) {
613 case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT
:
615 " PCI Endpoint Device\n"
618 case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE
:
620 " PCI Sub-hierachy\n"
627 " Length ............................................. 0x%02x\n",
628 DmarDeviceScopeEntry
->Length
631 " Enumeration ID ..................................... 0x%02x\n",
632 DmarDeviceScopeEntry
->EnumerationId
635 " Starting Bus Number ................................ 0x%02x\n",
636 DmarDeviceScopeEntry
->StartBusNumber
639 PciPathNumber
= (DmarDeviceScopeEntry
->Length
- sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
)) / sizeof(EFI_ACPI_DMAR_PCI_PATH
);
640 PciPath
= (EFI_ACPI_DMAR_PCI_PATH
*)(DmarDeviceScopeEntry
+ 1);
641 for (PciPathIndex
= 0; PciPathIndex
< PciPathNumber
; PciPathIndex
++) {
643 " Device ............................................. 0x%02x\n",
644 PciPath
[PciPathIndex
].Device
647 " Function ........................................... 0x%02x\n",
648 PciPath
[PciPathIndex
].Function
653 " *************************************************************************\n\n"
660 Dump DMAR RMRR table.
662 @param[in] Rmrr DMAR RMRR table
666 IN EFI_ACPI_DMAR_RMRR_HEADER
*Rmrr
669 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*DmarDeviceScopeEntry
;
677 " ***************************************************************************\n"
680 " * Reserved Memory Region Reporting Structure *\n"
683 " ***************************************************************************\n"
686 (sizeof(UINTN
) == sizeof(UINT64
)) ?
687 " RMRR address ........................................... 0x%016lx\n" :
688 " RMRR address ........................................... 0x%08x\n",
692 " Type ................................................. 0x%04x\n",
696 " Length ............................................... 0x%04x\n",
700 " Segment Number ....................................... 0x%04x\n",
704 " Reserved Memory Region Base Address .................. 0x%016lx\n",
705 Rmrr
->ReservedMemoryRegionBaseAddress
708 " Reserved Memory Region Limit Address ................. 0x%016lx\n",
709 Rmrr
->ReservedMemoryRegionLimitAddress
712 RmrrLen
= Rmrr
->Header
.Length
- sizeof(EFI_ACPI_DMAR_RMRR_HEADER
);
713 DmarDeviceScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)(Rmrr
+ 1);
714 while (RmrrLen
> 0) {
715 DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry
);
716 RmrrLen
-= DmarDeviceScopeEntry
->Length
;
717 DmarDeviceScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)DmarDeviceScopeEntry
+ DmarDeviceScopeEntry
->Length
);
721 " ***************************************************************************\n\n"
728 Dump DMAR DRHD table.
730 @param[in] Drhd DMAR DRHD table
734 IN EFI_ACPI_DMAR_DRHD_HEADER
*Drhd
737 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*DmarDeviceScopeEntry
;
745 " ***************************************************************************\n"
748 " * DMA-Remapping Hardware Definition Structure *\n"
751 " ***************************************************************************\n"
754 (sizeof(UINTN
) == sizeof(UINT64
)) ?
755 " DRHD address ........................................... 0x%016lx\n" :
756 " DRHD address ........................................... 0x%08x\n",
760 " Type ................................................. 0x%04x\n",
764 " Length ............................................... 0x%04x\n",
768 " Flags ................................................ 0x%02x\n",
772 " INCLUDE_PCI_ALL .................................... 0x%02x\n",
773 Drhd
->Flags
& EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL
776 " Segment Number ....................................... 0x%04x\n",
780 " Register Base Address ................................ 0x%016lx\n",
781 Drhd
->RegisterBaseAddress
784 DrhdLen
= Drhd
->Header
.Length
- sizeof(EFI_ACPI_DMAR_DRHD_HEADER
);
785 DmarDeviceScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)(Drhd
+ 1);
786 while (DrhdLen
> 0) {
787 DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry
);
788 DrhdLen
-= DmarDeviceScopeEntry
->Length
;
789 DmarDeviceScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)DmarDeviceScopeEntry
+ DmarDeviceScopeEntry
->Length
);
793 " ***************************************************************************\n\n"
800 Dump DMAR ACPI table.
802 @param[in] Dmar DMAR ACPI table
806 IN EFI_ACPI_DMAR_HEADER
*Dmar
809 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
820 "*****************************************************************************\n"
826 "*****************************************************************************\n"
830 (sizeof(UINTN
) == sizeof(UINT64
)) ?
831 "DMAR address ............................................. 0x%016lx\n" :
832 "DMAR address ............................................. 0x%08x\n",
840 " Host Address Width ................................... 0x%02x\n",
841 Dmar
->HostAddressWidth
844 " Flags ................................................ 0x%02x\n",
848 " INTR_REMAP ......................................... 0x%02x\n",
849 Dmar
->Flags
& EFI_ACPI_DMAR_FLAGS_INTR_REMAP
852 " X2APIC_OPT_OUT_SET ................................. 0x%02x\n",
853 Dmar
->Flags
& EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT
856 DmarLen
= Dmar
->Header
.Length
- sizeof(EFI_ACPI_DMAR_HEADER
);
857 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)(Dmar
+ 1);
858 while (DmarLen
> 0) {
859 switch (DmarHeader
->Type
) {
860 case EFI_ACPI_DMAR_TYPE_DRHD
:
861 DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER
*)DmarHeader
);
863 case EFI_ACPI_DMAR_TYPE_RMRR
:
864 DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER
*)DmarHeader
);
869 DmarLen
-= DmarHeader
->Length
;
870 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);
874 "*****************************************************************************\n\n"
881 Get VTd engine number.
883 @return the VTd engine number.
890 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
894 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)(mAcpiDmarTable
+ 1));
895 while ((UINTN
)DmarHeader
< (UINTN
)mAcpiDmarTable
+ mAcpiDmarTable
->Header
.Length
) {
896 switch (DmarHeader
->Type
) {
897 case EFI_ACPI_DMAR_TYPE_DRHD
:
903 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);
909 Process DMAR DHRD table.
911 @param[in] VtdIndex The index of VTd engine.
912 @param[in] DmarDrhd The DRHD table.
917 IN EFI_ACPI_DMAR_DRHD_HEADER
*DmarDrhd
920 DEBUG ((DEBUG_INFO
," VTD (%d) BaseAddress - 0x%016lx\n", VtdIndex
, DmarDrhd
->RegisterBaseAddress
));
921 mVTdInfo
->VTdEngineAddress
[VtdIndex
] = DmarDrhd
->RegisterBaseAddress
;
925 Parse DMAR DRHD table.
927 @return EFI_SUCCESS The DMAR DRHD table is parsed.
930 ParseDmarAcpiTableDrhd (
934 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
938 VtdUnitNumber
= GetVtdEngineNumber ();
939 if (VtdUnitNumber
== 0) {
940 return EFI_UNSUPPORTED
;
943 mVTdInfo
= AllocateZeroPool (sizeof(VTD_INFO
) + (VtdUnitNumber
- 1) * sizeof(UINT64
));
944 if (mVTdInfo
== NULL
) {
945 return EFI_OUT_OF_RESOURCES
;
947 mVTdInfo
->HostAddressWidth
= mAcpiDmarTable
->HostAddressWidth
;
948 mVTdInfo
->VTdEngineCount
= VtdUnitNumber
;
951 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)(mAcpiDmarTable
+ 1));
952 while ((UINTN
)DmarHeader
< (UINTN
)mAcpiDmarTable
+ mAcpiDmarTable
->Header
.Length
) {
953 switch (DmarHeader
->Type
) {
954 case EFI_ACPI_DMAR_TYPE_DRHD
:
955 ASSERT (VtdIndex
< VtdUnitNumber
);
956 ProcessDhrd (VtdIndex
, (EFI_ACPI_DMAR_DRHD_HEADER
*)DmarHeader
);
964 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);
966 ASSERT (VtdIndex
== VtdUnitNumber
);
969 // Initialize the engine mask to all.
971 mEngineMask
= LShiftU64 (1, VtdUnitNumber
) - 1;
977 Return the VTd engine index according to the Segment and DevScopeEntry.
979 @param Segment The segment of the VTd engine
980 @param DevScopeEntry The DevScopeEntry of the VTd engine
982 @return The VTd engine index according to the Segment and DevScopeEntry.
983 @retval -1 The VTd engine is not found.
986 GetVTdEngineFromDevScopeEntry (
988 IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*DevScopeEntry
991 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
993 EFI_ACPI_DMAR_DRHD_HEADER
*DmarDrhd
;
994 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*ThisDevScopeEntry
;
997 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)(mAcpiDmarTable
+ 1));
998 while ((UINTN
)DmarHeader
< (UINTN
)mAcpiDmarTable
+ mAcpiDmarTable
->Header
.Length
) {
999 switch (DmarHeader
->Type
) {
1000 case EFI_ACPI_DMAR_TYPE_DRHD
:
1001 DmarDrhd
= (EFI_ACPI_DMAR_DRHD_HEADER
*)DmarHeader
;
1002 if (DmarDrhd
->SegmentNumber
!= Segment
) {
1006 if ((DmarDrhd
->Header
.Length
== sizeof(EFI_ACPI_DMAR_DRHD_HEADER
)) ||
1007 ((DmarDrhd
->Flags
& EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL
) != 0)) {
1009 // Do not handle PCI_ALL
1012 ThisDevScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)(DmarDrhd
+ 1));
1013 while ((UINTN
)ThisDevScopeEntry
< (UINTN
)DmarDrhd
+ DmarDrhd
->Header
.Length
) {
1014 if ((ThisDevScopeEntry
->Length
== DevScopeEntry
->Length
) &&
1015 (CompareMem (ThisDevScopeEntry
, DevScopeEntry
, DevScopeEntry
->Length
) == 0)) {
1018 ThisDevScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)ThisDevScopeEntry
+ ThisDevScopeEntry
->Length
);
1024 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);
1030 Process DMAR RMRR table.
1032 @param[in] DmarRmrr The RMRR table.
1036 IN EFI_ACPI_DMAR_RMRR_HEADER
*DmarRmrr
1039 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*DmarDevScopeEntry
;
1047 DEBUG ((DEBUG_INFO
," RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr
->ReservedMemoryRegionBaseAddress
, DmarRmrr
->ReservedMemoryRegionLimitAddress
));
1049 if ((DmarRmrr
->ReservedMemoryRegionBaseAddress
== 0) ||
1050 (DmarRmrr
->ReservedMemoryRegionLimitAddress
== 0)) {
1054 DmarDevScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)(DmarRmrr
+ 1));
1055 while ((UINTN
)DmarDevScopeEntry
< (UINTN
)DmarRmrr
+ DmarRmrr
->Header
.Length
) {
1056 ASSERT (DmarDevScopeEntry
->Type
== EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT
);
1058 VTdIndex
= GetVTdEngineFromDevScopeEntry (DmarRmrr
->SegmentNumber
, DmarDevScopeEntry
);
1059 if (VTdIndex
!= (UINTN
)-1) {
1060 RmrrMask
= LShiftU64 (1, VTdIndex
);
1063 LowTop
= (UINTN
)DmarRmrr
->ReservedMemoryRegionBaseAddress
;
1064 HighBottom
= (UINTN
)DmarRmrr
->ReservedMemoryRegionLimitAddress
+ 1;
1065 HighTop
= GetTopMemory ();
1067 SetDmaProtectedRange (
1070 (UINT32
)(LowTop
- LowBottom
),
1072 HighTop
- HighBottom
1076 // Remove the engine from the engine mask.
1077 // The assumption is that any other PEI driver does not access
1078 // the device covered by this engine.
1080 mEngineMask
= mEngineMask
& (~RmrrMask
);
1083 DmarDevScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)DmarDevScopeEntry
+ DmarDevScopeEntry
->Length
);
1088 Parse DMAR DRHD table.
1091 ParseDmarAcpiTableRmrr (
1095 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
1097 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)(mAcpiDmarTable
+ 1));
1098 while ((UINTN
)DmarHeader
< (UINTN
)mAcpiDmarTable
+ mAcpiDmarTable
->Header
.Length
) {
1099 switch (DmarHeader
->Type
) {
1100 case EFI_ACPI_DMAR_TYPE_RMRR
:
1101 ProcessRmrr ((EFI_ACPI_DMAR_RMRR_HEADER
*)DmarHeader
);
1106 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);
1111 This function handles S3 resume task at the end of PEI
1113 @param[in] PeiServices Pointer to PEI Services Table.
1114 @param[in] NotifyDesc Pointer to the descriptor for the Notification event that
1115 caused this function to execute.
1116 @param[in] Ppi Pointer to the PPI data associated with this function.
1118 @retval EFI_STATUS Always return EFI_SUCCESS
1123 IN EFI_PEI_SERVICES
**PeiServices
,
1124 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDesc
,
1130 DEBUG((DEBUG_INFO
, "VTdPmr S3EndOfPeiNotify\n"));
1132 if ((PcdGet8(PcdVTdPolicyPropertyMask
) & BIT1
) == 0) {
1133 EngineMask
= LShiftU64 (1, mVTdInfo
->VTdEngineCount
) - 1;
1134 DisableDmaProtection (EngineMask
);
1139 EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc
= {
1140 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
1141 &gEfiEndOfPeiSignalPpiGuid
,
1146 Initializes the Intel VTd PMR PEIM.
1148 @param FileHandle Handle of the file being invoked.
1149 @param PeiServices Describes the list of possible PEI Services.
1151 @retval EFI_SUCCESS Usb bot driver is successfully initialized.
1152 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.
1157 IntelVTdPmrInitialize (
1158 IN EFI_PEI_FILE_HANDLE FileHandle
,
1159 IN CONST EFI_PEI_SERVICES
**PeiServices
1163 EFI_BOOT_MODE BootMode
;
1165 if ((PcdGet8(PcdVTdPolicyPropertyMask
) & BIT0
) == 0) {
1166 return EFI_UNSUPPORTED
;
1169 PeiServicesGetBootMode (&BootMode
);
1171 Status
= PeiServicesLocatePpi (
1172 &gEdkiiVTdInfoPpiGuid
,
1175 (VOID
**)&mAcpiDmarTable
1177 ASSERT_EFI_ERROR(Status
);
1179 DumpAcpiDMAR (mAcpiDmarTable
);
1182 // Get DMAR information to local VTdInfo
1184 Status
= ParseDmarAcpiTableDrhd ();
1185 if (EFI_ERROR(Status
)) {
1190 // If there is RMRR memory, parse it here.
1192 ParseDmarAcpiTableRmrr ();
1194 if (BootMode
== BOOT_ON_S3_RESUME
) {
1195 mDmaBufferSize
= TOTAL_DMA_BUFFER_SIZE_S3
;
1197 mDmaBufferSize
= TOTAL_DMA_BUFFER_SIZE
;
1199 DEBUG ((DEBUG_INFO
, " DmaBufferSize : 0x%x\n", mDmaBufferSize
));
1202 // Find a pre-memory in resource hob as DMA buffer
1203 // Mark PEI memory to be DMA protected.
1205 Status
= InitDmaProtection (mDmaBufferSize
, &mDmaBufferBase
);
1206 if (EFI_ERROR(Status
)) {
1210 DEBUG ((DEBUG_INFO
, " DmaBufferBase : 0x%x\n", mDmaBufferBase
));
1212 mDmaBufferCurrentTop
= mDmaBufferBase
+ mDmaBufferSize
;
1213 mDmaBufferCurrentBottom
= mDmaBufferBase
;
1218 Status
= PeiServicesInstallPpi (&mIoMmuPpiList
);
1219 ASSERT_EFI_ERROR(Status
);
1222 // Register EndOfPei Notify for S3 to run FSP NotifyPhase
1224 if (BootMode
== BOOT_ON_S3_RESUME
) {
1225 Status
= PeiServicesNotifyPpi (&mS3EndOfPeiNotifyDesc
);
1226 ASSERT_EFI_ERROR (Status
);