IntelSiliconPkg/VtdPmrPei: Add premem support.

Remove memory discovered dependency to support both premem
VTD_INFO_PPI and postmem VTD_INFO_PPI.

If VTD_INFO_PPI is installed before memory is ready, this
driver protects all memory region.
If VTD_INFO_PPI is installed or reinstalled after memory
is ready, this driver allocates DMA buffer and protect rest.

Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
This commit is contained in:
Jiewen Yao 2017-09-23 16:27:50 +08:00
parent e5d847476a
commit a1e7cd0b02
6 changed files with 1383 additions and 621 deletions

View File

@ -0,0 +1,580 @@
/** @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/DebugLib.h>
#include <Library/HobLib.h>
#include <IndustryStandard/Vtd.h>
#include <Ppi/VtdInfo.h>
#include "IntelVTdPmrPei.h"
/**
Dump DMAR DeviceScopeEntry.
@param[in] DmarDeviceScopeEntry DMAR DeviceScopeEntry
**/
VOID
DumpDmarDeviceScopeEntry (
IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry
)
{
UINTN PciPathNumber;
UINTN PciPathIndex;
EFI_ACPI_DMAR_PCI_PATH *PciPath;
if (DmarDeviceScopeEntry == NULL) {
return;
}
DEBUG ((DEBUG_INFO,
" *************************************************************************\n"
));
DEBUG ((DEBUG_INFO,
" * DMA-Remapping Device Scope Entry Structure *\n"
));
DEBUG ((DEBUG_INFO,
" *************************************************************************\n"
));
DEBUG ((DEBUG_INFO,
(sizeof(UINTN) == sizeof(UINT64)) ?
" DMAR Device Scope Entry address ...................... 0x%016lx\n" :
" DMAR Device Scope Entry address ...................... 0x%08x\n",
DmarDeviceScopeEntry
));
DEBUG ((DEBUG_INFO,
" Device Scope Entry Type ............................ 0x%02x\n",
DmarDeviceScopeEntry->Type
));
switch (DmarDeviceScopeEntry->Type) {
case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
DEBUG ((DEBUG_INFO,
" PCI Endpoint Device\n"
));
break;
case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
DEBUG ((DEBUG_INFO,
" PCI Sub-hierachy\n"
));
break;
default:
break;
}
DEBUG ((DEBUG_INFO,
" Length ............................................. 0x%02x\n",
DmarDeviceScopeEntry->Length
));
DEBUG ((DEBUG_INFO,
" Enumeration ID ..................................... 0x%02x\n",
DmarDeviceScopeEntry->EnumerationId
));
DEBUG ((DEBUG_INFO,
" Starting Bus Number ................................ 0x%02x\n",
DmarDeviceScopeEntry->StartBusNumber
));
PciPathNumber = (DmarDeviceScopeEntry->Length - sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER)) / sizeof(EFI_ACPI_DMAR_PCI_PATH);
PciPath = (EFI_ACPI_DMAR_PCI_PATH *)(DmarDeviceScopeEntry + 1);
for (PciPathIndex = 0; PciPathIndex < PciPathNumber; PciPathIndex++) {
DEBUG ((DEBUG_INFO,
" Device ............................................. 0x%02x\n",
PciPath[PciPathIndex].Device
));
DEBUG ((DEBUG_INFO,
" Function ........................................... 0x%02x\n",
PciPath[PciPathIndex].Function
));
}
DEBUG ((DEBUG_INFO,
" *************************************************************************\n\n"
));
return;
}
/**
Dump DMAR RMRR table.
@param[in] Rmrr DMAR RMRR table
**/
VOID
DumpDmarRmrr (
IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr
)
{
EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;
INTN RmrrLen;
if (Rmrr == NULL) {
return;
}
DEBUG ((DEBUG_INFO,
" ***************************************************************************\n"
));
DEBUG ((DEBUG_INFO,
" * Reserved Memory Region Reporting Structure *\n"
));
DEBUG ((DEBUG_INFO,
" ***************************************************************************\n"
));
DEBUG ((DEBUG_INFO,
(sizeof(UINTN) == sizeof(UINT64)) ?
" RMRR address ........................................... 0x%016lx\n" :
" RMRR address ........................................... 0x%08x\n",
Rmrr
));
DEBUG ((DEBUG_INFO,
" Type ................................................. 0x%04x\n",
Rmrr->Header.Type
));
DEBUG ((DEBUG_INFO,
" Length ............................................... 0x%04x\n",
Rmrr->Header.Length
));
DEBUG ((DEBUG_INFO,
" Segment Number ....................................... 0x%04x\n",
Rmrr->SegmentNumber
));
DEBUG ((DEBUG_INFO,
" Reserved Memory Region Base Address .................. 0x%016lx\n",
Rmrr->ReservedMemoryRegionBaseAddress
));
DEBUG ((DEBUG_INFO,
" Reserved Memory Region Limit Address ................. 0x%016lx\n",
Rmrr->ReservedMemoryRegionLimitAddress
));
RmrrLen = Rmrr->Header.Length - sizeof(EFI_ACPI_DMAR_RMRR_HEADER);
DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Rmrr + 1);
while (RmrrLen > 0) {
DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
RmrrLen -= DmarDeviceScopeEntry->Length;
DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
}
DEBUG ((DEBUG_INFO,
" ***************************************************************************\n\n"
));
return;
}
/**
Dump DMAR DRHD table.
@param[in] Drhd DMAR DRHD table
**/
VOID
DumpDmarDrhd (
IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd
)
{
EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;
INTN DrhdLen;
if (Drhd == NULL) {
return;
}
DEBUG ((DEBUG_INFO,
" ***************************************************************************\n"
));
DEBUG ((DEBUG_INFO,
" * DMA-Remapping Hardware Definition Structure *\n"
));
DEBUG ((DEBUG_INFO,
" ***************************************************************************\n"
));
DEBUG ((DEBUG_INFO,
(sizeof(UINTN) == sizeof(UINT64)) ?
" DRHD address ........................................... 0x%016lx\n" :
" DRHD address ........................................... 0x%08x\n",
Drhd
));
DEBUG ((DEBUG_INFO,
" Type ................................................. 0x%04x\n",
Drhd->Header.Type
));
DEBUG ((DEBUG_INFO,
" Length ............................................... 0x%04x\n",
Drhd->Header.Length
));
DEBUG ((DEBUG_INFO,
" Flags ................................................ 0x%02x\n",
Drhd->Flags
));
DEBUG ((DEBUG_INFO,
" INCLUDE_PCI_ALL .................................... 0x%02x\n",
Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL
));
DEBUG ((DEBUG_INFO,
" Segment Number ....................................... 0x%04x\n",
Drhd->SegmentNumber
));
DEBUG ((DEBUG_INFO,
" Register Base Address ................................ 0x%016lx\n",
Drhd->RegisterBaseAddress
));
DrhdLen = Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER);
DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Drhd + 1);
while (DrhdLen > 0) {
DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
DrhdLen -= DmarDeviceScopeEntry->Length;
DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
}
DEBUG ((DEBUG_INFO,
" ***************************************************************************\n\n"
));
return;
}
/**
Dump DMAR ACPI table.
@param[in] Dmar DMAR ACPI table
**/
VOID
DumpAcpiDMAR (
IN EFI_ACPI_DMAR_HEADER *Dmar
)
{
EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
INTN DmarLen;
if (Dmar == NULL) {
return;
}
//
// Dump Dmar table
//
DEBUG ((DEBUG_INFO,
"*****************************************************************************\n"
));
DEBUG ((DEBUG_INFO,
"* DMAR Table *\n"
));
DEBUG ((DEBUG_INFO,
"*****************************************************************************\n"
));
DEBUG ((DEBUG_INFO,
(sizeof(UINTN) == sizeof(UINT64)) ?
"DMAR address ............................................. 0x%016lx\n" :
"DMAR address ............................................. 0x%08x\n",
Dmar
));
DEBUG ((DEBUG_INFO,
" Table Contents:\n"
));
DEBUG ((DEBUG_INFO,
" Host Address Width ................................... 0x%02x\n",
Dmar->HostAddressWidth
));
DEBUG ((DEBUG_INFO,
" Flags ................................................ 0x%02x\n",
Dmar->Flags
));
DEBUG ((DEBUG_INFO,
" INTR_REMAP ......................................... 0x%02x\n",
Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP
));
DEBUG ((DEBUG_INFO,
" X2APIC_OPT_OUT_SET ................................. 0x%02x\n",
Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT
));
DmarLen = Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER);
DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1);
while (DmarLen > 0) {
switch (DmarHeader->Type) {
case EFI_ACPI_DMAR_TYPE_DRHD:
DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
break;
case EFI_ACPI_DMAR_TYPE_RMRR:
DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
break;
default:
break;
}
DmarLen -= DmarHeader->Length;
DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
}
DEBUG ((DEBUG_INFO,
"*****************************************************************************\n\n"
));
return;
}
/**
Get VTd engine number.
@param[in] AcpiDmarTable DMAR ACPI table
@return the VTd engine number.
**/
UINTN
GetVtdEngineNumber (
IN EFI_ACPI_DMAR_HEADER *AcpiDmarTable
)
{
EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
UINTN VtdIndex;
VtdIndex = 0;
DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
switch (DmarHeader->Type) {
case EFI_ACPI_DMAR_TYPE_DRHD:
VtdIndex++;
break;
default:
break;
}
DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
}
return VtdIndex ;
}
/**
Process DMAR DHRD table.
@param[in] VTdInfo The VTd engine context information.
@param[in] VtdIndex The index of VTd engine.
@param[in] DmarDrhd The DRHD table.
**/
VOID
ProcessDhrd (
IN VTD_INFO *VTdInfo,
IN UINTN VtdIndex,
IN EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd
)
{
DEBUG ((DEBUG_INFO," VTD (%d) BaseAddress - 0x%016lx\n", VtdIndex, DmarDrhd->RegisterBaseAddress));
VTdInfo->VTdEngineAddress[VtdIndex] = DmarDrhd->RegisterBaseAddress;
}
/**
Parse DMAR DRHD table.
@param[in] AcpiDmarTable DMAR ACPI table
@return EFI_SUCCESS The DMAR DRHD table is parsed.
**/
EFI_STATUS
ParseDmarAcpiTableDrhd (
IN EFI_ACPI_DMAR_HEADER *AcpiDmarTable
)
{
EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
UINTN VtdUnitNumber;
UINTN VtdIndex;
VTD_INFO *VTdInfo;
VtdUnitNumber = GetVtdEngineNumber (AcpiDmarTable);
if (VtdUnitNumber == 0) {
return EFI_UNSUPPORTED;
}
VTdInfo = BuildGuidHob (&mVTdInfoGuid, sizeof(VTD_INFO) + (VtdUnitNumber - 1) * sizeof(UINT64));
ASSERT(VTdInfo != NULL);
if (VTdInfo == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Initialize the engine mask to all.
//
VTdInfo->AcpiDmarTable = AcpiDmarTable;
VTdInfo->EngineMask = LShiftU64 (1, VtdUnitNumber) - 1;
VTdInfo->HostAddressWidth = AcpiDmarTable->HostAddressWidth;
VTdInfo->VTdEngineCount = VtdUnitNumber;
VtdIndex = 0;
DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
switch (DmarHeader->Type) {
case EFI_ACPI_DMAR_TYPE_DRHD:
ASSERT (VtdIndex < VtdUnitNumber);
ProcessDhrd (VTdInfo, VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
VtdIndex++;
break;
default:
break;
}
DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
}
ASSERT (VtdIndex == VtdUnitNumber);
return EFI_SUCCESS;
}
/**
Return the VTd engine index according to the Segment and DevScopeEntry.
@param AcpiDmarTable DMAR ACPI table
@param Segment The segment of the VTd engine
@param DevScopeEntry The DevScopeEntry of the VTd engine
@return The VTd engine index according to the Segment and DevScopeEntry.
@retval -1 The VTd engine is not found.
**/
UINTN
GetVTdEngineFromDevScopeEntry (
IN EFI_ACPI_DMAR_HEADER *AcpiDmarTable,
IN UINT16 Segment,
IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DevScopeEntry
)
{
EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
UINTN VtdIndex;
EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd;
EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *ThisDevScopeEntry;
VtdIndex = 0;
DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
switch (DmarHeader->Type) {
case EFI_ACPI_DMAR_TYPE_DRHD:
DmarDrhd = (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader;
if (DmarDrhd->SegmentNumber != Segment) {
// Mismatch
break;
}
if ((DmarDrhd->Header.Length == sizeof(EFI_ACPI_DMAR_DRHD_HEADER)) ||
((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0)) {
// No DevScopeEntry
// Do not handle PCI_ALL
break;
}
ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + 1));
while ((UINTN)ThisDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Length) {
if ((ThisDevScopeEntry->Length == DevScopeEntry->Length) &&
(CompareMem (ThisDevScopeEntry, DevScopeEntry, DevScopeEntry->Length) == 0)) {
return VtdIndex;
}
ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)ThisDevScopeEntry + ThisDevScopeEntry->Length);
}
break;
default:
break;
}
DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
}
return (UINTN)-1;
}
/**
Process DMAR RMRR table.
@param[in] VTdInfo The VTd engine context information.
@param[in] DmarRmrr The RMRR table.
**/
VOID
ProcessRmrr (
IN VTD_INFO *VTdInfo,
IN EFI_ACPI_DMAR_RMRR_HEADER *DmarRmrr
)
{
EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry;
UINTN VTdIndex;
UINT64 RmrrMask;
UINTN LowBottom;
UINTN LowTop;
UINTN HighBottom;
UINT64 HighTop;
EFI_ACPI_DMAR_HEADER *AcpiDmarTable;
AcpiDmarTable = VTdInfo->AcpiDmarTable;
DEBUG ((DEBUG_INFO," RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress));
if ((DmarRmrr->ReservedMemoryRegionBaseAddress == 0) ||
(DmarRmrr->ReservedMemoryRegionLimitAddress == 0)) {
return ;
}
DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarRmrr + 1));
while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Length) {
ASSERT (DmarDevScopeEntry->Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT);
VTdIndex = GetVTdEngineFromDevScopeEntry (AcpiDmarTable, DmarRmrr->SegmentNumber, DmarDevScopeEntry);
if (VTdIndex != (UINTN)-1) {
RmrrMask = LShiftU64 (1, VTdIndex);
LowBottom = 0;
LowTop = (UINTN)DmarRmrr->ReservedMemoryRegionBaseAddress;
HighBottom = (UINTN)DmarRmrr->ReservedMemoryRegionLimitAddress + 1;
HighTop = GetTopMemory ();
SetDmaProtectedRange (
VTdInfo,
RmrrMask,
0,
(UINT32)(LowTop - LowBottom),
HighBottom,
HighTop - HighBottom
);
//
// Remove the engine from the engine mask.
// The assumption is that any other PEI driver does not access
// the device covered by this engine.
//
VTdInfo->EngineMask = VTdInfo->EngineMask & (~RmrrMask);
}
DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);
}
}
/**
Parse DMAR DRHD table.
@param[in] VTdInfo The VTd engine context information.
**/
VOID
ParseDmarAcpiTableRmrr (
IN VTD_INFO *VTdInfo
)
{
EFI_ACPI_DMAR_HEADER *AcpiDmarTable;
EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
AcpiDmarTable = VTdInfo->AcpiDmarTable;
DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
switch (DmarHeader->Type) {
case EFI_ACPI_DMAR_TYPE_RMRR:
ProcessRmrr (VTdInfo, (EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
break;
default:
break;
}
DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
}
}

View File

@ -22,17 +22,17 @@
#include "IntelVTdPmrPei.h" #include "IntelVTdPmrPei.h"
extern VTD_INFO *mVTdInfo;
/** /**
Get protected low memory alignment. Get protected low memory alignment.
@param HostAddressWidth The host address width.
@param VtdUnitBaseAddress The base address of the VTd engine. @param VtdUnitBaseAddress The base address of the VTd engine.
@return protected low memory alignment. @return protected low memory alignment.
**/ **/
UINT32 UINT32
GetPlmrAlignment ( GetPlmrAlignment (
IN UINT8 HostAddressWidth,
IN UINTN VtdUnitBaseAddress IN UINTN VtdUnitBaseAddress
) )
{ {
@ -48,19 +48,18 @@ GetPlmrAlignment (
/** /**
Get protected high memory alignment. Get protected high memory alignment.
@param HostAddressWidth The host address width.
@param VtdUnitBaseAddress The base address of the VTd engine. @param VtdUnitBaseAddress The base address of the VTd engine.
@return protected high memory alignment. @return protected high memory alignment.
**/ **/
UINT64 UINT64
GetPhmrAlignment ( GetPhmrAlignment (
IN UINT8 HostAddressWidth,
IN UINTN VtdUnitBaseAddress IN UINTN VtdUnitBaseAddress
) )
{ {
UINT64 Data64; UINT64 Data64;
UINT8 HostAddressWidth;
HostAddressWidth = mVTdInfo->HostAddressWidth;
MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, 0xFFFFFFFFFFFFFFFF); MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, 0xFFFFFFFFFFFFFFFF);
Data64 = MmioRead64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG); Data64 = MmioRead64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG);
@ -73,12 +72,14 @@ GetPhmrAlignment (
/** /**
Get protected low memory alignment. Get protected low memory alignment.
@param VTdInfo The VTd engine context information.
@param EngineMask The mask of the VTd engine to be accessed. @param EngineMask The mask of the VTd engine to be accessed.
@return protected low memory alignment. @return protected low memory alignment.
**/ **/
UINT32 UINT32
GetLowMemoryAlignment ( GetLowMemoryAlignment (
IN VTD_INFO *VTdInfo,
IN UINT64 EngineMask IN UINT64 EngineMask
) )
{ {
@ -87,11 +88,11 @@ GetLowMemoryAlignment (
UINT32 FinalAlignment; UINT32 FinalAlignment;
FinalAlignment = 0; FinalAlignment = 0;
for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) { for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
if ((EngineMask & LShiftU64(1, Index)) == 0) { if ((EngineMask & LShiftU64(1, Index)) == 0) {
continue; continue;
} }
Alignment = GetPlmrAlignment ((UINTN)mVTdInfo->VTdEngineAddress[Index]); Alignment = GetPlmrAlignment (VTdInfo->HostAddressWidth, (UINTN)VTdInfo->VTdEngineAddress[Index]);
if (FinalAlignment < Alignment) { if (FinalAlignment < Alignment) {
FinalAlignment = Alignment; FinalAlignment = Alignment;
} }
@ -102,12 +103,14 @@ GetLowMemoryAlignment (
/** /**
Get protected high memory alignment. Get protected high memory alignment.
@param VTdInfo The VTd engine context information.
@param EngineMask The mask of the VTd engine to be accessed. @param EngineMask The mask of the VTd engine to be accessed.
@return protected high memory alignment. @return protected high memory alignment.
**/ **/
UINT64 UINT64
GetHighMemoryAlignment ( GetHighMemoryAlignment (
IN VTD_INFO *VTdInfo,
IN UINT64 EngineMask IN UINT64 EngineMask
) )
{ {
@ -116,11 +119,11 @@ GetHighMemoryAlignment (
UINT64 FinalAlignment; UINT64 FinalAlignment;
FinalAlignment = 0; FinalAlignment = 0;
for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) { for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
if ((EngineMask & LShiftU64(1, Index)) == 0) { if ((EngineMask & LShiftU64(1, Index)) == 0) {
continue; continue;
} }
Alignment = GetPhmrAlignment ((UINTN)mVTdInfo->VTdEngineAddress[Index]); Alignment = GetPhmrAlignment (VTdInfo->HostAddressWidth, (UINTN)VTdInfo->VTdEngineAddress[Index]);
if (FinalAlignment < Alignment) { if (FinalAlignment < Alignment) {
FinalAlignment = Alignment; FinalAlignment = Alignment;
} }
@ -144,12 +147,19 @@ EnablePmr (
UINT32 Reg32; UINT32 Reg32;
VTD_CAP_REG CapReg; VTD_CAP_REG CapReg;
DEBUG ((DEBUG_INFO, "EnablePmr - %x\n", VtdUnitBaseAddress));
CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG); CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) { if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG); Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
if (Reg32 == 0xFFFFFFFF) {
DEBUG ((DEBUG_ERROR, "R_PMEN_ENABLE_REG - 0x%x\n", Reg32));
ASSERT(FALSE);
}
if ((Reg32 & BIT0) == 0) { if ((Reg32 & BIT0) == 0) {
MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, BIT31); MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, BIT31);
do { do {
@ -157,6 +167,8 @@ EnablePmr (
} while((Reg32 & BIT0) == 0); } while((Reg32 & BIT0) == 0);
} }
DEBUG ((DEBUG_INFO, "EnablePmr - Done\n"));
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -182,6 +194,11 @@ DisablePmr (
} }
Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG); Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
if (Reg32 == 0xFFFFFFFF) {
DEBUG ((DEBUG_ERROR, "R_PMEN_ENABLE_REG - 0x%x\n", Reg32));
ASSERT(FALSE);
}
if ((Reg32 & BIT0) != 0) { if ((Reg32 & BIT0) != 0) {
MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, 0x0); MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, 0x0);
do { do {
@ -195,6 +212,7 @@ DisablePmr (
/** /**
Set PMR region in the VTd engine. Set PMR region in the VTd engine.
@param HostAddressWidth The host address width.
@param VtdUnitBaseAddress The base address of the VTd engine. @param VtdUnitBaseAddress The base address of the VTd engine.
@param LowMemoryBase The protected low memory region base. @param LowMemoryBase The protected low memory region base.
@param LowMemoryLength The protected low memory region length. @param LowMemoryLength The protected low memory region length.
@ -206,6 +224,7 @@ DisablePmr (
**/ **/
EFI_STATUS EFI_STATUS
SetPmrRegion ( SetPmrRegion (
IN UINT8 HostAddressWidth,
IN UINTN VtdUnitBaseAddress, IN UINTN VtdUnitBaseAddress,
IN UINT32 LowMemoryBase, IN UINT32 LowMemoryBase,
IN UINT32 LowMemoryLength, IN UINT32 LowMemoryLength,
@ -225,9 +244,9 @@ SetPmrRegion (
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
PlmrAlignment = GetPlmrAlignment (VtdUnitBaseAddress); PlmrAlignment = GetPlmrAlignment (HostAddressWidth, VtdUnitBaseAddress);
DEBUG ((DEBUG_INFO, "PlmrAlignment - 0x%x\n", PlmrAlignment)); DEBUG ((DEBUG_INFO, "PlmrAlignment - 0x%x\n", PlmrAlignment));
PhmrAlignment = GetPhmrAlignment (VtdUnitBaseAddress); PhmrAlignment = GetPhmrAlignment (HostAddressWidth, VtdUnitBaseAddress);
DEBUG ((DEBUG_INFO, "PhmrAlignment - 0x%lx\n", PhmrAlignment)); DEBUG ((DEBUG_INFO, "PhmrAlignment - 0x%lx\n", PhmrAlignment));
if ((LowMemoryBase != ALIGN_VALUE(LowMemoryBase, PlmrAlignment)) || if ((LowMemoryBase != ALIGN_VALUE(LowMemoryBase, PlmrAlignment)) ||
@ -247,8 +266,10 @@ SetPmrRegion (
MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG, LowMemoryBase); MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG, LowMemoryBase);
MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_LIMITE_REG, LowMemoryBase + LowMemoryLength - 1); MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_LIMITE_REG, LowMemoryBase + LowMemoryLength - 1);
DEBUG ((DEBUG_INFO, "PLMR set done\n"));
MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, HighMemoryBase); MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, HighMemoryBase);
MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_LIMITE_REG, HighMemoryBase + HighMemoryLength - 1); MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_LIMITE_REG, HighMemoryBase + HighMemoryLength - 1);
DEBUG ((DEBUG_INFO, "PHMR set done\n"));
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -256,6 +277,7 @@ SetPmrRegion (
/** /**
Set DMA protected region. Set DMA protected region.
@param VTdInfo The VTd engine context information.
@param EngineMask The mask of the VTd engine to be accessed. @param EngineMask The mask of the VTd engine to be accessed.
@param LowMemoryBase The protected low memory region base. @param LowMemoryBase The protected low memory region base.
@param LowMemoryLength The protected low memory region length. @param LowMemoryLength The protected low memory region length.
@ -267,6 +289,7 @@ SetPmrRegion (
**/ **/
EFI_STATUS EFI_STATUS
SetDmaProtectedRange ( SetDmaProtectedRange (
IN VTD_INFO *VTdInfo,
IN UINT64 EngineMask, IN UINT64 EngineMask,
IN UINT32 LowMemoryBase, IN UINT32 LowMemoryBase,
IN UINT32 LowMemoryLength, IN UINT32 LowMemoryLength,
@ -279,13 +302,14 @@ SetDmaProtectedRange (
DEBUG ((DEBUG_INFO, "SetDmaProtectedRange(0x%lx) - [0x%x, 0x%x] [0x%lx, 0x%lx]\n", EngineMask, LowMemoryBase, LowMemoryLength, HighMemoryBase, HighMemoryLength)); DEBUG ((DEBUG_INFO, "SetDmaProtectedRange(0x%lx) - [0x%x, 0x%x] [0x%lx, 0x%lx]\n", EngineMask, LowMemoryBase, LowMemoryLength, HighMemoryBase, HighMemoryLength));
for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) { for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
if ((EngineMask & LShiftU64(1, Index)) == 0) { if ((EngineMask & LShiftU64(1, Index)) == 0) {
continue; continue;
} }
DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]); DisablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);
Status = SetPmrRegion ( Status = SetPmrRegion (
(UINTN)mVTdInfo->VTdEngineAddress[Index], VTdInfo->HostAddressWidth,
(UINTN)VTdInfo->VTdEngineAddress[Index],
LowMemoryBase, LowMemoryBase,
LowMemoryLength, LowMemoryLength,
HighMemoryBase, HighMemoryBase,
@ -294,7 +318,7 @@ SetDmaProtectedRange (
if (EFI_ERROR(Status)) { if (EFI_ERROR(Status)) {
return Status; return Status;
} }
Status = EnablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]); Status = EnablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);
if (EFI_ERROR(Status)) { if (EFI_ERROR(Status)) {
return Status; return Status;
} }
@ -306,25 +330,29 @@ SetDmaProtectedRange (
/** /**
Diable DMA protection. Diable DMA protection.
@param VTdInfo The VTd engine context information.
@param EngineMask The mask of the VTd engine to be accessed. @param EngineMask The mask of the VTd engine to be accessed.
@retval DMA protection is disabled. @retval EFI_SUCCESS DMA protection is disabled.
**/ **/
EFI_STATUS EFI_STATUS
DisableDmaProtection ( DisableDmaProtection (
IN VTD_INFO *VTdInfo,
IN UINT64 EngineMask IN UINT64 EngineMask
) )
{ {
UINTN Index; UINTN Index;
EFI_STATUS Status; EFI_STATUS Status;
DEBUG ((DEBUG_INFO, "DisableDmaProtection\n")); DEBUG ((DEBUG_INFO, "DisableDmaProtection - 0x%lx\n", EngineMask));
for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
DEBUG ((DEBUG_INFO, "Disabling...%d\n", Index));
for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
if ((EngineMask & LShiftU64(1, Index)) == 0) { if ((EngineMask & LShiftU64(1, Index)) == 0) {
continue; continue;
} }
Status = DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]); Status = DisablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);
if (EFI_ERROR(Status)) { if (EFI_ERROR(Status)) {
return Status; return Status;
} }
@ -332,3 +360,67 @@ DisableDmaProtection (
return EFI_SUCCESS; return EFI_SUCCESS;
} }
/**
Return if the PMR is enabled.
@param VtdUnitBaseAddress The base address of the VTd engine.
@retval TRUE PMR is enabled.
@retval FALSE PMR is disabled or unsupported.
**/
BOOLEAN
IsPmrEnabled (
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 FALSE;
}
Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
if ((Reg32 & BIT0) == 0) {
return FALSE;
}
return TRUE;
}
/**
Return the mask of the VTd engine which is enabled.
@param VTdInfo The VTd engine context information.
@param EngineMask The mask of the VTd engine to be accessed.
@return the mask of the VTd engine which is enabled.
**/
UINT64
GetDmaProtectionEnabledEngineMask (
IN VTD_INFO *VTdInfo,
IN UINT64 EngineMask
)
{
UINTN Index;
BOOLEAN Result;
UINT64 EnabledEngineMask;
DEBUG ((DEBUG_INFO, "GetDmaProtectionEnabledEngineMask - 0x%lx\n", EngineMask));
EnabledEngineMask = 0;
for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
if ((EngineMask & LShiftU64(1, Index)) == 0) {
continue;
}
Result = IsPmrEnabled ((UINTN)VTdInfo->VTdEngineAddress[Index]);
if (Result) {
EnabledEngineMask |= LShiftU64(1, Index);
}
}
DEBUG ((DEBUG_INFO, "EnabledEngineMask - 0x%lx\n", EnabledEngineMask));
return EnabledEngineMask;
}

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,8 @@
#define __DMA_ACCESS_LIB_H__ #define __DMA_ACCESS_LIB_H__
typedef struct { typedef struct {
EFI_ACPI_DMAR_HEADER *AcpiDmarTable;
UINT64 EngineMask;
UINT8 HostAddressWidth; UINT8 HostAddressWidth;
UINTN VTdEngineCount; UINTN VTdEngineCount;
UINT64 VTdEngineAddress[1]; UINT64 VTdEngineAddress[1];
@ -24,6 +26,7 @@ typedef struct {
/** /**
Set DMA protected region. Set DMA protected region.
@param VTdInfo The VTd engine context information.
@param EngineMask The mask of the VTd engine to be accessed. @param EngineMask The mask of the VTd engine to be accessed.
@param LowMemoryBase The protected low memory region base. @param LowMemoryBase The protected low memory region base.
@param LowMemoryLength The protected low memory region length. @param LowMemoryLength The protected low memory region length.
@ -35,6 +38,7 @@ typedef struct {
**/ **/
EFI_STATUS EFI_STATUS
SetDmaProtectedRange ( SetDmaProtectedRange (
IN VTD_INFO *VTdInfo,
IN UINT64 EngineMask, IN UINT64 EngineMask,
IN UINT32 LowMemoryBase, IN UINT32 LowMemoryBase,
IN UINT32 LowMemoryLength, IN UINT32 LowMemoryLength,
@ -45,38 +49,127 @@ SetDmaProtectedRange (
/** /**
Diable DMA protection. Diable DMA protection.
@param VTdInfo The VTd engine context information.
@param EngineMask The mask of the VTd engine to be accessed. @param EngineMask The mask of the VTd engine to be accessed.
@retval DMA protection is disabled. @retval DMA protection is disabled.
**/ **/
EFI_STATUS EFI_STATUS
DisableDmaProtection ( DisableDmaProtection (
IN VTD_INFO *VTdInfo,
IN UINT64 EngineMask
);
/**
Return if the DMA protection is enabled.
@param VTdInfo The VTd engine context information.
@param EngineMask The mask of the VTd engine to be accessed.
@retval TRUE DMA protection is enabled in at least one VTd engine.
@retval FALSE DMA protection is disabled in all VTd engines.
**/
UINT64
GetDmaProtectionEnabledEngineMask (
IN VTD_INFO *VTdInfo,
IN UINT64 EngineMask IN UINT64 EngineMask
); );
/** /**
Get protected low memory alignment. Get protected low memory alignment.
@param VTdInfo The VTd engine context information.
@param EngineMask The mask of the VTd engine to be accessed. @param EngineMask The mask of the VTd engine to be accessed.
@return protected low memory alignment. @return protected low memory alignment.
**/ **/
UINT32 UINT32
GetLowMemoryAlignment ( GetLowMemoryAlignment (
IN VTD_INFO *VTdInfo,
IN UINT64 EngineMask IN UINT64 EngineMask
); );
/** /**
Get protected high memory alignment. Get protected high memory alignment.
@param VTdInfo The VTd engine context information.
@param EngineMask The mask of the VTd engine to be accessed. @param EngineMask The mask of the VTd engine to be accessed.
@return protected high memory alignment. @return protected high memory alignment.
**/ **/
UINT64 UINT64
GetHighMemoryAlignment ( GetHighMemoryAlignment (
IN VTD_INFO *VTdInfo,
IN UINT64 EngineMask IN UINT64 EngineMask
); );
/**
Enable VTd translation table protection.
@param VTdInfo The VTd engine context information.
@param EngineMask The mask of the VTd engine to be accessed.
**/
VOID
EnableVTdTranslationProtection (
IN VTD_INFO *VTdInfo,
IN UINT64 EngineMask
);
/**
Disable VTd translation table protection.
@param VTdInfo The VTd engine context information.
@param EngineMask The mask of the VTd engine to be accessed.
**/
VOID
DisableVTdTranslationProtection (
IN VTD_INFO *VTdInfo,
IN UINT64 EngineMask
);
/**
Parse DMAR DRHD table.
@param[in] AcpiDmarTable DMAR ACPI table
@return EFI_SUCCESS The DMAR DRHD table is parsed.
**/
EFI_STATUS
ParseDmarAcpiTableDrhd (
IN EFI_ACPI_DMAR_HEADER *AcpiDmarTable
);
/**
Parse DMAR DRHD table.
@param VTdInfo The VTd engine context information.
**/
VOID
ParseDmarAcpiTableRmrr (
IN VTD_INFO *VTdInfo
);
/**
Dump DMAR ACPI table.
@param[in] Dmar DMAR ACPI table
**/
VOID
DumpAcpiDMAR (
IN EFI_ACPI_DMAR_HEADER *Dmar
);
/**
Get the highest memory.
@return the highest memory.
**/
UINT64
GetTopMemory (
VOID
);
extern EFI_GUID mVTdInfoGuid;
#endif #endif

View File

@ -33,6 +33,8 @@
IntelVTdPmrPei.c IntelVTdPmrPei.c
IntelVTdPmrPei.h IntelVTdPmrPei.h
IntelVTdPmr.c IntelVTdPmr.c
DmarTable.c
VtdReg.c
[LibraryClasses] [LibraryClasses]
DebugLib DebugLib
@ -42,17 +44,18 @@
PeiServicesLib PeiServicesLib
HobLib HobLib
IoLib IoLib
CacheMaintenanceLib
[Ppis] [Ppis]
gEdkiiIoMmuPpiGuid ## PRODUCES gEdkiiIoMmuPpiGuid ## PRODUCES
gEdkiiVTdInfoPpiGuid ## CONSUMES gEdkiiVTdInfoPpiGuid ## CONSUMES
gEfiPeiMemoryDiscoveredPpiGuid ## CONSUMES
gEfiEndOfPeiSignalPpiGuid ## CONSUMES gEfiEndOfPeiSignalPpiGuid ## CONSUMES
[Pcd] [Pcd]
gIntelSiliconPkgTokenSpaceGuid.PcdVTdPolicyPropertyMask ## CONSUMES gIntelSiliconPkgTokenSpaceGuid.PcdVTdPolicyPropertyMask ## CONSUMES
[Depex] [Depex]
gEfiPeiMemoryDiscoveredPpiGuid AND
gEfiPeiMasterBootModePpiGuid AND gEfiPeiMasterBootModePpiGuid AND
gEdkiiVTdInfoPpiGuid gEdkiiVTdInfoPpiGuid

View File

@ -0,0 +1,293 @@
/** @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 <Library/MemoryAllocationLib.h>
#include <Library/CacheMaintenanceLib.h>
#include <IndustryStandard/Vtd.h>
#include <Ppi/VtdInfo.h>
#include "IntelVTdPmrPei.h"
/**
Flush VTD page table and context table memory.
This action is to make sure the IOMMU engine can get final data in memory.
@param[in] Base The base address of memory to be flushed.
@param[in] Size The size of memory in bytes to be flushed.
**/
VOID
FlushPageTableMemory (
IN UINTN Base,
IN UINTN Size
)
{
WriteBackDataCacheRange ((VOID *)Base, Size);
}
/**
Flush VTd engine write buffer.
@param VtdUnitBaseAddress The base address of the VTd engine.
**/
VOID
FlushWriteBuffer (
IN UINTN VtdUnitBaseAddress
)
{
UINT32 Reg32;
VTD_CAP_REG CapReg;
CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
if (CapReg.Bits.RWBF != 0) {
Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_WBF);
do {
Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
} while ((Reg32 & B_GSTS_REG_WBF) != 0);
}
}
/**
Invalidate VTd context cache.
@param VtdUnitBaseAddress The base address of the VTd engine.
**/
EFI_STATUS
InvalidateContextCache (
IN UINTN VtdUnitBaseAddress
)
{
UINT64 Reg64;
Reg64 = MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG);
if ((Reg64 & B_CCMD_REG_ICC) != 0) {
DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC is set for VTD(%x)\n",VtdUnitBaseAddress));
return EFI_DEVICE_ERROR;
}
Reg64 &= ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK));
Reg64 |= (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL);
MmioWrite64 (VtdUnitBaseAddress + R_CCMD_REG, Reg64);
do {
Reg64 = MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG);
} while ((Reg64 & B_CCMD_REG_ICC) != 0);
return EFI_SUCCESS;
}
/**
Invalidate VTd IOTLB.
@param VtdUnitBaseAddress The base address of the VTd engine.
**/
EFI_STATUS
InvalidateIOTLB (
IN UINTN VtdUnitBaseAddress
)
{
UINT64 Reg64;
VTD_ECAP_REG ECapReg;
ECapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_ECAP_REG);
Reg64 = MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
if ((Reg64 & B_IOTLB_REG_IVT) != 0) {
DEBUG ((DEBUG_ERROR,"ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set for VTD(%x)\n", VtdUnitBaseAddress));
return EFI_DEVICE_ERROR;
}
Reg64 &= ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK));
Reg64 |= (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL);
MmioWrite64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);
do {
Reg64 = MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
} while ((Reg64 & B_IOTLB_REG_IVT) != 0);
return EFI_SUCCESS;
}
/**
Enable DMAR translation.
@param VtdUnitBaseAddress The base address of the VTd engine.
@param RootEntryTable The address of the VTd RootEntryTable.
@retval EFI_SUCCESS DMAR translation is enabled.
@retval EFI_DEVICE_ERROR DMAR translation is not enabled.
**/
EFI_STATUS
EnableDmar (
IN UINTN VtdUnitBaseAddress,
IN UINTN RootEntryTable
)
{
UINT32 Reg32;
DEBUG((DEBUG_INFO, ">>>>>>EnableDmar() for engine [%x] \n", VtdUnitBaseAddress));
DEBUG((DEBUG_INFO, "RootEntryTable 0x%x \n", RootEntryTable));
MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, (UINT64)(UINTN)RootEntryTable);
MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
do {
Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
} while((Reg32 & B_GSTS_REG_RTPS) == 0);
//
// Init DMAr Fault Event and Data registers
//
Reg32 = MmioRead32 (VtdUnitBaseAddress + R_FEDATA_REG);
//
// Write Buffer Flush before invalidation
//
FlushWriteBuffer (VtdUnitBaseAddress);
//
// Invalidate the context cache
//
InvalidateContextCache (VtdUnitBaseAddress);
//
// Invalidate the IOTLB cache
//
InvalidateIOTLB (VtdUnitBaseAddress);
//
// Enable VTd
//
MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_TE);
DEBUG((DEBUG_INFO, "EnableDmar: Waiting B_GSTS_REG_TE ...\n"));
do {
Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
} while ((Reg32 & B_GSTS_REG_TE) == 0);
DEBUG ((DEBUG_INFO,"VTD () enabled!<<<<<<\n"));
return EFI_SUCCESS;
}
/**
Disable DMAR translation.
@param VtdUnitBaseAddress The base address of the VTd engine.
@retval EFI_SUCCESS DMAR translation is disabled.
@retval EFI_DEVICE_ERROR DMAR translation is not disabled.
**/
EFI_STATUS
DisableDmar (
IN UINTN VtdUnitBaseAddress
)
{
UINT32 Reg32;
DEBUG((DEBUG_INFO, ">>>>>>DisableDmar() for engine [%x] \n", VtdUnitBaseAddress));
//
// Write Buffer Flush before invalidation
//
FlushWriteBuffer (VtdUnitBaseAddress);
//
// Disable VTd
//
MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
do {
Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
} while((Reg32 & B_GSTS_REG_RTPS) == 0);
Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
DEBUG((DEBUG_INFO, "DisableDmar: GSTS_REG - 0x%08x\n", Reg32));
MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, 0);
DEBUG ((DEBUG_INFO,"VTD () Disabled!<<<<<<\n"));
return EFI_SUCCESS;
}
/**
Enable VTd translation table protection.
@param VTdInfo The VTd engine context information.
@param EngineMask The mask of the VTd engine to be accessed.
**/
VOID
EnableVTdTranslationProtection (
IN VTD_INFO *VTdInfo,
IN UINT64 EngineMask
)
{
UINTN Index;
VOID *RootEntryTable;
DEBUG ((DEBUG_INFO, "EnableVTdTranslationProtection - 0x%lx\n", EngineMask));
RootEntryTable = AllocatePages (1);
ASSERT (RootEntryTable != NULL);
if (RootEntryTable == NULL) {
DEBUG ((DEBUG_INFO, " EnableVTdTranslationProtection : OutOfResource\n"));
return ;
}
ZeroMem (RootEntryTable, EFI_PAGES_TO_SIZE(1));
FlushPageTableMemory ((UINTN)RootEntryTable, EFI_PAGES_TO_SIZE(1));
for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
if ((EngineMask & LShiftU64(1, Index)) == 0) {
continue;
}
EnableDmar ((UINTN)VTdInfo->VTdEngineAddress[Index], (UINTN)RootEntryTable);
}
return ;
}
/**
Disable VTd translation table protection.
@param VTdInfo The VTd engine context information.
@param EngineMask The mask of the VTd engine to be accessed.
**/
VOID
DisableVTdTranslationProtection (
IN VTD_INFO *VTdInfo,
IN UINT64 EngineMask
)
{
UINTN Index;
DEBUG ((DEBUG_INFO, "DisableVTdTranslationProtection - 0x%lx\n", EngineMask));
for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
if ((EngineMask & LShiftU64(1, Index)) == 0) {
continue;
}
DisableDmar ((UINTN)VTdInfo->VTdEngineAddress[Index]);
}
return ;
}