From nobody Thu Dec 26 13:56:19 2024 Delivered-To: importer@patchew.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Authentication-Results: mx.zohomail.com; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1504883067266451.3017544202967; Fri, 8 Sep 2017 08:04:27 -0700 (PDT) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 66EBE21D492ED; Fri, 8 Sep 2017 08:01:17 -0700 (PDT) Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id E8B5B21D492E9 for ; Fri, 8 Sep 2017 08:01:15 -0700 (PDT) Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 08 Sep 2017 08:04:08 -0700 Received: from jyao1-mobl.ccr.corp.intel.com ([10.254.209.82]) by fmsmga004.fm.intel.com with ESMTP; 08 Sep 2017 08:04:07 -0700 X-Original-To: edk2-devel@lists.01.org X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.42,361,1500966000"; d="scan'208";a="309511665" From: Jiewen Yao To: edk2-devel@lists.01.org Date: Fri, 8 Sep 2017 23:03:50 +0800 Message-Id: <1504883034-22060-8-git-send-email-jiewen.yao@intel.com> X-Mailer: git-send-email 2.7.4.windows.1 In-Reply-To: <1504883034-22060-1-git-send-email-jiewen.yao@intel.com> References: <1504883034-22060-1-git-send-email-jiewen.yao@intel.com> Subject: [edk2] [PATCH 07/11] IntelSiliconPkg: Add IntelVTdPmrPei. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Star Zeng MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" This PEIM is to produce IOMMU_PPI, so that PEI device driver can have better DAM management. This PEIM will setup VTD PMR register to protect most DRAM. It allocates a big chunk DMA buffer in the entrypoint, and only use this buffer for DMA. Any other region is DMA protected. Cc: Star Zeng Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Jiewen Yao --- IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmr.c | 314 ++++++++++ IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmrPei.c | 615 +++++++++++++= +++++++ IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmrPei.h | 68 +++ IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmrPei.inf | 59 ++ IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmrPei.uni | 20 + IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmrPeiExtra.uni | 20 + 6 files changed, 1096 insertions(+) diff --git a/IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmr.c b/IntelSiliconPkg= /IntelVTdPmrPei/IntelVTdPmr.c new file mode 100644 index 0000000..ef08e29 --- /dev/null +++ b/IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmr.c @@ -0,0 +1,314 @@ +/** @file + + Copyright (c) 2017, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials are licensed and made availa= ble under + the terms and conditions of the BSD License which accompanies this distr= ibution. + 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 IMP= LIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include + +#include "IntelVTdPmrPei.h" + +extern EDKII_VTD_INFO_PPI *mVTdInfoPpi; + +/** + Get protected low memory alignment. + + @param VtdUnitBaseAddress The base address of the VTd engine. + + @return protected low memory alignment. +**/ +UINT32 +GetPlmrAlignment ( + IN UINTN VtdUnitBaseAddress + ) +{ + UINT32 Data32; + + MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG, 0xFFFFFFFF); + Data32 =3D MmioRead32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG); + Data32 =3D ~Data32 + 1; + + return Data32; +} + +/** + Get protected high memory alignment. + + @param VtdUnitBaseAddress The base address of the VTd engine. + + @return protected high memory alignment. +**/ +UINT64 +GetPhmrAlignment ( + IN UINTN VtdUnitBaseAddress + ) +{ + UINT64 Data64; + UINT8 HostAddressWidth; + + HostAddressWidth =3D mVTdInfoPpi->HostAddressWidth; + + MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, 0xFFFFFFFFFFFFFF= FF); + Data64 =3D MmioRead64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG); + Data64 =3D ~Data64 + 1; + Data64 =3D Data64 & (LShiftU64 (1, HostAddressWidth) - 1); + + return Data64; +} + +/** + Get protected low memory alignment. + + @return protected low memory alignment. +**/ +UINT32 +GetLowMemoryAlignment ( + VOID + ) +{ + UINTN Index; + UINT32 Alignment; + UINT32 FinalAlignment; + + FinalAlignment =3D 0; + for (Index =3D 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) { + Alignment =3D GetPlmrAlignment ((UINTN)mVTdInfoPpi->VTdEngineAddress[I= ndex]); + if (FinalAlignment < Alignment) { + FinalAlignment =3D Alignment; + } + } + return FinalAlignment; +} + +/** + Get protected high memory alignment. + + @return protected high memory alignment. +**/ +UINT64 +GetHighMemoryAlignment ( + VOID + ) +{ + UINTN Index; + UINT64 Alignment; + UINT64 FinalAlignment; + + FinalAlignment =3D 0; + for (Index =3D 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) { + Alignment =3D GetPhmrAlignment ((UINTN)mVTdInfoPpi->VTdEngineAddress[I= ndex]); + if (FinalAlignment < Alignment) { + FinalAlignment =3D Alignment; + } + } + return FinalAlignment; +} + +/** + Enable PMR in the VTd engine. + + @param VtdUnitBaseAddress The base address of the VTd engine. + + @retval EFI_SUCCESS The PMR is enabled. + @retval EFI_UNSUPPORTED The PMR is not supported. +**/ +EFI_STATUS +EnablePmr ( + IN UINTN VtdUnitBaseAddress + ) +{ + UINT32 Reg32; + VTD_CAP_REG CapReg; + + CapReg.Uint64 =3D MmioRead64 (VtdUnitBaseAddress + R_CAP_REG); + if (CapReg.Bits.PLMR =3D=3D 0 || CapReg.Bits.PHMR =3D=3D 0) { + return EFI_UNSUPPORTED; + } + + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG); + if ((Reg32 & BIT0) =3D=3D 0) { + MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, BIT31); + do { + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG); + } while((Reg32 & BIT0) =3D=3D 0); + } + + return EFI_SUCCESS; +} + +/** + Disable PMR in the VTd engine. + + @param VtdUnitBaseAddress The base address of the VTd engine. + + @retval EFI_SUCCESS The PMR is disabled. + @retval EFI_UNSUPPORTED The PMR is not supported. +**/ +EFI_STATUS +DisablePmr ( + IN UINTN VtdUnitBaseAddress + ) +{ + UINT32 Reg32; + VTD_CAP_REG CapReg; + + CapReg.Uint64 =3D MmioRead64 (VtdUnitBaseAddress + R_CAP_REG); + if (CapReg.Bits.PLMR =3D=3D 0 || CapReg.Bits.PHMR =3D=3D 0) { + return EFI_UNSUPPORTED; + } + + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG); + if ((Reg32 & BIT0) !=3D 0) { + MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, 0x0); + do { + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG); + } while((Reg32 & BIT0) !=3D 0); + } + + return EFI_SUCCESS; +} + +/** + Set PMR region in the VTd engine. + + @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. + @param HighMemoryBase The protected high memory region base. + @param HighMemoryLength The protected high memory region length. + + @retval EFI_SUCCESS The PMR is set to protected region. + @retval EFI_UNSUPPORTED The PMR is not supported. +**/ +EFI_STATUS +SetPmrRegion ( + IN UINTN VtdUnitBaseAddress, + IN UINT32 LowMemoryBase, + IN UINT32 LowMemoryLength, + IN UINT64 HighMemoryBase, + IN UINT64 HighMemoryLength + ) +{ + VTD_CAP_REG CapReg; + UINT32 PlmrAlignment; + UINT64 PhmrAlignment; + + DEBUG ((DEBUG_INFO, "VtdUnitBaseAddress - 0x%x\n", VtdUnitBaseAddress)); + + CapReg.Uint64 =3D MmioRead64 (VtdUnitBaseAddress + R_CAP_REG); + if (CapReg.Bits.PLMR =3D=3D 0 || CapReg.Bits.PHMR =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "PLMR/PHMR unsupported\n")); + return EFI_UNSUPPORTED; + } + + PlmrAlignment =3D GetPlmrAlignment (VtdUnitBaseAddress); + DEBUG ((DEBUG_INFO, "PlmrAlignment - 0x%x\n", PlmrAlignment)); + PhmrAlignment =3D GetPhmrAlignment (VtdUnitBaseAddress); + DEBUG ((DEBUG_INFO, "PhmrAlignment - 0x%lx\n", PhmrAlignment)); + + if ((LowMemoryBase !=3D ALIGN_VALUE(LowMemoryBase, PlmrAlignment)) || + (LowMemoryLength !=3D ALIGN_VALUE(LowMemoryLength, PlmrAlignment)) = || + (HighMemoryBase !=3D ALIGN_VALUE(HighMemoryBase, PhmrAlignment)) || + (HighMemoryLength !=3D ALIGN_VALUE(HighMemoryLength, PhmrAlignment))= ) { + DEBUG ((DEBUG_ERROR, "PLMR/PHMR alignment issue\n")); + return EFI_UNSUPPORTED; + } + + if (LowMemoryBase =3D=3D 0 && LowMemoryLength =3D=3D 0) { + LowMemoryBase =3D 0xFFFFFFFF; + } + if (HighMemoryBase =3D=3D 0 && HighMemoryLength =3D=3D 0) { + HighMemoryBase =3D 0xFFFFFFFFFFFFFFFF; + } + + MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG, LowMemoryBase); + MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_LIMITE_REG, LowMemoryBase = + LowMemoryLength - 1); + MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, HighMemoryBase= ); + MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_LIMITE_REG, HighMemoryBase= + HighMemoryLength - 1); + + return EFI_SUCCESS; +} + +/** + Set DMA protected region. + + @param LowMemoryBase The protected low memory region base. + @param LowMemoryLength The protected low memory region length. + @param HighMemoryBase The protected high memory region base. + @param HighMemoryLength The protected high memory region length. + + @retval EFI_SUCCESS The DMA protection is set. + @retval EFI_UNSUPPORTED The DMA protection is not set. +**/ +EFI_STATUS +SetDmaProtectedRange ( + IN UINT32 LowMemoryBase, + IN UINT32 LowMemoryLength, + IN UINT64 HighMemoryBase, + IN UINT64 HighMemoryLength + ) +{ + UINTN Index; + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO, "SetDmaProtectedRange - [0x%x, 0x%x] [0x%lx, 0x%lx]\= n", LowMemoryBase, LowMemoryLength, HighMemoryBase, HighMemoryLength)); + + for (Index =3D 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) { + DisablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); + Status =3D SetPmrRegion ( + (UINTN)mVTdInfoPpi->VTdEngineAddress[Index], + LowMemoryBase, + LowMemoryLength, + HighMemoryBase, + HighMemoryLength + ); + if (EFI_ERROR(Status)) { + return Status; + } + Status =3D EnablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); + if (EFI_ERROR(Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} + +/** + Diable DMA protection. + + @retval DMA protection is disabled. +**/ +EFI_STATUS +DisableDmaProtection ( + VOID + ) +{ + UINTN Index; + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO, "DisableDmaProtection\n")); + + for (Index =3D 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) { + Status =3D DisablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); + if (EFI_ERROR(Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} diff --git a/IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmrPei.c b/IntelSilicon= Pkg/IntelVTdPmrPei/IntelVTdPmrPei.c new file mode 100644 index 0000000..d118b7e --- /dev/null +++ b/IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmrPei.c @@ -0,0 +1,615 @@ +/** @file + + Copyright (c) 2017, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials are licensed and made availa= ble under + the terms and conditions of the BSD License which accompanies this distr= ibution. + 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 IMP= LIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "IntelVTdPmrPei.h" + +#define TOTAL_DMA_BUFFER_SIZE SIZE_4MB + +EDKII_VTD_INFO_PPI *mVTdInfoPpi; +UINTN mDmaBufferBase; +UINTN mDmaBufferSize =3D TOTAL_DMA_BUFFER_SIZE; +UINTN mDmaBufferCurrentTop; +UINTN mDmaBufferCurrentBottom; + +#define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P') +typedef struct { + UINT32 Signature; + EDKII_IOMMU_OPERATION Operation; + UINTN NumberOfBytes; + EFI_PHYSICAL_ADDRESS HostAddress; + EFI_PHYSICAL_ADDRESS DeviceAddress; +} MAP_INFO; + +/** + + PEI Memory Layout: + + +------------------+ <------- EfiMemoryTop + | PEI allocated | + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D+ + ^ | Commom Buf | + | | -------------- | + DMA Buffer | * DMA FREE * | + | | -------------- | + V | Read/Write Buf | + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D+ + | PEI allocated | + | -------------- | <------- EfiFreeMemoryTop + | * PEI FREE * | + | -------------- | <------- EfiFreeMemoryBottom + | hob | + | -------------- | + | Stack | + +------------------+ <------- EfiMemoryBottom / Stack Bottom + + +------------------+ + | Mem Alloc Hob | + +------------------+ + +**/ + + +/** + Set IOMMU attribute for a system memory. + + If the IOMMU PPI exists, the system memory cannot be used + for DMA by default. + + When a device requests a DMA access for a system memory, + the device driver need use SetAttribute() to update the IOMMU + attribute to request DMA access (read and/or write). + + @param[in] This The PPI instance pointer. + @param[in] Mapping The mapping value returned from Map(). + @param[in] IoMmuAccess The IOMMU access. + + @retval EFI_SUCCESS The IoMmuAccess is set for the memory ran= ge specified by DeviceAddress and Length. + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned = by Map(). + @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combinat= ion of access. + @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not suppor= ted by the IOMMU. + @retval EFI_UNSUPPORTED The IOMMU does not support the memory ran= ge specified by Mapping. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available = to modify the IOMMU access. + @retval EFI_DEVICE_ERROR The IOMMU device reported an error while = attempting the operation. + +**/ +EFI_STATUS +EFIAPI +PeiIoMmuSetAttribute ( + IN EDKII_IOMMU_PPI *This, + IN VOID *Mapping, + IN UINT64 IoMmuAccess + ) +{ + return EFI_SUCCESS; +} + +/** + Provides the controller-specific addresses required to access system mem= ory from a + DMA bus master. + + @param This The PPI instance pointer. + @param Operation Indicates if the bus master is going to re= ad or write to system memory. + @param HostAddress The system memory address to map to the PC= I controller. + @param NumberOfBytes On input the number of bytes to map. On ou= tput the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus mast= er PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned Numb= erOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a comm= on buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to = a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requ= ested address. + +**/ +EFI_STATUS +EFIAPI +PeiIoMmuMap ( + IN EDKII_IOMMU_PPI *This, + IN EDKII_IOMMU_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + MAP_INFO *MapInfo; + UINTN Length; + + if (Operation =3D=3D EdkiiIoMmuOperationBusMasterCommonBuffer || + Operation =3D=3D EdkiiIoMmuOperationBusMasterCommonBuffer64) { + *DeviceAddress =3D (UINTN)HostAddress; + *Mapping =3D 0; + return EFI_SUCCESS; + } + + DEBUG ((DEBUG_VERBOSE, "PeiIoMmuMap - HostAddress - 0x%x, NumberOfBytes = - %x\n", HostAddress, *NumberOfBytes)); + DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurren= tTop)); + DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCur= rentBottom)); + + Length =3D *NumberOfBytes + sizeof(MAP_INFO); + if (Length > mDmaBufferCurrentTop - mDmaBufferCurrentBottom) { + DEBUG ((DEBUG_ERROR, "PeiIoMmuMap - OUT_OF_RESOURCE\n")); + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + + *DeviceAddress =3D mDmaBufferCurrentBottom; + mDmaBufferCurrentBottom +=3D Length; + + MapInfo =3D (VOID *)(UINTN)(*DeviceAddress + *NumberOfBytes); + MapInfo->Signature =3D MAP_INFO_SIGNATURE; + MapInfo->Operation =3D Operation; + MapInfo->NumberOfBytes =3D *NumberOfBytes; + MapInfo->HostAddress =3D (UINTN)HostAddress; + MapInfo->DeviceAddress =3D *DeviceAddress; + *Mapping =3D MapInfo; + DEBUG ((DEBUG_VERBOSE, " Op(%x):DeviceAddress - %x, Mapping - %x\n", Op= eration, (UINTN)*DeviceAddress, MapInfo)); + + // + // If this is a read operation from the Bus Master's point of view, + // then copy the contents of the real buffer into the mapped buffer + // so the Bus Master can read the contents of the real buffer. + // + if (Operation =3D=3D EdkiiIoMmuOperationBusMasterRead || + Operation =3D=3D EdkiiIoMmuOperationBusMasterRead64) { + CopyMem ( + (VOID *) (UINTN) MapInfo->DeviceAddress, + (VOID *) (UINTN) MapInfo->HostAddress, + MapInfo->NumberOfBytes + ); + } + + return EFI_SUCCESS; +} + +/** + Completes the Map() operation and releases any corresponding resources. + + @param This The PPI instance pointer. + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned b= y Map(). + @retval EFI_DEVICE_ERROR The data was not committed to the target s= ystem memory. +**/ +EFI_STATUS +EFIAPI +PeiIoMmuUnmap ( + IN EDKII_IOMMU_PPI *This, + IN VOID *Mapping + ) +{ + MAP_INFO *MapInfo; + UINTN Length; + + if (Mapping =3D=3D NULL) { + return EFI_SUCCESS; + } + + DEBUG ((DEBUG_VERBOSE, "PeiIoMmuUnmap - Mapping - %x\n", Mapping)); + DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurren= tTop)); + DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCur= rentBottom)); + + MapInfo =3D Mapping; + ASSERT (MapInfo->Signature =3D=3D MAP_INFO_SIGNATURE); + DEBUG ((DEBUG_VERBOSE, " Op(%x):DeviceAddress - %x, NumberOfBytes - %x\= n", MapInfo->Operation, (UINTN)MapInfo->DeviceAddress, MapInfo->NumberOfByt= es)); + + // + // If this is a write operation from the Bus Master's point of view, + // then copy the contents of the mapped buffer into the real buffer + // so the processor can read the contents of the real buffer. + // + if (MapInfo->Operation =3D=3D EdkiiIoMmuOperationBusMasterWrite || + MapInfo->Operation =3D=3D EdkiiIoMmuOperationBusMasterWrite64) { + CopyMem ( + (VOID *) (UINTN) MapInfo->HostAddress, + (VOID *) (UINTN) MapInfo->DeviceAddress, + MapInfo->NumberOfBytes + ); + } + + Length =3D MapInfo->NumberOfBytes + sizeof(MAP_INFO); + if (mDmaBufferCurrentBottom =3D=3D MapInfo->DeviceAddress + Length) { + mDmaBufferCurrentBottom -=3D Length; + } + + return EFI_SUCCESS; +} + +/** + Allocates pages that are suitable for an OperationBusMasterCommonBuffer = or + OperationBusMasterCommonBuffer64 mapping. + + @param This The PPI instance pointer. + @param MemoryType The type of memory to allocate, EfiBootSer= vicesData or + EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory = address of the + allocated range. + @param Attributes The requested bit mask of attributes for t= he allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal = attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +EFIAPI +PeiIoMmuAllocateBuffer ( + IN EDKII_IOMMU_PPI *This, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN OUT VOID **HostAddress, + IN UINT64 Attributes + ) +{ + UINTN Length; + + DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - page - %x\n", Pages)); + DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurren= tTop)); + DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCur= rentBottom)); + + Length =3D EFI_PAGES_TO_SIZE(Pages); + if (Length > mDmaBufferCurrentTop - mDmaBufferCurrentBottom) { + DEBUG ((DEBUG_ERROR, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n")); + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + *HostAddress =3D (VOID *)(UINTN)(mDmaBufferCurrentTop - Length); + mDmaBufferCurrentTop -=3D Length; + + DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - allocate - %x\n", *Host= Address)); + return EFI_SUCCESS; +} + +/** + Frees memory that was allocated with AllocateBuffer(). + + @param This The PPI instance pointer. + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allo= cated range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress = and Pages + was not allocated with AllocateBuffer(). + +**/ +EFI_STATUS +EFIAPI +PeiIoMmuFreeBuffer ( + IN EDKII_IOMMU_PPI *This, + IN UINTN Pages, + IN VOID *HostAddress + ) +{ + UINTN Length; + + DEBUG ((DEBUG_VERBOSE, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n"= , Pages, HostAddress)); + DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurren= tTop)); + DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCur= rentBottom)); + + Length =3D EFI_PAGES_TO_SIZE(Pages); + if ((UINTN)HostAddress =3D=3D mDmaBufferCurrentTop) { + mDmaBufferCurrentTop +=3D Length; + } + + return EFI_SUCCESS; +} + +EDKII_IOMMU_PPI mIoMmuPpi =3D { + EDKII_IOMMU_PPI_REVISION, + PeiIoMmuSetAttribute, + PeiIoMmuMap, + PeiIoMmuUnmap, + PeiIoMmuAllocateBuffer, + PeiIoMmuFreeBuffer, +}; + +CONST EFI_PEI_PPI_DESCRIPTOR mIoMmuPpiList =3D { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gEdkiiIoMmuPpiGuid, + (VOID *) &mIoMmuPpi +}; + +#define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \ + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \ + EFI_RESOURCE_ATTRIBUTE_TESTED | \ + EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \ + EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \ + EFI_RESOURCE_ATTRIBUTE_64_BIT_IO \ + ) + +#define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | EF= I_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED) + +#define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | EF= I_RESOURCE_ATTRIBUTE_INITIALIZED) + +#define PRESENT_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT) + +GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mResourceTypeShortName[] =3D { + "Mem", + "MMIO", + "I/O", + "FD", + "MM Port I/O", + "Reserved Mem", + "Reserved I/O", +}; + +/** + Return the short name of resource type. + + @param Type resource type. + + @return the short name of resource type. +**/ +CHAR8 * +ShortNameOfResourceType ( + IN UINT32 Type + ) +{ + if (Type < sizeof(mResourceTypeShortName) / sizeof(mResourceTypeShortNam= e[0])) { + return mResourceTypeShortName[Type]; + } else { + return "Unknown"; + } +} + +/** + Dump resource hob. + + @param HobList the HOB list. +**/ +VOID +DumpResourceHob ( + IN VOID *HobList + ) +{ + EFI_PEI_HOB_POINTERS Hob; + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; + + DEBUG ((DEBUG_VERBOSE, "Resource Descriptor HOBs\n")); + for (Hob.Raw =3D HobList; !END_OF_HOB_LIST (Hob); Hob.Raw =3D GET_NEXT_H= OB (Hob)) { + if (GET_HOB_TYPE (Hob) =3D=3D EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + ResourceHob =3D Hob.ResourceDescriptor; + DEBUG ((DEBUG_VERBOSE, + " BA=3D%016lx L=3D%016lx Attr=3D%08x ", + ResourceHob->PhysicalStart, + ResourceHob->ResourceLength, + ResourceHob->ResourceAttribute + )); + DEBUG ((DEBUG_VERBOSE, ShortNameOfResourceType(ResourceHob->Resource= Type))); + switch (ResourceHob->ResourceType) { + case EFI_RESOURCE_SYSTEM_MEMORY: + if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_PERSI= STENT) !=3D 0) { + DEBUG ((DEBUG_VERBOSE, " (Persistent)")); + } else if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUT= E_MORE_RELIABLE) !=3D 0) { + DEBUG ((DEBUG_VERBOSE, " (MoreReliable)")); + } else if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK= ) =3D=3D TESTED_MEMORY_ATTRIBUTES) { + DEBUG ((DEBUG_VERBOSE, " (Tested)")); + } else if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK= ) =3D=3D INITIALIZED_MEMORY_ATTRIBUTES) { + DEBUG ((DEBUG_VERBOSE, " (Init)")); + } else if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK= ) =3D=3D PRESENT_MEMORY_ATTRIBUTES) { + DEBUG ((DEBUG_VERBOSE, " (Present)")); + } else { + DEBUG ((DEBUG_VERBOSE, " (Unknown)")); + } + break; + default: + break; + } + DEBUG ((DEBUG_VERBOSE, "\n")); + } + } +} + +/** + Dump PHIT hob. + + @param HobList the HOB list. +**/ +VOID +DumpPhitHob ( + IN VOID *HobList + ) +{ + EFI_HOB_HANDOFF_INFO_TABLE *PhitHob; + + PhitHob =3D HobList; + ASSERT(GET_HOB_TYPE(HobList) =3D=3D EFI_HOB_TYPE_HANDOFF); + DEBUG ((DEBUG_VERBOSE, "PHIT HOB\n")); + DEBUG ((DEBUG_VERBOSE, " PhitHob - 0x%x\n", PhitHob)); + DEBUG ((DEBUG_VERBOSE, " BootMode - 0x%x\n", PhitHob->BootMo= de)); + DEBUG ((DEBUG_VERBOSE, " EfiMemoryTop - 0x%016lx\n", PhitHob->Ef= iMemoryTop)); + DEBUG ((DEBUG_VERBOSE, " EfiMemoryBottom - 0x%016lx\n", PhitHob->Ef= iMemoryBottom)); + DEBUG ((DEBUG_VERBOSE, " EfiFreeMemoryTop - 0x%016lx\n", PhitHob->Ef= iFreeMemoryTop)); + DEBUG ((DEBUG_VERBOSE, " EfiFreeMemoryBottom - 0x%016lx\n", PhitHob->Ef= iFreeMemoryBottom)); + DEBUG ((DEBUG_VERBOSE, " EfiEndOfHobList - 0x%lx\n", PhitHob->EfiEn= dOfHobList)); +} + +/** + Get the highest memory. + + @param HobList the HOB list. + + @return the highest memory. +**/ +UINT64 +GetTopMemory ( + IN VOID *HobList + ) +{ + EFI_PEI_HOB_POINTERS Hob; + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; + UINT64 TopMemory; + UINT64 ResourceTop; + + TopMemory =3D 0; + for (Hob.Raw =3D HobList; !END_OF_HOB_LIST (Hob); Hob.Raw =3D GET_NEXT_H= OB (Hob)) { + if (GET_HOB_TYPE (Hob) =3D=3D EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + ResourceHob =3D Hob.ResourceDescriptor; + switch (ResourceHob->ResourceType) { + case EFI_RESOURCE_SYSTEM_MEMORY: + ResourceTop =3D ResourceHob->PhysicalStart + ResourceHob->Resource= Length; + if (TopMemory < ResourceTop) { + TopMemory =3D ResourceTop; + } + break; + default: + break; + } + DEBUG ((DEBUG_VERBOSE, "\n")); + } + } + return TopMemory; +} + +/** + Initialize DMA protection. + + @param DmaBufferSize the DMA buffer size + @param DmaBufferBase the DMA buffer base + + @retval EFI_SUCCESS the DMA protection is initialized. + @retval EFI_OUT_OF_RESOURCES no enough resource to initialize DMA prote= ction. +**/ +EFI_STATUS +InitDmaProtection ( + IN UINTN DmaBufferSize, + OUT UINTN *DmaBufferBase + ) +{ + EFI_STATUS Status; + VOID *HobList; + EFI_HOB_HANDOFF_INFO_TABLE *PhitHob; + UINT32 LowMemoryAlignment; + UINT64 HighMemoryAlignment; + UINTN MemoryAlignment; + UINTN LowBottom; + UINTN LowTop; + UINTN HighBottom; + UINT64 HighTop; + + HobList =3D GetHobList (); + DumpPhitHob (HobList); + DumpResourceHob (HobList); + + PhitHob =3D HobList; + + ASSERT (PhitHob->EfiMemoryBottom < PhitHob->EfiMemoryTop); + + LowMemoryAlignment =3D GetLowMemoryAlignment (); + HighMemoryAlignment =3D GetHighMemoryAlignment (); + if (LowMemoryAlignment < HighMemoryAlignment) { + MemoryAlignment =3D (UINTN)HighMemoryAlignment; + } else { + MemoryAlignment =3D LowMemoryAlignment; + } + ASSERT (DmaBufferSize =3D=3D ALIGN_VALUE(DmaBufferSize, MemoryAlignment)= ); + *DmaBufferBase =3D (UINTN)AllocateAlignedPages (EFI_SIZE_TO_PAGES(DmaBuf= ferSize), MemoryAlignment); + if (*DmaBufferBase =3D=3D 0) { + DEBUG ((DEBUG_INFO, " InitDmaProtection : OutOfResource\n")); + return EFI_OUT_OF_RESOURCES; + } + + LowBottom =3D 0; + LowTop =3D *DmaBufferBase; + HighBottom =3D *DmaBufferBase + DmaBufferSize; + HighTop =3D GetTopMemory (HobList); + + Status =3D SetDmaProtectedRange ( + (UINT32)LowBottom, + (UINT32)(LowTop - LowBottom), + HighBottom, + HighTop - HighBottom + ); + + if (EFI_ERROR(Status)) { + FreePages ((VOID *)*DmaBufferBase, EFI_SIZE_TO_PAGES(DmaBufferSize)); + } + + return Status; +} + +/** + Initializes the Intel VTd PMR PEIM. + + @param FileHandle Handle of the file being invoked. + @param PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCESS Usb bot driver is successfully initialize= d. + @retval EFI_OUT_OF_RESOURCES Can't initialize the driver. + +**/ +EFI_STATUS +EFIAPI +IntelVTdPmrInitialize ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) =3D=3D 0) { + return EFI_UNSUPPORTED; + } + + Status =3D PeiServicesLocatePpi ( + &gEdkiiVTdInfoPpiGuid, + 0, + NULL, + (VOID **)&mVTdInfoPpi + ); + ASSERT_EFI_ERROR(Status); + + // + // Find a pre-memory in resource hob as DMA buffer + // Mark PEI memory to be DMA protected. + // + Status =3D InitDmaProtection (mDmaBufferSize, &mDmaBufferBase); + if (EFI_ERROR(Status)) { + return Status; + } + + DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", mDmaBufferBase)); + DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", mDmaBufferSize)); + + mDmaBufferCurrentTop =3D mDmaBufferBase + mDmaBufferSize; + mDmaBufferCurrentBottom =3D mDmaBufferBase; + + // + // Install PPI. + // + Status =3D PeiServicesInstallPpi (&mIoMmuPpiList); + ASSERT_EFI_ERROR(Status); + + return Status; +} + diff --git a/IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmrPei.h b/IntelSilicon= Pkg/IntelVTdPmrPei/IntelVTdPmrPei.h new file mode 100644 index 0000000..aa5926a7 --- /dev/null +++ b/IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmrPei.h @@ -0,0 +1,68 @@ +/** @file + The definition for DMA access Library. + + 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 BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#ifndef __DMA_ACCESS_LIB_H__ +#define __DMA_ACCESS_LIB_H__ + +/** + Set DMA protected region. + + @param LowMemoryBase The protected low memory region base. + @param LowMemoryLength The protected low memory region length. + @param HighMemoryBase The protected high memory region base. + @param HighMemoryLength The protected high memory region length. + + @retval EFI_SUCCESS The DMA protection is set. + @retval EFI_UNSUPPORTED The DMA protection is not set. +**/ +EFI_STATUS +SetDmaProtectedRange ( + IN UINT32 LowMemoryBase, + IN UINT32 LowMemoryLength, + IN UINT64 HighMemoryBase, + IN UINT64 HighMemoryLength + ); + +/** + Diable DMA protection. + + @retval DMA protection is disabled. +**/ +EFI_STATUS +DisableDmaProtection ( + VOID + ); + +/** + Get protected low memory alignment. + + @return protected low memory alignment. +**/ +UINT32 +GetLowMemoryAlignment ( + VOID + ); + +/** + Get protected high memory alignment. + + @return protected high memory alignment. +**/ +UINT64 +GetHighMemoryAlignment ( + VOID + ); + +#endif + diff --git a/IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmrPei.inf b/IntelSilic= onPkg/IntelVTdPmrPei/IntelVTdPmrPei.inf new file mode 100644 index 0000000..86cd7d1 --- /dev/null +++ b/IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmrPei.inf @@ -0,0 +1,59 @@ +## @file +# Component INF file for the Intel VTd PMR PEIM. +# +# This driver initializes VTd engine based upon EDKII_VTD_INFO_PPI +# and provide DMA protection in PEI. +# +# 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 BS= D License +# which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. +# +## + +[Defines] + INF_VERSION =3D 0x00010017 + BASE_NAME =3D IntelVTdPmrPei + MODULE_UNI_FILE =3D IntelVTdPmrPei.uni + FILE_GUID =3D F906769F-4AED-4A0D-8C7C-FF21B9D1051A + MODULE_TYPE =3D PEIM + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D IntelVTdPmrInitialize + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelSiliconPkg/IntelSiliconPkg.dec + +[Sources] + IntelVTdPmrPei.c + IntelVTdPmrPei.h + IntelVTdPmr.c + +[LibraryClasses] + DebugLib + BaseMemoryLib + BaseLib + PeimEntryPoint + PeiServicesLib + HobLib + IoLib + +[Ppis] + gEdkiiIoMmuPpiGuid ## PRODUCES + gEdkiiVTdInfoPpiGuid ## CONSUMES + +[Pcd] + gIntelSiliconPkgTokenSpaceGuid.PcdVTdPolicyPropertyMask ## CONSUMES + +[Depex] + gEfiPeiMemoryDiscoveredPpiGuid AND + gEdkiiVTdInfoPpiGuid + +[UserExtensions.TianoCore."ExtraFiles"] + IntelVTdPmrPeiExtra.uni + diff --git a/IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmrPei.uni b/IntelSilic= onPkg/IntelVTdPmrPei/IntelVTdPmrPei.uni new file mode 100644 index 0000000..11508a4 --- /dev/null +++ b/IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmrPei.uni @@ -0,0 +1,20 @@ +// /** @file +// IntelVTdPmrPei Module Localized Abstract and Description Content +// +// 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 L= icense +// 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 IM= PLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Intel VTd PMR PEI= Driver." + +#string STR_MODULE_DESCRIPTION #language en-US "This driver initi= alizes VTd engine based upon EDKII_VTD_INFO_PPI and provide DMA protection = to device in PEI." + diff --git a/IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmrPeiExtra.uni b/Intel= SiliconPkg/IntelVTdPmrPei/IntelVTdPmrPeiExtra.uni new file mode 100644 index 0000000..c6b2dec --- /dev/null +++ b/IntelSiliconPkg/IntelVTdPmrPei/IntelVTdPmrPeiExtra.uni @@ -0,0 +1,20 @@ +// /** @file +// IntelVTdPmrPei Localized Strings and Content +// +// 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 L= icense +// 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 IM= PLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"Intel VTd PMR PEI Driver" + + --=20 2.7.4.windows.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel