/** @file
Copyright (c) 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "IntelVTdDmarPei.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
));
DEBUG ((DEBUG_INFO,
" DMA_CTRL_PLATFORM_OPT_IN_FLAG ...................... 0x%02x\n",
Dmar->Flags & EFI_ACPI_DMAR_FLAGS_DMA_CTRL_PLATFORM_OPT_IN_FLAG
));
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 ;
}
/**
Get PCI device information from DMAR DevScopeEntry.
@param[in] Segment The segment number.
@param[in] DmarDevScopeEntry DMAR DevScopeEntry
@param[out] Bus The bus number.
@param[out] Device The device number.
@param[out] Function The function number.
@retval EFI_SUCCESS The PCI device information is returned.
**/
EFI_STATUS
GetPciBusDeviceFunction (
IN UINT16 Segment,
IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry,
OUT UINT8 *Bus,
OUT UINT8 *Device,
OUT UINT8 *Function
)
{
EFI_ACPI_DMAR_PCI_PATH *DmarPciPath;
UINT8 MyBus;
UINT8 MyDevice;
UINT8 MyFunction;
DmarPciPath = (EFI_ACPI_DMAR_PCI_PATH *) ((UINTN) (DmarDevScopeEntry + 1));
MyBus = DmarDevScopeEntry->StartBusNumber;
MyDevice = DmarPciPath->Device;
MyFunction = DmarPciPath->Function;
switch (DmarDevScopeEntry->Type) {
case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
while ((UINTN) DmarPciPath + sizeof (EFI_ACPI_DMAR_PCI_PATH) < (UINTN) DmarDevScopeEntry + DmarDevScopeEntry->Length) {
MyBus = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS (Segment, MyBus, MyDevice, MyFunction, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
DmarPciPath ++;
MyDevice = DmarPciPath->Device;
MyFunction = DmarPciPath->Function;
}
break;
case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC:
case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET:
case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE:
break;
}
*Bus = MyBus;
*Device = MyDevice;
*Function = MyFunction;
return EFI_SUCCESS;
}
/**
Return the index of PCI data.
@param[in] VTdUnitInfo The VTd engine unit information.
@param[in] Segment The Segment used to identify a VTd engine.
@param[in] SourceId The SourceId used to identify a VTd engine and table entry.
@return The index of the PCI data.
@retval (UINTN)-1 The PCI data is not found.
**/
UINTN
GetPciDataIndex (
IN VTD_UNIT_INFO *VTdUnitInfo,
IN UINT16 Segment,
IN VTD_SOURCE_ID SourceId
)
{
UINTN Index;
VTD_SOURCE_ID *PciSourceId;
PEI_PCI_DEVICE_DATA *PciDeviceDataBase;
if (Segment != VTdUnitInfo->Segment) {
return (UINTN)-1;
}
for (Index = 0; Index < VTdUnitInfo->PciDeviceInfo.PciDeviceDataNumber; Index++) {
PciDeviceDataBase = (PEI_PCI_DEVICE_DATA*) (UINTN) VTdUnitInfo->PciDeviceInfo.PciDeviceData;
PciSourceId = &PciDeviceDataBase[Index].PciSourceId;
if ((PciSourceId->Bits.Bus == SourceId.Bits.Bus) &&
(PciSourceId->Bits.Device == SourceId.Bits.Device) &&
(PciSourceId->Bits.Function == SourceId.Bits.Function) ) {
return Index;
}
}
return (UINTN)-1;
}
/**
Register PCI device to VTd engine.
@param[in] VTdUnitInfo The VTd engine unit information.
@param[in] Segment The segment of the source.
@param[in] SourceId The SourceId of the source.
@param[in] DeviceType The DMAR device scope type.
@param[in] CheckExist TRUE: ERROR will be returned if the PCI device is already registered.
FALSE: SUCCESS will be returned if the PCI device is registered.
@retval EFI_SUCCESS The PCI device is registered.
@retval EFI_OUT_OF_RESOURCES No enough resource to register a new PCI device.
@retval EFI_ALREADY_STARTED The device is already registered.
**/
EFI_STATUS
RegisterPciDevice (
IN VTD_UNIT_INFO *VTdUnitInfo,
IN UINT16 Segment,
IN VTD_SOURCE_ID SourceId,
IN UINT8 DeviceType,
IN BOOLEAN CheckExist
)
{
PEI_PCI_DEVICE_INFORMATION *PciDeviceInfo;
VTD_SOURCE_ID *PciSourceId;
UINTN PciDataIndex;
UINTN PciDeviceDataSize;
PEI_PCI_DEVICE_DATA *NewPciDeviceData;
PEI_PCI_DEVICE_DATA *PciDeviceDataBase;
PciDeviceInfo = &VTdUnitInfo->PciDeviceInfo;
PciDataIndex = GetPciDataIndex (VTdUnitInfo, Segment, SourceId);
if (PciDataIndex == (UINTN)-1) {
//
// Register new
//
if (PciDeviceInfo->PciDeviceDataNumber >= PciDeviceInfo->PciDeviceDataMaxNumber) {
//
// Reallocate
//
PciDeviceDataSize = sizeof(*NewPciDeviceData) * (PciDeviceInfo->PciDeviceDataMaxNumber + MAX_VTD_PCI_DATA_NUMBER);
DEBUG ((DEBUG_INFO, "New PciDeviceDataSize:%d Page:%d\n", PciDeviceDataSize, EFI_SIZE_TO_PAGES (PciDeviceDataSize)));
NewPciDeviceData = AllocateZeroPages (EFI_SIZE_TO_PAGES(PciDeviceDataSize));
if (NewPciDeviceData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
PciDeviceInfo->PciDeviceDataMaxNumber += MAX_VTD_PCI_DATA_NUMBER;
if (PciDeviceInfo->PciDeviceData != 0) {
CopyMem (NewPciDeviceData, (VOID *) (UINTN) PciDeviceInfo->PciDeviceData, sizeof (*NewPciDeviceData) * PciDeviceInfo->PciDeviceDataNumber);
FreePages((VOID *) (UINTN) PciDeviceInfo->PciDeviceData, PciDeviceInfo->PciDeviceDataPageSize);
}
PciDeviceInfo->PciDeviceData = (UINT32) (UINTN) NewPciDeviceData;
PciDeviceInfo->PciDeviceDataPageSize = (UINT32) EFI_SIZE_TO_PAGES (PciDeviceDataSize);
}
ASSERT (PciDeviceInfo->PciDeviceDataNumber < PciDeviceInfo->PciDeviceDataMaxNumber);
PciDeviceDataBase = (PEI_PCI_DEVICE_DATA *) (UINTN) PciDeviceInfo->PciDeviceData;
PciSourceId = &PciDeviceDataBase[PciDeviceInfo->PciDeviceDataNumber].PciSourceId;
PciSourceId->Bits.Bus = SourceId.Bits.Bus;
PciSourceId->Bits.Device = SourceId.Bits.Device;
PciSourceId->Bits.Function = SourceId.Bits.Function;
DEBUG ((DEBUG_INFO, " RegisterPciDevice: PCI S%04x B%02x D%02x F%02x", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
PciDeviceDataBase[PciDeviceInfo->PciDeviceDataNumber].DeviceType = DeviceType;
if ((DeviceType != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) &&
(DeviceType != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE)) {
DEBUG ((DEBUG_INFO, " (*)"));
}
DEBUG ((DEBUG_INFO, "\n"));
PciDeviceInfo->PciDeviceDataNumber++;
} else {
if (CheckExist) {
DEBUG ((DEBUG_INFO, " RegisterPciDevice: PCI S%04x B%02x D%02x F%02x already registered\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
return EFI_ALREADY_STARTED;
}
}
return EFI_SUCCESS;
}
/**
Process DMAR DHRD table.
@param[in] VTdUnitInfo The VTd engine unit information.
@param[in] DmarDrhd The DRHD table.
**/
VOID
ProcessDhrd (
IN VTD_UNIT_INFO *VTdUnitInfo,
IN EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd
)
{
EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry;
UINT8 Bus;
UINT8 Device;
UINT8 Function;
EFI_STATUS Status;
VTD_SOURCE_ID SourceId;
DEBUG ((DEBUG_INFO," VTD BaseAddress - 0x%016lx\n", DmarDrhd->RegisterBaseAddress));
VTdUnitInfo->VtdUnitBaseAddress = (UINT32) DmarDrhd->RegisterBaseAddress;
VTdUnitInfo->EnableQueuedInvalidation = 0;
DEBUG ((DEBUG_INFO," VTD Segment - %d\n", DmarDrhd->SegmentNumber));
VTdUnitInfo->Segment = DmarDrhd->SegmentNumber;
VTdUnitInfo->FixedSecondLevelPagingEntry = 0;
VTdUnitInfo->RmrrSecondLevelPagingEntry = 0;
VTdUnitInfo->RootEntryTable = 0;
VTdUnitInfo->ExtRootEntryTable = 0;
VTdUnitInfo->RootEntryTablePageSize = 0;
VTdUnitInfo->ExtRootEntryTablePageSize = 0;
VTdUnitInfo->PciDeviceInfo.IncludeAllFlag = 0;
VTdUnitInfo->PciDeviceInfo.PciDeviceDataMaxNumber = 0;
VTdUnitInfo->PciDeviceInfo.PciDeviceDataNumber = 0;
VTdUnitInfo->PciDeviceInfo.PciDeviceDataPageSize = 0;
VTdUnitInfo->PciDeviceInfo.PciDeviceData = 0;
if ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0) {
VTdUnitInfo->PciDeviceInfo.IncludeAllFlag = TRUE;
DEBUG ((DEBUG_INFO," ProcessDhrd: with INCLUDE ALL\n"));
} else {
VTdUnitInfo->PciDeviceInfo.IncludeAllFlag = FALSE;
DEBUG ((DEBUG_INFO," ProcessDhrd: without INCLUDE ALL\n"));
}
VTdUnitInfo->PciDeviceInfo.PciDeviceDataNumber = 0;
VTdUnitInfo->PciDeviceInfo.PciDeviceDataMaxNumber = 0;
VTdUnitInfo->PciDeviceInfo.PciDeviceDataPageSize = 0;
VTdUnitInfo->PciDeviceInfo.PciDeviceData = 0;
DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *) ((UINTN) (DmarDrhd + 1));
while ((UINTN)DmarDevScopeEntry < (UINTN) DmarDrhd + DmarDrhd->Header.Length) {
Status = GetPciBusDeviceFunction (DmarDrhd->SegmentNumber, DmarDevScopeEntry, &Bus, &Device, &Function);
if (EFI_ERROR (Status)) {
return;
}
DEBUG ((DEBUG_INFO," ProcessDhrd: "));
switch (DmarDevScopeEntry->Type) {
case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
DEBUG ((DEBUG_INFO,"PCI Endpoint"));
break;
case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
DEBUG ((DEBUG_INFO,"PCI-PCI bridge"));
break;
case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC:
DEBUG ((DEBUG_INFO,"IOAPIC"));
break;
case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET:
DEBUG ((DEBUG_INFO,"MSI Capable HPET"));
break;
case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE:
DEBUG ((DEBUG_INFO,"ACPI Namespace Device"));
break;
}
DEBUG ((DEBUG_INFO," S%04x B%02x D%02x F%02x\n", DmarDrhd->SegmentNumber, Bus, Device, Function));
SourceId.Bits.Bus = Bus;
SourceId.Bits.Device = Device;
SourceId.Bits.Function = Function;
Status = RegisterPciDevice (VTdUnitInfo, DmarDrhd->SegmentNumber, SourceId, DmarDevScopeEntry->Type, TRUE);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR,"RegisterPciDevice Failed !\n"));
}
DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *) ((UINTN) DmarDevScopeEntry + DmarDevScopeEntry->Length);
}
}
/**
Dump the PCI device information managed by this VTd engine.
@param[in] VTdInfo The VTd engine context information.
@param[in] VtdIndex The index of VTd engine.
**/
VOID
DumpPciDeviceInfo (
IN VTD_INFO *VTdInfo,
IN UINTN VtdIndex
)
{
UINTN Index;
PEI_PCI_DEVICE_DATA *PciDeviceDataBase;
DEBUG ((DEBUG_INFO,"PCI Device Information (Number 0x%x, IncludeAll - %d):\n",
VTdInfo->VtdUnitInfo[VtdIndex].PciDeviceInfo.PciDeviceDataNumber,
VTdInfo->VtdUnitInfo[VtdIndex].PciDeviceInfo.IncludeAllFlag
));
PciDeviceDataBase = (PEI_PCI_DEVICE_DATA *) (UINTN) VTdInfo->VtdUnitInfo[VtdIndex].PciDeviceInfo.PciDeviceData;
for (Index = 0; Index < VTdInfo->VtdUnitInfo[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {
DEBUG ((DEBUG_INFO," S%04x B%02x D%02x F%02x\n",
VTdInfo->VtdUnitInfo[VtdIndex].Segment,
PciDeviceDataBase[Index].PciSourceId.Bits.Bus,
PciDeviceDataBase[Index].PciSourceId.Bits.Device,
PciDeviceDataBase[Index].PciSourceId.Bits.Function
));
}
}
/**
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 (VTD_UNIT_INFO));
ASSERT(VTdInfo != NULL);
if (VTdInfo == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Initialize the engine mask to all.
//
VTdInfo->AcpiDmarTable = (UINT32) (UINTN) AcpiDmarTable;
VTdInfo->HostAddressWidth = AcpiDmarTable->HostAddressWidth;
VTdInfo->VTdEngineCount = (UINT32) 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->VtdUnitInfo[VtdIndex], (EFI_ACPI_DMAR_DRHD_HEADER *) DmarHeader);
VtdIndex++;
break;
default:
break;
}
DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *) ((UINTN) DmarHeader + DmarHeader->Length);
}
ASSERT (VtdIndex == VtdUnitNumber);
for (VtdIndex = 0; VtdIndex < VtdUnitNumber; VtdIndex++) {
DumpPciDeviceInfo (VTdInfo, VtdIndex);
}
return EFI_SUCCESS;
}
/**
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;
UINT8 Bus;
UINT8 Device;
UINT8 Function;
EFI_STATUS Status;
VTD_SOURCE_ID SourceId;
DEBUG ((DEBUG_INFO," PEI 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) {
if (DmarDevScopeEntry->Type != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) {
DEBUG ((DEBUG_INFO,"RMRR DevScopeEntryType is not endpoint, type[0x%x] \n", DmarDevScopeEntry->Type));
return;
}
Status = GetPciBusDeviceFunction (DmarRmrr->SegmentNumber, DmarDevScopeEntry, &Bus, &Device, &Function);
if (EFI_ERROR (Status)) {
continue;
}
DEBUG ((DEBUG_INFO,"RMRR S%04x B%02x D%02x F%02x\n", DmarRmrr->SegmentNumber, Bus, Device, Function));
SourceId.Bits.Bus = Bus;
SourceId.Bits.Device = Device;
SourceId.Bits.Function = Function;
Status = EnableRmrrPageAttribute (
VTdInfo,
DmarRmrr->SegmentNumber,
SourceId,
DmarRmrr->ReservedMemoryRegionBaseAddress,
DmarRmrr->ReservedMemoryRegionLimitAddress,
EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "EnableRmrrPageAttribute : %r\n", Status));
}
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 = (EFI_ACPI_DMAR_HEADER *) (UINTN) 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);
}
}