mirror of https://github.com/acidanthera/audk.git
294 lines
7.7 KiB
C
294 lines
7.7 KiB
C
|
/** @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 ;
|
||
|
}
|