From: Jiewen Yao Date: Sat, 23 Sep 2017 08:27:50 +0000 (+0800) Subject: IntelSiliconPkg/VtdPmrPei: Add premem support. X-Git-Tag: edk2-stable201903~3159 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=a1e7cd0b020ac024015095068b02e03a68edd96c 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 Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Jiewen Yao --- diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/DmarTable.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/DmarTable.c new file mode 100644 index 0000000000..891efa6546 --- /dev/null +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/DmarTable.c @@ -0,0 +1,580 @@ +/** @file + + Copyright (c) 2017, Intel Corporation. All rights reserved.
+ 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 +#include +#include +#include +#include +#include +#include +#include + +#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); + } +} diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c index 6179dfe5dc..000a81ba18 100644 --- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c @@ -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; +} diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c index 3fe6d654cd..240a6d2817 100644 --- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "IntelVTdPmrPei.h" @@ -31,13 +32,20 @@ #define TOTAL_DMA_BUFFER_SIZE SIZE_4MB #define TOTAL_DMA_BUFFER_SIZE_S3 SIZE_1MB -EFI_ACPI_DMAR_HEADER *mAcpiDmarTable; -VTD_INFO *mVTdInfo; -UINT64 mEngineMask; -UINTN mDmaBufferBase; -UINTN mDmaBufferSize; -UINTN mDmaBufferCurrentTop; -UINTN mDmaBufferCurrentBottom; +EFI_GUID mVTdInfoGuid = { + 0x222f5e30, 0x5cd, 0x49c6, { 0x8a, 0xc, 0x36, 0xd6, 0x58, 0x41, 0xe0, 0x82 } +}; + +EFI_GUID mDmaBufferInfoGuid = { + 0x7b624ec7, 0xfb67, 0x4f9c, { 0xb6, 0xb0, 0x4d, 0xfa, 0x9c, 0x88, 0x20, 0x39 } +}; + +typedef struct { + UINTN DmaBufferBase; + UINTN DmaBufferSize; + UINTN DmaBufferCurrentTop; + UINTN DmaBufferCurrentBottom; +} DMA_BUFFER_INFO; #define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P') typedef struct { @@ -83,7 +91,6 @@ typedef struct { +------------------+ <=============== PLMR.Base (0) **/ - /** Set IOMMU attribute for a system memory. @@ -149,8 +156,13 @@ PeiIoMmuMap ( OUT VOID **Mapping ) { - MAP_INFO *MapInfo; - UINTN Length; + MAP_INFO *MapInfo; + UINTN Length; + VOID *Hob; + DMA_BUFFER_INFO *DmaBufferInfo; + + Hob = GetFirstGuidHob (&mDmaBufferInfoGuid); + DmaBufferInfo = GET_GUID_HOB_DATA(Hob); if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer || Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) { @@ -160,18 +172,18 @@ PeiIoMmuMap ( } DEBUG ((DEBUG_VERBOSE, "PeiIoMmuMap - HostAddress - 0x%x, NumberOfBytes - %x\n", HostAddress, *NumberOfBytes)); - DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop)); - DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom)); + DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop)); + DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom)); Length = *NumberOfBytes + sizeof(MAP_INFO); - if (Length > mDmaBufferCurrentTop - mDmaBufferCurrentBottom) { + if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) { DEBUG ((DEBUG_ERROR, "PeiIoMmuMap - OUT_OF_RESOURCE\n")); ASSERT (FALSE); return EFI_OUT_OF_RESOURCES; } - *DeviceAddress = mDmaBufferCurrentBottom; - mDmaBufferCurrentBottom += Length; + *DeviceAddress = DmaBufferInfo->DmaBufferCurrentBottom; + DmaBufferInfo->DmaBufferCurrentBottom += Length; MapInfo = (VOID *)(UINTN)(*DeviceAddress + *NumberOfBytes); MapInfo->Signature = MAP_INFO_SIGNATURE; @@ -216,16 +228,21 @@ PeiIoMmuUnmap ( IN VOID *Mapping ) { - MAP_INFO *MapInfo; - UINTN Length; + MAP_INFO *MapInfo; + UINTN Length; + VOID *Hob; + DMA_BUFFER_INFO *DmaBufferInfo; + + Hob = GetFirstGuidHob (&mDmaBufferInfoGuid); + DmaBufferInfo = GET_GUID_HOB_DATA(Hob); if (Mapping == NULL) { return EFI_SUCCESS; } DEBUG ((DEBUG_VERBOSE, "PeiIoMmuUnmap - Mapping - %x\n", Mapping)); - DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop)); - DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom)); + DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop)); + DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom)); MapInfo = Mapping; ASSERT (MapInfo->Signature == MAP_INFO_SIGNATURE); @@ -246,8 +263,8 @@ PeiIoMmuUnmap ( } Length = MapInfo->NumberOfBytes + sizeof(MAP_INFO); - if (mDmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) { - mDmaBufferCurrentBottom -= Length; + if (DmaBufferInfo->DmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) { + DmaBufferInfo->DmaBufferCurrentBottom -= Length; } return EFI_SUCCESS; @@ -282,20 +299,25 @@ PeiIoMmuAllocateBuffer ( IN UINT64 Attributes ) { - UINTN Length; + UINTN Length; + VOID *Hob; + DMA_BUFFER_INFO *DmaBufferInfo; + + Hob = GetFirstGuidHob (&mDmaBufferInfoGuid); + DmaBufferInfo = GET_GUID_HOB_DATA(Hob); DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - page - %x\n", Pages)); - DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop)); - DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom)); + DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop)); + DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom)); Length = EFI_PAGES_TO_SIZE(Pages); - if (Length > mDmaBufferCurrentTop - mDmaBufferCurrentBottom) { + if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) { DEBUG ((DEBUG_ERROR, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n")); ASSERT (FALSE); return EFI_OUT_OF_RESOURCES; } - *HostAddress = (VOID *)(UINTN)(mDmaBufferCurrentTop - Length); - mDmaBufferCurrentTop -= Length; + *HostAddress = (VOID *)(UINTN)(DmaBufferInfo->DmaBufferCurrentTop - Length); + DmaBufferInfo->DmaBufferCurrentTop -= Length; DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - allocate - %x\n", *HostAddress)); return EFI_SUCCESS; @@ -321,15 +343,20 @@ PeiIoMmuFreeBuffer ( IN VOID *HostAddress ) { - UINTN Length; + UINTN Length; + VOID *Hob; + DMA_BUFFER_INFO *DmaBufferInfo; + + Hob = GetFirstGuidHob (&mDmaBufferInfoGuid); + DmaBufferInfo = GET_GUID_HOB_DATA(Hob); DEBUG ((DEBUG_VERBOSE, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n", Pages, HostAddress)); - DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop)); - DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom)); + DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop)); + DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom)); Length = EFI_PAGES_TO_SIZE(Pages); - if ((UINTN)HostAddress == mDmaBufferCurrentTop) { - mDmaBufferCurrentTop += Length; + if ((UINTN)HostAddress == DmaBufferInfo->DmaBufferCurrentTop) { + DmaBufferInfo->DmaBufferCurrentTop += Length; } return EFI_SUCCESS; @@ -506,6 +533,7 @@ GetTopMemory ( /** Initialize DMA protection. + @param VTdInfo The VTd engine context information. @param DmaBufferSize the DMA buffer size @param DmaBufferBase the DMA buffer base @@ -514,8 +542,9 @@ GetTopMemory ( **/ EFI_STATUS InitDmaProtection ( - IN UINTN DmaBufferSize, - OUT UINTN *DmaBufferBase + IN VTD_INFO *VTdInfo, + IN UINTN DmaBufferSize, + OUT UINTN *DmaBufferBase ) { EFI_STATUS Status; @@ -537,8 +566,8 @@ InitDmaProtection ( ASSERT (PhitHob->EfiMemoryBottom < PhitHob->EfiMemoryTop); - LowMemoryAlignment = GetLowMemoryAlignment (mEngineMask); - HighMemoryAlignment = GetHighMemoryAlignment (mEngineMask); + LowMemoryAlignment = GetLowMemoryAlignment (VTdInfo, VTdInfo->EngineMask); + HighMemoryAlignment = GetHighMemoryAlignment (VTdInfo, VTdInfo->EngineMask); if (LowMemoryAlignment < HighMemoryAlignment) { MemoryAlignment = (UINTN)HighMemoryAlignment; } else { @@ -558,12 +587,13 @@ InitDmaProtection ( HighTop = GetTopMemory (); Status = SetDmaProtectedRange ( - mEngineMask, - (UINT32)LowBottom, - (UINT32)(LowTop - LowBottom), - HighBottom, - HighTop - HighBottom - ); + VTdInfo, + VTdInfo->EngineMask, + (UINT32)LowBottom, + (UINT32)(LowTop - LowBottom), + HighBottom, + HighTop - HighBottom + ); if (EFI_ERROR(Status)) { FreePages ((VOID *)*DmaBufferBase, EFI_SIZE_TO_PAGES(DmaBufferSize)); @@ -573,542 +603,191 @@ InitDmaProtection ( } /** - Dump DMAR DeviceScopeEntry. + Initializes the Intel VTd Info. + + @retval EFI_SUCCESS Usb bot driver is successfully initialized. + @retval EFI_OUT_OF_RESOURCES Can't initialize the driver. - @param[in] DmarDeviceScopeEntry DMAR DeviceScopeEntry **/ -VOID -DumpDmarDeviceScopeEntry ( - IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry +EFI_STATUS +InitVTdInfo ( + VOID ) { - 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; -} + EFI_STATUS Status; + EFI_ACPI_DMAR_HEADER *AcpiDmarTable; + VOID *Hob; -/** - Dump DMAR RMRR table. + Status = PeiServicesLocatePpi ( + &gEdkiiVTdInfoPpiGuid, + 0, + NULL, + (VOID **)&AcpiDmarTable + ); + ASSERT_EFI_ERROR(Status); - @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; + DumpAcpiDMAR (AcpiDmarTable); - if (Rmrr == NULL) { - return; + // + // Clear old VTdInfo Hob. + // + Hob = GetFirstGuidHob (&mVTdInfoGuid); + if (Hob != NULL) { + ZeroMem (&((EFI_HOB_GUID_TYPE *)Hob)->Name, sizeof(EFI_GUID)); } - 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); + // + // Get DMAR information to local VTdInfo + // + Status = ParseDmarAcpiTableDrhd (AcpiDmarTable); + if (EFI_ERROR(Status)) { + return Status; } - DEBUG ((DEBUG_INFO, - " ***************************************************************************\n\n" - )); + // + // NOTE: Do not parse RMRR here, because RMRR may cause PMR programming. + // - return; + return EFI_SUCCESS; } /** - Dump DMAR DRHD table. + Initializes the Intel VTd PMR for all memory. + + @retval EFI_SUCCESS Usb bot driver is successfully initialized. + @retval EFI_OUT_OF_RESOURCES Can't initialize the driver. - @param[in] Drhd DMAR DRHD table **/ -VOID -DumpDmarDrhd ( - IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd +EFI_STATUS +InitVTdPmrForAll ( + VOID ) { - EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry; - INTN DrhdLen; + EFI_STATUS Status; + VOID *Hob; + VTD_INFO *VTdInfo; + UINTN LowBottom; + UINTN LowTop; + UINTN HighBottom; + UINT64 HighTop; - if (Drhd == NULL) { - return; - } + Hob = GetFirstGuidHob (&mVTdInfoGuid); + VTdInfo = GET_GUID_HOB_DATA(Hob); - 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); - } + LowBottom = 0; + LowTop = 0; + HighBottom = 0; + HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth); - DEBUG ((DEBUG_INFO, - " ***************************************************************************\n\n" - )); + Status = SetDmaProtectedRange ( + VTdInfo, + VTdInfo->EngineMask, + (UINT32)LowBottom, + (UINT32)(LowTop - LowBottom), + HighBottom, + HighTop - HighBottom + ); - return; + return Status; } /** - Dump DMAR ACPI table. + Initializes the Intel VTd PMR for DMA buffer. + + @retval EFI_SUCCESS Usb bot driver is successfully initialized. + @retval EFI_OUT_OF_RESOURCES Can't initialize the driver. - @param[in] Dmar DMAR ACPI table **/ -VOID -DumpAcpiDMAR ( - IN EFI_ACPI_DMAR_HEADER *Dmar +EFI_STATUS +InitVTdPmrForDma ( + VOID ) { - EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; - INTN DmarLen; + EFI_STATUS Status; + VOID *Hob; + VTD_INFO *VTdInfo; + DMA_BUFFER_INFO *DmaBufferInfo; - if (Dmar == NULL) { - return; - } + Hob = GetFirstGuidHob (&mVTdInfoGuid); + VTdInfo = GET_GUID_HOB_DATA(Hob); // - // Dump Dmar table + // If there is RMRR memory, parse it here. // - 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; -} + ParseDmarAcpiTableRmrr (VTdInfo); -/** - Get VTd engine number. + Hob = GetFirstGuidHob (&mDmaBufferInfoGuid); + DmaBufferInfo = GET_GUID_HOB_DATA(Hob); - @return the VTd engine number. -**/ -UINTN -GetVtdEngineNumber ( - VOID - ) -{ - EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; - UINTN VtdIndex; - - VtdIndex = 0; - DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1)); - while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->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); + DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", DmaBufferInfo->DmaBufferSize)); + // + // Find a pre-memory in resource hob as DMA buffer + // Mark PEI memory to be DMA protected. + // + Status = InitDmaProtection (VTdInfo, DmaBufferInfo->DmaBufferSize, &DmaBufferInfo->DmaBufferBase); + if (EFI_ERROR(Status)) { + return Status; } - return VtdIndex ; -} - -/** - Process DMAR DHRD table. - - @param[in] VtdIndex The index of VTd engine. - @param[in] DmarDrhd The DRHD table. -**/ -VOID -ProcessDhrd ( - IN UINTN VtdIndex, - IN EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd - ) -{ - DEBUG ((DEBUG_INFO," VTD (%d) BaseAddress - 0x%016lx\n", VtdIndex, DmarDrhd->RegisterBaseAddress)); - mVTdInfo->VTdEngineAddress[VtdIndex] = DmarDrhd->RegisterBaseAddress; -} -/** - Parse DMAR DRHD table. - - @return EFI_SUCCESS The DMAR DRHD table is parsed. -**/ -EFI_STATUS -ParseDmarAcpiTableDrhd ( - VOID - ) -{ - EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; - UINTN VtdUnitNumber; - UINTN VtdIndex; + DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", DmaBufferInfo->DmaBufferBase)); - VtdUnitNumber = GetVtdEngineNumber (); - if (VtdUnitNumber == 0) { - return EFI_UNSUPPORTED; - } - - mVTdInfo = AllocateZeroPool (sizeof(VTD_INFO) + (VtdUnitNumber - 1) * sizeof(UINT64)); - if (mVTdInfo == NULL) { - return EFI_OUT_OF_RESOURCES; - } - mVTdInfo->HostAddressWidth = mAcpiDmarTable->HostAddressWidth; - mVTdInfo->VTdEngineCount = VtdUnitNumber; - - VtdIndex = 0; - DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1)); - while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) { - switch (DmarHeader->Type) { - case EFI_ACPI_DMAR_TYPE_DRHD: - ASSERT (VtdIndex < VtdUnitNumber); - ProcessDhrd (VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader); - VtdIndex++; - - break; - - default: - break; - } - DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length); - } - ASSERT (VtdIndex == VtdUnitNumber); + DmaBufferInfo->DmaBufferCurrentTop = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize; + DmaBufferInfo->DmaBufferCurrentBottom = DmaBufferInfo->DmaBufferBase; // - // Initialize the engine mask to all. + // Install PPI. // - mEngineMask = LShiftU64 (1, VtdUnitNumber) - 1; + Status = PeiServicesInstallPpi (&mIoMmuPpiList); + ASSERT_EFI_ERROR(Status); - return EFI_SUCCESS; + return Status; } /** - Return the VTd engine index according to the Segment and DevScopeEntry. + This function handles S3 resume task at the end of PEI - @param Segment The segment of the VTd engine - @param DevScopeEntry The DevScopeEntry of the VTd engine + @param[in] PeiServices Pointer to PEI Services Table. + @param[in] NotifyDesc Pointer to the descriptor for the Notification event that + caused this function to execute. + @param[in] Ppi Pointer to the PPI data associated with this function. - @return The VTd engine index according to the Segment and DevScopeEntry. - @retval -1 The VTd engine is not found. + @retval EFI_STATUS Always return EFI_SUCCESS **/ -UINTN -GetVTdEngineFromDevScopeEntry ( - IN UINT16 Segment, - IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DevScopeEntry +EFI_STATUS +EFIAPI +S3EndOfPeiNotify( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, + IN VOID *Ppi ) { - 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)(mAcpiDmarTable + 1)); - while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->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. + VOID *Hob; + VTD_INFO *VTdInfo; + UINT64 EngineMask; - @param[in] DmarRmrr The RMRR table. -**/ -VOID -ProcessRmrr ( - 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; - - DEBUG ((DEBUG_INFO," RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress)); - - if ((DmarRmrr->ReservedMemoryRegionBaseAddress == 0) || - (DmarRmrr->ReservedMemoryRegionLimitAddress == 0)) { - return ; - } + DEBUG((DEBUG_INFO, "VTdPmr S3EndOfPeiNotify\n")); - 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 (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 ( - 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. - // - mEngineMask = mEngineMask & (~RmrrMask); + if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) { + Hob = GetFirstGuidHob (&mVTdInfoGuid); + if (Hob == NULL) { + return EFI_SUCCESS; } + VTdInfo = GET_GUID_HOB_DATA(Hob); - DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length); + EngineMask = LShiftU64 (1, VTdInfo->VTdEngineCount) - 1; + DisableDmaProtection (VTdInfo, EngineMask); } + return EFI_SUCCESS; } -/** - Parse DMAR DRHD table. -**/ -VOID -ParseDmarAcpiTableRmrr ( - VOID - ) -{ - EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; - - DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1)); - while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) { - switch (DmarHeader->Type) { - case EFI_ACPI_DMAR_TYPE_RMRR: - ProcessRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader); - break; - default: - break; - } - DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length); - } -} +EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc = { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiEndOfPeiSignalPpiGuid, + S3EndOfPeiNotify +}; /** - This function handles S3 resume task at the end of PEI + This function handles VTd engine setup @param[in] PeiServices Pointer to PEI Services Table. @param[in] NotifyDesc Pointer to the descriptor for the Notification event that @@ -1119,27 +798,80 @@ ParseDmarAcpiTableRmrr ( **/ EFI_STATUS EFIAPI -S3EndOfPeiNotify( +VTdInfoNotify ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, IN VOID *Ppi ) { - UINT64 EngineMask; + EFI_STATUS Status; + VOID *MemoryDiscovered; + UINT64 EnabledEngineMask; + VOID *Hob; + VTD_INFO *VTdInfo; + BOOLEAN MemoryInitialized; - DEBUG((DEBUG_INFO, "VTdPmr S3EndOfPeiNotify\n")); + DEBUG ((DEBUG_INFO, "VTdInfoNotify\n")); + + // + // Check if memory is initialized. + // + MemoryInitialized = FALSE; + Status = PeiServicesLocatePpi ( + &gEfiPeiMemoryDiscoveredPpiGuid, + 0, + NULL, + &MemoryDiscovered + ); + if (!EFI_ERROR(Status)) { + MemoryInitialized = TRUE; + } + + DEBUG ((DEBUG_INFO, "MemoryInitialized - %x\n", MemoryInitialized)); + + if (!MemoryInitialized) { + // + // If the memory is not initialized, + // Protect all system memory + // + InitVTdInfo (); + InitVTdPmrForAll (); + } else { + // + // If the memory is initialized, + // Allocate DMA buffer and protect rest system memory + // + + // + // NOTE: We need reinit VTdInfo because previous information might be overriden. + // + InitVTdInfo (); + + Hob = GetFirstGuidHob (&mVTdInfoGuid); + VTdInfo = GET_GUID_HOB_DATA(Hob); + + // + // NOTE: We need check if PMR is enabled or not. + // + EnabledEngineMask = GetDmaProtectionEnabledEngineMask (VTdInfo, VTdInfo->EngineMask); + if (EnabledEngineMask != 0) { + EnableVTdTranslationProtection (VTdInfo, EnabledEngineMask); + DisableDmaProtection (VTdInfo, EnabledEngineMask); + } + InitVTdPmrForDma (); + if (EnabledEngineMask != 0) { + DisableVTdTranslationProtection (VTdInfo, EnabledEngineMask); + } - if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) { - EngineMask = LShiftU64 (1, mVTdInfo->VTdEngineCount) - 1; - DisableDmaProtection (EngineMask); } + return EFI_SUCCESS; } -EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc = { +EFI_PEI_NOTIFY_DESCRIPTOR mVTdInfoNotifyDesc = { (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), - &gEfiEndOfPeiSignalPpiGuid, - S3EndOfPeiNotify + &gEdkiiVTdInfoPpiGuid, + VTdInfoNotify }; /** @@ -1161,71 +893,40 @@ IntelVTdPmrInitialize ( { EFI_STATUS Status; EFI_BOOT_MODE BootMode; + DMA_BUFFER_INFO *DmaBufferInfo; + + DEBUG ((DEBUG_INFO, "IntelVTdPmrInitialize\n")); if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) == 0) { return EFI_UNSUPPORTED; } - PeiServicesGetBootMode (&BootMode); - - Status = PeiServicesLocatePpi ( - &gEdkiiVTdInfoPpiGuid, - 0, - NULL, - (VOID **)&mAcpiDmarTable - ); - ASSERT_EFI_ERROR(Status); - - DumpAcpiDMAR (mAcpiDmarTable); - - // - // Get DMAR information to local VTdInfo - // - Status = ParseDmarAcpiTableDrhd (); - if (EFI_ERROR(Status)) { - return Status; + DmaBufferInfo = BuildGuidHob (&mDmaBufferInfoGuid, sizeof(DMA_BUFFER_INFO)); + ASSERT(DmaBufferInfo != NULL); + if (DmaBufferInfo == NULL) { + return EFI_OUT_OF_RESOURCES; } + ZeroMem (DmaBufferInfo, sizeof(DMA_BUFFER_INFO)); - // - // If there is RMRR memory, parse it here. - // - ParseDmarAcpiTableRmrr (); + PeiServicesGetBootMode (&BootMode); if (BootMode == BOOT_ON_S3_RESUME) { - mDmaBufferSize = TOTAL_DMA_BUFFER_SIZE_S3; + DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE_S3; } else { - mDmaBufferSize = TOTAL_DMA_BUFFER_SIZE; - } - DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", mDmaBufferSize)); - - // - // Find a pre-memory in resource hob as DMA buffer - // Mark PEI memory to be DMA protected. - // - Status = InitDmaProtection (mDmaBufferSize, &mDmaBufferBase); - if (EFI_ERROR(Status)) { - return Status; + DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE; } - DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", mDmaBufferBase)); - - mDmaBufferCurrentTop = mDmaBufferBase + mDmaBufferSize; - mDmaBufferCurrentBottom = mDmaBufferBase; - - // - // Install PPI. - // - Status = PeiServicesInstallPpi (&mIoMmuPpiList); - ASSERT_EFI_ERROR(Status); + Status = PeiServicesNotifyPpi (&mVTdInfoNotifyDesc); + ASSERT_EFI_ERROR (Status); // - // Register EndOfPei Notify for S3 to run FSP NotifyPhase + // Register EndOfPei Notify for S3 // if (BootMode == BOOT_ON_S3_RESUME) { Status = PeiServicesNotifyPpi (&mS3EndOfPeiNotifyDesc); ASSERT_EFI_ERROR (Status); } - return Status; + return EFI_SUCCESS; } diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h index 720f5d42c3..499119d3ff 100644 --- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h @@ -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 diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf index 4d0e187dc3..e6d0323acc 100644 --- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf @@ -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 diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/VtdReg.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/VtdReg.c new file mode 100644 index 0000000000..888905d40d --- /dev/null +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/VtdReg.c @@ -0,0 +1,293 @@ +/** @file + + Copyright (c) 2017, Intel Corporation. All rights reserved.
+ + 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 ; +}