mirror of https://github.com/acidanthera/audk.git
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:
parent
e5d847476a
commit
a1e7cd0b02
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -22,17 +22,17 @@
|
|||
|
||||
#include "IntelVTdPmrPei.h"
|
||||
|
||||
extern VTD_INFO *mVTdInfo;
|
||||
|
||||
/**
|
||||
Get protected low memory alignment.
|
||||
|
||||
@param HostAddressWidth The host address width.
|
||||
@param VtdUnitBaseAddress The base address of the VTd engine.
|
||||
|
||||
@return protected low memory alignment.
|
||||
**/
|
||||
UINT32
|
||||
GetPlmrAlignment (
|
||||
IN UINT8 HostAddressWidth,
|
||||
IN UINTN VtdUnitBaseAddress
|
||||
)
|
||||
{
|
||||
|
@ -48,19 +48,18 @@ GetPlmrAlignment (
|
|||
/**
|
||||
Get protected high memory alignment.
|
||||
|
||||
@param HostAddressWidth The host address width.
|
||||
@param VtdUnitBaseAddress The base address of the VTd engine.
|
||||
|
||||
@return protected high memory alignment.
|
||||
**/
|
||||
UINT64
|
||||
GetPhmrAlignment (
|
||||
IN UINT8 HostAddressWidth,
|
||||
IN UINTN VtdUnitBaseAddress
|
||||
)
|
||||
{
|
||||
UINT64 Data64;
|
||||
UINT8 HostAddressWidth;
|
||||
|
||||
HostAddressWidth = mVTdInfo->HostAddressWidth;
|
||||
|
||||
MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, 0xFFFFFFFFFFFFFFFF);
|
||||
Data64 = MmioRead64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG);
|
||||
|
@ -73,12 +72,14 @@ GetPhmrAlignment (
|
|||
/**
|
||||
Get protected low memory alignment.
|
||||
|
||||
@param VTdInfo The VTd engine context information.
|
||||
@param EngineMask The mask of the VTd engine to be accessed.
|
||||
|
||||
@return protected low memory alignment.
|
||||
**/
|
||||
UINT32
|
||||
GetLowMemoryAlignment (
|
||||
IN VTD_INFO *VTdInfo,
|
||||
IN UINT64 EngineMask
|
||||
)
|
||||
{
|
||||
|
@ -87,11 +88,11 @@ GetLowMemoryAlignment (
|
|||
UINT32 FinalAlignment;
|
||||
|
||||
FinalAlignment = 0;
|
||||
for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
|
||||
for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
|
||||
if ((EngineMask & LShiftU64(1, Index)) == 0) {
|
||||
continue;
|
||||
}
|
||||
Alignment = GetPlmrAlignment ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
|
||||
Alignment = GetPlmrAlignment (VTdInfo->HostAddressWidth, (UINTN)VTdInfo->VTdEngineAddress[Index]);
|
||||
if (FinalAlignment < Alignment) {
|
||||
FinalAlignment = Alignment;
|
||||
}
|
||||
|
@ -102,12 +103,14 @@ GetLowMemoryAlignment (
|
|||
/**
|
||||
Get protected high memory alignment.
|
||||
|
||||
@param VTdInfo The VTd engine context information.
|
||||
@param EngineMask The mask of the VTd engine to be accessed.
|
||||
|
||||
@return protected high memory alignment.
|
||||
**/
|
||||
UINT64
|
||||
GetHighMemoryAlignment (
|
||||
IN VTD_INFO *VTdInfo,
|
||||
IN UINT64 EngineMask
|
||||
)
|
||||
{
|
||||
|
@ -116,11 +119,11 @@ GetHighMemoryAlignment (
|
|||
UINT64 FinalAlignment;
|
||||
|
||||
FinalAlignment = 0;
|
||||
for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
|
||||
for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
|
||||
if ((EngineMask & LShiftU64(1, Index)) == 0) {
|
||||
continue;
|
||||
}
|
||||
Alignment = GetPhmrAlignment ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
|
||||
Alignment = GetPhmrAlignment (VTdInfo->HostAddressWidth, (UINTN)VTdInfo->VTdEngineAddress[Index]);
|
||||
if (FinalAlignment < Alignment) {
|
||||
FinalAlignment = Alignment;
|
||||
}
|
||||
|
@ -144,12 +147,19 @@ EnablePmr (
|
|||
UINT32 Reg32;
|
||||
VTD_CAP_REG CapReg;
|
||||
|
||||
DEBUG ((DEBUG_INFO, "EnablePmr - %x\n", VtdUnitBaseAddress));
|
||||
|
||||
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 == 0xFFFFFFFF) {
|
||||
DEBUG ((DEBUG_ERROR, "R_PMEN_ENABLE_REG - 0x%x\n", Reg32));
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
if ((Reg32 & BIT0) == 0) {
|
||||
MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, BIT31);
|
||||
do {
|
||||
|
@ -157,6 +167,8 @@ EnablePmr (
|
|||
} while((Reg32 & BIT0) == 0);
|
||||
}
|
||||
|
||||
DEBUG ((DEBUG_INFO, "EnablePmr - Done\n"));
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -182,6 +194,11 @@ DisablePmr (
|
|||
}
|
||||
|
||||
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) {
|
||||
MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, 0x0);
|
||||
do {
|
||||
|
@ -195,6 +212,7 @@ DisablePmr (
|
|||
/**
|
||||
Set PMR region in the VTd engine.
|
||||
|
||||
@param HostAddressWidth The host address width.
|
||||
@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.
|
||||
|
@ -206,6 +224,7 @@ DisablePmr (
|
|||
**/
|
||||
EFI_STATUS
|
||||
SetPmrRegion (
|
||||
IN UINT8 HostAddressWidth,
|
||||
IN UINTN VtdUnitBaseAddress,
|
||||
IN UINT32 LowMemoryBase,
|
||||
IN UINT32 LowMemoryLength,
|
||||
|
@ -225,9 +244,9 @@ SetPmrRegion (
|
|||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
PlmrAlignment = GetPlmrAlignment (VtdUnitBaseAddress);
|
||||
PlmrAlignment = GetPlmrAlignment (HostAddressWidth, VtdUnitBaseAddress);
|
||||
DEBUG ((DEBUG_INFO, "PlmrAlignment - 0x%x\n", PlmrAlignment));
|
||||
PhmrAlignment = GetPhmrAlignment (VtdUnitBaseAddress);
|
||||
PhmrAlignment = GetPhmrAlignment (HostAddressWidth, VtdUnitBaseAddress);
|
||||
DEBUG ((DEBUG_INFO, "PhmrAlignment - 0x%lx\n", PhmrAlignment));
|
||||
|
||||
if ((LowMemoryBase != ALIGN_VALUE(LowMemoryBase, PlmrAlignment)) ||
|
||||
|
@ -247,8 +266,10 @@ SetPmrRegion (
|
|||
|
||||
MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG, LowMemoryBase);
|
||||
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_LIMITE_REG, HighMemoryBase + HighMemoryLength - 1);
|
||||
DEBUG ((DEBUG_INFO, "PHMR set done\n"));
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
@ -256,6 +277,7 @@ SetPmrRegion (
|
|||
/**
|
||||
Set DMA protected region.
|
||||
|
||||
@param VTdInfo The VTd engine context information.
|
||||
@param EngineMask The mask of the VTd engine to be accessed.
|
||||
@param LowMemoryBase The protected low memory region base.
|
||||
@param LowMemoryLength The protected low memory region length.
|
||||
|
@ -267,6 +289,7 @@ SetPmrRegion (
|
|||
**/
|
||||
EFI_STATUS
|
||||
SetDmaProtectedRange (
|
||||
IN VTD_INFO *VTdInfo,
|
||||
IN UINT64 EngineMask,
|
||||
IN UINT32 LowMemoryBase,
|
||||
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));
|
||||
|
||||
for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
|
||||
for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
|
||||
if ((EngineMask & LShiftU64(1, Index)) == 0) {
|
||||
continue;
|
||||
}
|
||||
DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
|
||||
DisablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);
|
||||
Status = SetPmrRegion (
|
||||
(UINTN)mVTdInfo->VTdEngineAddress[Index],
|
||||
VTdInfo->HostAddressWidth,
|
||||
(UINTN)VTdInfo->VTdEngineAddress[Index],
|
||||
LowMemoryBase,
|
||||
LowMemoryLength,
|
||||
HighMemoryBase,
|
||||
|
@ -294,7 +318,7 @@ SetDmaProtectedRange (
|
|||
if (EFI_ERROR(Status)) {
|
||||
return Status;
|
||||
}
|
||||
Status = EnablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
|
||||
Status = EnablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);
|
||||
if (EFI_ERROR(Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
@ -306,25 +330,29 @@ SetDmaProtectedRange (
|
|||
/**
|
||||
Diable DMA protection.
|
||||
|
||||
@param VTdInfo The VTd engine context information.
|
||||
@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
|
||||
DisableDmaProtection (
|
||||
IN VTD_INFO *VTdInfo,
|
||||
IN UINT64 EngineMask
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
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) {
|
||||
continue;
|
||||
}
|
||||
Status = DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
|
||||
Status = DisablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);
|
||||
if (EFI_ERROR(Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
@ -332,3 +360,67 @@ DisableDmaProtection (
|
|||
|
||||
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
|
@ -16,6 +16,8 @@
|
|||
#define __DMA_ACCESS_LIB_H__
|
||||
|
||||
typedef struct {
|
||||
EFI_ACPI_DMAR_HEADER *AcpiDmarTable;
|
||||
UINT64 EngineMask;
|
||||
UINT8 HostAddressWidth;
|
||||
UINTN VTdEngineCount;
|
||||
UINT64 VTdEngineAddress[1];
|
||||
|
@ -24,6 +26,7 @@ typedef struct {
|
|||
/**
|
||||
Set DMA protected region.
|
||||
|
||||
@param VTdInfo The VTd engine context information.
|
||||
@param EngineMask The mask of the VTd engine to be accessed.
|
||||
@param LowMemoryBase The protected low memory region base.
|
||||
@param LowMemoryLength The protected low memory region length.
|
||||
|
@ -35,6 +38,7 @@ typedef struct {
|
|||
**/
|
||||
EFI_STATUS
|
||||
SetDmaProtectedRange (
|
||||
IN VTD_INFO *VTdInfo,
|
||||
IN UINT64 EngineMask,
|
||||
IN UINT32 LowMemoryBase,
|
||||
IN UINT32 LowMemoryLength,
|
||||
|
@ -45,38 +49,127 @@ SetDmaProtectedRange (
|
|||
/**
|
||||
Diable DMA protection.
|
||||
|
||||
@param VTdInfo The VTd engine context information.
|
||||
@param EngineMask The mask of the VTd engine to be accessed.
|
||||
|
||||
@retval DMA protection is disabled.
|
||||
**/
|
||||
EFI_STATUS
|
||||
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
|
||||
);
|
||||
|
||||
/**
|
||||
Get protected low memory alignment.
|
||||
|
||||
@param VTdInfo The VTd engine context information.
|
||||
@param EngineMask The mask of the VTd engine to be accessed.
|
||||
|
||||
@return protected low memory alignment.
|
||||
**/
|
||||
UINT32
|
||||
GetLowMemoryAlignment (
|
||||
IN VTD_INFO *VTdInfo,
|
||||
IN UINT64 EngineMask
|
||||
);
|
||||
|
||||
/**
|
||||
Get protected high memory alignment.
|
||||
|
||||
@param VTdInfo The VTd engine context information.
|
||||
@param EngineMask The mask of the VTd engine to be accessed.
|
||||
|
||||
@return protected high memory alignment.
|
||||
**/
|
||||
UINT64
|
||||
GetHighMemoryAlignment (
|
||||
IN VTD_INFO *VTdInfo,
|
||||
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
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
IntelVTdPmrPei.c
|
||||
IntelVTdPmrPei.h
|
||||
IntelVTdPmr.c
|
||||
DmarTable.c
|
||||
VtdReg.c
|
||||
|
||||
[LibraryClasses]
|
||||
DebugLib
|
||||
|
@ -42,17 +44,18 @@
|
|||
PeiServicesLib
|
||||
HobLib
|
||||
IoLib
|
||||
CacheMaintenanceLib
|
||||
|
||||
[Ppis]
|
||||
gEdkiiIoMmuPpiGuid ## PRODUCES
|
||||
gEdkiiVTdInfoPpiGuid ## CONSUMES
|
||||
gEfiEndOfPeiSignalPpiGuid ## CONSUMES
|
||||
gEdkiiIoMmuPpiGuid ## PRODUCES
|
||||
gEdkiiVTdInfoPpiGuid ## CONSUMES
|
||||
gEfiPeiMemoryDiscoveredPpiGuid ## CONSUMES
|
||||
gEfiEndOfPeiSignalPpiGuid ## CONSUMES
|
||||
|
||||
[Pcd]
|
||||
gIntelSiliconPkgTokenSpaceGuid.PcdVTdPolicyPropertyMask ## CONSUMES
|
||||
|
||||
[Depex]
|
||||
gEfiPeiMemoryDiscoveredPpiGuid AND
|
||||
gEfiPeiMasterBootModePpiGuid AND
|
||||
gEdkiiVTdInfoPpiGuid
|
||||
|
||||
|
|
|
@ -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 ;
|
||||
}
|
Loading…
Reference in New Issue