IntelSiliconPkg: Add IntelVTdPmrPei.

This PEIM is to produce IOMMU_PPI, so that PEI device
driver can have better DAM management.

This PEIM will setup VTD PMR register to protect
most DRAM. It allocates a big chunk DMA buffer in
the entrypoint, and only use this buffer for DMA.
Any other region is DMA protected.

Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Star Zeng <star.zeng@intel.com>
This commit is contained in:
Jiewen Yao 2017-09-01 16:30:46 +08:00
parent 0b7df50021
commit 3f5ed3fa13
6 changed files with 1096 additions and 0 deletions

View File

@ -0,0 +1,314 @@
/** @file
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License which accompanies this distribution.
The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <PiPei.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/IoLib.h>
#include <Library/DebugLib.h>
#include <IndustryStandard/Vtd.h>
#include <Ppi/VTdInfo.h>
#include "IntelVTdPmrPei.h"
extern EDKII_VTD_INFO_PPI *mVTdInfoPpi;
/**
Get protected low memory alignment.
@param VtdUnitBaseAddress The base address of the VTd engine.
@return protected low memory alignment.
**/
UINT32
GetPlmrAlignment (
IN UINTN VtdUnitBaseAddress
)
{
UINT32 Data32;
MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG, 0xFFFFFFFF);
Data32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG);
Data32 = ~Data32 + 1;
return Data32;
}
/**
Get protected high memory alignment.
@param VtdUnitBaseAddress The base address of the VTd engine.
@return protected high memory alignment.
**/
UINT64
GetPhmrAlignment (
IN UINTN VtdUnitBaseAddress
)
{
UINT64 Data64;
UINT8 HostAddressWidth;
HostAddressWidth = mVTdInfoPpi->HostAddressWidth;
MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, 0xFFFFFFFFFFFFFFFF);
Data64 = MmioRead64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG);
Data64 = ~Data64 + 1;
Data64 = Data64 & (LShiftU64 (1, HostAddressWidth) - 1);
return Data64;
}
/**
Get protected low memory alignment.
@return protected low memory alignment.
**/
UINT32
GetLowMemoryAlignment (
VOID
)
{
UINTN Index;
UINT32 Alignment;
UINT32 FinalAlignment;
FinalAlignment = 0;
for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) {
Alignment = GetPlmrAlignment ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);
if (FinalAlignment < Alignment) {
FinalAlignment = Alignment;
}
}
return FinalAlignment;
}
/**
Get protected high memory alignment.
@return protected high memory alignment.
**/
UINT64
GetHighMemoryAlignment (
VOID
)
{
UINTN Index;
UINT64 Alignment;
UINT64 FinalAlignment;
FinalAlignment = 0;
for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) {
Alignment = GetPhmrAlignment ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);
if (FinalAlignment < Alignment) {
FinalAlignment = Alignment;
}
}
return FinalAlignment;
}
/**
Enable PMR in the VTd engine.
@param VtdUnitBaseAddress The base address of the VTd engine.
@retval EFI_SUCCESS The PMR is enabled.
@retval EFI_UNSUPPORTED The PMR is not supported.
**/
EFI_STATUS
EnablePmr (
IN UINTN VtdUnitBaseAddress
)
{
UINT32 Reg32;
VTD_CAP_REG CapReg;
CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {
return EFI_UNSUPPORTED;
}
Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
if ((Reg32 & BIT0) == 0) {
MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, BIT31);
do {
Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
} while((Reg32 & BIT0) == 0);
}
return EFI_SUCCESS;
}
/**
Disable PMR in the VTd engine.
@param VtdUnitBaseAddress The base address of the VTd engine.
@retval EFI_SUCCESS The PMR is disabled.
@retval EFI_UNSUPPORTED The PMR is not supported.
**/
EFI_STATUS
DisablePmr (
IN UINTN VtdUnitBaseAddress
)
{
UINT32 Reg32;
VTD_CAP_REG CapReg;
CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {
return EFI_UNSUPPORTED;
}
Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
if ((Reg32 & BIT0) != 0) {
MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, 0x0);
do {
Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
} while((Reg32 & BIT0) != 0);
}
return EFI_SUCCESS;
}
/**
Set PMR region in the VTd engine.
@param VtdUnitBaseAddress The base address of the VTd engine.
@param LowMemoryBase The protected low memory region base.
@param LowMemoryLength The protected low memory region length.
@param HighMemoryBase The protected high memory region base.
@param HighMemoryLength The protected high memory region length.
@retval EFI_SUCCESS The PMR is set to protected region.
@retval EFI_UNSUPPORTED The PMR is not supported.
**/
EFI_STATUS
SetPmrRegion (
IN UINTN VtdUnitBaseAddress,
IN UINT32 LowMemoryBase,
IN UINT32 LowMemoryLength,
IN UINT64 HighMemoryBase,
IN UINT64 HighMemoryLength
)
{
VTD_CAP_REG CapReg;
UINT32 PlmrAlignment;
UINT64 PhmrAlignment;
DEBUG ((DEBUG_INFO, "VtdUnitBaseAddress - 0x%x\n", VtdUnitBaseAddress));
CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {
DEBUG ((DEBUG_ERROR, "PLMR/PHMR unsupported\n"));
return EFI_UNSUPPORTED;
}
PlmrAlignment = GetPlmrAlignment (VtdUnitBaseAddress);
DEBUG ((DEBUG_INFO, "PlmrAlignment - 0x%x\n", PlmrAlignment));
PhmrAlignment = GetPhmrAlignment (VtdUnitBaseAddress);
DEBUG ((DEBUG_INFO, "PhmrAlignment - 0x%lx\n", PhmrAlignment));
if ((LowMemoryBase != ALIGN_VALUE(LowMemoryBase, PlmrAlignment)) ||
(LowMemoryLength != ALIGN_VALUE(LowMemoryLength, PlmrAlignment)) ||
(HighMemoryBase != ALIGN_VALUE(HighMemoryBase, PhmrAlignment)) ||
(HighMemoryLength != ALIGN_VALUE(HighMemoryLength, PhmrAlignment))) {
DEBUG ((DEBUG_ERROR, "PLMR/PHMR alignment issue\n"));
return EFI_UNSUPPORTED;
}
if (LowMemoryBase == 0 && LowMemoryLength == 0) {
LowMemoryBase = 0xFFFFFFFF;
}
if (HighMemoryBase == 0 && HighMemoryLength == 0) {
HighMemoryBase = 0xFFFFFFFFFFFFFFFF;
}
MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG, LowMemoryBase);
MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_LIMITE_REG, LowMemoryBase + LowMemoryLength - 1);
MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, HighMemoryBase);
MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_LIMITE_REG, HighMemoryBase + HighMemoryLength - 1);
return EFI_SUCCESS;
}
/**
Set DMA protected region.
@param LowMemoryBase The protected low memory region base.
@param LowMemoryLength The protected low memory region length.
@param HighMemoryBase The protected high memory region base.
@param HighMemoryLength The protected high memory region length.
@retval EFI_SUCCESS The DMA protection is set.
@retval EFI_UNSUPPORTED The DMA protection is not set.
**/
EFI_STATUS
SetDmaProtectedRange (
IN UINT32 LowMemoryBase,
IN UINT32 LowMemoryLength,
IN UINT64 HighMemoryBase,
IN UINT64 HighMemoryLength
)
{
UINTN Index;
EFI_STATUS Status;
DEBUG ((DEBUG_INFO, "SetDmaProtectedRange - [0x%x, 0x%x] [0x%lx, 0x%lx]\n", LowMemoryBase, LowMemoryLength, HighMemoryBase, HighMemoryLength));
for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) {
DisablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);
Status = SetPmrRegion (
(UINTN)mVTdInfoPpi->VTdEngineAddress[Index],
LowMemoryBase,
LowMemoryLength,
HighMemoryBase,
HighMemoryLength
);
if (EFI_ERROR(Status)) {
return Status;
}
Status = EnablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);
if (EFI_ERROR(Status)) {
return Status;
}
}
return EFI_SUCCESS;
}
/**
Diable DMA protection.
@retval DMA protection is disabled.
**/
EFI_STATUS
DisableDmaProtection (
VOID
)
{
UINTN Index;
EFI_STATUS Status;
DEBUG ((DEBUG_INFO, "DisableDmaProtection\n"));
for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) {
Status = DisablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);
if (EFI_ERROR(Status)) {
return Status;
}
}
return EFI_SUCCESS;
}

View File

@ -0,0 +1,615 @@
/** @file
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License which accompanies this distribution.
The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Uefi.h>
#include <PiPei.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/IoLib.h>
#include <Library/DebugLib.h>
#include <Library/PeiServicesLib.h>
#include <Library/HobLib.h>
#include <IndustryStandard/Vtd.h>
#include <Ppi/IoMmu.h>
#include <Ppi/VTdInfo.h>
#include "IntelVTdPmrPei.h"
#define TOTAL_DMA_BUFFER_SIZE SIZE_4MB
EDKII_VTD_INFO_PPI *mVTdInfoPpi;
UINTN mDmaBufferBase;
UINTN mDmaBufferSize = TOTAL_DMA_BUFFER_SIZE;
UINTN mDmaBufferCurrentTop;
UINTN mDmaBufferCurrentBottom;
#define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P')
typedef struct {
UINT32 Signature;
EDKII_IOMMU_OPERATION Operation;
UINTN NumberOfBytes;
EFI_PHYSICAL_ADDRESS HostAddress;
EFI_PHYSICAL_ADDRESS DeviceAddress;
} MAP_INFO;
/**
PEI Memory Layout:
+------------------+ <------- EfiMemoryTop
| PEI allocated |
=========== +==================+
^ | Commom Buf |
| | -------------- |
DMA Buffer | * DMA FREE * |
| | -------------- |
V | Read/Write Buf |
=========== +==================+
| PEI allocated |
| -------------- | <------- EfiFreeMemoryTop
| * PEI FREE * |
| -------------- | <------- EfiFreeMemoryBottom
| hob |
| -------------- |
| Stack |
+------------------+ <------- EfiMemoryBottom / Stack Bottom
+------------------+
| Mem Alloc Hob |
+------------------+
**/
/**
Set IOMMU attribute for a system memory.
If the IOMMU PPI exists, the system memory cannot be used
for DMA by default.
When a device requests a DMA access for a system memory,
the device driver need use SetAttribute() to update the IOMMU
attribute to request DMA access (read and/or write).
@param[in] This The PPI instance pointer.
@param[in] Mapping The mapping value returned from Map().
@param[in] IoMmuAccess The IOMMU access.
@retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by DeviceAddress and Length.
@retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
@retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.
@retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.
@retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by Mapping.
@retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.
@retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.
**/
EFI_STATUS
EFIAPI
PeiIoMmuSetAttribute (
IN EDKII_IOMMU_PPI *This,
IN VOID *Mapping,
IN UINT64 IoMmuAccess
)
{
return EFI_SUCCESS;
}
/**
Provides the controller-specific addresses required to access system memory from a
DMA bus master.
@param This The PPI instance pointer.
@param Operation Indicates if the bus master is going to read or write to system memory.
@param HostAddress The system memory address to map to the PCI controller.
@param NumberOfBytes On input the number of bytes to map. On output the number of bytes
that were mapped.
@param DeviceAddress The resulting map address for the bus master PCI controller to use to
access the hosts HostAddress.
@param Mapping A resulting value to pass to Unmap().
@retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
@retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
@retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
**/
EFI_STATUS
EFIAPI
PeiIoMmuMap (
IN EDKII_IOMMU_PPI *This,
IN EDKII_IOMMU_OPERATION Operation,
IN VOID *HostAddress,
IN OUT UINTN *NumberOfBytes,
OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
OUT VOID **Mapping
)
{
MAP_INFO *MapInfo;
UINTN Length;
if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||
Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {
*DeviceAddress = (UINTN)HostAddress;
*Mapping = 0;
return EFI_SUCCESS;
}
DEBUG ((DEBUG_VERBOSE, "PeiIoMmuMap - HostAddress - 0x%x, NumberOfBytes - %x\n", HostAddress, *NumberOfBytes));
DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));
DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));
Length = *NumberOfBytes + sizeof(MAP_INFO);
if (Length > mDmaBufferCurrentTop - mDmaBufferCurrentBottom) {
DEBUG ((DEBUG_ERROR, "PeiIoMmuMap - OUT_OF_RESOURCE\n"));
ASSERT (FALSE);
return EFI_OUT_OF_RESOURCES;
}
*DeviceAddress = mDmaBufferCurrentBottom;
mDmaBufferCurrentBottom += Length;
MapInfo = (VOID *)(UINTN)(*DeviceAddress + *NumberOfBytes);
MapInfo->Signature = MAP_INFO_SIGNATURE;
MapInfo->Operation = Operation;
MapInfo->NumberOfBytes = *NumberOfBytes;
MapInfo->HostAddress = (UINTN)HostAddress;
MapInfo->DeviceAddress = *DeviceAddress;
*Mapping = MapInfo;
DEBUG ((DEBUG_VERBOSE, " Op(%x):DeviceAddress - %x, Mapping - %x\n", Operation, (UINTN)*DeviceAddress, MapInfo));
//
// If this is a read operation from the Bus Master's point of view,
// then copy the contents of the real buffer into the mapped buffer
// so the Bus Master can read the contents of the real buffer.
//
if (Operation == EdkiiIoMmuOperationBusMasterRead ||
Operation == EdkiiIoMmuOperationBusMasterRead64) {
CopyMem (
(VOID *) (UINTN) MapInfo->DeviceAddress,
(VOID *) (UINTN) MapInfo->HostAddress,
MapInfo->NumberOfBytes
);
}
return EFI_SUCCESS;
}
/**
Completes the Map() operation and releases any corresponding resources.
@param This The PPI instance pointer.
@param Mapping The mapping value returned from Map().
@retval EFI_SUCCESS The range was unmapped.
@retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
@retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
**/
EFI_STATUS
EFIAPI
PeiIoMmuUnmap (
IN EDKII_IOMMU_PPI *This,
IN VOID *Mapping
)
{
MAP_INFO *MapInfo;
UINTN Length;
if (Mapping == NULL) {
return EFI_SUCCESS;
}
DEBUG ((DEBUG_VERBOSE, "PeiIoMmuUnmap - Mapping - %x\n", Mapping));
DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));
DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));
MapInfo = Mapping;
ASSERT (MapInfo->Signature == MAP_INFO_SIGNATURE);
DEBUG ((DEBUG_VERBOSE, " Op(%x):DeviceAddress - %x, NumberOfBytes - %x\n", MapInfo->Operation, (UINTN)MapInfo->DeviceAddress, MapInfo->NumberOfBytes));
//
// If this is a write operation from the Bus Master's point of view,
// then copy the contents of the mapped buffer into the real buffer
// so the processor can read the contents of the real buffer.
//
if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite ||
MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite64) {
CopyMem (
(VOID *) (UINTN) MapInfo->HostAddress,
(VOID *) (UINTN) MapInfo->DeviceAddress,
MapInfo->NumberOfBytes
);
}
Length = MapInfo->NumberOfBytes + sizeof(MAP_INFO);
if (mDmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) {
mDmaBufferCurrentBottom -= Length;
}
return EFI_SUCCESS;
}
/**
Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
OperationBusMasterCommonBuffer64 mapping.
@param This The PPI instance pointer.
@param MemoryType The type of memory to allocate, EfiBootServicesData or
EfiRuntimeServicesData.
@param Pages The number of pages to allocate.
@param HostAddress A pointer to store the base system memory address of the
allocated range.
@param Attributes The requested bit mask of attributes for the allocated range.
@retval EFI_SUCCESS The requested memory pages were allocated.
@retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
MEMORY_WRITE_COMBINE and MEMORY_CACHED.
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
@retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
**/
EFI_STATUS
EFIAPI
PeiIoMmuAllocateBuffer (
IN EDKII_IOMMU_PPI *This,
IN EFI_MEMORY_TYPE MemoryType,
IN UINTN Pages,
IN OUT VOID **HostAddress,
IN UINT64 Attributes
)
{
UINTN Length;
DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - page - %x\n", Pages));
DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));
DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));
Length = EFI_PAGES_TO_SIZE(Pages);
if (Length > mDmaBufferCurrentTop - mDmaBufferCurrentBottom) {
DEBUG ((DEBUG_ERROR, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n"));
ASSERT (FALSE);
return EFI_OUT_OF_RESOURCES;
}
*HostAddress = (VOID *)(UINTN)(mDmaBufferCurrentTop - Length);
mDmaBufferCurrentTop -= Length;
DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - allocate - %x\n", *HostAddress));
return EFI_SUCCESS;
}
/**
Frees memory that was allocated with AllocateBuffer().
@param This The PPI instance pointer.
@param Pages The number of pages to free.
@param HostAddress The base system memory address of the allocated range.
@retval EFI_SUCCESS The requested memory pages were freed.
@retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
was not allocated with AllocateBuffer().
**/
EFI_STATUS
EFIAPI
PeiIoMmuFreeBuffer (
IN EDKII_IOMMU_PPI *This,
IN UINTN Pages,
IN VOID *HostAddress
)
{
UINTN Length;
DEBUG ((DEBUG_VERBOSE, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n", Pages, HostAddress));
DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));
DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));
Length = EFI_PAGES_TO_SIZE(Pages);
if ((UINTN)HostAddress == mDmaBufferCurrentTop) {
mDmaBufferCurrentTop += Length;
}
return EFI_SUCCESS;
}
EDKII_IOMMU_PPI mIoMmuPpi = {
EDKII_IOMMU_PPI_REVISION,
PeiIoMmuSetAttribute,
PeiIoMmuMap,
PeiIoMmuUnmap,
PeiIoMmuAllocateBuffer,
PeiIoMmuFreeBuffer,
};
CONST EFI_PEI_PPI_DESCRIPTOR mIoMmuPpiList = {
EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
&gEdkiiIoMmuPpiGuid,
(VOID *) &mIoMmuPpi
};
#define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
EFI_RESOURCE_ATTRIBUTE_TESTED | \
EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \
EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \
EFI_RESOURCE_ATTRIBUTE_64_BIT_IO \
)
#define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED)
#define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED)
#define PRESENT_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT)
GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mResourceTypeShortName[] = {
"Mem",
"MMIO",
"I/O",
"FD",
"MM Port I/O",
"Reserved Mem",
"Reserved I/O",
};
/**
Return the short name of resource type.
@param Type resource type.
@return the short name of resource type.
**/
CHAR8 *
ShortNameOfResourceType (
IN UINT32 Type
)
{
if (Type < sizeof(mResourceTypeShortName) / sizeof(mResourceTypeShortName[0])) {
return mResourceTypeShortName[Type];
} else {
return "Unknown";
}
}
/**
Dump resource hob.
@param HobList the HOB list.
**/
VOID
DumpResourceHob (
IN VOID *HobList
)
{
EFI_PEI_HOB_POINTERS Hob;
EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
DEBUG ((DEBUG_VERBOSE, "Resource Descriptor HOBs\n"));
for (Hob.Raw = HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
ResourceHob = Hob.ResourceDescriptor;
DEBUG ((DEBUG_VERBOSE,
" BA=%016lx L=%016lx Attr=%08x ",
ResourceHob->PhysicalStart,
ResourceHob->ResourceLength,
ResourceHob->ResourceAttribute
));
DEBUG ((DEBUG_VERBOSE, ShortNameOfResourceType(ResourceHob->ResourceType)));
switch (ResourceHob->ResourceType) {
case EFI_RESOURCE_SYSTEM_MEMORY:
if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) != 0) {
DEBUG ((DEBUG_VERBOSE, " (Persistent)"));
} else if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) != 0) {
DEBUG ((DEBUG_VERBOSE, " (MoreReliable)"));
} else if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) {
DEBUG ((DEBUG_VERBOSE, " (Tested)"));
} else if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) {
DEBUG ((DEBUG_VERBOSE, " (Init)"));
} else if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) {
DEBUG ((DEBUG_VERBOSE, " (Present)"));
} else {
DEBUG ((DEBUG_VERBOSE, " (Unknown)"));
}
break;
default:
break;
}
DEBUG ((DEBUG_VERBOSE, "\n"));
}
}
}
/**
Dump PHIT hob.
@param HobList the HOB list.
**/
VOID
DumpPhitHob (
IN VOID *HobList
)
{
EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
PhitHob = HobList;
ASSERT(GET_HOB_TYPE(HobList) == EFI_HOB_TYPE_HANDOFF);
DEBUG ((DEBUG_VERBOSE, "PHIT HOB\n"));
DEBUG ((DEBUG_VERBOSE, " PhitHob - 0x%x\n", PhitHob));
DEBUG ((DEBUG_VERBOSE, " BootMode - 0x%x\n", PhitHob->BootMode));
DEBUG ((DEBUG_VERBOSE, " EfiMemoryTop - 0x%016lx\n", PhitHob->EfiMemoryTop));
DEBUG ((DEBUG_VERBOSE, " EfiMemoryBottom - 0x%016lx\n", PhitHob->EfiMemoryBottom));
DEBUG ((DEBUG_VERBOSE, " EfiFreeMemoryTop - 0x%016lx\n", PhitHob->EfiFreeMemoryTop));
DEBUG ((DEBUG_VERBOSE, " EfiFreeMemoryBottom - 0x%016lx\n", PhitHob->EfiFreeMemoryBottom));
DEBUG ((DEBUG_VERBOSE, " EfiEndOfHobList - 0x%lx\n", PhitHob->EfiEndOfHobList));
}
/**
Get the highest memory.
@param HobList the HOB list.
@return the highest memory.
**/
UINT64
GetTopMemory (
IN VOID *HobList
)
{
EFI_PEI_HOB_POINTERS Hob;
EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
UINT64 TopMemory;
UINT64 ResourceTop;
TopMemory = 0;
for (Hob.Raw = HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
ResourceHob = Hob.ResourceDescriptor;
switch (ResourceHob->ResourceType) {
case EFI_RESOURCE_SYSTEM_MEMORY:
ResourceTop = ResourceHob->PhysicalStart + ResourceHob->ResourceLength;
if (TopMemory < ResourceTop) {
TopMemory = ResourceTop;
}
break;
default:
break;
}
DEBUG ((DEBUG_VERBOSE, "\n"));
}
}
return TopMemory;
}
/**
Initialize DMA protection.
@param DmaBufferSize the DMA buffer size
@param DmaBufferBase the DMA buffer base
@retval EFI_SUCCESS the DMA protection is initialized.
@retval EFI_OUT_OF_RESOURCES no enough resource to initialize DMA protection.
**/
EFI_STATUS
InitDmaProtection (
IN UINTN DmaBufferSize,
OUT UINTN *DmaBufferBase
)
{
EFI_STATUS Status;
VOID *HobList;
EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
UINT32 LowMemoryAlignment;
UINT64 HighMemoryAlignment;
UINTN MemoryAlignment;
UINTN LowBottom;
UINTN LowTop;
UINTN HighBottom;
UINT64 HighTop;
HobList = GetHobList ();
DumpPhitHob (HobList);
DumpResourceHob (HobList);
PhitHob = HobList;
ASSERT (PhitHob->EfiMemoryBottom < PhitHob->EfiMemoryTop);
LowMemoryAlignment = GetLowMemoryAlignment ();
HighMemoryAlignment = GetHighMemoryAlignment ();
if (LowMemoryAlignment < HighMemoryAlignment) {
MemoryAlignment = (UINTN)HighMemoryAlignment;
} else {
MemoryAlignment = LowMemoryAlignment;
}
ASSERT (DmaBufferSize == ALIGN_VALUE(DmaBufferSize, MemoryAlignment));
*DmaBufferBase = (UINTN)AllocateAlignedPages (EFI_SIZE_TO_PAGES(DmaBufferSize), MemoryAlignment);
if (*DmaBufferBase == 0) {
DEBUG ((DEBUG_INFO, " InitDmaProtection : OutOfResource\n"));
return EFI_OUT_OF_RESOURCES;
}
LowBottom = 0;
LowTop = *DmaBufferBase;
HighBottom = *DmaBufferBase + DmaBufferSize;
HighTop = GetTopMemory (HobList);
Status = SetDmaProtectedRange (
(UINT32)LowBottom,
(UINT32)(LowTop - LowBottom),
HighBottom,
HighTop - HighBottom
);
if (EFI_ERROR(Status)) {
FreePages ((VOID *)*DmaBufferBase, EFI_SIZE_TO_PAGES(DmaBufferSize));
}
return Status;
}
/**
Initializes the Intel VTd PMR PEIM.
@param FileHandle Handle of the file being invoked.
@param PeiServices Describes the list of possible PEI Services.
@retval EFI_SUCCESS Usb bot driver is successfully initialized.
@retval EFI_OUT_OF_RESOURCES Can't initialize the driver.
**/
EFI_STATUS
EFIAPI
IntelVTdPmrInitialize (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) == 0) {
return EFI_UNSUPPORTED;
}
Status = PeiServicesLocatePpi (
&gEdkiiVTdInfoPpiGuid,
0,
NULL,
(VOID **)&mVTdInfoPpi
);
ASSERT_EFI_ERROR(Status);
//
// Find a pre-memory in resource hob as DMA buffer
// Mark PEI memory to be DMA protected.
//
Status = InitDmaProtection (mDmaBufferSize, &mDmaBufferBase);
if (EFI_ERROR(Status)) {
return Status;
}
DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", mDmaBufferBase));
DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", mDmaBufferSize));
mDmaBufferCurrentTop = mDmaBufferBase + mDmaBufferSize;
mDmaBufferCurrentBottom = mDmaBufferBase;
//
// Install PPI.
//
Status = PeiServicesInstallPpi (&mIoMmuPpiList);
ASSERT_EFI_ERROR(Status);
return Status;
}

