audk/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c

811 lines
26 KiB
C

/** @file
Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#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 <Ppi/MemoryDiscovered.h>
#include <Ppi/EndOfPeiPhase.h>
#include "IntelVTdPmrPei.h"
EFI_GUID mVTdInfoGuid = {
0x222f5e30, 0x5cd, 0x49c6, { 0x8a, 0xc, 0x36, 0xd6, 0x58, 0x41, 0xe0, 0x82 }
};
EFI_GUID mDmaBufferInfoGuid = {
0x7b624ec7, 0xfb67, 0x4f9c, { 0xb6, 0xb0, 0x4d, 0xfa, 0x9c, 0x88, 0x20, 0x39 }
};
typedef struct {
UINTN DmaBufferBase;
UINTN DmaBufferSize;
UINTN DmaBufferCurrentTop;
UINTN DmaBufferCurrentBottom;
} DMA_BUFFER_INFO;
#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:
+------------------+ <=============== PHMR.Limit (+ alignment) (1 << (HostAddressWidth + 1))
| Mem Resource |
| |
+------------------+ <------- EfiMemoryTop
| PEI allocated |
=========== +==================+ <=============== PHMR.Base
^ | Commom Buf |
| | -------------- |
DMA Buffer | * DMA FREE * |
| | -------------- |
V | Read/Write Buf |
=========== +==================+ <=============== PLMR.Limit (+ alignment)
| PEI allocated |
| -------------- | <------- EfiFreeMemoryTop
| * PEI FREE * |
| -------------- | <------- EfiFreeMemoryBottom
| hob |
| -------------- |
| Stack |
+------------------+ <------- EfiMemoryBottom / Stack Bottom
+------------------+
| Mem Alloc Hob |
+------------------+
| |
| Mem Resource |
+------------------+ <=============== PLMR.Base (0)
**/
/**
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.
@retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are
not available to be allocated yet.
**/
EFI_STATUS
EFIAPI
PeiIoMmuSetAttribute (
IN EDKII_IOMMU_PPI *This,
IN VOID *Mapping,
IN UINT64 IoMmuAccess
)
{
VOID *Hob;
DMA_BUFFER_INFO *DmaBufferInfo;
Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
if (DmaBufferInfo->DmaBufferCurrentTop == 0) {
return EFI_NOT_AVAILABLE_YET;
}
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.
@retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are
not available to be allocated yet.
**/
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;
VOID *Hob;
DMA_BUFFER_INFO *DmaBufferInfo;
Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
DEBUG ((DEBUG_VERBOSE, "PeiIoMmuMap - HostAddress - 0x%x, NumberOfBytes - %x\n", HostAddress, *NumberOfBytes));
DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
if (DmaBufferInfo->DmaBufferCurrentTop == 0) {
return EFI_NOT_AVAILABLE_YET;
}
if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||
Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {
*DeviceAddress = (UINTN)HostAddress;
*Mapping = NULL;
return EFI_SUCCESS;
}
Length = *NumberOfBytes + sizeof(MAP_INFO);
if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {
DEBUG ((DEBUG_ERROR, "PeiIoMmuMap - OUT_OF_RESOURCE\n"));
ASSERT (FALSE);
return EFI_OUT_OF_RESOURCES;
}
*DeviceAddress = DmaBufferInfo->DmaBufferCurrentBottom;
DmaBufferInfo->DmaBufferCurrentBottom += 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.
@retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are
not available to be allocated yet.
**/
EFI_STATUS
EFIAPI
PeiIoMmuUnmap (
IN EDKII_IOMMU_PPI *This,
IN VOID *Mapping
)
{
MAP_INFO *MapInfo;
UINTN Length;
VOID *Hob;
DMA_BUFFER_INFO *DmaBufferInfo;
Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
DEBUG ((DEBUG_VERBOSE, "PeiIoMmuUnmap - Mapping - %x\n", Mapping));
DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
if (DmaBufferInfo->DmaBufferCurrentTop == 0) {
return EFI_NOT_AVAILABLE_YET;
}
if (Mapping == NULL) {
return EFI_SUCCESS;
}
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 (DmaBufferInfo->DmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) {
DmaBufferInfo->DmaBufferCurrentBottom -= 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, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
@retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
@retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are
not available to be allocated yet.
**/
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;
VOID *Hob;
DMA_BUFFER_INFO *DmaBufferInfo;
Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - page - %x\n", Pages));
DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
if (DmaBufferInfo->DmaBufferCurrentTop == 0) {
return EFI_NOT_AVAILABLE_YET;
}
Length = EFI_PAGES_TO_SIZE(Pages);
if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {
DEBUG ((DEBUG_ERROR, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n"));
ASSERT (FALSE);
return EFI_OUT_OF_RESOURCES;
}
*HostAddress = (VOID *)(UINTN)(DmaBufferInfo->DmaBufferCurrentTop - Length);
DmaBufferInfo->DmaBufferCurrentTop -= 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().
@retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are
not available to be allocated yet.
**/
EFI_STATUS
EFIAPI
PeiIoMmuFreeBuffer (
IN EDKII_IOMMU_PPI *This,
IN UINTN Pages,
IN VOID *HostAddress
)
{
UINTN Length;
VOID *Hob;
DMA_BUFFER_INFO *DmaBufferInfo;
Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
DEBUG ((DEBUG_VERBOSE, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n", Pages, HostAddress));
DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
if (DmaBufferInfo->DmaBufferCurrentTop == 0) {
return EFI_NOT_AVAILABLE_YET;
}
Length = EFI_PAGES_TO_SIZE(Pages);
if ((UINTN)HostAddress == DmaBufferInfo->DmaBufferCurrentTop) {
DmaBufferInfo->DmaBufferCurrentTop += 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
};
/**
Initialize DMA protection.
@param VTdInfo The VTd engine context information.
@retval EFI_SUCCESS the DMA protection is initialized.
@retval EFI_OUT_OF_RESOURCES no enough resource to initialize DMA protection.
**/
EFI_STATUS
InitDmaProtection (
IN VTD_INFO *VTdInfo
)
{
EFI_STATUS Status;
UINT32 LowMemoryAlignment;
UINT64 HighMemoryAlignment;
UINTN MemoryAlignment;
UINTN LowBottom;
UINTN LowTop;
UINTN HighBottom;
UINT64 HighTop;
DMA_BUFFER_INFO *DmaBufferInfo;
VOID *Hob;
EFI_PEI_PPI_DESCRIPTOR *OldDescriptor;
EDKII_IOMMU_PPI *OldIoMmuPpi;
Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", DmaBufferInfo->DmaBufferSize));
LowMemoryAlignment = GetLowMemoryAlignment (VTdInfo, VTdInfo->EngineMask);
HighMemoryAlignment = GetHighMemoryAlignment (VTdInfo, VTdInfo->EngineMask);
if (LowMemoryAlignment < HighMemoryAlignment) {
MemoryAlignment = (UINTN)HighMemoryAlignment;
} else {
MemoryAlignment = LowMemoryAlignment;
}
ASSERT (DmaBufferInfo->DmaBufferSize == ALIGN_VALUE(DmaBufferInfo->DmaBufferSize, MemoryAlignment));
DmaBufferInfo->DmaBufferBase = (UINTN)AllocateAlignedPages (EFI_SIZE_TO_PAGES(DmaBufferInfo->DmaBufferSize), MemoryAlignment);
ASSERT (DmaBufferInfo->DmaBufferBase != 0);
if (DmaBufferInfo->DmaBufferBase == 0) {
DEBUG ((DEBUG_INFO, " InitDmaProtection : OutOfResource\n"));
return EFI_OUT_OF_RESOURCES;
}
DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", DmaBufferInfo->DmaBufferBase));
DmaBufferInfo->DmaBufferCurrentTop = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;
DmaBufferInfo->DmaBufferCurrentBottom = DmaBufferInfo->DmaBufferBase;
//
// (Re)Install PPI.
//
Status = PeiServicesLocatePpi (
&gEdkiiIoMmuPpiGuid,
0,
&OldDescriptor,
(VOID **) &OldIoMmuPpi
);
if (!EFI_ERROR (Status)) {
Status = PeiServicesReInstallPpi (OldDescriptor, &mIoMmuPpiList);
} else {
Status = PeiServicesInstallPpi (&mIoMmuPpiList);
}
ASSERT_EFI_ERROR (Status);
LowBottom = 0;
LowTop = DmaBufferInfo->DmaBufferBase;
HighBottom = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;
HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth + 1);
Status = SetDmaProtectedRange (
VTdInfo,
VTdInfo->EngineMask,
(UINT32)LowBottom,
(UINT32)(LowTop - LowBottom),
HighBottom,
HighTop - HighBottom
);
if (EFI_ERROR(Status)) {
FreePages ((VOID *)DmaBufferInfo->DmaBufferBase, EFI_SIZE_TO_PAGES(DmaBufferInfo->DmaBufferSize));
}
return Status;
}
/**
Initializes the Intel VTd Info.
@retval EFI_SUCCESS Usb bot driver is successfully initialized.
@retval EFI_OUT_OF_RESOURCES Can't initialize the driver.
**/
EFI_STATUS
InitVTdInfo (
VOID
)
{
EFI_STATUS Status;
EFI_ACPI_DMAR_HEADER *AcpiDmarTable;
VOID *Hob;
Status = PeiServicesLocatePpi (
&gEdkiiVTdInfoPpiGuid,
0,
NULL,
(VOID **)&AcpiDmarTable
);
ASSERT_EFI_ERROR(Status);
DumpAcpiDMAR (AcpiDmarTable);
//
// Clear old VTdInfo Hob.
//
Hob = GetFirstGuidHob (&mVTdInfoGuid);
if (Hob != NULL) {
ZeroMem (&((EFI_HOB_GUID_TYPE *)Hob)->Name, sizeof(EFI_GUID));
}
//
// Get DMAR information to local VTdInfo
//
Status = ParseDmarAcpiTableDrhd (AcpiDmarTable);
if (EFI_ERROR(Status)) {
return Status;
}
//
// NOTE: Do not parse RMRR here, because RMRR may cause PMR programming.
//
return EFI_SUCCESS;
}
/**
Initializes the Intel VTd PMR for all memory.
@retval EFI_SUCCESS Usb bot driver is successfully initialized.
@retval EFI_OUT_OF_RESOURCES Can't initialize the driver.
**/
EFI_STATUS
InitVTdPmrForAll (
VOID
)
{
EFI_STATUS Status;
VOID *Hob;
VTD_INFO *VTdInfo;
UINTN LowBottom;
UINTN LowTop;
UINTN HighBottom;
UINT64 HighTop;
Hob = GetFirstGuidHob (&mVTdInfoGuid);
VTdInfo = GET_GUID_HOB_DATA(Hob);
LowBottom = 0;
LowTop = 0;
HighBottom = 0;
HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth + 1);
Status = SetDmaProtectedRange (
VTdInfo,
VTdInfo->EngineMask,
(UINT32)LowBottom,
(UINT32)(LowTop - LowBottom),
HighBottom,
HighTop - HighBottom
);
return Status;
}
/**
Initializes the Intel VTd PMR for DMA buffer.
@retval EFI_SUCCESS Usb bot driver is successfully initialized.
@retval EFI_OUT_OF_RESOURCES Can't initialize the driver.
**/
EFI_STATUS
InitVTdPmrForDma (
VOID
)
{
EFI_STATUS Status;
VOID *Hob;
VTD_INFO *VTdInfo;
Hob = GetFirstGuidHob (&mVTdInfoGuid);
VTdInfo = GET_GUID_HOB_DATA(Hob);
//
// If there is RMRR memory, parse it here.
//
ParseDmarAcpiTableRmrr (VTdInfo);
//
// Allocate a range in PEI memory as DMA buffer
// Mark others to be DMA protected.
//
Status = InitDmaProtection (VTdInfo);
return Status;
}
/**
This function handles S3 resume task at the end of PEI
@param[in] PeiServices Pointer to PEI Services Table.
@param[in] NotifyDesc Pointer to the descriptor for the Notification event that
caused this function to execute.
@param[in] Ppi Pointer to the PPI data associated with this function.
@retval EFI_STATUS Always return EFI_SUCCESS
**/
EFI_STATUS
EFIAPI
S3EndOfPeiNotify(
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
IN VOID *Ppi
)
{
VOID *Hob;
VTD_INFO *VTdInfo;
UINT64 EngineMask;
DEBUG((DEBUG_INFO, "VTdPmr S3EndOfPeiNotify\n"));
if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {
Hob = GetFirstGuidHob (&mVTdInfoGuid);
if (Hob == NULL) {
return EFI_SUCCESS;
}
VTdInfo = GET_GUID_HOB_DATA(Hob);
EngineMask = LShiftU64 (1, VTdInfo->VTdEngineCount) - 1;
DisableDmaProtection (VTdInfo, EngineMask);
}
return EFI_SUCCESS;
}
EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc = {
(EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gEfiEndOfPeiSignalPpiGuid,
S3EndOfPeiNotify
};
/**
This function handles VTd engine setup
@param[in] PeiServices Pointer to PEI Services Table.
@param[in] NotifyDesc Pointer to the descriptor for the Notification event that
caused this function to execute.
@param[in] Ppi Pointer to the PPI data associated with this function.
@retval EFI_STATUS Always return EFI_SUCCESS
**/
EFI_STATUS
EFIAPI
VTdInfoNotify (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
IN VOID *Ppi
)
{
EFI_STATUS Status;
VOID *MemoryDiscovered;
UINT64 EnabledEngineMask;
VOID *Hob;
VTD_INFO *VTdInfo;
BOOLEAN MemoryInitialized;
DEBUG ((DEBUG_INFO, "VTdInfoNotify\n"));
//
// Check if memory is initialized.
//
MemoryInitialized = FALSE;
Status = PeiServicesLocatePpi (
&gEfiPeiMemoryDiscoveredPpiGuid,
0,
NULL,
&MemoryDiscovered
);
if (!EFI_ERROR(Status)) {
MemoryInitialized = TRUE;
}
DEBUG ((DEBUG_INFO, "MemoryInitialized - %x\n", MemoryInitialized));
if (!MemoryInitialized) {
//
// If the memory is not initialized,
// Protect all system memory
//
InitVTdInfo ();
InitVTdPmrForAll ();
//
// Install PPI.
//
Status = PeiServicesInstallPpi (&mIoMmuPpiList);
ASSERT_EFI_ERROR(Status);
} else {
//
// If the memory is initialized,
// Allocate DMA buffer and protect rest system memory
//
//
// NOTE: We need reinit VTdInfo because previous information might be overriden.
//
InitVTdInfo ();
Hob = GetFirstGuidHob (&mVTdInfoGuid);
VTdInfo = GET_GUID_HOB_DATA(Hob);
//
// NOTE: We need check if PMR is enabled or not.
//
EnabledEngineMask = GetDmaProtectionEnabledEngineMask (VTdInfo, VTdInfo->EngineMask);
if (EnabledEngineMask != 0) {
EnableVTdTranslationProtection (VTdInfo, EnabledEngineMask);
DisableDmaProtection (VTdInfo, EnabledEngineMask);
}
InitVTdPmrForDma ();
if (EnabledEngineMask != 0) {
DisableVTdTranslationProtection (VTdInfo, EnabledEngineMask);
}
}
return EFI_SUCCESS;
}
EFI_PEI_NOTIFY_DESCRIPTOR mVTdInfoNotifyDesc = {
(EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gEdkiiVTdInfoPpiGuid,
VTdInfoNotify
};
/**
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;
EFI_BOOT_MODE BootMode;
DMA_BUFFER_INFO *DmaBufferInfo;
DEBUG ((DEBUG_INFO, "IntelVTdPmrInitialize\n"));
if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) == 0) {
return EFI_UNSUPPORTED;
}
DmaBufferInfo = BuildGuidHob (&mDmaBufferInfoGuid, sizeof(DMA_BUFFER_INFO));
ASSERT(DmaBufferInfo != NULL);
if (DmaBufferInfo == NULL) {
return EFI_OUT_OF_RESOURCES;
}
ZeroMem (DmaBufferInfo, sizeof(DMA_BUFFER_INFO));
PeiServicesGetBootMode (&BootMode);
if (BootMode == BOOT_ON_S3_RESUME) {
DmaBufferInfo->DmaBufferSize = PcdGet32 (PcdVTdPeiDmaBufferSizeS3);
} else {
DmaBufferInfo->DmaBufferSize = PcdGet32 (PcdVTdPeiDmaBufferSize);
}
Status = PeiServicesNotifyPpi (&mVTdInfoNotifyDesc);
ASSERT_EFI_ERROR (Status);
//
// Register EndOfPei Notify for S3
//
if (BootMode == BOOT_ON_S3_RESUME) {
Status = PeiServicesNotifyPpi (&mS3EndOfPeiNotifyDesc);
ASSERT_EFI_ERROR (Status);
}
return EFI_SUCCESS;
}