View File

@ -0,0 +1,68 @@
/** @file
The definition for DMA access Library.
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __DMA_ACCESS_LIB_H__
#define __DMA_ACCESS_LIB_H__
/**
Set DMA protected region.
@param LowMemoryBase The protected low memory region base.
@param LowMemoryLength The protected low memory region length.
@param HighMemoryBase The protected high memory region base.
@param HighMemoryLength The protected high memory region length.
@retval EFI_SUCCESS The DMA protection is set.
@retval EFI_UNSUPPORTED The DMA protection is not set.
**/
EFI_STATUS
SetDmaProtectedRange (
IN UINT32 LowMemoryBase,
IN UINT32 LowMemoryLength,
IN UINT64 HighMemoryBase,
IN UINT64 HighMemoryLength
);
/**
Diable DMA protection.
@retval DMA protection is disabled.
**/
EFI_STATUS
DisableDmaProtection (
VOID
);
/**
Get protected low memory alignment.
@return protected low memory alignment.
**/
UINT32
GetLowMemoryAlignment (
VOID
);
/**
Get protected high memory alignment.
@return protected high memory alignment.
**/
UINT64
GetHighMemoryAlignment (
VOID
);
#endif

View File

@ -0,0 +1,59 @@
## @file
# Component INF file for the Intel VTd PMR PEIM.
#
# This driver initializes VTd engine based upon EDKII_VTD_INFO_PPI
# and provide DMA protection in PEI.
#
# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010017
BASE_NAME = IntelVTdPmrPei
MODULE_UNI_FILE = IntelVTdPmrPei.uni
FILE_GUID = F906769F-4AED-4A0D-8C7C-FF21B9D1051A
MODULE_TYPE = PEIM
VERSION_STRING = 1.0
ENTRY_POINT = IntelVTdPmrInitialize
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
IntelSiliconPkg/IntelSiliconPkg.dec
[Sources]
IntelVTdPmrPei.c
IntelVTdPmrPei.h
IntelVTdPmr.c
[LibraryClasses]
DebugLib
BaseMemoryLib
BaseLib
PeimEntryPoint
PeiServicesLib
HobLib
IoLib
[Ppis]
gEdkiiIoMmuPpiGuid ## PRODUCES
gEdkiiVTdInfoPpiGuid ## CONSUMES
[Pcd]
gIntelSiliconPkgTokenSpaceGuid.PcdVTdPolicyPropertyMask ## CONSUMES
[Depex]
gEfiPeiMemoryDiscoveredPpiGuid AND
gEdkiiVTdInfoPpiGuid
[UserExtensions.TianoCore."ExtraFiles"]
IntelVTdPmrPeiExtra.uni

View File

@ -0,0 +1,20 @@
// /** @file
// IntelVTdPmrPei Module Localized Abstract and Description Content
//
// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
//
// This program and the accompanying materials are
// licensed and made available under the terms and conditions of the BSD License
// which accompanies this distribution. The full text of the license may be found at
// http://opensource.org/licenses/bsd-license.php
//
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
//
// **/
#string STR_MODULE_ABSTRACT #language en-US "Intel VTd PMR PEI Driver."
#string STR_MODULE_DESCRIPTION #language en-US "This driver initializes VTd engine based upon EDKII_VTD_INFO_PPI and provide DMA protection to device in PEI."

View File

@ -0,0 +1,20 @@
// /** @file
// IntelVTdPmrPei Localized Strings and Content
//
// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
//
// This program and the accompanying materials are
// licensed and made available under the terms and conditions of the BSD License
// which accompanies this distribution. The full text of the license may be found at
// http://opensource.org/licenses/bsd-license.php
//
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
//
// **/
#string STR_PROPERTIES_MODULE_NAME
#language en-US
"Intel VTd PMR PEI Driver"