From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by mx.groups.io with SMTP id smtpd.web10.65195.1679544853768342241 for ; Wed, 22 Mar 2023 21:14:14 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="unable to parse pub key" header.i=@intel.com header.s=intel header.b=erdG51ag; spf=pass (domain: intel.com, ip: 192.55.52.120, mailfrom: w.sheng@intel.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1679544853; x=1711080853; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=AuF8FimjCp3FHVvGhuODdK+PggkL8x2xg5mFTuf8pE0=; b=erdG51agfMb1QcPJjuYCemY5hqLtIUvTvXIfGqbMIuSvNjA5MuT+MTEr DaxkqP/gZ97bH6EdoCyF+a4+OQaPRnkpvX82/oX95yOo6u+DLMXhkVFjg 4LN1bQcw65FolvVPKjXvgzJ/rmHmf7hUC9Xql5Rgi39qjStDMohrZz2hi vaBzL0GPzEc5pZIr3D8oPyJpKS4eIh4v5/DiL6S4jyR/Au9O4x2d/d+5v BOas2MSbqhHwBeGm8jDWmrAI+/LKVu1Yxn7jFtrtWH8mz7kppaBB/GdUo UDIYOSHnuCtHBlC9wqVib/FVQ1xdQZmyNdCOhIzZr233Qx6vCGKrzeQOq w==; X-IronPort-AV: E=McAfee;i="6600,9927,10657"; a="338112040" X-IronPort-AV: E=Sophos;i="5.98,283,1673942400"; d="scan'208";a="338112040" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2023 21:14:13 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10657"; a="751331319" X-IronPort-AV: E=Sophos;i="5.98,283,1673942400"; d="scan'208";a="751331319" Received: from shwdesssddpdwei.ccr.corp.intel.com ([10.239.55.24]) by fmsmga004.fm.intel.com with ESMTP; 22 Mar 2023 21:14:08 -0700 From: "Sheng Wei" To: devel@edk2.groups.io Cc: Ray Ni , Rangasai V Chaganty , Jenny Huang , Robert Kowalewski Subject: [PATCH v3] IntelSiliconPkg/Vtd: Add Vtd core drivers Date: Thu, 23 Mar 2023 12:14:05 +0800 Message-Id: <20230323041406.412-1-w.sheng@intel.com> X-Mailer: git-send-email 2.26.2.windows.1 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Add 2 drivers (IntelVTdCorePei, IntelVTdCoreDxe) for pre-boot DMA protection feature. Signed-off-by: Sheng Wei Cc: Ray Ni Cc: Rangasai V Chaganty Cc: Jenny Huang Cc: Robert Kowalewski --- .../Feature/VTd/IntelVTdCoreDxe/BmDma.c | 547 +++++ .../VTd/IntelVTdCoreDxe/DmaProtection.c | 705 +++++++ .../VTd/IntelVTdCoreDxe/DmaProtection.h | 668 ++++++ .../VTd/IntelVTdCoreDxe/DmarAcpiTable.c | 398 ++++ .../VTd/IntelVTdCoreDxe/IntelVTdCoreDxe.c | 412 ++++ .../VTd/IntelVTdCoreDxe/IntelVTdCoreDxe.inf | 93 + .../VTd/IntelVTdCoreDxe/IntelVTdCoreDxe.uni | 14 + .../IntelVTdCoreDxe/IntelVTdCoreDxeExtra.uni | 14 + .../Feature/VTd/IntelVTdCoreDxe/PciInfo.c | 418 ++++ .../VTd/IntelVTdCoreDxe/TranslationTable.c | 1112 ++++++++++ .../VTd/IntelVTdCoreDxe/TranslationTableEx.c | 108 + .../Feature/VTd/IntelVTdCoreDxe/VtdLog.c | 383 ++++ .../Feature/VTd/IntelVTdCoreDxe/VtdReg.c | 757 +++++++ .../Feature/VTd/IntelVTdCorePei/DmarTable.c | 63 + .../VTd/IntelVTdCorePei/IntelVTdCorePei.c | 1099 ++++++++++ .../VTd/IntelVTdCorePei/IntelVTdCorePei.h | 262 +++ .../VTd/IntelVTdCorePei/IntelVTdCorePei.inf | 70 + .../VTd/IntelVTdCorePei/IntelVTdCorePei.uni | 14 + .../IntelVTdCorePei/IntelVTdCorePeiExtra.uni | 14 + .../VTd/IntelVTdCorePei/IntelVTdDmar.c | 727 +++++++ .../VTd/IntelVTdCorePei/TranslationTable.c | 926 +++++++++ .../Include/Guid/VtdLogDataHob.h | 151 ++ .../Include/Library/IntelVTdPeiDxeLib.h | 329 +++ .../IntelSiliconPkg/Include/Protocol/VtdLog.h | 59 + .../Intel/IntelSiliconPkg/IntelSiliconPkg.dec | 21 + .../Intel/IntelSiliconPkg/IntelSiliconPkg.dsc | 1 + .../IntelVTdPeiDxeLib/IntelVTdPeiDxeLib.c | 1793 +++++++++++++++++ .../IntelVTdPeiDxeLib/IntelVTdPeiDxeLib.inf | 30 + .../IntelVTdPeiDxeLibExt.inf | 34 + 29 files changed, 11222 insertions(+) create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreD= xe/BmDma.c create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreD= xe/DmaProtection.c create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreD= xe/DmaProtection.h create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreD= xe/DmarAcpiTable.c create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreD= xe/IntelVTdCoreDxe.c create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreD= xe/IntelVTdCoreDxe.inf create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreD= xe/IntelVTdCoreDxe.uni create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreD= xe/IntelVTdCoreDxeExtra.uni create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreD= xe/PciInfo.c create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreD= xe/TranslationTable.c create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreD= xe/TranslationTableEx.c create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreD= xe/VtdLog.c create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreD= xe/VtdReg.c create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreP= ei/DmarTable.c create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreP= ei/IntelVTdCorePei.c create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreP= ei/IntelVTdCorePei.h create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreP= ei/IntelVTdCorePei.inf create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreP= ei/IntelVTdCorePei.uni create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreP= ei/IntelVTdCorePeiExtra.uni create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreP= ei/IntelVTdDmar.c create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreP= ei/TranslationTable.c create mode 100644 Silicon/Intel/IntelSiliconPkg/Include/Guid/VtdLogDataHo= b.h create mode 100644 Silicon/Intel/IntelSiliconPkg/Include/Library/IntelVTdP= eiDxeLib.h create mode 100644 Silicon/Intel/IntelSiliconPkg/Include/Protocol/VtdLog.h create mode 100644 Silicon/Intel/IntelSiliconPkg/Library/IntelVTdPeiDxeLib= /IntelVTdPeiDxeLib.c create mode 100644 Silicon/Intel/IntelSiliconPkg/Library/IntelVTdPeiDxeLib= /IntelVTdPeiDxeLib.inf create mode 100644 Silicon/Intel/IntelSiliconPkg/Library/IntelVTdPeiDxeLib= /IntelVTdPeiDxeLibExt.inf diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/BmDm= a.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/BmDma.c new file mode 100644 index 000000000..41917a004 --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/BmDma.c @@ -0,0 +1,547 @@ +/** @file=0D + BmDma related function=0D +=0D + Copyright (c) 2017 - 2023, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include "DmaProtection.h"=0D +=0D +// TBD: May make it a policy=0D +#define DMA_MEMORY_TOP MAX_UINTN=0D +//#define DMA_MEMORY_TOP 0x0000000001FFFFFFULL=0D +=0D +#define MAP_HANDLE_INFO_SIGNATURE SIGNATURE_32 ('H', 'M', 'A', 'P')=0D +typedef struct {=0D + UINT32 Signature;=0D + LIST_ENTRY Link;=0D + EFI_HANDLE DeviceHandle;=0D + UINT64 IoMmuAccess;=0D +} MAP_HANDLE_INFO;=0D +#define MAP_HANDLE_INFO_FROM_LINK(a) CR (a, MAP_HANDLE_INFO, Link, MAP_HAN= DLE_INFO_SIGNATURE)=0D +=0D +#define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P')=0D +typedef struct {=0D + UINT32 Signature;=0D + LIST_ENTRY Link;=0D + EDKII_IOMMU_OPERATION Operation;=0D + UINTN NumberOfBytes;=0D + UINTN NumberOfPages;=0D + EFI_PHYSICAL_ADDRESS HostAddress;=0D + EFI_PHYSICAL_ADDRESS DeviceAddress;=0D + LIST_ENTRY HandleList;=0D +} MAP_INFO;=0D +#define MAP_INFO_FROM_LINK(a) CR (a, MAP_INFO, Link, MAP_INFO_SIGNATURE)=0D +=0D +LIST_ENTRY gMaps =3D INITIALIZE_LIST_HEAD_VARIABLE(= gMaps);=0D +=0D +/**=0D + This function fills DeviceHandle/IoMmuAccess to the MAP_HANDLE_INFO,=0D + based upon the DeviceAddress.=0D +=0D + @param[in] DeviceHandle The device who initiates the DMA access re= quest.=0D + @param[in] DeviceAddress The base of device memory address to be us= ed as the DMA memory.=0D + @param[in] Length The length of device memory address to be = used as the DMA memory.=0D + @param[in] IoMmuAccess The IOMMU access.=0D +=0D +**/=0D +VOID=0D +SyncDeviceHandleToMapInfo (=0D + IN EFI_HANDLE DeviceHandle,=0D + IN EFI_PHYSICAL_ADDRESS DeviceAddress,=0D + IN UINT64 Length,=0D + IN UINT64 IoMmuAccess=0D + )=0D +{=0D + MAP_INFO *MapInfo;=0D + MAP_HANDLE_INFO *MapHandleInfo;=0D + LIST_ENTRY *Link;=0D + EFI_TPL OriginalTpl;=0D +=0D + //=0D + // Find MapInfo according to DeviceAddress=0D + //=0D + OriginalTpl =3D gBS->RaiseTPL (VTD_TPL_LEVEL);=0D + MapInfo =3D NULL;=0D + for (Link =3D GetFirstNode (&gMaps)=0D + ; !IsNull (&gMaps, Link)=0D + ; Link =3D GetNextNode (&gMaps, Link)=0D + ) {=0D + MapInfo =3D MAP_INFO_FROM_LINK (Link);=0D + if (MapInfo->DeviceAddress =3D=3D DeviceAddress) {=0D + break;=0D + }=0D + }=0D + if ((MapInfo =3D=3D NULL) || (MapInfo->DeviceAddress !=3D DeviceAddress)= ) {=0D + DEBUG ((DEBUG_ERROR, "SyncDeviceHandleToMapInfo: DeviceAddress(0x%lx) = - not found\n", DeviceAddress));=0D + gBS->RestoreTPL (OriginalTpl);=0D + return ;=0D + }=0D +=0D + //=0D + // Find MapHandleInfo according to DeviceHandle=0D + //=0D + MapHandleInfo =3D NULL;=0D + for (Link =3D GetFirstNode (&MapInfo->HandleList)=0D + ; !IsNull (&MapInfo->HandleList, Link)=0D + ; Link =3D GetNextNode (&MapInfo->HandleList, Link)=0D + ) {=0D + MapHandleInfo =3D MAP_HANDLE_INFO_FROM_LINK (Link);=0D + if (MapHandleInfo->DeviceHandle =3D=3D DeviceHandle) {=0D + break;=0D + }=0D + }=0D + if ((MapHandleInfo !=3D NULL) && (MapHandleInfo->DeviceHandle =3D=3D Dev= iceHandle)) {=0D + MapHandleInfo->IoMmuAccess =3D IoMmuAccess;=0D + gBS->RestoreTPL (OriginalTpl);=0D + return ;=0D + }=0D +=0D + //=0D + // No DeviceHandle=0D + // Initialize and insert the MAP_HANDLE_INFO structure=0D + //=0D + MapHandleInfo =3D AllocatePool (sizeof (MAP_HANDLE_INFO));=0D + if (MapHandleInfo =3D=3D NULL) {=0D + DEBUG ((DEBUG_ERROR, "SyncDeviceHandleToMapInfo: %r\n", EFI_OUT_OF_RES= OURCES));=0D + gBS->RestoreTPL (OriginalTpl);=0D + return ;=0D + }=0D +=0D + MapHandleInfo->Signature =3D MAP_HANDLE_INFO_SIGNATURE;=0D + MapHandleInfo->DeviceHandle =3D DeviceHandle;=0D + MapHandleInfo->IoMmuAccess =3D IoMmuAccess;=0D +=0D + InsertTailList (&MapInfo->HandleList, &MapHandleInfo->Link);=0D + gBS->RestoreTPL (OriginalTpl);=0D +=0D + return ;=0D +}=0D +=0D +/**=0D + Provides the controller-specific addresses required to access system mem= ory from a=0D + DMA bus master.=0D +=0D + @param This The protocol instance pointer.=0D + @param Operation Indicates if the bus master is going to re= ad or write to system memory.=0D + @param HostAddress The system memory address to map to the PC= I controller.=0D + @param NumberOfBytes On input the number of bytes to map. On ou= tput the number of bytes=0D + that were mapped.=0D + @param DeviceAddress The resulting map address for the bus mast= er PCI controller to use to=0D + access the hosts HostAddress.=0D + @param Mapping A resulting value to pass to Unmap().=0D +=0D + @retval EFI_SUCCESS The range was mapped for the returned Numb= erOfBytes.=0D + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a comm= on buffer.=0D + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.=0D + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to = a lack of resources.=0D + @retval EFI_DEVICE_ERROR The system hardware could not map the requ= ested address.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoMmuMap (=0D + IN EDKII_IOMMU_PROTOCOL *This,=0D + IN EDKII_IOMMU_OPERATION Operation,=0D + IN VOID *HostAddress,=0D + IN OUT UINTN *NumberOfBytes,=0D + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,=0D + OUT VOID **Mapping=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_PHYSICAL_ADDRESS PhysicalAddress;=0D + MAP_INFO *MapInfo;=0D + EFI_PHYSICAL_ADDRESS DmaMemoryTop;=0D + BOOLEAN NeedRemap;=0D + EFI_TPL OriginalTpl;=0D +=0D + if (NumberOfBytes =3D=3D NULL || DeviceAddress =3D=3D NULL ||=0D + Mapping =3D=3D NULL) {=0D + DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_INVALID_PARAMETER));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + DEBUG ((DEBUG_VERBOSE, "IoMmuMap: =3D=3D> 0x%08x - 0x%08x (%x)\n", HostA= ddress, *NumberOfBytes, Operation));=0D +=0D + //=0D + // Make sure that Operation is valid=0D + //=0D + if ((UINT32) Operation >=3D EdkiiIoMmuOperationMaximum) {=0D + DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_INVALID_PARAMETER));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + NeedRemap =3D FALSE;=0D + PhysicalAddress =3D (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;=0D +=0D + DmaMemoryTop =3D DMA_MEMORY_TOP;=0D +=0D + //=0D + // Alignment check=0D + //=0D + if ((*NumberOfBytes !=3D ALIGN_VALUE(*NumberOfBytes, SIZE_4KB)) ||=0D + (PhysicalAddress !=3D ALIGN_VALUE(PhysicalAddress, SIZE_4KB))) {=0D + if ((Operation =3D=3D EdkiiIoMmuOperationBusMasterCommonBuffer) ||=0D + (Operation =3D=3D EdkiiIoMmuOperationBusMasterCommonBuffer64)) {=0D + //=0D + // The input buffer might be a subset from IoMmuAllocateBuffer.=0D + // Skip the check.=0D + //=0D + } else {=0D + NeedRemap =3D TRUE;=0D + }=0D + }=0D +=0D + if ((PhysicalAddress + *NumberOfBytes) >=3D DMA_MEMORY_TOP) {=0D + NeedRemap =3D TRUE;=0D + }=0D +=0D + if (((Operation !=3D EdkiiIoMmuOperationBusMasterRead64 &&=0D + Operation !=3D EdkiiIoMmuOperationBusMasterWrite64 &&=0D + Operation !=3D EdkiiIoMmuOperationBusMasterCommonBuffer64)) &&=0D + ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB)) {=0D + //=0D + // If the root bridge or the device cannot handle performing DMA above= =0D + // 4GB but any part of the DMA transfer being mapped is above 4GB, the= n=0D + // map the DMA transfer to a buffer below 4GB.=0D + //=0D + NeedRemap =3D TRUE;=0D + DmaMemoryTop =3D MIN (DmaMemoryTop, SIZE_4GB - 1);=0D + }=0D +=0D + if (Operation =3D=3D EdkiiIoMmuOperationBusMasterCommonBuffer ||=0D + Operation =3D=3D EdkiiIoMmuOperationBusMasterCommonBuffer64) {=0D + if (NeedRemap) {=0D + //=0D + // Common Buffer operations can not be remapped. If the common buff= er=0D + // is above 4GB, then it is not possible to generate a mapping, so r= eturn=0D + // an error.=0D + //=0D + DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_UNSUPPORTED));=0D + return EFI_UNSUPPORTED;=0D + }=0D + }=0D +=0D + //=0D + // Allocate a MAP_INFO structure to remember the mapping when Unmap() is= =0D + // called later.=0D + //=0D + MapInfo =3D AllocatePool (sizeof (MAP_INFO));=0D + if (MapInfo =3D=3D NULL) {=0D + *NumberOfBytes =3D 0;=0D + DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_OUT_OF_RESOURCES));=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + //=0D + // Initialize the MAP_INFO structure=0D + //=0D + MapInfo->Signature =3D MAP_INFO_SIGNATURE;=0D + MapInfo->Operation =3D Operation;=0D + MapInfo->NumberOfBytes =3D *NumberOfBytes;=0D + MapInfo->NumberOfPages =3D EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes= );=0D + MapInfo->HostAddress =3D PhysicalAddress;=0D + MapInfo->DeviceAddress =3D DmaMemoryTop;=0D + InitializeListHead(&MapInfo->HandleList);=0D +=0D + //=0D + // Allocate a buffer below 4GB to map the transfer to.=0D + //=0D + if (NeedRemap) {=0D + Status =3D gBS->AllocatePages (=0D + AllocateMaxAddress,=0D + EfiBootServicesData,=0D + MapInfo->NumberOfPages,=0D + &MapInfo->DeviceAddress=0D + );=0D + if (EFI_ERROR (Status)) {=0D + FreePool (MapInfo);=0D + *NumberOfBytes =3D 0;=0D + DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", Status));=0D + return Status;=0D + }=0D +=0D + //=0D + // If this is a read operation from the Bus Master's point of view,=0D + // then copy the contents of the real buffer into the mapped buffer=0D + // so the Bus Master can read the contents of the real buffer.=0D + //=0D + if (Operation =3D=3D EdkiiIoMmuOperationBusMasterRead ||=0D + Operation =3D=3D EdkiiIoMmuOperationBusMasterRead64) {=0D + CopyMem (=0D + (VOID *) (UINTN) MapInfo->DeviceAddress,=0D + (VOID *) (UINTN) MapInfo->HostAddress,=0D + MapInfo->NumberOfBytes=0D + );=0D + }=0D + } else {=0D + MapInfo->DeviceAddress =3D MapInfo->HostAddress;=0D + }=0D +=0D + OriginalTpl =3D gBS->RaiseTPL (VTD_TPL_LEVEL);=0D + InsertTailList (&gMaps, &MapInfo->Link);=0D + gBS->RestoreTPL (OriginalTpl);=0D +=0D + //=0D + // The DeviceAddress is the address of the maped buffer below 4GB=0D + //=0D + *DeviceAddress =3D MapInfo->DeviceAddress;=0D + //=0D + // Return a pointer to the MAP_INFO structure in Mapping=0D + //=0D + *Mapping =3D MapInfo;=0D +=0D + DEBUG ((DEBUG_VERBOSE, "IoMmuMap: 0x%08x - 0x%08x <=3D=3D\n", *DeviceAdd= ress, *Mapping));=0D +=0D + VTdLogAddEvent (VTDLOG_DXE_IOMMU_MAP, (UINT64) (*DeviceAddress), (UINT64= ) Operation);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Completes the Map() operation and releases any corresponding resources.= =0D +=0D + @param This The protocol instance pointer.=0D + @param Mapping The mapping value returned from Map().=0D +=0D + @retval EFI_SUCCESS The range was unmapped.=0D + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned b= y Map().=0D + @retval EFI_DEVICE_ERROR The data was not committed to the target s= ystem memory.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoMmuUnmap (=0D + IN EDKII_IOMMU_PROTOCOL *This,=0D + IN VOID *Mapping=0D + )=0D +{=0D + MAP_INFO *MapInfo;=0D + MAP_HANDLE_INFO *MapHandleInfo;=0D + LIST_ENTRY *Link;=0D + EFI_TPL OriginalTpl;=0D +=0D + DEBUG ((DEBUG_VERBOSE, "IoMmuUnmap: 0x%08x\n", Mapping));=0D +=0D + if (Mapping =3D=3D NULL) {=0D + DEBUG ((DEBUG_ERROR, "IoMmuUnmap: %r\n", EFI_INVALID_PARAMETER));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + OriginalTpl =3D gBS->RaiseTPL (VTD_TPL_LEVEL);=0D + MapInfo =3D NULL;=0D + for (Link =3D GetFirstNode (&gMaps)=0D + ; !IsNull (&gMaps, Link)=0D + ; Link =3D GetNextNode (&gMaps, Link)=0D + ) {=0D + MapInfo =3D MAP_INFO_FROM_LINK (Link);=0D + if (MapInfo =3D=3D Mapping) {=0D + break;=0D + }=0D + }=0D + //=0D + // Mapping is not a valid value returned by Map()=0D + //=0D + if (MapInfo !=3D Mapping) {=0D + gBS->RestoreTPL (OriginalTpl);=0D + DEBUG ((DEBUG_ERROR, "IoMmuUnmap: %r\n", EFI_INVALID_PARAMETER));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + RemoveEntryList (&MapInfo->Link);=0D + gBS->RestoreTPL (OriginalTpl);=0D +=0D + //=0D + // remove all nodes in MapInfo->HandleList=0D + //=0D + while (!IsListEmpty (&MapInfo->HandleList)) {=0D + MapHandleInfo =3D MAP_HANDLE_INFO_FROM_LINK (MapInfo->HandleList.Forwa= rdLink);=0D + RemoveEntryList (&MapHandleInfo->Link);=0D + FreePool (MapHandleInfo);=0D + }=0D +=0D + if (MapInfo->DeviceAddress !=3D MapInfo->HostAddress) {=0D + //=0D + // If this is a write operation from the Bus Master's point of view,=0D + // then copy the contents of the mapped buffer into the real buffer=0D + // so the processor can read the contents of the real buffer.=0D + //=0D + if (MapInfo->Operation =3D=3D EdkiiIoMmuOperationBusMasterWrite ||=0D + MapInfo->Operation =3D=3D EdkiiIoMmuOperationBusMasterWrite64) {=0D + CopyMem (=0D + (VOID *) (UINTN) MapInfo->HostAddress,=0D + (VOID *) (UINTN) MapInfo->DeviceAddress,=0D + MapInfo->NumberOfBytes=0D + );=0D + }=0D +=0D + //=0D + // Free the mapped buffer and the MAP_INFO structure.=0D + //=0D + gBS->FreePages (MapInfo->DeviceAddress, MapInfo->NumberOfPages);=0D + }=0D +=0D + VTdLogAddEvent (VTDLOG_DXE_IOMMU_UNMAP, MapInfo->NumberOfBytes, MapInfo-= >DeviceAddress);=0D +=0D + FreePool (Mapping);=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Allocates pages that are suitable for an OperationBusMasterCommonBuffer = or=0D + OperationBusMasterCommonBuffer64 mapping.=0D +=0D + @param This The protocol instance pointer.=0D + @param Type This parameter is not used and must be ign= ored.=0D + @param MemoryType The type of memory to allocate, EfiBootSer= vicesData or=0D + EfiRuntimeServicesData.=0D + @param Pages The number of pages to allocate.=0D + @param HostAddress A pointer to store the base system memory = address of the=0D + allocated range.=0D + @param Attributes The requested bit mask of attributes for t= he allocated range.=0D +=0D + @retval EFI_SUCCESS The requested memory pages were allocated.= =0D + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal = attribute bits are=0D + MEMORY_WRITE_COMBINE, MEMORY_CACHED and DU= AL_ADDRESS_CYCLE.=0D + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.=0D + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoMmuAllocateBuffer (=0D + IN EDKII_IOMMU_PROTOCOL *This,=0D + IN EFI_ALLOCATE_TYPE Type,=0D + IN EFI_MEMORY_TYPE MemoryType,=0D + IN UINTN Pages,=0D + IN OUT VOID **HostAddress,=0D + IN UINT64 Attributes=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_PHYSICAL_ADDRESS PhysicalAddress;=0D +=0D + DEBUG ((DEBUG_VERBOSE, "IoMmuAllocateBuffer: =3D=3D> 0x%08x\n", Pages));= =0D +=0D + //=0D + // Validate Attributes=0D + //=0D + if ((Attributes & EDKII_IOMMU_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != =3D 0) {=0D + DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_UNSUPPORTED));=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + //=0D + // Check for invalid inputs=0D + //=0D + if (HostAddress =3D=3D NULL) {=0D + DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_INVALID_PARAMETE= R));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + //=0D + // The only valid memory types are EfiBootServicesData and=0D + // EfiRuntimeServicesData=0D + //=0D + if (MemoryType !=3D EfiBootServicesData &&=0D + MemoryType !=3D EfiRuntimeServicesData) {=0D + DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_INVALID_PARAMETE= R));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + PhysicalAddress =3D DMA_MEMORY_TOP;=0D + if ((Attributes & EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE) =3D=3D 0) {= =0D + //=0D + // Limit allocations to memory below 4GB=0D + //=0D + PhysicalAddress =3D MIN (PhysicalAddress, SIZE_4GB - 1);=0D + }=0D + Status =3D gBS->AllocatePages (=0D + AllocateMaxAddress,=0D + MemoryType,=0D + Pages,=0D + &PhysicalAddress=0D + );=0D + if (!EFI_ERROR (Status)) {=0D + *HostAddress =3D (VOID *) (UINTN) PhysicalAddress;=0D +=0D + VTdLogAddEvent (VTDLOG_DXE_IOMMU_ALLOC_BUFFER, (UINT64) Pages, (UINT64= ) (*HostAddress));=0D + }=0D +=0D + DEBUG ((DEBUG_VERBOSE, "IoMmuAllocateBuffer: 0x%08x <=3D=3D\n", *HostAdd= ress));=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + Frees memory that was allocated with AllocateBuffer().=0D +=0D + @param This The protocol instance pointer.=0D + @param Pages The number of pages to free.=0D + @param HostAddress The base system memory address of the allo= cated range.=0D +=0D + @retval EFI_SUCCESS The requested memory pages were freed.=0D + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress = and Pages=0D + was not allocated with AllocateBuffer().=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoMmuFreeBuffer (=0D + IN EDKII_IOMMU_PROTOCOL *This,=0D + IN UINTN Pages,=0D + IN VOID *HostAddress=0D + )=0D +{=0D + DEBUG ((DEBUG_VERBOSE, "IoMmuFreeBuffer: 0x%\n", Pages));=0D +=0D + VTdLogAddEvent (VTDLOG_DXE_IOMMU_FREE_BUFFER, Pages, (UINT64) HostAddres= s);=0D +=0D + return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages= );=0D +}=0D +=0D +/**=0D + Get device information from mapping.=0D +=0D + @param[in] Mapping The mapping.=0D + @param[out] DeviceAddress The device address of the mapping.=0D + @param[out] NumberOfPages The number of pages of the mapping.=0D +=0D + @retval EFI_SUCCESS The device information is returned.=0D + @retval EFI_INVALID_PARAMETER The mapping is invalid.=0D +**/=0D +EFI_STATUS=0D +GetDeviceInfoFromMapping (=0D + IN VOID *Mapping,=0D + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,=0D + OUT UINTN *NumberOfPages=0D + )=0D +{=0D + MAP_INFO *MapInfo;=0D + LIST_ENTRY *Link;=0D +=0D + if (Mapping =3D=3D NULL) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + MapInfo =3D NULL;=0D + for (Link =3D GetFirstNode (&gMaps)=0D + ; !IsNull (&gMaps, Link)=0D + ; Link =3D GetNextNode (&gMaps, Link)=0D + ) {=0D + MapInfo =3D MAP_INFO_FROM_LINK (Link);=0D + if (MapInfo =3D=3D Mapping) {=0D + break;=0D + }=0D + }=0D + //=0D + // Mapping is not a valid value returned by Map()=0D + //=0D + if (MapInfo !=3D Mapping) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + *DeviceAddress =3D MapInfo->DeviceAddress;=0D + *NumberOfPages =3D MapInfo->NumberOfPages;=0D + return EFI_SUCCESS;=0D +}=0D +=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/DmaP= rotection.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/Dma= Protection.c new file mode 100644 index 000000000..9fd2b4a44 --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/DmaProtecti= on.c @@ -0,0 +1,705 @@ +/** @file=0D +=0D + Copyright (c) 2017 - 2023, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include "DmaProtection.h"=0D +=0D +UINT64 mBelow4GMemoryLimit;=0D +UINT64 mAbove4GMemoryLimit;=0D +=0D +EDKII_PLATFORM_VTD_POLICY_PROTOCOL *mPlatformVTdPolicy;=0D +=0D +VTD_ACCESS_REQUEST *mAccessRequest =3D NULL;=0D +UINTN mAccessRequestCount =3D 0;=0D +UINTN mAccessRequestMaxCount =3D 0;=0D +=0D +/**=0D + Append VTd Access Request to global.=0D +=0D + @param[in] Segment The Segment used to identify a VTd engine.= =0D + @param[in] SourceId The SourceId used to identify a VTd engine= and table entry.=0D + @param[in] BaseAddress The base of device memory address to be us= ed as the DMA memory.=0D + @param[in] Length The length of device memory address to be = used as the DMA memory.=0D + @param[in] IoMmuAccess The IOMMU access.=0D +=0D + @retval EFI_SUCCESS The IoMmuAccess is set for the memory rang= e specified by BaseAddress and Length.=0D + @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned= .=0D + @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.=0D + @retval EFI_INVALID_PARAMETER Length is 0.=0D + @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combinati= on of access.=0D + @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not support= ed by the IOMMU.=0D + @retval EFI_UNSUPPORTED The IOMMU does not support the memory rang= e specified by BaseAddress and Length.=0D + @retval EFI_OUT_OF_RESOURCES There are not enough resources available t= o modify the IOMMU access.=0D + @retval EFI_DEVICE_ERROR The IOMMU device reported an error while a= ttempting the operation.=0D +=0D +**/=0D +EFI_STATUS=0D +RequestAccessAttribute (=0D + IN UINT16 Segment,=0D + IN VTD_SOURCE_ID SourceId,=0D + IN UINT64 BaseAddress,=0D + IN UINT64 Length,=0D + IN UINT64 IoMmuAccess=0D + )=0D +{=0D + VTD_ACCESS_REQUEST *NewAccessRequest;=0D + UINTN Index;=0D +=0D + //=0D + // Optimization for memory.=0D + //=0D + // If the last record is to IoMmuAccess=3D0,=0D + // Check previous records and remove the matched entry.=0D + //=0D + if (IoMmuAccess =3D=3D 0) {=0D + for (Index =3D 0; Index < mAccessRequestCount; Index++) {=0D + if ((mAccessRequest[Index].Segment =3D=3D Segment) &&=0D + (mAccessRequest[Index].SourceId.Uint16 =3D=3D SourceId.Uint16) &= &=0D + (mAccessRequest[Index].BaseAddress =3D=3D BaseAddress) &&=0D + (mAccessRequest[Index].Length =3D=3D Length) &&=0D + (mAccessRequest[Index].IoMmuAccess !=3D 0)) {=0D + //=0D + // Remove this record [Index].=0D + // No need to add the new record.=0D + //=0D + if (Index !=3D mAccessRequestCount - 1) {=0D + CopyMem (=0D + &mAccessRequest[Index],=0D + &mAccessRequest[Index + 1],=0D + sizeof (VTD_ACCESS_REQUEST) * (mAccessRequestCount - 1 - Index= )=0D + );=0D + }=0D + ZeroMem (&mAccessRequest[mAccessRequestCount - 1], sizeof(VTD_ACCE= SS_REQUEST));=0D + mAccessRequestCount--;=0D + return EFI_SUCCESS;=0D + }=0D + }=0D + }=0D +=0D + if (mAccessRequestCount >=3D mAccessRequestMaxCount) {=0D + NewAccessRequest =3D AllocateZeroPool (sizeof(*NewAccessRequest) * (mA= ccessRequestMaxCount + MAX_VTD_ACCESS_REQUEST));=0D + if (NewAccessRequest =3D=3D NULL) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + mAccessRequestMaxCount +=3D MAX_VTD_ACCESS_REQUEST;=0D + if (mAccessRequest !=3D NULL) {=0D + CopyMem (NewAccessRequest, mAccessRequest, sizeof(*NewAccessRequest)= * mAccessRequestCount);=0D + FreePool (mAccessRequest);=0D + }=0D + mAccessRequest =3D NewAccessRequest;=0D + }=0D +=0D + ASSERT (mAccessRequestCount < mAccessRequestMaxCount);=0D +=0D + mAccessRequest[mAccessRequestCount].Segment =3D Segment;=0D + mAccessRequest[mAccessRequestCount].SourceId =3D SourceId;=0D + mAccessRequest[mAccessRequestCount].BaseAddress =3D BaseAddress;=0D + mAccessRequest[mAccessRequestCount].Length =3D Length;=0D + mAccessRequest[mAccessRequestCount].IoMmuAccess =3D IoMmuAccess;=0D +=0D + mAccessRequestCount++;=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Process Access Requests from before DMAR table is installed.=0D +=0D +**/=0D +VOID=0D +ProcessRequestedAccessAttribute (=0D + VOID=0D + )=0D +{=0D + UINTN Index;=0D + EFI_STATUS Status;=0D +=0D + DEBUG ((DEBUG_INFO, "ProcessRequestedAccessAttribute ...\n"));=0D +=0D + for (Index =3D 0; Index < mAccessRequestCount; Index++) {=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "PCI(S%x.B%x.D%x.F%x) ",=0D + mAccessRequest[Index].Segment,=0D + mAccessRequest[Index].SourceId.Bits.Bus,=0D + mAccessRequest[Index].SourceId.Bits.Device,=0D + mAccessRequest[Index].SourceId.Bits.Function=0D + ));=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "(0x%lx~0x%lx) - %lx\n",=0D + mAccessRequest[Index].BaseAddress,=0D + mAccessRequest[Index].Length,=0D + mAccessRequest[Index].IoMmuAccess=0D + ));=0D + Status =3D SetAccessAttribute (=0D + mAccessRequest[Index].Segment,=0D + mAccessRequest[Index].SourceId,=0D + mAccessRequest[Index].BaseAddress,=0D + mAccessRequest[Index].Length,=0D + mAccessRequest[Index].IoMmuAccess=0D + );=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "SetAccessAttribute %r: ", Status));=0D + }=0D + }=0D +=0D + if (mAccessRequest !=3D NULL) {=0D + FreePool (mAccessRequest);=0D + }=0D + mAccessRequest =3D NULL;=0D + mAccessRequestCount =3D 0;=0D + mAccessRequestMaxCount =3D 0;=0D +=0D + DEBUG ((DEBUG_INFO, "ProcessRequestedAccessAttribute Done\n"));=0D +}=0D +=0D +/**=0D + Return UEFI memory map information.=0D +=0D + @param[out] Below4GMemoryLimit The below 4GiB memory limit address or 0= if insufficient resources exist to=0D + determine the address.=0D + @param[out] Above4GMemoryLimit The above 4GiB memory limit address or 0= if insufficient resources exist to=0D + determine the address.=0D +=0D +**/=0D +VOID=0D +ReturnUefiMemoryMap (=0D + OUT UINT64 *Below4GMemoryLimit,=0D + OUT UINT64 *Above4GMemoryLimit=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;=0D + EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;=0D + EFI_MEMORY_DESCRIPTOR *EfiEntry;=0D + EFI_MEMORY_DESCRIPTOR *NextEfiEntry;=0D + EFI_MEMORY_DESCRIPTOR TempEfiEntry;=0D + UINTN EfiMemoryMapSize;=0D + UINTN EfiMapKey;=0D + UINTN EfiDescriptorSize;=0D + UINT32 EfiDescriptorVersion;=0D + UINT64 MemoryBlockLength;=0D +=0D + *Below4GMemoryLimit =3D 0;=0D + *Above4GMemoryLimit =3D 0;=0D +=0D + //=0D + // Get the EFI memory map.=0D + //=0D + EfiMemoryMapSize =3D 0;=0D + EfiMemoryMap =3D NULL;=0D + Status =3D gBS->GetMemoryMap (=0D + &EfiMemoryMapSize,=0D + EfiMemoryMap,=0D + &EfiMapKey,=0D + &EfiDescriptorSize,=0D + &EfiDescriptorVersion=0D + );=0D + ASSERT (Status =3D=3D EFI_BUFFER_TOO_SMALL);=0D +=0D + do {=0D + //=0D + // Use size returned back plus 1 descriptor for the AllocatePool.=0D + // We don't just multiply by 2 since the "for" loop below terminates o= n=0D + // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize= =0D + // we process bogus entries and create bogus E820 entries.=0D + //=0D + EfiMemoryMap =3D (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapS= ize);=0D + if (EfiMemoryMap =3D=3D NULL) {=0D + ASSERT (EfiMemoryMap !=3D NULL);=0D + return;=0D + }=0D +=0D + Status =3D gBS->GetMemoryMap (=0D + &EfiMemoryMapSize,=0D + EfiMemoryMap,=0D + &EfiMapKey,=0D + &EfiDescriptorSize,=0D + &EfiDescriptorVersion=0D + );=0D + if (EFI_ERROR (Status)) {=0D + FreePool (EfiMemoryMap);=0D + }=0D + } while (Status =3D=3D EFI_BUFFER_TOO_SMALL);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + //=0D + // Sort memory map from low to high=0D + //=0D + EfiEntry =3D EfiMemoryMap;=0D + NextEfiEntry =3D NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize)= ;=0D + EfiMemoryMapEnd =3D (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + = EfiMemoryMapSize);=0D + while (EfiEntry < EfiMemoryMapEnd) {=0D + while (NextEfiEntry < EfiMemoryMapEnd) {=0D + if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {=0D + CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));= =0D + CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));= =0D + CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTO= R));=0D + }=0D +=0D + NextEfiEntry =3D NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptor= Size);=0D + }=0D +=0D + EfiEntry =3D NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize)= ;=0D + NextEfiEntry =3D NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize)= ;=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, "MemoryMap:\n"));=0D + EfiEntry =3D EfiMemoryMap;=0D + EfiMemoryMapEnd =3D (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + = EfiMemoryMapSize);=0D + while (EfiEntry < EfiMemoryMapEnd) {=0D + MemoryBlockLength =3D (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12= ));=0D + DEBUG ((DEBUG_INFO, "Entry(0x%02x) 0x%016lx - 0x%016lx\n", EfiEntry->T= ype, EfiEntry->PhysicalStart, EfiEntry->PhysicalStart + MemoryBlockLength))= ;=0D + switch (EfiEntry->Type) {=0D + case EfiLoaderCode:=0D + case EfiLoaderData:=0D + case EfiBootServicesCode:=0D + case EfiBootServicesData:=0D + case EfiConventionalMemory:=0D + case EfiRuntimeServicesCode:=0D + case EfiRuntimeServicesData:=0D + case EfiACPIReclaimMemory:=0D + case EfiACPIMemoryNVS:=0D + case EfiReservedMemoryType:=0D + if ((EfiEntry->PhysicalStart + MemoryBlockLength) <=3D BASE_1MB) {=0D + //=0D + // Skip the memory block is under 1MB=0D + //=0D + } else if (EfiEntry->PhysicalStart >=3D BASE_4GB) {=0D + if (*Above4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLen= gth) {=0D + *Above4GMemoryLimit =3D EfiEntry->PhysicalStart + MemoryBlockLen= gth;=0D + }=0D + } else {=0D + if (*Below4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLen= gth) {=0D + *Below4GMemoryLimit =3D EfiEntry->PhysicalStart + MemoryBlockLen= gth;=0D + }=0D + }=0D + break;=0D + }=0D + EfiEntry =3D NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);=0D + }=0D +=0D + FreePool (EfiMemoryMap);=0D +=0D + DEBUG ((DEBUG_INFO, "Result:\n"));=0D + DEBUG ((DEBUG_INFO, "Below4GMemoryLimit: 0x%016lx\n", *Below4GMemoryLim= it));=0D + DEBUG ((DEBUG_INFO, "Above4GMemoryLimit: 0x%016lx\n", *Above4GMemoryLim= it));=0D +=0D + return ;=0D +}=0D +=0D +/**=0D + The scan bus callback function to always enable page attribute.=0D +=0D + @param[in] Context The context of the callback.=0D + @param[in] Segment The segment of the source.=0D + @param[in] Bus The bus of the source.=0D + @param[in] Device The device of the source.=0D + @param[in] Function The function of the source.=0D +=0D + @retval EFI_SUCCESS The VTd entry is updated to always enable = all DMA access for the specific device.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +ScanBusCallbackAlwaysEnablePageAttribute (=0D + IN VOID *Context,=0D + IN UINT16 Segment,=0D + IN UINT8 Bus,=0D + IN UINT8 Device,=0D + IN UINT8 Function=0D + )=0D +{=0D + VTD_SOURCE_ID SourceId;=0D + EFI_STATUS Status;=0D +=0D + SourceId.Bits.Bus =3D Bus;=0D + SourceId.Bits.Device =3D Device;=0D + SourceId.Bits.Function =3D Function;=0D + Status =3D AlwaysEnablePageAttribute (Segment, SourceId);=0D + return Status;=0D +}=0D +=0D +/**=0D + Always enable the VTd page attribute for the device in the DeviceScope.= =0D +=0D + @param[in] DeviceScope the input device scope data structure=0D +=0D + @retval EFI_SUCCESS The VTd entry is updated to always enable = all DMA access for the specific device in the device scope.=0D +**/=0D +EFI_STATUS=0D +AlwaysEnablePageAttributeDeviceScope (=0D + IN EDKII_PLATFORM_VTD_DEVICE_SCOPE *DeviceScope=0D + )=0D +{=0D + UINT8 Bus;=0D + UINT8 Device;=0D + UINT8 Function;=0D + VTD_SOURCE_ID SourceId;=0D + UINT8 SecondaryBusNumber;=0D + EFI_STATUS Status;=0D +=0D + Status =3D GetPciBusDeviceFunction (DeviceScope->SegmentNumber, &DeviceS= cope->DeviceScope, &Bus, &Device, &Function);=0D +=0D + if (DeviceScope->DeviceScope.Type =3D=3D EFI_ACPI_DEVICE_SCOPE_ENTRY_TYP= E_PCI_BRIDGE) {=0D + //=0D + // Need scan the bridge and add all devices.=0D + //=0D + SecondaryBusNumber =3D PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Device= Scope->SegmentNumber, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGIS= TER_OFFSET));=0D + Status =3D ScanPciBus (NULL, DeviceScope->SegmentNumber, SecondaryBusN= umber, ScanBusCallbackAlwaysEnablePageAttribute);=0D + return Status;=0D + } else {=0D + SourceId.Bits.Bus =3D Bus;=0D + SourceId.Bits.Device =3D Device;=0D + SourceId.Bits.Function =3D Function;=0D + Status =3D AlwaysEnablePageAttribute (DeviceScope->SegmentNumber, Sour= ceId);=0D + return Status;=0D + }=0D +}=0D +=0D +/**=0D + Always enable the VTd page attribute for the device matching DeviceId.=0D +=0D + @param[in] PciDeviceId the input PCI device ID=0D +=0D + @retval EFI_SUCCESS The VTd entry is updated to always enable = all DMA access for the specific device matching DeviceId.=0D +**/=0D +EFI_STATUS=0D +AlwaysEnablePageAttributePciDeviceId (=0D + IN EDKII_PLATFORM_VTD_PCI_DEVICE_ID *PciDeviceId=0D + )=0D +{=0D + UINTN VtdIndex;=0D + UINTN PciIndex;=0D + PCI_DEVICE_DATA *PciDeviceData;=0D + EFI_STATUS Status;=0D +=0D + for (VtdIndex =3D 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {=0D + for (PciIndex =3D 0; PciIndex < mVtdUnitInformation[VtdIndex].PciDevic= eInfo->PciDeviceDataNumber; PciIndex++) {=0D + PciDeviceData =3D &mVtdUnitInformation[VtdIndex].PciDeviceInfo->PciD= eviceData[PciIndex];=0D +=0D + if (((PciDeviceId->VendorId =3D=3D 0xFFFF) || (PciDeviceId->VendorId= =3D=3D PciDeviceData->PciDeviceId.VendorId)) &&=0D + ((PciDeviceId->DeviceId =3D=3D 0xFFFF) || (PciDeviceId->DeviceId= =3D=3D PciDeviceData->PciDeviceId.DeviceId)) &&=0D + ((PciDeviceId->RevisionId =3D=3D 0xFF) || (PciDeviceId->Revision= Id =3D=3D PciDeviceData->PciDeviceId.RevisionId)) &&=0D + ((PciDeviceId->SubsystemVendorId =3D=3D 0xFFFF) || (PciDeviceId-= >SubsystemVendorId =3D=3D PciDeviceData->PciDeviceId.SubsystemVendorId)) &&= =0D + ((PciDeviceId->SubsystemDeviceId =3D=3D 0xFFFF) || (PciDeviceId-= >SubsystemDeviceId =3D=3D PciDeviceData->PciDeviceId.SubsystemDeviceId)) ) = {=0D + Status =3D AlwaysEnablePageAttribute (mVtdUnitInformation[VtdIndex= ].Segment, PciDeviceData->PciSourceId);=0D + if (EFI_ERROR(Status)) {=0D + continue;=0D + }=0D + }=0D + }=0D + }=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Always enable the VTd page attribute for the device.=0D +=0D + @param[in] DeviceInfo the exception device information=0D +=0D + @retval EFI_SUCCESS The VTd entry is updated to always enable = all DMA access for the specific device in the device info.=0D +**/=0D +EFI_STATUS=0D +AlwaysEnablePageAttributeExceptionDeviceInfo (=0D + IN EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO *DeviceInfo=0D + )=0D +{=0D + switch (DeviceInfo->Type) {=0D + case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_DEVICE_SCOPE:=0D + return AlwaysEnablePageAttributeDeviceScope ((VOID *)(DeviceInfo + 1))= ;=0D + case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_PCI_DEVICE_ID:=0D + return AlwaysEnablePageAttributePciDeviceId ((VOID *)(DeviceInfo + 1))= ;=0D + default:=0D + return EFI_UNSUPPORTED;=0D + }=0D +}=0D +=0D +/**=0D + Initialize platform VTd policy.=0D +**/=0D +VOID=0D +InitializePlatformVTdPolicy (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN DeviceInfoCount;=0D + VOID *DeviceInfo;=0D + EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO *ThisDeviceInfo;=0D + UINTN Index;=0D +=0D + //=0D + // It is optional.=0D + //=0D + Status =3D gBS->LocateProtocol (=0D + &gEdkiiPlatformVTdPolicyProtocolGuid,=0D + NULL,=0D + (VOID **)&mPlatformVTdPolicy=0D + );=0D + if (!EFI_ERROR(Status)) {=0D + DEBUG ((DEBUG_INFO, "InitializePlatformVTdPolicy\n"));=0D + Status =3D mPlatformVTdPolicy->GetExceptionDeviceList (mPlatformVTdPol= icy, &DeviceInfoCount, &DeviceInfo);=0D + if (!EFI_ERROR(Status)) {=0D + ThisDeviceInfo =3D DeviceInfo;=0D + for (Index =3D 0; Index < DeviceInfoCount; Index++) {=0D + if (ThisDeviceInfo->Type =3D=3D EDKII_PLATFORM_VTD_EXCEPTION_DEVIC= E_INFO_TYPE_END) {=0D + break;=0D + }=0D + AlwaysEnablePageAttributeExceptionDeviceInfo (ThisDeviceInfo);=0D + ThisDeviceInfo =3D (VOID *)((UINTN)ThisDeviceInfo + ThisDeviceInfo= ->Length);=0D + }=0D + FreePool (DeviceInfo);=0D + }=0D + }=0D +}=0D +=0D +/**=0D + Setup VTd engine.=0D +**/=0D +VOID=0D +SetupVtd (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D + VOID *PciEnumerationComplete;=0D + UINTN Index;=0D + UINT64 Below4GMemoryLimit;=0D + UINT64 Above4GMemoryLimit;=0D + VTD_ROOT_TABLE_INFO RootTableInfo;=0D +=0D + //=0D + // PCI Enumeration must be done=0D + //=0D + Status =3D gBS->LocateProtocol (=0D + &gEfiPciEnumerationCompleteProtocolGuid,=0D + NULL,=0D + &PciEnumerationComplete=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + ReturnUefiMemoryMap (&Below4GMemoryLimit, &Above4GMemoryLimit);=0D + Below4GMemoryLimit =3D ALIGN_VALUE_UP(Below4GMemoryLimit, SIZE_256MB);=0D + DEBUG ((DEBUG_INFO, " Adjusted Below4GMemoryLimit: 0x%016lx\n", Below4GM= emoryLimit));=0D +=0D + mBelow4GMemoryLimit =3D Below4GMemoryLimit;=0D + mAbove4GMemoryLimit =3D Above4GMemoryLimit;=0D +=0D + VTdLogAddEvent (VTDLOG_DXE_SETUP_VTD, Below4GMemoryLimit, Above4GMemoryL= imit);=0D +=0D + //=0D + // 1. setup=0D + //=0D + DEBUG ((DEBUG_INFO, "ParseDmarAcpiTable\n"));=0D + Status =3D ParseDmarAcpiTableDrhd ();=0D + if (EFI_ERROR (Status)) {=0D + return;=0D + }=0D +=0D + DumpVtdIfError ();=0D +=0D + DEBUG ((DEBUG_INFO, "PrepareVtdConfig\n"));=0D + PrepareVtdConfig ();=0D +=0D + //=0D + // 2. initialization=0D + //=0D + DEBUG ((DEBUG_INFO, "SetupTranslationTable\n"));=0D + Status =3D SetupTranslationTable ();=0D + if (EFI_ERROR (Status)) {=0D + return;=0D + }=0D +=0D + InitializePlatformVTdPolicy ();=0D +=0D + ParseDmarAcpiTableRmrr ();=0D +=0D + if ((PcdGet8 (PcdVTdPolicyPropertyMask) & BIT2) =3D=3D 0) {=0D + //=0D + // Support IOMMU access attribute request recording before DMAR table = is installed.=0D + // Here is to process the requests.=0D + //=0D + ProcessRequestedAccessAttribute ();=0D + }=0D +=0D + for (Index =3D 0; Index < mVtdUnitNumber; Index++) {=0D + DEBUG ((DEBUG_INFO,"VTD Unit %d (Segment: %04x)\n", Index, mVtdUnitInf= ormation[Index].Segment));=0D +=0D + if (mVtdUnitInformation[Index].ExtRootEntryTable !=3D NULL) {=0D + VtdLibDumpDmarExtContextEntryTable (NULL, NULL, mVtdUnitInformation[= Index].ExtRootEntryTable, mVtdUnitInformation[Index].Is5LevelPaging);=0D +=0D + RootTableInfo.BaseAddress =3D mVtdUnitInformation[Index].VtdUnitBase= Address;=0D + RootTableInfo.TableAddress =3D (UINT64) (UINTN) mVtdUnitInformation[= Index].RootEntryTable;=0D + RootTableInfo.Is5LevelPaging =3D mVtdUnitInformation[Index].Is5Level= Paging;=0D + VTdLogAddDataEvent (VTDLOG_DXE_ROOT_TABLE, 1, &RootTableInfo, sizeof= (VTD_ROOT_TABLE_INFO));=0D + }=0D +=0D + if (mVtdUnitInformation[Index].RootEntryTable !=3D NULL) {=0D + VtdLibDumpDmarContextEntryTable (NULL, NULL, mVtdUnitInformation[Ind= ex].RootEntryTable, mVtdUnitInformation[Index].Is5LevelPaging);=0D +=0D + RootTableInfo.BaseAddress =3D mVtdUnitInformation[Index].VtdUnitBase= Address;=0D + RootTableInfo.TableAddress =3D (UINT64) (UINTN) mVtdUnitInformation[= Index].RootEntryTable;=0D + RootTableInfo.Is5LevelPaging =3D mVtdUnitInformation[Index].Is5Level= Paging;=0D + VTdLogAddDataEvent (VTDLOG_DXE_ROOT_TABLE, 0, &RootTableInfo, sizeof= (VTD_ROOT_TABLE_INFO));=0D + }=0D + }=0D +=0D + //=0D + // 3. enable=0D + //=0D + DEBUG ((DEBUG_INFO, "EnableDmar\n"));=0D + Status =3D EnableDmar ();=0D + if (EFI_ERROR (Status)) {=0D + return;=0D + }=0D + DEBUG ((DEBUG_INFO, "DumpVtdRegs\n"));=0D + DumpVtdRegsAll ();=0D +}=0D +=0D +/**=0D + Notification function of ACPI Table change.=0D +=0D + This is a notification function registered on ACPI Table change event.=0D +=0D + @param Event Event whose notification function is being invoked.= =0D + @param Context Pointer to the notification function's context.=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +AcpiNotificationFunc (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + Status =3D GetDmarAcpiTable ();=0D + if (EFI_ERROR (Status)) {=0D + if (Status =3D=3D EFI_ALREADY_STARTED) {=0D + gBS->CloseEvent (Event);=0D + }=0D + return;=0D + }=0D + SetupVtd ();=0D + gBS->CloseEvent (Event);=0D +}=0D +=0D +/**=0D + Exit boot service callback function.=0D +=0D + @param[in] Event The event handle.=0D + @param[in] Context The event content.=0D +**/=0D +VOID=0D +EFIAPI=0D +OnExitBootServices (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + )=0D +{=0D + UINTN VtdIndex;=0D +=0D + DEBUG ((DEBUG_INFO, "Vtd OnExitBootServices\n"));=0D +=0D + DumpVtdRegsAll ();=0D +=0D + DEBUG ((DEBUG_INFO, "Invalidate all\n"));=0D + for (VtdIndex =3D 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {=0D + VtdLibFlushWriteBuffer (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddre= ss);=0D +=0D + InvalidateContextCache (VtdIndex);=0D +=0D + InvalidateIOTLB (VtdIndex);=0D + }=0D +=0D + if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) =3D=3D 0) {=0D + DisableDmar ();=0D + DumpVtdRegsAll ();=0D + }=0D +}=0D +=0D +/**=0D + Legacy boot callback function.=0D +=0D + @param[in] Event The event handle.=0D + @param[in] Context The event content.=0D +**/=0D +VOID=0D +EFIAPI=0D +OnLegacyBoot (=0D + EFI_EVENT Event,=0D + VOID *Context=0D + )=0D +{=0D + DEBUG ((DEBUG_INFO, "Vtd OnLegacyBoot\n"));=0D + DumpVtdRegsAll ();=0D + DisableDmar ();=0D + DumpVtdRegsAll ();=0D +}=0D +=0D +/**=0D + Initialize DMA protection.=0D +**/=0D +VOID=0D +InitializeDmaProtection (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_EVENT ExitBootServicesEvent;=0D + EFI_EVENT LegacyBootEvent;=0D + EFI_EVENT EventAcpi10;=0D + EFI_EVENT EventAcpi20;=0D +=0D + Status =3D gBS->CreateEventEx (=0D + EVT_NOTIFY_SIGNAL,=0D + VTD_TPL_LEVEL,=0D + AcpiNotificationFunc,=0D + NULL,=0D + &gEfiAcpi10TableGuid,=0D + &EventAcpi10=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D gBS->CreateEventEx (=0D + EVT_NOTIFY_SIGNAL,=0D + VTD_TPL_LEVEL,=0D + AcpiNotificationFunc,=0D + NULL,=0D + &gEfiAcpi20TableGuid,=0D + &EventAcpi20=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + //=0D + // Signal the events initially for the case=0D + // that DMAR table has been installed.=0D + //=0D + gBS->SignalEvent (EventAcpi20);=0D + gBS->SignalEvent (EventAcpi10);=0D +=0D + Status =3D gBS->CreateEventEx (=0D + EVT_NOTIFY_SIGNAL,=0D + TPL_CALLBACK,=0D + OnExitBootServices,=0D + NULL,=0D + &gEfiEventExitBootServicesGuid,=0D + &ExitBootServicesEvent=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D EfiCreateEventLegacyBootEx (=0D + TPL_CALLBACK,=0D + OnLegacyBoot,=0D + NULL,=0D + &LegacyBootEvent=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + return ;=0D +}=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/DmaP= rotection.h b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/Dma= Protection.h new file mode 100644 index 000000000..4b2f451b1 --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/DmaProtecti= on.h @@ -0,0 +1,668 @@ +/** @file=0D +=0D + Copyright (c) 2017 - 2023, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#ifndef _DMAR_PROTECTION_H_=0D +#define _DMAR_PROTECTION_H_=0D +=0D +#include =0D +#include =0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include =0D +#include =0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include =0D +#include =0D +#include =0D +=0D +#include =0D +=0D +#define VTD_64BITS_ADDRESS(Lo, Hi) (LShiftU64 (Lo, 12) | LShiftU64 (Hi, 32= ))=0D +=0D +#define ALIGN_VALUE_UP(Value, Alignment) (((Value) + (Alignment) - 1) & (= ~((Alignment) - 1)))=0D +#define ALIGN_VALUE_LOW(Value, Alignment) ((Value) & (~((Alignment) - 1)))= =0D +=0D +#define VTD_TPL_LEVEL TPL_NOTIFY=0D +=0D +//=0D +// Use 256-bit descriptor=0D +// Queue size is 128.=0D +//=0D +#define VTD_QUEUED_INVALIDATION_DESCRIPTOR_WIDTH 1=0D +#define VTD_INVALIDATION_QUEUE_SIZE 0=0D +=0D +//=0D +// This is the initial max PCI DATA number.=0D +// The number may be enlarged later.=0D +//=0D +#define MAX_VTD_PCI_DATA_NUMBER 0x100=0D +=0D +typedef struct {=0D + UINTN VtdUnitBaseAddress;=0D + UINT16 Segment;=0D + VTD_VER_REG VerReg;=0D + VTD_CAP_REG CapReg;=0D + VTD_ECAP_REG ECapReg;=0D + VTD_ROOT_ENTRY *RootEntryTable;=0D + VTD_EXT_ROOT_ENTRY *ExtRootEntryTable;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *FixedSecondLevelPagingEntry;=0D + BOOLEAN HasDirtyContext;=0D + BOOLEAN HasDirtyPages;=0D + PCI_DEVICE_INFORMATION *PciDeviceInfo;=0D + BOOLEAN Is5LevelPaging;=0D + UINT8 EnableQueuedInvalidation;=0D + VOID *QiDescBuffer;=0D + UINTN QiDescBufferSize;=0D +} VTD_UNIT_INFORMATION;=0D +=0D +//=0D +// This is the initial max ACCESS request.=0D +// The number may be enlarged later.=0D +//=0D +#define MAX_VTD_ACCESS_REQUEST 0x100=0D +=0D +typedef struct {=0D + UINT16 Segment;=0D + VTD_SOURCE_ID SourceId;=0D + UINT64 BaseAddress;=0D + UINT64 Length;=0D + UINT64 IoMmuAccess;=0D +} VTD_ACCESS_REQUEST;=0D +=0D +=0D +/**=0D + The scan bus callback function.=0D +=0D + It is called in PCI bus scan for each PCI device under the bus.=0D +=0D + @param[in] Context The context of the callback.=0D + @param[in] Segment The segment of the source.=0D + @param[in] Bus The bus of the source.=0D + @param[in] Device The device of the source.=0D + @param[in] Function The function of the source.=0D +=0D + @retval EFI_SUCCESS The specific PCI device is processed in th= e callback.=0D +**/=0D +typedef=0D +EFI_STATUS=0D +(EFIAPI *SCAN_BUS_FUNC_CALLBACK_FUNC) (=0D + IN VOID *Context,=0D + IN UINT16 Segment,=0D + IN UINT8 Bus,=0D + IN UINT8 Device,=0D + IN UINT8 Function=0D + );=0D +=0D +extern EFI_ACPI_DMAR_HEADER *mAcpiDmarTable;=0D +=0D +extern UINTN mVtdUnitNumber;=0D +extern VTD_UNIT_INFORMATION *mVtdUnitInformation;=0D +=0D +extern UINT64 mBelow4GMemoryLimit;=0D +extern UINT64 mAbove4GMemoryLimit;=0D +=0D +extern EDKII_PLATFORM_VTD_POLICY_PROTOCOL *mPlatformVTdPolicy;=0D +=0D +/**=0D + Prepare VTD configuration.=0D +**/=0D +VOID=0D +PrepareVtdConfig (=0D + VOID=0D + );=0D +=0D +/**=0D + Setup VTd translation table.=0D +=0D + @retval EFI_SUCCESS Setup translation table successfully.=0D + @retval EFI_OUT_OF_RESOURCE Setup translation table fail.=0D +**/=0D +EFI_STATUS=0D +SetupTranslationTable (=0D + VOID=0D + );=0D +=0D +/**=0D + Enable DMAR translation.=0D +=0D + @retval EFI_SUCCESS DMAR translation is enabled.=0D + @retval EFI_DEVICE_ERROR DMAR translation is not enabled.=0D +**/=0D +EFI_STATUS=0D +EnableDmar (=0D + VOID=0D + );=0D +=0D +/**=0D + Disable DMAR translation.=0D +=0D + @retval EFI_SUCCESS DMAR translation is disabled.=0D + @retval EFI_DEVICE_ERROR DMAR translation is not disabled.=0D +**/=0D +EFI_STATUS=0D +DisableDmar (=0D + VOID=0D + );=0D +=0D +/**=0D + Perpare cache invalidation interface.=0D +=0D + @param[in] VtdIndex The index used to identify a VTd engine.=0D +=0D + @retval EFI_SUCCESS The operation was successful.=0D + @retval EFI_UNSUPPORTED Invalidation method is not supported.=0D + @retval EFI_OUT_OF_RESOURCES A memory allocation failed.=0D +**/=0D +EFI_STATUS=0D +PerpareCacheInvalidationInterface (=0D + IN UINTN VtdIndex=0D + );=0D +=0D +/**=0D + Invalidate VTd context cache.=0D +=0D + @param[in] VtdIndex The index used to identify a VTd engine.=0D +**/=0D +EFI_STATUS=0D +InvalidateContextCache (=0D + IN UINTN VtdIndex=0D + );=0D +=0D +/**=0D + Invalidate VTd IOTLB.=0D +=0D + @param[in] VtdIndex The index used to identify a VTd engine.=0D +**/=0D +EFI_STATUS=0D +InvalidateIOTLB (=0D + IN UINTN VtdIndex=0D + );=0D +=0D +/**=0D + Invalid VTd global IOTLB.=0D +=0D + @param[in] VtdIndex The index of VTd engine.=0D +=0D + @retval EFI_SUCCESS VTd global IOTLB is invalidated.=0D + @retval EFI_DEVICE_ERROR VTd global IOTLB is not invalidated.=0D +**/=0D +EFI_STATUS=0D +InvalidateVtdIOTLBGlobal (=0D + IN UINTN VtdIndex=0D + );=0D +=0D +/**=0D + Dump VTd registers.=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D +**/=0D +VOID=0D +DumpVtdRegs (=0D + IN UINTN VtdUnitBaseAddress=0D + );=0D +=0D +/**=0D + Dump VTd registers for all VTd engine.=0D +**/=0D +VOID=0D +DumpVtdRegsAll (=0D + VOID=0D + );=0D +=0D +/**=0D + Dump VTd version registers.=0D +=0D + @param[in] VerReg The version register.=0D +**/=0D +VOID=0D +DumpVtdVerRegs (=0D + IN VTD_VER_REG *VerReg=0D + );=0D +=0D +/**=0D + Dump VTd capability registers.=0D +=0D + @param[in] CapReg The capability register.=0D +**/=0D +VOID=0D +DumpVtdCapRegs (=0D + IN VTD_CAP_REG *CapReg=0D + );=0D +=0D +/**=0D + Dump VTd extended capability registers.=0D +=0D + @param[in] ECapReg The extended capability register.=0D +**/=0D +VOID=0D +DumpVtdECapRegs (=0D + IN VTD_ECAP_REG *ECapReg=0D + );=0D +=0D +/**=0D + Register PCI device to VTd engine.=0D +=0D + @param[in] VtdIndex The index of VTd engine.=0D + @param[in] Segment The segment of the source.=0D + @param[in] SourceId The SourceId of the source.=0D + @param[in] DeviceType The DMAR device scope type.=0D + @param[in] CheckExist TRUE: ERROR will be returned if the PC= I device is already registered.=0D + FALSE: SUCCESS will be returned if the= PCI device is registered.=0D +=0D + @retval EFI_SUCCESS The PCI device is registered.=0D + @retval EFI_OUT_OF_RESOURCES No enough resource to register a new PCI d= evice.=0D + @retval EFI_ALREADY_STARTED The device is already registered.=0D +**/=0D +EFI_STATUS=0D +RegisterPciDevice (=0D + IN UINTN VtdIndex,=0D + IN UINT16 Segment,=0D + IN VTD_SOURCE_ID SourceId,=0D + IN UINT8 DeviceType,=0D + IN BOOLEAN CheckExist=0D + );=0D +=0D +/**=0D + The scan bus callback function to always enable page attribute.=0D +=0D + @param[in] Context The context of the callback.=0D + @param[in] Segment The segment of the source.=0D + @param[in] Bus The bus of the source.=0D + @param[in] Device The device of the source.=0D + @param[in] Function The function of the source.=0D +=0D + @retval EFI_SUCCESS The VTd entry is updated to always enable = all DMA access for the specific device.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +ScanBusCallbackRegisterPciDevice (=0D + IN VOID *Context,=0D + IN UINT16 Segment,=0D + IN UINT8 Bus,=0D + IN UINT8 Device,=0D + IN UINT8 Function=0D + );=0D +=0D +/**=0D + Scan PCI bus and invoke callback function for each PCI devices under the= bus.=0D +=0D + @param[in] Context The context of the callback function.= =0D + @param[in] Segment The segment of the source.=0D + @param[in] Bus The bus of the source.=0D + @param[in] Callback The callback function in PCI scan.=0D +=0D + @retval EFI_SUCCESS The PCI devices under the bus are scaned.= =0D +**/=0D +EFI_STATUS=0D +ScanPciBus (=0D + IN VOID *Context,=0D + IN UINT16 Segment,=0D + IN UINT8 Bus,=0D + IN SCAN_BUS_FUNC_CALLBACK_FUNC Callback=0D + );=0D +=0D +/**=0D + Scan PCI bus and invoke callback function for each PCI devices under all= root bus.=0D +=0D + @param[in] Context The context of the callback function.= =0D + @param[in] Segment The segment of the source.=0D + @param[in] Callback The callback function in PCI scan.=0D +=0D + @retval EFI_SUCCESS The PCI devices under the bus are scaned.= =0D +**/=0D +EFI_STATUS=0D +ScanAllPciBus (=0D + IN VOID *Context,=0D + IN UINT16 Segment,=0D + IN SCAN_BUS_FUNC_CALLBACK_FUNC Callback=0D + );=0D +=0D +/**=0D + Find the VTd index by the Segment and SourceId.=0D +=0D + @param[in] Segment The segment of the source.=0D + @param[in] SourceId The SourceId of the source.=0D + @param[out] ExtContextEntry The ExtContextEntry of the source.=0D + @param[out] ContextEntry The ContextEntry of the source.=0D +=0D + @return The index of the VTd engine.=0D + @retval (UINTN)-1 The VTd engine is not found.=0D +**/=0D +UINTN=0D +FindVtdIndexByPciDevice (=0D + IN UINT16 Segment,=0D + IN VTD_SOURCE_ID SourceId,=0D + OUT VTD_EXT_CONTEXT_ENTRY **ExtContextEntry,=0D + OUT VTD_CONTEXT_ENTRY **ContextEntry=0D + );=0D +=0D +/**=0D + Get the DMAR ACPI table.=0D +=0D + @retval EFI_SUCCESS The DMAR ACPI table is got.=0D + @retval EFI_ALREADY_STARTED The DMAR ACPI table has been got previousl= y.=0D + @retval EFI_NOT_FOUND The DMAR ACPI table is not found.=0D +**/=0D +EFI_STATUS=0D +GetDmarAcpiTable (=0D + VOID=0D + );=0D +=0D +/**=0D + Parse DMAR DRHD table.=0D +=0D + @return EFI_SUCCESS The DMAR DRHD table is parsed.=0D +**/=0D +EFI_STATUS=0D +ParseDmarAcpiTableDrhd (=0D + VOID=0D + );=0D +=0D +/**=0D + Parse DMAR RMRR table.=0D +=0D + @return EFI_SUCCESS The DMAR RMRR table is parsed.=0D +**/=0D +EFI_STATUS=0D +ParseDmarAcpiTableRmrr (=0D + VOID=0D + );=0D +=0D +/**=0D + Set VTd attribute for a system memory.=0D +=0D + @param[in] VtdIndex The index used to identify a VTd eng= ine.=0D + @param[in] DomainIdentifier The domain ID of the source.=0D + @param[in] SecondLevelPagingEntry The second level paging entry in VTd= table for the device.=0D + @param[in] BaseAddress The base of device memory address to= be used as the DMA memory.=0D + @param[in] Length The length of device memory address = to be used as the DMA memory.=0D + @param[in] IoMmuAccess The IOMMU access.=0D +=0D + @retval EFI_SUCCESS The IoMmuAccess is set for the memory ran= ge specified by BaseAddress and Length.=0D + @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligne= d.=0D + @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.=0D + @retval EFI_INVALID_PARAMETER Length is 0.=0D + @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combinat= ion of access.=0D + @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not suppor= ted by the IOMMU.=0D + @retval EFI_UNSUPPORTED The IOMMU does not support the memory ran= ge specified by BaseAddress and Length.=0D + @retval EFI_OUT_OF_RESOURCES There are not enough resources available = to modify the IOMMU access.=0D + @retval EFI_DEVICE_ERROR The IOMMU device reported an error while = attempting the operation.=0D +**/=0D +EFI_STATUS=0D +SetPageAttribute (=0D + IN UINTN VtdIndex,=0D + IN UINT16 DomainIdentifier,=0D + IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,=0D + IN UINT64 BaseAddress,=0D + IN UINT64 Length,=0D + IN UINT64 IoMmuAccess=0D + );=0D +=0D +/**=0D + Set VTd attribute for a system memory.=0D +=0D + @param[in] Segment The Segment used to identify a VTd engine.= =0D + @param[in] SourceId The SourceId used to identify a VTd engine= and table entry.=0D + @param[in] BaseAddress The base of device memory address to be us= ed as the DMA memory.=0D + @param[in] Length The length of device memory address to be = used as the DMA memory.=0D + @param[in] IoMmuAccess The IOMMU access.=0D +=0D + @retval EFI_SUCCESS The IoMmuAccess is set for the memory ran= ge specified by BaseAddress and Length.=0D + @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligne= d.=0D + @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.=0D + @retval EFI_INVALID_PARAMETER Length is 0.=0D + @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combinat= ion of access.=0D + @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not suppor= ted by the IOMMU.=0D + @retval EFI_UNSUPPORTED The IOMMU does not support the memory ran= ge specified by BaseAddress and Length.=0D + @retval EFI_OUT_OF_RESOURCES There are not enough resources available = to modify the IOMMU access.=0D + @retval EFI_DEVICE_ERROR The IOMMU device reported an error while = attempting the operation.=0D +**/=0D +EFI_STATUS=0D +SetAccessAttribute (=0D + IN UINT16 Segment,=0D + IN VTD_SOURCE_ID SourceId,=0D + IN UINT64 BaseAddress,=0D + IN UINT64 Length,=0D + IN UINT64 IoMmuAccess=0D + );=0D +=0D +/**=0D + Return the index of PCI data.=0D +=0D + @param[in] VtdIndex The index used to identify a VTd engine.=0D + @param[in] Segment The Segment used to identify a VTd engine.= =0D + @param[in] SourceId The SourceId used to identify a VTd engine= and table entry.=0D +=0D + @return The index of the PCI data.=0D + @retval (UINTN)-1 The PCI data is not found.=0D +**/=0D +UINTN=0D +GetPciDataIndex (=0D + IN UINTN VtdIndex,=0D + IN UINT16 Segment,=0D + IN VTD_SOURCE_ID SourceId=0D + );=0D +=0D +/**=0D + Dump VTd registers if there is error.=0D +**/=0D +VOID=0D +DumpVtdIfError (=0D + VOID=0D + );=0D +=0D +/**=0D + Initialize platform VTd policy.=0D +**/=0D +VOID=0D +InitializePlatformVTdPolicy (=0D + VOID=0D + );=0D +=0D +/**=0D + Always enable the VTd page attribute for the device.=0D +=0D + @param[in] Segment The Segment used to identify a VTd engine.= =0D + @param[in] SourceId The SourceId used to identify a VTd engine= and table entry.=0D +=0D + @retval EFI_SUCCESS The VTd entry is updated to always enable = all DMA access for the specific device.=0D +**/=0D +EFI_STATUS=0D +AlwaysEnablePageAttribute (=0D + IN UINT16 Segment,=0D + IN VTD_SOURCE_ID SourceId=0D + );=0D +=0D +/**=0D + Convert the DeviceHandle to SourceId and Segment.=0D +=0D + @param[in] DeviceHandle The device who initiates the DMA access re= quest.=0D + @param[out] Segment The Segment used to identify a VTd engine.= =0D + @param[out] SourceId The SourceId used to identify a VTd engine= and table entry.=0D +=0D + @retval EFI_SUCCESS The Segment and SourceId are returned.=0D + @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle.=0D + @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU.=0D +**/=0D +EFI_STATUS=0D +DeviceHandleToSourceId (=0D + IN EFI_HANDLE DeviceHandle,=0D + OUT UINT16 *Segment,=0D + OUT VTD_SOURCE_ID *SourceId=0D + );=0D +=0D +/**=0D + Get device information from mapping.=0D +=0D + @param[in] Mapping The mapping.=0D + @param[out] DeviceAddress The device address of the mapping.=0D + @param[out] NumberOfPages The number of pages of the mapping.=0D +=0D + @retval EFI_SUCCESS The device information is returned.=0D + @retval EFI_INVALID_PARAMETER The mapping is invalid.=0D +**/=0D +EFI_STATUS=0D +GetDeviceInfoFromMapping (=0D + IN VOID *Mapping,=0D + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,=0D + OUT UINTN *NumberOfPages=0D + );=0D +=0D +/**=0D + Initialize DMA protection.=0D +**/=0D +VOID=0D +InitializeDmaProtection (=0D + VOID=0D + );=0D +=0D +/**=0D + Allocate zero pages.=0D +=0D + @param[in] Pages the number of pages.=0D +=0D + @return the page address.=0D + @retval NULL No resource to allocate pages.=0D +**/=0D +VOID *=0D +EFIAPI=0D +AllocateZeroPages (=0D + IN UINTN Pages=0D + );=0D +=0D +/**=0D + Flush VTD page table and context table memory.=0D +=0D + This action is to make sure the IOMMU engine can get final data in memor= y.=0D +=0D + @param[in] VtdIndex The index used to identify a VTd engine.=0D + @param[in] Base The base address of memory to be flushed.= =0D + @param[in] Size The size of memory in bytes to be flushed.= =0D +**/=0D +VOID=0D +FlushPageTableMemory (=0D + IN UINTN VtdIndex,=0D + IN UINTN Base,=0D + IN UINTN Size=0D + );=0D +=0D +/**=0D + Get PCI device information from DMAR DevScopeEntry.=0D +=0D + @param[in] Segment The segment number.=0D + @param[in] DmarDevScopeEntry DMAR DevScopeEntry=0D + @param[out] Bus The bus number.=0D + @param[out] Device The device number.=0D + @param[out] Function The function number.=0D +=0D + @retval EFI_SUCCESS The PCI device information is returned.=0D +**/=0D +EFI_STATUS=0D +GetPciBusDeviceFunction (=0D + IN UINT16 Segment,=0D + IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry,=0D + OUT UINT8 *Bus,=0D + OUT UINT8 *Device,=0D + OUT UINT8 *Function=0D + );=0D +=0D +/**=0D + Append VTd Access Request to global.=0D +=0D + @param[in] Segment The Segment used to identify a VTd engine.= =0D + @param[in] SourceId The SourceId used to identify a VTd engine= and table entry.=0D + @param[in] BaseAddress The base of device memory address to be us= ed as the DMA memory.=0D + @param[in] Length The length of device memory address to be = used as the DMA memory.=0D + @param[in] IoMmuAccess The IOMMU access.=0D +=0D + @retval EFI_SUCCESS The IoMmuAccess is set for the memory rang= e specified by BaseAddress and Length.=0D + @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned= .=0D + @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.=0D + @retval EFI_INVALID_PARAMETER Length is 0.=0D + @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combinati= on of access.=0D + @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not support= ed by the IOMMU.=0D + @retval EFI_UNSUPPORTED The IOMMU does not support the memory rang= e specified by BaseAddress and Length.=0D + @retval EFI_OUT_OF_RESOURCES There are not enough resources available t= o modify the IOMMU access.=0D + @retval EFI_DEVICE_ERROR The IOMMU device reported an error while a= ttempting the operation.=0D +=0D +**/=0D +EFI_STATUS=0D +RequestAccessAttribute (=0D + IN UINT16 Segment,=0D + IN VTD_SOURCE_ID SourceId,=0D + IN UINT64 BaseAddress,=0D + IN UINT64 Length,=0D + IN UINT64 IoMmuAccess=0D + );=0D +=0D +/**=0D + Add a new VTd log event.=0D +=0D + @param[in] EventType Event type=0D + @param[in] Data1 First parameter=0D + @param[in] Data2 Second parameter=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +VTdLogAddEvent (=0D + IN CONST VTDLOG_EVENT_TYPE EventType,=0D + IN CONST UINT64 Data1,=0D + IN CONST UINT64 Data2=0D + );=0D +=0D +/**=0D + Add a new VTd log event with data.=0D +=0D + @param[in] EventType Event type=0D + @param[in] Param parameter=0D + @param[in] Data Data=0D + @param[in] DataSize Data size=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +VTdLogAddDataEvent (=0D + IN CONST VTDLOG_EVENT_TYPE EventType,=0D + IN CONST UINT64 Param,=0D + IN CONST VOID *Data,=0D + IN CONST UINT32 DataSize=0D + );=0D +=0D +/**=0D + Initializes the VTd Log.=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +VTdLogInitialize(=0D + VOID=0D + );=0D +=0D +#endif=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/Dmar= AcpiTable.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/Dma= rAcpiTable.c new file mode 100644 index 000000000..21f559983 --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/DmarAcpiTab= le.c @@ -0,0 +1,398 @@ +/** @file=0D +=0D + Copyright (c) 2017 - 2023, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include "DmaProtection.h"=0D +=0D +#pragma pack(1)=0D +=0D +typedef struct {=0D + EFI_ACPI_DESCRIPTION_HEADER Header;=0D + UINT32 Entry;=0D +} RSDT_TABLE;=0D +=0D +typedef struct {=0D + EFI_ACPI_DESCRIPTION_HEADER Header;=0D + UINT64 Entry;=0D +} XSDT_TABLE;=0D +=0D +#pragma pack()=0D +=0D +EFI_ACPI_DMAR_HEADER *mAcpiDmarTable =3D NULL;=0D +=0D +/**=0D + Dump DMAR ACPI table.=0D +**/=0D +VOID=0D +VtdDumpDmarTable (=0D + VOID=0D + )=0D +{=0D + VtdLibDumpAcpiDmar (NULL, NULL, (EFI_ACPI_DMAR_HEADER *) (UINTN) mAcpiDm= arTable);=0D +=0D + VTdLogAddDataEvent (VTDLOG_DXE_DMAR_TABLE, mAcpiDmarTable->Header.Length= , (VOID *)mAcpiDmarTable, mAcpiDmarTable->Header.Length); =0D +}=0D +=0D +/**=0D + Get PCI device information from DMAR DevScopeEntry.=0D +=0D + @param[in] Segment The segment number.=0D + @param[in] DmarDevScopeEntry DMAR DevScopeEntry=0D + @param[out] Bus The bus number.=0D + @param[out] Device The device number.=0D + @param[out] Function The function number.=0D +=0D + @retval EFI_SUCCESS The PCI device information is returned.=0D +**/=0D +EFI_STATUS=0D +GetPciBusDeviceFunction (=0D + IN UINT16 Segment,=0D + IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry,=0D + OUT UINT8 *Bus,=0D + OUT UINT8 *Device,=0D + OUT UINT8 *Function=0D + )=0D +{=0D + EFI_ACPI_DMAR_PCI_PATH *DmarPciPath;=0D + UINT8 MyBus;=0D + UINT8 MyDevice;=0D + UINT8 MyFunction;=0D +=0D + DmarPciPath =3D (EFI_ACPI_DMAR_PCI_PATH *)((UINTN)(DmarDevScopeEntry + 1= ));=0D + MyBus =3D DmarDevScopeEntry->StartBusNumber;=0D + MyDevice =3D DmarPciPath->Device;=0D + MyFunction =3D DmarPciPath->Function;=0D +=0D + switch (DmarDevScopeEntry->Type) {=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:=0D + while ((UINTN)DmarPciPath + sizeof(EFI_ACPI_DMAR_PCI_PATH) < (UINTN)Dm= arDevScopeEntry + DmarDevScopeEntry->Length) {=0D + MyBus =3D PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, MyBus, M= yDevice, MyFunction, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));=0D + DmarPciPath ++;=0D + MyDevice =3D DmarPciPath->Device;=0D + MyFunction =3D DmarPciPath->Function;=0D + }=0D + break;=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC:=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET:=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE:=0D + break;=0D + }=0D +=0D + *Bus =3D MyBus;=0D + *Device =3D MyDevice;=0D + *Function =3D MyFunction;=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Process DMAR DRHD table.=0D +=0D + @param[in] VtdIndex The index of VTd engine.=0D + @param[in] DmarDrhd The DRHD table.=0D +=0D + @retval EFI_SUCCESS The DRHD table is processed.=0D +**/=0D +EFI_STATUS=0D +ProcessDrhd (=0D + IN UINTN VtdIndex,=0D + IN EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd=0D + )=0D +{=0D + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry;=0D + UINT8 Bus;=0D + UINT8 Device;=0D + UINT8 Function;=0D + UINT8 SecondaryBusNumber;=0D + EFI_STATUS Status;=0D + VTD_SOURCE_ID SourceId;=0D +=0D + mVtdUnitInformation[VtdIndex].PciDeviceInfo =3D AllocateZeroPool (sizeof= (PCI_DEVICE_INFORMATION) + sizeof (PCI_DEVICE_DATA) * MAX_VTD_PCI_DATA_NUM= BER);=0D + if (mVtdUnitInformation[VtdIndex].PciDeviceInfo =3D=3D NULL) {=0D + ASSERT (FALSE);=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + mVtdUnitInformation[VtdIndex].Segment =3D DmarDrhd->SegmentNu= mber;=0D + mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress =3D (UINTN)DmarDrhd->Re= gisterBaseAddress;=0D + DEBUG ((DEBUG_INFO," VTD (%d) BaseAddress - 0x%016lx\n", VtdIndex, Dma= rDrhd->RegisterBaseAddress));=0D +=0D + mVtdUnitInformation[VtdIndex].PciDeviceInfo->Segment =3D = DmarDrhd->SegmentNumber;=0D + mVtdUnitInformation[VtdIndex].PciDeviceInfo->PciDeviceDataMaxNumber =3D = MAX_VTD_PCI_DATA_NUMBER;=0D +=0D + if ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) !=3D 0)= {=0D + mVtdUnitInformation[VtdIndex].PciDeviceInfo->IncludeAllFlag =3D TRUE;= =0D + DEBUG ((DEBUG_INFO," ProcessDrhd: with INCLUDE ALL\n"));=0D +=0D + Status =3D ScanAllPciBus((VOID *)VtdIndex, DmarDrhd->SegmentNumber, Sc= anBusCallbackRegisterPciDevice);=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + } else {=0D + mVtdUnitInformation[VtdIndex].PciDeviceInfo->IncludeAllFlag =3D FALSE;= =0D + DEBUG ((DEBUG_INFO," ProcessDrhd: without INCLUDE ALL\n"));=0D + }=0D +=0D + DmarDevScopeEntry =3D (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((U= INTN)(DmarDrhd + 1));=0D + while ((UINTN)DmarDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Len= gth) {=0D +=0D + Status =3D GetPciBusDeviceFunction (DmarDrhd->SegmentNumber, DmarDevSc= opeEntry, &Bus, &Device, &Function);=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D +=0D + DEBUG ((DEBUG_INFO," ProcessDrhd: "));=0D + switch (DmarDevScopeEntry->Type) {=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:=0D + DEBUG ((DEBUG_INFO,"PCI Endpoint"));=0D + break;=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:=0D + DEBUG ((DEBUG_INFO,"PCI-PCI bridge"));=0D + break;=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC:=0D + DEBUG ((DEBUG_INFO,"IOAPIC"));=0D + break;=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET:=0D + DEBUG ((DEBUG_INFO,"MSI Capable HPET"));=0D + break;=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE:=0D + DEBUG ((DEBUG_INFO,"ACPI Namespace Device"));=0D + break;=0D + }=0D + DEBUG ((DEBUG_INFO," S%04x B%02x D%02x F%02x\n", DmarDrhd->SegmentNumb= er, Bus, Device, Function));=0D +=0D + SourceId.Bits.Bus =3D Bus;=0D + SourceId.Bits.Device =3D Device;=0D + SourceId.Bits.Function =3D Function;=0D +=0D + Status =3D RegisterPciDevice (VtdIndex, DmarDrhd->SegmentNumber, Sourc= eId, DmarDevScopeEntry->Type, TRUE);=0D + if (EFI_ERROR (Status)) {=0D + //=0D + // There might be duplication for special device other than standard= PCI device.=0D + //=0D + switch (DmarDevScopeEntry->Type) {=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:=0D + return Status;=0D + }=0D + }=0D +=0D + switch (DmarDevScopeEntry->Type) {=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:=0D + SecondaryBusNumber =3D PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Dmar= Drhd->SegmentNumber, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGIST= ER_OFFSET));=0D + Status =3D ScanPciBus ((VOID *)VtdIndex, DmarDrhd->SegmentNumber, Se= condaryBusNumber, ScanBusCallbackRegisterPciDevice);=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + break;=0D + default:=0D + break;=0D + }=0D +=0D + DmarDevScopeEntry =3D (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(= (UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Process DMAR RMRR table.=0D +=0D + @param[in] DmarRmrr The RMRR table.=0D +=0D + @retval EFI_SUCCESS The RMRR table is processed.=0D +**/=0D +EFI_STATUS=0D +ProcessRmrr (=0D + IN EFI_ACPI_DMAR_RMRR_HEADER *DmarRmrr=0D + )=0D +{=0D + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry;=0D + UINT8 Bus;=0D + UINT8 Device;=0D + UINT8 Function;=0D + EFI_STATUS Status;=0D + VTD_SOURCE_ID SourceId;=0D +=0D + DEBUG ((DEBUG_INFO," RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr-= >ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddres= s));=0D +=0D + DmarDevScopeEntry =3D (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((U= INTN)(DmarRmrr + 1));=0D + while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Len= gth) {=0D + if (DmarDevScopeEntry->Type !=3D EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_= ENDPOINT) {=0D + DEBUG ((DEBUG_INFO,"RMRR DevScopeEntryType is not endpoint, type[0x%= x] \n", DmarDevScopeEntry->Type));=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + Status =3D GetPciBusDeviceFunction (DmarRmrr->SegmentNumber, DmarDevSc= opeEntry, &Bus, &Device, &Function);=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D +=0D + DEBUG ((DEBUG_INFO,"RMRR S%04x B%02x D%02x F%02x\n", DmarRmrr->Segment= Number, Bus, Device, Function));=0D +=0D + SourceId.Bits.Bus =3D Bus;=0D + SourceId.Bits.Device =3D Device;=0D + SourceId.Bits.Function =3D Function;=0D + Status =3D SetAccessAttribute (=0D + DmarRmrr->SegmentNumber,=0D + SourceId,=0D + DmarRmrr->ReservedMemoryRegionBaseAddress,=0D + DmarRmrr->ReservedMemoryRegionLimitAddress + 1 - DmarRmrr->= ReservedMemoryRegionBaseAddress,=0D + EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE=0D + );=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D +=0D + DmarDevScopeEntry =3D (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(= (UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Get VTd engine number.=0D +**/=0D +UINTN=0D +GetVtdEngineNumber (=0D + VOID=0D + )=0D +{=0D + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;=0D + UINTN VtdIndex;=0D +=0D + VtdIndex =3D 0;=0D + DmarHeader =3D (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable= + 1));=0D + while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Heade= r.Length) {=0D + switch (DmarHeader->Type) {=0D + case EFI_ACPI_DMAR_TYPE_DRHD:=0D + VtdIndex++;=0D + break;=0D + default:=0D + break;=0D + }=0D + DmarHeader =3D (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + = DmarHeader->Length);=0D + }=0D + return VtdIndex ;=0D +}=0D +=0D +/**=0D + Parse DMAR DRHD table.=0D +=0D + @return EFI_SUCCESS The DMAR DRHD table is parsed.=0D +**/=0D +EFI_STATUS=0D +ParseDmarAcpiTableDrhd (=0D + VOID=0D + )=0D +{=0D + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;=0D + EFI_STATUS Status;=0D + UINTN VtdIndex;=0D +=0D + mVtdUnitNumber =3D GetVtdEngineNumber ();=0D + DEBUG ((DEBUG_INFO," VtdUnitNumber - %d\n", mVtdUnitNumber));=0D + ASSERT (mVtdUnitNumber > 0);=0D + if (mVtdUnitNumber =3D=3D 0) {=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + mVtdUnitInformation =3D AllocateZeroPool (sizeof(*mVtdUnitInformation) *= mVtdUnitNumber);=0D + ASSERT (mVtdUnitInformation !=3D NULL);=0D + if (mVtdUnitInformation =3D=3D NULL) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + VtdIndex =3D 0;=0D + DmarHeader =3D (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable= + 1));=0D + while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Heade= r.Length) {=0D + switch (DmarHeader->Type) {=0D + case EFI_ACPI_DMAR_TYPE_DRHD:=0D + ASSERT (VtdIndex < mVtdUnitNumber);=0D + Status =3D ProcessDrhd (VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarH= eader);=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + VtdIndex++;=0D +=0D + break;=0D +=0D + default:=0D + break;=0D + }=0D + DmarHeader =3D (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + = DmarHeader->Length);=0D + }=0D + ASSERT (VtdIndex =3D=3D mVtdUnitNumber);=0D +=0D + for (VtdIndex =3D 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {=0D + VtdLibDumpPciDeviceInfo (NULL, NULL, mVtdUnitInformation[VtdIndex].Pci= DeviceInfo);=0D +=0D + VTdLogAddDataEvent (VTDLOG_DXE_PCI_DEVICE,=0D + mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress,= =0D + mVtdUnitInformation[VtdIndex].PciDeviceInfo,=0D + sizeof (PCI_DEVICE_INFORMATION) + sizeof (PCI_DEVI= CE_DATA) * mVtdUnitInformation[VtdIndex].PciDeviceInfo->PciDeviceDataNumber= );=0D + }=0D + return EFI_SUCCESS ;=0D +}=0D +=0D +/**=0D + Parse DMAR DRHD table.=0D +=0D + @return EFI_SUCCESS The DMAR DRHD table is parsed.=0D +**/=0D +EFI_STATUS=0D +ParseDmarAcpiTableRmrr (=0D + VOID=0D + )=0D +{=0D + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;=0D + EFI_STATUS Status;=0D +=0D + DmarHeader =3D (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable= + 1));=0D + while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Heade= r.Length) {=0D + switch (DmarHeader->Type) {=0D + case EFI_ACPI_DMAR_TYPE_RMRR:=0D + Status =3D ProcessRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + break;=0D + default:=0D + break;=0D + }=0D + DmarHeader =3D (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + = DmarHeader->Length);=0D + }=0D + return EFI_SUCCESS ;=0D +}=0D +=0D +/**=0D + Get the DMAR ACPI table.=0D +=0D + @retval EFI_SUCCESS The DMAR ACPI table is got.=0D + @retval EFI_ALREADY_STARTED The DMAR ACPI table has been got previousl= y.=0D + @retval EFI_NOT_FOUND The DMAR ACPI table is not found.=0D +**/=0D +EFI_STATUS=0D +GetDmarAcpiTable (=0D + VOID=0D + )=0D +{=0D + if (mAcpiDmarTable !=3D NULL) {=0D + return EFI_ALREADY_STARTED;=0D + }=0D +=0D + mAcpiDmarTable =3D (EFI_ACPI_DMAR_HEADER *) EfiLocateFirstAcpiTable (=0D + EFI_ACPI_4_0_DMA_REMAPPING_T= ABLE_SIGNATURE=0D + );=0D + if (mAcpiDmarTable =3D=3D NULL) {=0D + return EFI_NOT_FOUND;=0D + }=0D + DEBUG ((DEBUG_INFO,"DMAR Table - 0x%08x\n", mAcpiDmarTable));=0D + VtdDumpDmarTable();=0D +=0D + return EFI_SUCCESS;=0D +}=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/Inte= lVTdCoreDxe.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/I= ntelVTdCoreDxe.c new file mode 100644 index 000000000..8449b2885 --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/IntelVTdCor= eDxe.c @@ -0,0 +1,412 @@ +/** @file=0D + Intel VTd driver.=0D +=0D + Copyright (c) 2017 - 2023, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include "DmaProtection.h"=0D +=0D +/**=0D + Provides the controller-specific addresses required to access system mem= ory from a=0D + DMA bus master.=0D +=0D + @param This The protocol instance pointer.=0D + @param Operation Indicates if the bus master is going to re= ad or write to system memory.=0D + @param HostAddress The system memory address to map to the PC= I controller.=0D + @param NumberOfBytes On input the number of bytes to map. On ou= tput the number of bytes=0D + that were mapped.=0D + @param DeviceAddress The resulting map address for the bus mast= er PCI controller to use to=0D + access the hosts HostAddress.=0D + @param Mapping A resulting value to pass to Unmap().=0D +=0D + @retval EFI_SUCCESS The range was mapped for the returned Numb= erOfBytes.=0D + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a comm= on buffer.=0D + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.=0D + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to = a lack of resources.=0D + @retval EFI_DEVICE_ERROR The system hardware could not map the requ= ested address.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoMmuMap (=0D + IN EDKII_IOMMU_PROTOCOL *This,=0D + IN EDKII_IOMMU_OPERATION Operation,=0D + IN VOID *HostAddress,=0D + IN OUT UINTN *NumberOfBytes,=0D + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,=0D + OUT VOID **Mapping=0D + );=0D +=0D +/**=0D + Completes the Map() operation and releases any corresponding resources.= =0D +=0D + @param This The protocol instance pointer.=0D + @param Mapping The mapping value returned from Map().=0D +=0D + @retval EFI_SUCCESS The range was unmapped.=0D + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned b= y Map().=0D + @retval EFI_DEVICE_ERROR The data was not committed to the target s= ystem memory.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoMmuUnmap (=0D + IN EDKII_IOMMU_PROTOCOL *This,=0D + IN VOID *Mapping=0D + );=0D +=0D +/**=0D + Allocates pages that are suitable for an OperationBusMasterCommonBuffer = or=0D + OperationBusMasterCommonBuffer64 mapping.=0D +=0D + @param This The protocol instance pointer.=0D + @param Type This parameter is not used and must be ign= ored.=0D + @param MemoryType The type of memory to allocate, EfiBootSer= vicesData or=0D + EfiRuntimeServicesData.=0D + @param Pages The number of pages to allocate.=0D + @param HostAddress A pointer to store the base system memory = address of the=0D + allocated range.=0D + @param Attributes The requested bit mask of attributes for t= he allocated range.=0D +=0D + @retval EFI_SUCCESS The requested memory pages were allocated.= =0D + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal = attribute bits are=0D + MEMORY_WRITE_COMBINE, MEMORY_CACHED and DU= AL_ADDRESS_CYCLE.=0D + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.=0D + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoMmuAllocateBuffer (=0D + IN EDKII_IOMMU_PROTOCOL *This,=0D + IN EFI_ALLOCATE_TYPE Type,=0D + IN EFI_MEMORY_TYPE MemoryType,=0D + IN UINTN Pages,=0D + IN OUT VOID **HostAddress,=0D + IN UINT64 Attributes=0D + );=0D +=0D +/**=0D + Frees memory that was allocated with AllocateBuffer().=0D +=0D + @param This The protocol instance pointer.=0D + @param Pages The number of pages to free.=0D + @param HostAddress The base system memory address of the allo= cated range.=0D +=0D + @retval EFI_SUCCESS The requested memory pages were freed.=0D + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress = and Pages=0D + was not allocated with AllocateBuffer().=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoMmuFreeBuffer (=0D + IN EDKII_IOMMU_PROTOCOL *This,=0D + IN UINTN Pages,=0D + IN VOID *HostAddress=0D + );=0D +=0D +/**=0D + This function fills DeviceHandle/IoMmuAccess to the MAP_HANDLE_INFO,=0D + based upon the DeviceAddress.=0D +=0D + @param[in] DeviceHandle The device who initiates the DMA access re= quest.=0D + @param[in] DeviceAddress The base of device memory address to be us= ed as the DMA memory.=0D + @param[in] Length The length of device memory address to be = used as the DMA memory.=0D + @param[in] IoMmuAccess The IOMMU access.=0D +=0D +**/=0D +VOID=0D +SyncDeviceHandleToMapInfo (=0D + IN EFI_HANDLE DeviceHandle,=0D + IN EFI_PHYSICAL_ADDRESS DeviceAddress,=0D + IN UINT64 Length,=0D + IN UINT64 IoMmuAccess=0D + );=0D +=0D +/**=0D + Convert the DeviceHandle to SourceId and Segment.=0D +=0D + @param[in] DeviceHandle The device who initiates the DMA access re= quest.=0D + @param[out] Segment The Segment used to identify a VTd engine.= =0D + @param[out] SourceId The SourceId used to identify a VTd engine= and table entry.=0D +=0D + @retval EFI_SUCCESS The Segment and SourceId are returned.=0D + @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle.=0D + @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU.=0D +**/=0D +EFI_STATUS=0D +DeviceHandleToSourceId (=0D + IN EFI_HANDLE DeviceHandle,=0D + OUT UINT16 *Segment,=0D + OUT VTD_SOURCE_ID *SourceId=0D + )=0D +{=0D + EFI_PCI_IO_PROTOCOL *PciIo;=0D + UINTN Seg;=0D + UINTN Bus;=0D + UINTN Dev;=0D + UINTN Func;=0D + EFI_STATUS Status;=0D + EDKII_PLATFORM_VTD_DEVICE_INFO DeviceInfo;=0D +=0D + Status =3D EFI_NOT_FOUND;=0D + if (mPlatformVTdPolicy !=3D NULL) {=0D + Status =3D mPlatformVTdPolicy->GetDeviceId (mPlatformVTdPolicy, Device= Handle, &DeviceInfo);=0D + if (!EFI_ERROR(Status)) {=0D + *Segment =3D DeviceInfo.Segment;=0D + *SourceId =3D DeviceInfo.SourceId;=0D + return EFI_SUCCESS;=0D + }=0D + }=0D +=0D + Status =3D gBS->HandleProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, (V= OID **)&PciIo);=0D + if (EFI_ERROR(Status)) {=0D + return EFI_UNSUPPORTED;=0D + }=0D + Status =3D PciIo->GetLocation (PciIo, &Seg, &Bus, &Dev, &Func);=0D + if (EFI_ERROR(Status)) {=0D + return EFI_UNSUPPORTED;=0D + }=0D + *Segment =3D (UINT16)Seg;=0D + SourceId->Bits.Bus =3D (UINT8)Bus;=0D + SourceId->Bits.Device =3D (UINT8)Dev;=0D + SourceId->Bits.Function =3D (UINT8)Func;=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Set IOMMU attribute for a system memory.=0D +=0D + If the IOMMU protocol exists, the system memory cannot be used=0D + for DMA by default.=0D +=0D + When a device requests a DMA access for a system memory,=0D + the device driver need use SetAttribute() to update the IOMMU=0D + attribute to request DMA access (read and/or write).=0D +=0D + The DeviceHandle is used to identify which device submits the request.=0D + The IOMMU implementation need translate the device path to an IOMMU devi= ce ID,=0D + and set IOMMU hardware register accordingly.=0D + 1) DeviceHandle can be a standard PCI device.=0D + The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ.=0D + The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE.=0D + The memory for BusMasterCommonBuffer need set EDKII_IOMMU_ACCESS_READ= |EDKII_IOMMU_ACCESS_WRITE.=0D + After the memory is used, the memory need set 0 to keep it being prot= ected.=0D + 2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc).=0D + The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or EDK= II_IOMMU_ACCESS_WRITE.=0D +=0D + @param[in] This The protocol instance pointer.=0D + @param[in] DeviceHandle The device who initiates the DMA access re= quest.=0D + @param[in] DeviceAddress The base of device memory address to be us= ed as the DMA memory.=0D + @param[in] Length The length of device memory address to be = used as the DMA memory.=0D + @param[in] IoMmuAccess The IOMMU access.=0D +=0D + @retval EFI_SUCCESS The IoMmuAccess is set for the memory ran= ge specified by DeviceAddress and Length.=0D + @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle.=0D + @retval EFI_INVALID_PARAMETER DeviceAddress is not IoMmu Page size alig= ned.=0D + @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.=0D + @retval EFI_INVALID_PARAMETER Length is 0.=0D + @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combinat= ion of access.=0D + @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU.=0D + @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not suppor= ted by the IOMMU.=0D + @retval EFI_UNSUPPORTED The IOMMU does not support the memory ran= ge specified by DeviceAddress and Length.=0D + @retval EFI_OUT_OF_RESOURCES There are not enough resources available = to modify the IOMMU access.=0D + @retval EFI_DEVICE_ERROR The IOMMU device reported an error while = attempting the operation.=0D +=0D +**/=0D +EFI_STATUS=0D +VTdSetAttribute (=0D + IN EDKII_IOMMU_PROTOCOL *This,=0D + IN EFI_HANDLE DeviceHandle,=0D + IN EFI_PHYSICAL_ADDRESS DeviceAddress,=0D + IN UINT64 Length,=0D + IN UINT64 IoMmuAccess=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINT16 Segment;=0D + VTD_SOURCE_ID SourceId;=0D + CHAR8 PerfToken[sizeof("VTD(S0000.B00.D00.F00)")];= =0D + UINT32 Identifier;=0D + VTD_PROTOCOL_SET_ATTRIBUTE LogSetAttribute;=0D +=0D + DumpVtdIfError ();=0D +=0D + Status =3D DeviceHandleToSourceId (DeviceHandle, &Segment, &SourceId);=0D + if (EFI_ERROR(Status)) {=0D + return Status;=0D + }=0D +=0D + DEBUG ((DEBUG_VERBOSE, "IoMmuSetAttribute: "));=0D + DEBUG ((DEBUG_VERBOSE, "PCI(S%x.B%x.D%x.F%x) ", Segment, SourceId.Bits.B= us, SourceId.Bits.Device, SourceId.Bits.Function));=0D + DEBUG ((DEBUG_VERBOSE, "(0x%lx~0x%lx) - %lx\n", DeviceAddress, Length, I= oMmuAccess));=0D +=0D + if (mAcpiDmarTable =3D=3D NULL) {=0D + //=0D + // Record the entry to driver global variable.=0D + // As such once VTd is activated, the setting can be adopted.=0D + //=0D + if ((PcdGet8 (PcdVTdPolicyPropertyMask) & BIT2) !=3D 0) {=0D + //=0D + // Force no IOMMU access attribute request recording before DMAR tab= le is installed.=0D + //=0D + ASSERT_EFI_ERROR (EFI_NOT_READY);=0D + return EFI_NOT_READY;=0D + }=0D + Status =3D RequestAccessAttribute (Segment, SourceId, DeviceAddress, L= ength, IoMmuAccess);=0D + } else {=0D + PERF_CODE (=0D + AsciiSPrint (PerfToken, sizeof(PerfToken), "S%04xB%02xD%02xF%01x", S= egment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function);=0D + Identifier =3D (Segment << 16) | SourceId.Uint16;=0D + PERF_START_EX (gImageHandle, PerfToken, "IntelVTD", 0, Identifier);= =0D + );=0D +=0D + Status =3D SetAccessAttribute (Segment, SourceId, DeviceAddress, Lengt= h, IoMmuAccess);=0D +=0D + PERF_CODE (=0D + Identifier =3D (Segment << 16) | SourceId.Uint16;=0D + PERF_END_EX (gImageHandle, PerfToken, "IntelVTD", 0, Identifier);=0D + );=0D + }=0D +=0D + if (!EFI_ERROR(Status)) {=0D + SyncDeviceHandleToMapInfo (=0D + DeviceHandle,=0D + DeviceAddress,=0D + Length,=0D + IoMmuAccess=0D + );=0D + }=0D +=0D + LogSetAttribute.SourceId.Uint16 =3D SourceId.Uint16;=0D + LogSetAttribute.DeviceAddress =3D DeviceAddress;=0D + LogSetAttribute.Length =3D Length;=0D + LogSetAttribute.IoMmuAccess =3D IoMmuAccess;=0D + LogSetAttribute.Status =3D Status;=0D + VTdLogAddDataEvent (VTDLOG_DXE_IOMMU_SET_ATTRIBUTE, 0, &LogSetAttribute,= sizeof (VTD_PROTOCOL_SET_ATTRIBUTE));=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + Set IOMMU attribute for a system memory.=0D +=0D + If the IOMMU protocol exists, the system memory cannot be used=0D + for DMA by default.=0D +=0D + When a device requests a DMA access for a system memory,=0D + the device driver need use SetAttribute() to update the IOMMU=0D + attribute to request DMA access (read and/or write).=0D +=0D + The DeviceHandle is used to identify which device submits the request.=0D + The IOMMU implementation need translate the device path to an IOMMU devi= ce ID,=0D + and set IOMMU hardware register accordingly.=0D + 1) DeviceHandle can be a standard PCI device.=0D + The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ.=0D + The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE.=0D + The memory for BusMasterCommonBuffer need set EDKII_IOMMU_ACCESS_READ= |EDKII_IOMMU_ACCESS_WRITE.=0D + After the memory is used, the memory need set 0 to keep it being prot= ected.=0D + 2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc).=0D + The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or EDK= II_IOMMU_ACCESS_WRITE.=0D +=0D + @param[in] This The protocol instance pointer.=0D + @param[in] DeviceHandle The device who initiates the DMA access re= quest.=0D + @param[in] Mapping The mapping value returned from Map().=0D + @param[in] IoMmuAccess The IOMMU access.=0D +=0D + @retval EFI_SUCCESS The IoMmuAccess is set for the memory ran= ge specified by DeviceAddress and Length.=0D + @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle.=0D + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned = by Map().=0D + @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combinat= ion of access.=0D + @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU.=0D + @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not suppor= ted by the IOMMU.=0D + @retval EFI_UNSUPPORTED The IOMMU does not support the memory ran= ge specified by Mapping.=0D + @retval EFI_OUT_OF_RESOURCES There are not enough resources available = to modify the IOMMU access.=0D + @retval EFI_DEVICE_ERROR The IOMMU device reported an error while = attempting the operation.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IoMmuSetAttribute (=0D + IN EDKII_IOMMU_PROTOCOL *This,=0D + IN EFI_HANDLE DeviceHandle,=0D + IN VOID *Mapping,=0D + IN UINT64 IoMmuAccess=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_PHYSICAL_ADDRESS DeviceAddress;=0D + UINTN NumberOfPages;=0D + EFI_TPL OriginalTpl;=0D +=0D + OriginalTpl =3D gBS->RaiseTPL (VTD_TPL_LEVEL);=0D +=0D + Status =3D GetDeviceInfoFromMapping (Mapping, &DeviceAddress, &NumberOfP= ages);=0D + if (!EFI_ERROR(Status)) {=0D + Status =3D VTdSetAttribute (=0D + This,=0D + DeviceHandle,=0D + DeviceAddress,=0D + EFI_PAGES_TO_SIZE(NumberOfPages),=0D + IoMmuAccess=0D + );=0D + }=0D +=0D + gBS->RestoreTPL (OriginalTpl);=0D +=0D + return Status;=0D +}=0D +=0D +EDKII_IOMMU_PROTOCOL mIntelVTd =3D {=0D + EDKII_IOMMU_PROTOCOL_REVISION,=0D + IoMmuSetAttribute,=0D + IoMmuMap,=0D + IoMmuUnmap,=0D + IoMmuAllocateBuffer,=0D + IoMmuFreeBuffer,=0D +};=0D +=0D +/**=0D + Initialize the VTd driver.=0D +=0D + @param[in] ImageHandle ImageHandle of the loaded driver=0D + @param[in] SystemTable Pointer to the System Table=0D +=0D + @retval EFI_SUCCESS The Protocol is installed.=0D + @retval EFI_OUT_OF_RESOURCES Not enough resources available to initial= ize driver.=0D + @retval EFI_DEVICE_ERROR A device error occurred attempting to ini= tialize the driver.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IntelVTdInitialize (=0D + IN EFI_HANDLE ImageHandle,=0D + IN EFI_SYSTEM_TABLE *SystemTable=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_HANDLE Handle;=0D +=0D + if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) =3D=3D 0) {=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + VTdLogInitialize ();=0D +=0D + InitializeDmaProtection ();=0D +=0D + Handle =3D NULL;=0D + Status =3D gBS->InstallMultipleProtocolInterfaces (=0D + &Handle,=0D + &gEdkiiIoMmuProtocolGuid, &mIntelVTd,=0D + NULL=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + VTdLogAddEvent (VTDLOG_DXE_INSTALL_IOMMU_PROTOCOL, Status, 0);=0D +=0D + return Status;=0D +}=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/Inte= lVTdCoreDxe.inf b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe= /IntelVTdCoreDxe.inf new file mode 100644 index 000000000..210d6963f --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/IntelVTdCor= eDxe.inf @@ -0,0 +1,93 @@ +## @file=0D +# Intel VTd DXE Driver.=0D +#=0D +# This driver initializes VTd engine based upon DMAR ACPI tables=0D +# and provide DMA protection to PCI or ACPI device.=0D +#=0D +# Copyright (c) 2017 - 2023, Intel Corporation. All rights reserved.
=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010005=0D + BASE_NAME =3D IntelVTdCoreDxe=0D + MODULE_UNI_FILE =3D IntelVTdCoreDxe.uni=0D + FILE_GUID =3D 5c83381f-34d3-4672-b8f3-83c3d6f3b00e= =0D + MODULE_TYPE =3D DXE_DRIVER=0D + VERSION_STRING =3D 1.0=0D + ENTRY_POINT =3D IntelVTdInitialize=0D +=0D +#=0D +# The following information is for reference only and not required by the = build tools.=0D +#=0D +# VALID_ARCHITECTURES =3D IA32 X64 EBC=0D +#=0D +#=0D +=0D +[Sources]=0D + IntelVTdCoreDxe.c=0D + BmDma.c=0D + DmaProtection.c=0D + DmaProtection.h=0D + DmarAcpiTable.c=0D + PciInfo.c=0D + TranslationTable.c=0D + TranslationTableEx.c=0D + VtdLog.c=0D + VtdReg.c=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + MdeModulePkg/MdeModulePkg.dec=0D + IntelSiliconPkg/IntelSiliconPkg.dec=0D +=0D +[LibraryClasses]=0D + DebugLib=0D + UefiDriverEntryPoint=0D + UefiBootServicesTableLib=0D + BaseLib=0D + IoLib=0D + HobLib=0D + PciSegmentLib=0D + BaseMemoryLib=0D + MemoryAllocationLib=0D + UefiLib=0D + CacheMaintenanceLib=0D + PerformanceLib=0D + PrintLib=0D + ReportStatusCodeLib=0D + IntelVTdPeiDxeLib=0D +=0D +[Guids]=0D + gVTdLogBufferHobGuid ## CONSUMES=0D + gEfiEventExitBootServicesGuid ## CONSUMES ## Event=0D + ## CONSUMES ## SystemTable=0D + ## CONSUMES ## Event=0D + gEfiAcpi20TableGuid=0D + ## CONSUMES ## SystemTable=0D + ## CONSUMES ## Event=0D + gEfiAcpi10TableGuid=0D +=0D +[Protocols]=0D + gEdkiiIoMmuProtocolGuid ## PRODUCES=0D + gEfiPciIoProtocolGuid ## CONSUMES=0D + gEfiPciEnumerationCompleteProtocolGuid ## CONSUMES=0D + gEdkiiPlatformVTdPolicyProtocolGuid ## SOMETIMES_CONSUMES=0D + gEfiPciRootBridgeIoProtocolGuid ## CONSUMES=0D + gEdkiiVTdLogProtocolGuid ## PRODUCES=0D +=0D +[Pcd]=0D + gIntelSiliconPkgTokenSpaceGuid.PcdVTdPolicyPropertyMask ## CONSUMES=0D + gIntelSiliconPkgTokenSpaceGuid.PcdErrorCodeVTdError ## CONSUMES=0D + gIntelSiliconPkgTokenSpaceGuid.PcdVTdSupportAbortDmaMode ## CONSUMES=0D + gIntelSiliconPkgTokenSpaceGuid.PcdVTdLogLevel ## CONSUME= S=0D + gIntelSiliconPkgTokenSpaceGuid.PcdVTdPeiPostMemLogBufferSize ## CONSUME= S=0D + gIntelSiliconPkgTokenSpaceGuid.PcdVTdDxeLogBufferSize ## CONSUME= S=0D +=0D +[Depex]=0D + gEfiPciRootBridgeIoProtocolGuid=0D +=0D +[UserExtensions.TianoCore."ExtraFiles"]=0D + IntelVTdCoreDxeExtra.uni=0D +=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/Inte= lVTdCoreDxe.uni b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe= /IntelVTdCoreDxe.uni new file mode 100644 index 000000000..73d2c83c4 --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/IntelVTdCor= eDxe.uni @@ -0,0 +1,14 @@ +// /** @file=0D +// IntelVTdDxe Module Localized Abstract and Description Content=0D +//=0D +// Copyright (c) 2017, Intel Corporation. All rights reserved.
=0D +//=0D +// SPDX-License-Identifier: BSD-2-Clause-Patent=0D +//=0D +// **/=0D +=0D +=0D +#string STR_MODULE_ABSTRACT #language en-US "Intel VTd CORE DX= E Driver."=0D +=0D +#string STR_MODULE_DESCRIPTION #language en-US "This driver initi= alizes VTd engine based upon DMAR ACPI tables and provide DMA protection to= PCI or ACPI device."=0D +=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/Inte= lVTdCoreDxeExtra.uni b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCo= reDxe/IntelVTdCoreDxeExtra.uni new file mode 100644 index 000000000..7f1aec65e --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/IntelVTdCor= eDxeExtra.uni @@ -0,0 +1,14 @@ +// /** @file=0D +// IntelVTdDxe Localized Strings and Content=0D +//=0D +// Copyright (c) 2017, Intel Corporation. All rights reserved.
=0D +//=0D +// SPDX-License-Identifier: BSD-2-Clause-Patent=0D +//=0D +// **/=0D +=0D +#string STR_PROPERTIES_MODULE_NAME=0D +#language en-US=0D +"Intel VTd CORE DXE Driver"=0D +=0D +=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/PciI= nfo.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/PciInfo.c new file mode 100644 index 000000000..0eb832d6e --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/PciInfo.c @@ -0,0 +1,418 @@ +/** @file=0D +=0D + Copyright (c) 2017 - 2023, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include "DmaProtection.h"=0D +=0D +/**=0D + Return the index of PCI data.=0D +=0D + @param[in] VtdIndex The index used to identify a VTd engine.=0D + @param[in] Segment The Segment used to identify a VTd engine.= =0D + @param[in] SourceId The SourceId used to identify a VTd engine= and table entry.=0D +=0D + @return The index of the PCI data.=0D + @retval (UINTN)-1 The PCI data is not found.=0D +**/=0D +UINTN=0D +GetPciDataIndex (=0D + IN UINTN VtdIndex,=0D + IN UINT16 Segment,=0D + IN VTD_SOURCE_ID SourceId=0D + )=0D +{=0D + UINTN Index;=0D + VTD_SOURCE_ID *PciSourceId;=0D +=0D + if (Segment !=3D mVtdUnitInformation[VtdIndex].Segment) {=0D + return (UINTN)-1;=0D + }=0D +=0D + for (Index =3D 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo->P= ciDeviceDataNumber; Index++) {=0D + PciSourceId =3D &mVtdUnitInformation[VtdIndex].PciDeviceInfo->PciDevic= eData[Index].PciSourceId;=0D + if ((PciSourceId->Bits.Bus =3D=3D SourceId.Bits.Bus) &&=0D + (PciSourceId->Bits.Device =3D=3D SourceId.Bits.Device) &&=0D + (PciSourceId->Bits.Function =3D=3D SourceId.Bits.Function) ) {=0D + return Index;=0D + }=0D + }=0D +=0D + return (UINTN)-1;=0D +}=0D +=0D +/**=0D + Register PCI device to VTd engine.=0D +=0D + @param[in] VtdIndex The index of VTd engine.=0D + @param[in] Segment The segment of the source.=0D + @param[in] SourceId The SourceId of the source.=0D + @param[in] DeviceType The DMAR device scope type.=0D + @param[in] CheckExist TRUE: ERROR will be returned if the PC= I device is already registered.=0D + FALSE: SUCCESS will be returned if the= PCI device is registered.=0D +=0D + @retval EFI_SUCCESS The PCI device is registered.=0D + @retval EFI_OUT_OF_RESOURCES No enough resource to register a new PCI d= evice.=0D + @retval EFI_ALREADY_STARTED The device is already registered.=0D +**/=0D +EFI_STATUS=0D +RegisterPciDevice (=0D + IN UINTN VtdIndex,=0D + IN UINT16 Segment,=0D + IN VTD_SOURCE_ID SourceId,=0D + IN UINT8 DeviceType,=0D + IN BOOLEAN CheckExist=0D + )=0D +{=0D + PCI_DEVICE_INFORMATION *PciDeviceInfo;=0D + VTD_SOURCE_ID *PciSourceId;=0D + UINTN PciDataIndex;=0D + UINTN Index;=0D + PCI_DEVICE_INFORMATION *NewPciDeviceInfo;=0D + EDKII_PLATFORM_VTD_PCI_DEVICE_ID *PciDeviceId;=0D +=0D + PciDeviceInfo =3D mVtdUnitInformation[VtdIndex].PciDeviceInfo;=0D +=0D + if (PciDeviceInfo->IncludeAllFlag) {=0D + //=0D + // Do not register device in other VTD Unit=0D + //=0D + for (Index =3D 0; Index < VtdIndex; Index++) {=0D + PciDataIndex =3D GetPciDataIndex (Index, Segment, SourceId);=0D + if (PciDataIndex !=3D (UINTN)-1) {=0D + DEBUG ((DEBUG_INFO, " RegisterPciDevice: PCI S%04x B%02x D%02x F%= 02x already registered by Other Vtd(%d)\n", Segment, SourceId.Bits.Bus, Sou= rceId.Bits.Device, SourceId.Bits.Function, Index));=0D + return EFI_SUCCESS;=0D + }=0D + }=0D + }=0D +=0D + PciDataIndex =3D GetPciDataIndex (VtdIndex, Segment, SourceId);=0D + if (PciDataIndex =3D=3D (UINTN)-1) {=0D + //=0D + // Register new=0D + //=0D +=0D + if (PciDeviceInfo->PciDeviceDataNumber >=3D PciDeviceInfo->PciDeviceDa= taMaxNumber) {=0D + //=0D + // Reallocate=0D + //=0D + NewPciDeviceInfo =3D AllocateZeroPool (sizeof (PCI_DEVICE_INFORMATIO= N) + sizeof (PCI_DEVICE_DATA) * (PciDeviceInfo->PciDeviceDataMaxNumber + MA= X_VTD_PCI_DATA_NUMBER));=0D + if (NewPciDeviceInfo =3D=3D NULL) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + CopyMem (NewPciDeviceInfo, PciDeviceInfo, sizeof (PCI_DEVICE_INFORMA= TION) + sizeof (PCI_DEVICE_DATA) * (PciDeviceInfo->PciDeviceDataMaxNumber += MAX_VTD_PCI_DATA_NUMBER));=0D + FreePool (PciDeviceInfo);=0D +=0D + NewPciDeviceInfo->PciDeviceDataMaxNumber +=3D MAX_VTD_PCI_DATA_NUMBE= R;=0D + mVtdUnitInformation[VtdIndex].PciDeviceInfo =3D NewPciDeviceInfo;=0D + PciDeviceInfo =3D NewPciDeviceInfo;=0D + }=0D +=0D + ASSERT (PciDeviceInfo->PciDeviceDataNumber < PciDeviceInfo->PciDeviceD= ataMaxNumber);=0D +=0D + PciSourceId =3D &PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDevice= DataNumber].PciSourceId;=0D + PciSourceId->Bits.Bus =3D SourceId.Bits.Bus;=0D + PciSourceId->Bits.Device =3D SourceId.Bits.Device;=0D + PciSourceId->Bits.Function =3D SourceId.Bits.Function;=0D +=0D + DEBUG ((DEBUG_INFO, " RegisterPciDevice: PCI S%04x B%02x D%02x F%02x"= , Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function)= );=0D +=0D + PciDeviceId =3D &PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDevice= DataNumber].PciDeviceId;=0D + if ((DeviceType =3D=3D EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) = ||=0D + (DeviceType =3D=3D EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE)) {= =0D + PciDeviceId->VendorId =3D PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRES= S(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function,= PCI_VENDOR_ID_OFFSET));=0D + PciDeviceId->DeviceId =3D PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRES= S(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function,= PCI_DEVICE_ID_OFFSET));=0D + PciDeviceId->RevisionId =3D PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS= (Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, = PCI_REVISION_ID_OFFSET));=0D +=0D + DEBUG ((DEBUG_INFO, " (%04x:%04x:%02x", PciDeviceId->VendorId, PciDe= viceId->DeviceId, PciDeviceId->RevisionId));=0D +=0D + if (DeviceType =3D=3D EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT)= {=0D + PciDeviceId->SubsystemVendorId =3D PciSegmentRead16 (PCI_SEGMENT_L= IB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.= Function, PCI_SUBSYSTEM_VENDOR_ID_OFFSET));=0D + PciDeviceId->SubsystemDeviceId =3D PciSegmentRead16 (PCI_SEGMENT_L= IB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.= Function, PCI_SUBSYSTEM_ID_OFFSET));=0D + DEBUG ((DEBUG_INFO, ":%04x:%04x", PciDeviceId->SubsystemVendorId, = PciDeviceId->SubsystemDeviceId));=0D + }=0D + DEBUG ((DEBUG_INFO, ")"));=0D + }=0D +=0D + PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDeviceDataNumber].Devic= eType =3D DeviceType;=0D +=0D + if ((DeviceType !=3D EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) &&= =0D + (DeviceType !=3D EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE)) {=0D + DEBUG ((DEBUG_INFO, " (*)"));=0D + }=0D + DEBUG ((DEBUG_INFO, "\n"));=0D +=0D + PciDeviceInfo->PciDeviceDataNumber++;=0D + } else {=0D + if (CheckExist) {=0D + DEBUG ((DEBUG_INFO, " RegisterPciDevice: PCI S%04x B%02x D%02x F%02= x already registered\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, = SourceId.Bits.Function));=0D + return EFI_ALREADY_STARTED;=0D + }=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + The scan bus callback function to register PCI device.=0D +=0D + @param[in] Context The context of the callback.=0D + @param[in] Segment The segment of the source.=0D + @param[in] Bus The bus of the source.=0D + @param[in] Device The device of the source.=0D + @param[in] Function The function of the source.=0D +=0D + @retval EFI_SUCCESS The PCI device is registered.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +ScanBusCallbackRegisterPciDevice (=0D + IN VOID *Context,=0D + IN UINT16 Segment,=0D + IN UINT8 Bus,=0D + IN UINT8 Device,=0D + IN UINT8 Function=0D + )=0D +{=0D + VTD_SOURCE_ID SourceId;=0D + UINTN VtdIndex;=0D + UINT8 BaseClass;=0D + UINT8 SubClass;=0D + UINT8 DeviceType;=0D + EFI_STATUS Status;=0D +=0D + VtdIndex =3D (UINTN)Context;=0D + SourceId.Bits.Bus =3D Bus;=0D + SourceId.Bits.Device =3D Device;=0D + SourceId.Bits.Function =3D Function;=0D +=0D + DeviceType =3D EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT;=0D + BaseClass =3D PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Dev= ice, Function, PCI_CLASSCODE_OFFSET + 2));=0D + if (BaseClass =3D=3D PCI_CLASS_BRIDGE) {=0D + SubClass =3D PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, De= vice, Function, PCI_CLASSCODE_OFFSET + 1));=0D + if (SubClass =3D=3D PCI_CLASS_BRIDGE_P2P) {=0D + DeviceType =3D EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE;=0D + }=0D + }=0D +=0D + Status =3D RegisterPciDevice (VtdIndex, Segment, SourceId, DeviceType, F= ALSE);=0D + return Status;=0D +}=0D +=0D +/**=0D + Scan PCI bus and invoke callback function for each PCI devices under the= bus.=0D +=0D + @param[in] Context The context of the callback function.= =0D + @param[in] Segment The segment of the source.=0D + @param[in] Bus The bus of the source.=0D + @param[in] Callback The callback function in PCI scan.=0D +=0D + @retval EFI_SUCCESS The PCI devices under the bus are scaned.= =0D +**/=0D +EFI_STATUS=0D +ScanPciBus (=0D + IN VOID *Context,=0D + IN UINT16 Segment,=0D + IN UINT8 Bus,=0D + IN SCAN_BUS_FUNC_CALLBACK_FUNC Callback=0D + )=0D +{=0D + UINT8 Device;=0D + UINT8 Function;=0D + UINT8 SecondaryBusNumber;=0D + UINT8 HeaderType;=0D + UINT8 BaseClass;=0D + UINT8 SubClass;=0D + UINT16 VendorID;=0D + UINT16 DeviceID;=0D + EFI_STATUS Status;=0D +=0D + // Scan the PCI bus for devices=0D + for (Device =3D 0; Device <=3D PCI_MAX_DEVICE; Device++) {=0D + for (Function =3D 0; Function <=3D PCI_MAX_FUNC; Function++) {=0D + VendorID =3D PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus= , Device, Function, PCI_VENDOR_ID_OFFSET));=0D + DeviceID =3D PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus= , Device, Function, PCI_DEVICE_ID_OFFSET));=0D + if (VendorID =3D=3D 0xFFFF && DeviceID =3D=3D 0xFFFF) {=0D + if (Function =3D=3D 0) {=0D + //=0D + // If function 0 is not implemented, do not scan other functions= .=0D + //=0D + break;=0D + }=0D + continue;=0D + }=0D +=0D + Status =3D Callback (Context, Segment, Bus, Device, Function);=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D +=0D + BaseClass =3D PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus,= Device, Function, PCI_CLASSCODE_OFFSET + 2));=0D + if (BaseClass =3D=3D PCI_CLASS_BRIDGE) {=0D + SubClass =3D PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus= , Device, Function, PCI_CLASSCODE_OFFSET + 1));=0D + if (SubClass =3D=3D PCI_CLASS_BRIDGE_P2P) {=0D + SecondaryBusNumber =3D PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(= Segment, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));= =0D + DEBUG ((DEBUG_INFO," ScanPciBus: PCI bridge S%04x B%02x D%02x F= %02x (SecondBus:%02x)\n", Segment, Bus, Device, Function, SecondaryBusNumbe= r));=0D + if (SecondaryBusNumber !=3D 0) {=0D + Status =3D ScanPciBus (Context, Segment, SecondaryBusNumber, C= allback);=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + }=0D + }=0D + }=0D +=0D + if (Function =3D=3D 0) {=0D + HeaderType =3D PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, B= us, Device, 0, PCI_HEADER_TYPE_OFFSET));=0D + if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) =3D=3D 0x00) {=0D + //=0D + // It is not a multi-function device, do not scan other function= s.=0D + //=0D + break;=0D + }=0D + }=0D + }=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Scan PCI bus and invoke callback function for each PCI devices under all= root bus.=0D +=0D + @param[in] Context The context of the callback function.= =0D + @param[in] Segment The segment of the source.=0D + @param[in] Callback The callback function in PCI scan.=0D +=0D + @retval EFI_SUCCESS The PCI devices under the bus are scaned.= =0D +**/=0D +EFI_STATUS=0D +ScanAllPciBus (=0D + IN VOID *Context,=0D + IN UINT16 Segment,=0D + IN SCAN_BUS_FUNC_CALLBACK_FUNC Callback=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN Index;=0D + UINTN HandleCount;=0D + EFI_HANDLE *HandleBuffer;=0D + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;=0D + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;=0D +=0D + DEBUG ((DEBUG_INFO, "ScanAllPciBus ()\n"));=0D +=0D + Status =3D gBS->LocateHandleBuffer (=0D + ByProtocol,=0D + &gEfiPciRootBridgeIoProtocolGuid,=0D + NULL,=0D + &HandleCount,=0D + &HandleBuffer=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + DEBUG ((DEBUG_INFO,"Find %d root bridges\n", HandleCount));=0D +=0D + for (Index =3D 0; Index < HandleCount; Index++) {=0D + Status =3D gBS->HandleProtocol (=0D + HandleBuffer[Index],=0D + &gEfiPciRootBridgeIoProtocolGuid,=0D + (VOID **) &PciRootBridgeIo=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) = &Descriptors);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + while (Descriptors->Desc !=3D ACPI_END_TAG_DESCRIPTOR) {=0D + if (Descriptors->ResType =3D=3D ACPI_ADDRESS_SPACE_TYPE_BUS) {=0D + break;=0D + }=0D + Descriptors++;=0D + }=0D +=0D + if (Descriptors->Desc =3D=3D ACPI_END_TAG_DESCRIPTOR) {=0D + continue;=0D + }=0D +=0D + DEBUG ((DEBUG_INFO,"Scan root bridges : %d, Segment : %d, Bus : 0x%02X= \n", Index, PciRootBridgeIo->SegmentNumber, Descriptors->AddrRangeMin));=0D + Status =3D ScanPciBus(Context, (UINT16) PciRootBridgeIo->SegmentNumber= , (UINT8) Descriptors->AddrRangeMin, Callback);=0D + if (EFI_ERROR (Status)) {=0D + break;=0D + }=0D + }=0D +=0D + FreePool(HandleBuffer);=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + Find the VTd index by the Segment and SourceId.=0D +=0D + @param[in] Segment The segment of the source.=0D + @param[in] SourceId The SourceId of the source.=0D + @param[out] ExtContextEntry The ExtContextEntry of the source.=0D + @param[out] ContextEntry The ContextEntry of the source.=0D +=0D + @return The index of the VTd engine.=0D + @retval (UINTN)-1 The VTd engine is not found.=0D +**/=0D +UINTN=0D +FindVtdIndexByPciDevice (=0D + IN UINT16 Segment,=0D + IN VTD_SOURCE_ID SourceId,=0D + OUT VTD_EXT_CONTEXT_ENTRY **ExtContextEntry,=0D + OUT VTD_CONTEXT_ENTRY **ContextEntry=0D + )=0D +{=0D + UINTN VtdIndex;=0D + VTD_ROOT_ENTRY *RootEntry;=0D + VTD_CONTEXT_ENTRY *ContextEntryTable;=0D + VTD_CONTEXT_ENTRY *ThisContextEntry;=0D + VTD_EXT_ROOT_ENTRY *ExtRootEntry;=0D + VTD_EXT_CONTEXT_ENTRY *ExtContextEntryTable;=0D + VTD_EXT_CONTEXT_ENTRY *ThisExtContextEntry;=0D + UINTN PciDataIndex;=0D +=0D + for (VtdIndex =3D 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {=0D + if (Segment !=3D mVtdUnitInformation[VtdIndex].Segment) {=0D + continue;=0D + }=0D +=0D + PciDataIndex =3D GetPciDataIndex (VtdIndex, Segment, SourceId);=0D + if (PciDataIndex =3D=3D (UINTN)-1) {=0D + continue;=0D + }=0D +=0D +// DEBUG ((DEBUG_INFO,"FindVtdIndex(0x%x) for S%04x B%02x D%02x F%02x\n= ", VtdIndex, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bit= s.Function));=0D +=0D + if (mVtdUnitInformation[VtdIndex].ExtRootEntryTable !=3D 0) {=0D + ExtRootEntry =3D &mVtdUnitInformation[VtdIndex].ExtRootEntryTable[So= urceId.Index.RootIndex];=0D + ExtContextEntryTable =3D (VTD_EXT_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_= ADDRESS(ExtRootEntry->Bits.LowerContextTablePointerLo, ExtRootEntry->Bits.L= owerContextTablePointerHi) ;=0D + ThisExtContextEntry =3D &ExtContextEntryTable[SourceId.Index.Contex= tIndex];=0D + if (ThisExtContextEntry->Bits.AddressWidth =3D=3D 0) {=0D + continue;=0D + }=0D + *ExtContextEntry =3D ThisExtContextEntry;=0D + *ContextEntry =3D NULL;=0D + } else {=0D + RootEntry =3D &mVtdUnitInformation[VtdIndex].RootEntryTable[SourceId= .Index.RootIndex];=0D + ContextEntryTable =3D (VTD_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS= (RootEntry->Bits.ContextTablePointerLo, RootEntry->Bits.ContextTablePointer= Hi) ;=0D + ThisContextEntry =3D &ContextEntryTable[SourceId.Index.ContextIndex= ];=0D + if (ThisContextEntry->Bits.AddressWidth =3D=3D 0) {=0D + continue;=0D + }=0D + *ExtContextEntry =3D NULL;=0D + *ContextEntry =3D ThisContextEntry;=0D + }=0D +=0D + return VtdIndex;=0D + }=0D +=0D + return (UINTN)-1;=0D +}=0D +=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/Tran= slationTable.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/= TranslationTable.c new file mode 100644 index 000000000..37ca6e405 --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/Translation= Table.c @@ -0,0 +1,1112 @@ +/** @file=0D +=0D + Copyright (c) 2017 - 2023, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include "DmaProtection.h"=0D +=0D +/**=0D + Create extended context entry.=0D +=0D + @param[in] VtdIndex The index of the VTd engine.=0D +=0D + @retval EFI_SUCCESS The extended context entry is created.=0D + @retval EFI_OUT_OF_RESOURCE No enough resource to create extended conte= xt entry.=0D +**/=0D +EFI_STATUS=0D +CreateExtContextEntry (=0D + IN UINTN VtdIndex=0D + );=0D +=0D +/**=0D + Allocate zero pages.=0D +=0D + @param[in] Pages the number of pages.=0D +=0D + @return the page address.=0D + @retval NULL No resource to allocate pages.=0D +**/=0D +VOID *=0D +EFIAPI=0D +AllocateZeroPages (=0D + IN UINTN Pages=0D + )=0D +{=0D + VOID *Addr;=0D +=0D + Addr =3D AllocatePages (Pages);=0D + if (Addr =3D=3D NULL) {=0D + return NULL;=0D + }=0D + ZeroMem (Addr, EFI_PAGES_TO_SIZE(Pages));=0D + return Addr;=0D +}=0D +=0D +/**=0D + Set second level paging entry attribute based upon IoMmuAccess.=0D +=0D + @param[in] PtEntry The paging entry.=0D + @param[in] IoMmuAccess The IOMMU access.=0D +**/=0D +VOID=0D +SetSecondLevelPagingEntryAttribute (=0D + IN VTD_SECOND_LEVEL_PAGING_ENTRY *PtEntry,=0D + IN UINT64 IoMmuAccess=0D + )=0D +{=0D + PtEntry->Bits.Read =3D ((IoMmuAccess & EDKII_IOMMU_ACCESS_READ) !=3D 0)= ;=0D + PtEntry->Bits.Write =3D ((IoMmuAccess & EDKII_IOMMU_ACCESS_WRITE) !=3D 0= );=0D +}=0D +=0D +/**=0D + Create context entry.=0D +=0D + @param[in] VtdIndex The index of the VTd engine.=0D +=0D + @retval EFI_SUCCESS The context entry is created.=0D + @retval EFI_OUT_OF_RESOURCE No enough resource to create context entry.= =0D +**/=0D +EFI_STATUS=0D +CreateContextEntry (=0D + IN UINTN VtdIndex=0D + )=0D +{=0D + UINTN Index;=0D + VOID *Buffer;=0D + UINTN RootPages;=0D + UINTN ContextPages;=0D + VTD_ROOT_ENTRY *RootEntry;=0D + VTD_CONTEXT_ENTRY *ContextEntryTable;=0D + VTD_CONTEXT_ENTRY *ContextEntry;=0D + VTD_SOURCE_ID *PciSourceId;=0D + VTD_SOURCE_ID SourceId;=0D + UINTN MaxBusNumber;=0D + UINTN EntryTablePages;=0D +=0D + MaxBusNumber =3D 0;=0D + for (Index =3D 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo->P= ciDeviceDataNumber; Index++) {=0D + PciSourceId =3D &mVtdUnitInformation[VtdIndex].PciDeviceInfo->PciDevic= eData[Index].PciSourceId;=0D + if (PciSourceId->Bits.Bus > MaxBusNumber) {=0D + MaxBusNumber =3D PciSourceId->Bits.Bus;=0D + }=0D + }=0D + DEBUG ((DEBUG_INFO," MaxBusNumber - 0x%x\n", MaxBusNumber));=0D +=0D + RootPages =3D EFI_SIZE_TO_PAGES (sizeof (VTD_ROOT_ENTRY) * VTD_ROOT_ENTR= Y_NUMBER);=0D + ContextPages =3D EFI_SIZE_TO_PAGES (sizeof (VTD_CONTEXT_ENTRY) * VTD_CON= TEXT_ENTRY_NUMBER);=0D + EntryTablePages =3D RootPages + ContextPages * (MaxBusNumber + 1);=0D + Buffer =3D AllocateZeroPages (EntryTablePages);=0D + if (Buffer =3D=3D NULL) {=0D + DEBUG ((DEBUG_INFO,"Could not Alloc Root Entry Table.. \n"));=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + mVtdUnitInformation[VtdIndex].RootEntryTable =3D (VTD_ROOT_ENTRY *)Buffe= r;=0D + Buffer =3D (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (RootPages);=0D +=0D + for (Index =3D 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo->P= ciDeviceDataNumber; Index++) {=0D + PciSourceId =3D &mVtdUnitInformation[VtdIndex].PciDeviceInfo->PciDevic= eData[Index].PciSourceId;=0D +=0D + SourceId.Bits.Bus =3D PciSourceId->Bits.Bus;=0D + SourceId.Bits.Device =3D PciSourceId->Bits.Device;=0D + SourceId.Bits.Function =3D PciSourceId->Bits.Function;=0D +=0D + RootEntry =3D &mVtdUnitInformation[VtdIndex].RootEntryTable[SourceId.I= ndex.RootIndex];=0D + if (RootEntry->Bits.Present =3D=3D 0) {=0D + RootEntry->Bits.ContextTablePointerLo =3D (UINT32) RShiftU64 ((UINT= 64)(UINTN)Buffer, 12);=0D + RootEntry->Bits.ContextTablePointerHi =3D (UINT32) RShiftU64 ((UINT= 64)(UINTN)Buffer, 32);=0D + RootEntry->Bits.Present =3D 1;=0D + Buffer =3D (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (ContextPages);=0D + }=0D +=0D + ContextEntryTable =3D (VTD_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(R= ootEntry->Bits.ContextTablePointerLo, RootEntry->Bits.ContextTablePointerHi= ) ;=0D + ContextEntry =3D &ContextEntryTable[SourceId.Index.ContextIndex];=0D + ContextEntry->Bits.TranslationType =3D 0;=0D + ContextEntry->Bits.FaultProcessingDisable =3D 0;=0D + ContextEntry->Bits.Present =3D 0;=0D +=0D + DEBUG ((DEBUG_INFO,"Source: S%04x B%02x D%02x F%02x\n", mVtdUnitInform= ation[VtdIndex].Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.= Bits.Function));=0D +=0D + mVtdUnitInformation[VtdIndex].Is5LevelPaging =3D FALSE;=0D + if ((mVtdUnitInformation[VtdIndex].CapReg.Bits.SAGAW & BIT3) !=3D 0) {= =0D + mVtdUnitInformation[VtdIndex].Is5LevelPaging =3D TRUE;=0D + if ((mAcpiDmarTable->HostAddressWidth <=3D 48) &&=0D + ((mVtdUnitInformation[VtdIndex].CapReg.Bits.SAGAW & BIT2) !=3D 0= )) {=0D + mVtdUnitInformation[VtdIndex].Is5LevelPaging =3D FALSE;=0D + }=0D + } else if ((mVtdUnitInformation[VtdIndex].CapReg.Bits.SAGAW & BIT2) = =3D=3D 0) {=0D + DEBUG((DEBUG_ERROR, "!!!! Page-table type is not supported on VTD %d= !!!!\n", VtdIndex));=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + if (mVtdUnitInformation[VtdIndex].Is5LevelPaging) {=0D + ContextEntry->Bits.AddressWidth =3D 0x3;=0D + DEBUG((DEBUG_INFO, "Using 5-level page-table on VTD %d\n", VtdIndex)= );=0D + } else {=0D + ContextEntry->Bits.AddressWidth =3D 0x2;=0D + DEBUG((DEBUG_INFO, "Using 4-level page-table on VTD %d\n", VtdIndex)= );=0D + }=0D + }=0D +=0D + FlushPageTableMemory (VtdIndex, (UINTN)mVtdUnitInformation[VtdIndex].Roo= tEntryTable, EFI_PAGES_TO_SIZE(EntryTablePages));=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Create second level paging entry table.=0D +=0D + @param[in] VtdIndex The index of the VTd engine.=0D + @param[in] SecondLevelPagingEntry The second level paging entry.=0D + @param[in] MemoryBase The base of the memory.=0D + @param[in] MemoryLimit The limit of the memory.=0D + @param[in] IoMmuAccess The IOMMU access.=0D + @param[in] Is5LevelPaging If it is the 5 level paging.=0D +=0D + @return The second level paging entry.=0D +**/=0D +VTD_SECOND_LEVEL_PAGING_ENTRY *=0D +CreateSecondLevelPagingEntryTable (=0D + IN UINTN VtdIndex,=0D + IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,=0D + IN UINT64 MemoryBase,=0D + IN UINT64 MemoryLimit,=0D + IN UINT64 IoMmuAccess,=0D + IN BOOLEAN Is5LevelPaging=0D + )=0D +{=0D + UINTN Index5;=0D + UINTN Index4;=0D + UINTN Index3;=0D + UINTN Index2;=0D + UINTN Lvl5Start;=0D + UINTN Lvl5End;=0D + UINTN Lvl4PagesStart;=0D + UINTN Lvl4PagesEnd;=0D + UINTN Lvl4Start;=0D + UINTN Lvl4End;=0D + UINTN Lvl3Start;=0D + UINTN Lvl3End;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl5PtEntry;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl4PtEntry;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl3PtEntry;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl2PtEntry;=0D + UINT64 BaseAddress;=0D + UINT64 EndAddress;=0D +=0D + if (MemoryLimit =3D=3D 0) {=0D + return NULL;=0D + }=0D +=0D + Lvl4PagesStart =3D 0;=0D + Lvl4PagesEnd =3D 0;=0D + Lvl4PtEntry =3D NULL;=0D + Lvl5PtEntry =3D NULL;=0D +=0D + BaseAddress =3D ALIGN_VALUE_LOW(MemoryBase, SIZE_2MB);=0D + EndAddress =3D ALIGN_VALUE_UP(MemoryLimit, SIZE_2MB);=0D + DEBUG ((DEBUG_INFO,"CreateSecondLevelPagingEntryTable: BaseAddress - 0x%= 016lx, EndAddress - 0x%016lx\n", BaseAddress, EndAddress));=0D +=0D + if (SecondLevelPagingEntry =3D=3D NULL) {=0D + SecondLevelPagingEntry =3D AllocateZeroPages (1);=0D + if (SecondLevelPagingEntry =3D=3D NULL) {=0D + DEBUG ((DEBUG_ERROR,"Could not Alloc LVL4 or LVL5 PT. \n"));=0D + return NULL;=0D + }=0D + FlushPageTableMemory (VtdIndex, (UINTN)SecondLevelPagingEntry, EFI_PAG= ES_TO_SIZE(1));=0D + }=0D +=0D + //=0D + // If no access is needed, just create not present entry.=0D + //=0D + if (IoMmuAccess =3D=3D 0) {=0D + return SecondLevelPagingEntry;=0D + }=0D +=0D + if (Is5LevelPaging) {=0D + Lvl5Start =3D RShiftU64 (BaseAddress, 48) & 0x1FF;=0D + Lvl5End =3D RShiftU64 (EndAddress - 1, 48) & 0x1FF;=0D + DEBUG ((DEBUG_INFO," Lvl5Start - 0x%x, Lvl5End - 0x%x\n", Lvl5Start, = Lvl5End));=0D +=0D + Lvl4Start =3D RShiftU64 (BaseAddress, 39) & 0x1FF;=0D + Lvl4End =3D RShiftU64 (EndAddress - 1, 39) & 0x1FF;=0D +=0D + Lvl4PagesStart =3D (Lvl5Start<<9) | Lvl4Start;=0D + Lvl4PagesEnd =3D (Lvl5End<<9) | Lvl4End;=0D + DEBUG ((DEBUG_INFO," Lvl4PagesStart - 0x%x, Lvl4PagesEnd - 0x%x\n", L= vl4PagesStart, Lvl4PagesEnd));=0D +=0D + Lvl5PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *)SecondLevelPagingEntr= y;=0D + } else {=0D + Lvl5Start =3D RShiftU64 (BaseAddress, 48) & 0x1FF;=0D + Lvl5End =3D Lvl5Start;=0D +=0D + Lvl4Start =3D RShiftU64 (BaseAddress, 39) & 0x1FF;=0D + Lvl4End =3D RShiftU64 (EndAddress - 1, 39) & 0x1FF;=0D + DEBUG ((DEBUG_INFO," Lvl4Start - 0x%x, Lvl4End - 0x%x\n", Lvl4Start, = Lvl4End));=0D +=0D + Lvl4PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *)SecondLevelPagingEntr= y;=0D + }=0D +=0D + for (Index5 =3D Lvl5Start; Index5 <=3D Lvl5End; Index5++) {=0D + if (Is5LevelPaging) {=0D + if (Lvl5PtEntry[Index5].Uint64 =3D=3D 0) {=0D + Lvl5PtEntry[Index5].Uint64 =3D (UINT64)(UINTN)AllocateZeroPages (1= );=0D + if (Lvl5PtEntry[Index5].Uint64 =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!!= \n", Index5));=0D + ASSERT(FALSE);=0D + return NULL;=0D + }=0D + FlushPageTableMemory (VtdIndex, (UINTN)Lvl5PtEntry[Index5].Uint64,= SIZE_4KB);=0D + SetSecondLevelPagingEntryAttribute (&Lvl5PtEntry[Index5], EDKII_IO= MMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);=0D + }=0D + Lvl4Start =3D Lvl4PagesStart & 0x1FF;=0D + if (((Index5+1)<<9) > Lvl4PagesEnd) {=0D + Lvl4End =3D SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY) - 1;;=0D + Lvl4PagesStart =3D (Index5+1)<<9;=0D + } else {=0D + Lvl4End =3D Lvl4PagesEnd & 0x1FF;=0D + }=0D + DEBUG ((DEBUG_INFO," Lvl5(0x%x): Lvl4Start - 0x%x, Lvl4End - 0x%x\n= ", Index5, Lvl4Start, Lvl4End));=0D + Lvl4PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_A= DDRESS(Lvl5PtEntry[Index5].Bits.AddressLo, Lvl5PtEntry[Index5].Bits.Address= Hi);=0D + }=0D +=0D + for (Index4 =3D Lvl4Start; Index4 <=3D Lvl4End; Index4++) {=0D + if (Lvl4PtEntry[Index4].Uint64 =3D=3D 0) {=0D + Lvl4PtEntry[Index4].Uint64 =3D (UINT64)(UINTN)AllocateZeroPages (1= );=0D + if (Lvl4PtEntry[Index4].Uint64 =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!!= \n", Index4));=0D + ASSERT(FALSE);=0D + return NULL;=0D + }=0D + FlushPageTableMemory (VtdIndex, (UINTN)Lvl4PtEntry[Index4].Uint64,= SIZE_4KB);=0D + SetSecondLevelPagingEntryAttribute (&Lvl4PtEntry[Index4], EDKII_IO= MMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);=0D + }=0D +=0D + Lvl3Start =3D RShiftU64 (BaseAddress, 30) & 0x1FF;=0D + if (ALIGN_VALUE_LOW(BaseAddress + SIZE_1GB, SIZE_1GB) <=3D EndAddres= s) {=0D + Lvl3End =3D SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY) - 1;=0D + } else {=0D + Lvl3End =3D RShiftU64 (EndAddress - 1, 30) & 0x1FF;=0D + }=0D + DEBUG ((DEBUG_INFO," Lvl4(0x%x): Lvl3Start - 0x%x, Lvl3End - 0x%x\n= ", Index4, Lvl3Start, Lvl3End));=0D +=0D + Lvl3PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_A= DDRESS(Lvl4PtEntry[Index4].Bits.AddressLo, Lvl4PtEntry[Index4].Bits.Address= Hi);=0D + for (Index3 =3D Lvl3Start; Index3 <=3D Lvl3End; Index3++) {=0D + if (Lvl3PtEntry[Index3].Uint64 =3D=3D 0) {=0D + Lvl3PtEntry[Index3].Uint64 =3D (UINT64)(UINTN)AllocateZeroPages = (1);=0D + if (Lvl3PtEntry[Index3].Uint64 =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL3 PAGE FAIL (0x%x, 0x%= x)!!!!!!\n", Index4, Index3));=0D + ASSERT(FALSE);=0D + return NULL;=0D + }=0D + FlushPageTableMemory (VtdIndex, (UINTN)Lvl3PtEntry[Index3].Uint6= 4, SIZE_4KB);=0D + SetSecondLevelPagingEntryAttribute (&Lvl3PtEntry[Index3], EDKII_= IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);=0D + }=0D +=0D + Lvl2PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS= _ADDRESS(Lvl3PtEntry[Index3].Bits.AddressLo, Lvl3PtEntry[Index3].Bits.Addre= ssHi);=0D + for (Index2 =3D 0; Index2 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGIN= G_ENTRY); Index2++) {=0D + Lvl2PtEntry[Index2].Uint64 =3D BaseAddress;=0D + SetSecondLevelPagingEntryAttribute (&Lvl2PtEntry[Index2], IoMmuA= ccess);=0D + Lvl2PtEntry[Index2].Bits.PageSize =3D 1;=0D + BaseAddress +=3D SIZE_2MB;=0D + if (BaseAddress >=3D MemoryLimit) {=0D + break;=0D + }=0D + }=0D + FlushPageTableMemory (VtdIndex, (UINTN)Lvl2PtEntry, SIZE_4KB);=0D + if (BaseAddress >=3D MemoryLimit) {=0D + break;=0D + }=0D + }=0D + FlushPageTableMemory (VtdIndex, (UINTN)&Lvl3PtEntry[Lvl3Start], (UIN= TN)&Lvl3PtEntry[Lvl3End + 1] - (UINTN)&Lvl3PtEntry[Lvl3Start]);=0D + if (BaseAddress >=3D MemoryLimit) {=0D + break;=0D + }=0D + }=0D + FlushPageTableMemory (VtdIndex, (UINTN)&Lvl4PtEntry[Lvl4Start], (UINTN= )&Lvl4PtEntry[Lvl4End + 1] - (UINTN)&Lvl4PtEntry[Lvl4Start]);=0D + }=0D + FlushPageTableMemory (VtdIndex, (UINTN)&Lvl5PtEntry[Lvl5Start], (UINTN)&= Lvl5PtEntry[Lvl5End + 1] - (UINTN)&Lvl5PtEntry[Lvl5Start]);=0D +=0D + return SecondLevelPagingEntry;=0D +}=0D +=0D +/**=0D + Create second level paging entry.=0D +=0D + @param[in] VtdIndex The index of the VTd engine.=0D + @param[in] IoMmuAccess The IOMMU access.=0D + @param[in] Is5LevelPaging If it is the 5 level paging.=0D +=0D + @return The second level paging entry.=0D +**/=0D +VTD_SECOND_LEVEL_PAGING_ENTRY *=0D +CreateSecondLevelPagingEntry (=0D + IN UINTN VtdIndex,=0D + IN UINT64 IoMmuAccess,=0D + IN BOOLEAN Is5LevelPaging=0D + )=0D +{=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;=0D +=0D + SecondLevelPagingEntry =3D NULL;=0D + SecondLevelPagingEntry =3D CreateSecondLevelPagingEntryTable (VtdIndex, = SecondLevelPagingEntry, 0, mBelow4GMemoryLimit, IoMmuAccess, Is5LevelPaging= );=0D + if (SecondLevelPagingEntry =3D=3D NULL) {=0D + return NULL;=0D + }=0D +=0D + if (mAbove4GMemoryLimit !=3D 0) {=0D + ASSERT (mAbove4GMemoryLimit > BASE_4GB);=0D + SecondLevelPagingEntry =3D CreateSecondLevelPagingEntryTable (VtdIndex= , SecondLevelPagingEntry, SIZE_4GB, mAbove4GMemoryLimit, IoMmuAccess, Is5Le= velPaging);=0D + if (SecondLevelPagingEntry =3D=3D NULL) {=0D + return NULL;=0D + }=0D + }=0D +=0D + return SecondLevelPagingEntry;=0D +}=0D +=0D +/**=0D + Setup VTd translation table.=0D +=0D + @retval EFI_SUCCESS Setup translation table successfully.=0D + @retval EFI_OUT_OF_RESOURCE Setup translation table fail.=0D +**/=0D +EFI_STATUS=0D +SetupTranslationTable (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN Index;=0D +=0D + for (Index =3D 0; Index < mVtdUnitNumber; Index++) {=0D + DEBUG((DEBUG_INFO, "CreateContextEntry - %d\n", Index));=0D +=0D + if (mVtdUnitInformation[Index].ECapReg.Bits.SMTS) {=0D + if (mVtdUnitInformation[Index].ECapReg.Bits.DEP_24) {=0D + DEBUG ((DEBUG_ERROR,"ECapReg.bit24 is not zero\n"));=0D + ASSERT(FALSE);=0D + Status =3D EFI_UNSUPPORTED;=0D + } else {=0D + Status =3D CreateContextEntry (Index);=0D + }=0D + } else {=0D + if (mVtdUnitInformation[Index].ECapReg.Bits.DEP_24) {=0D + //=0D + // To compatible with pervious VTd engine=0D + // It was ECS(Extended Context Support) bit.=0D + //=0D + Status =3D CreateExtContextEntry (Index);=0D + } else {=0D + Status =3D CreateContextEntry (Index);=0D + }=0D + }=0D +=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Dump DMAR second level paging entry.=0D +=0D + @param[in] SecondLevelPagingEntry The second level paging entry.=0D + @param[in] Is5LevelPaging If it is the 5 level paging.=0D +**/=0D +VOID=0D +DumpSecondLevelPagingEntry (=0D + IN VOID *SecondLevelPagingEntry,=0D + IN BOOLEAN Is5LevelPaging=0D + )=0D +{=0D + UINTN Index5;=0D + UINTN Index4;=0D + UINTN Index3;=0D + UINTN Index2;=0D + UINTN Index1;=0D + UINTN Lvl5IndexEnd;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl5PtEntry;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl4PtEntry;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl3PtEntry;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl2PtEntry;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl1PtEntry;=0D +=0D + DEBUG ((DEBUG_VERBOSE,"=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\= n"));=0D + DEBUG ((DEBUG_VERBOSE,"DMAR Second Level Page Table:\n"));=0D + DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry Base - 0x%x, Is5LevelPagin= g - %d\n", SecondLevelPagingEntry, Is5LevelPaging));=0D +=0D + Lvl5IndexEnd =3D Is5LevelPaging ? SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGIN= G_ENTRY) : 1;=0D + Lvl4PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *)SecondLevelPagingEntry;= =0D + Lvl5PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *)SecondLevelPagingEntry;= =0D +=0D + for (Index5 =3D 0; Index5 < Lvl5IndexEnd; Index5++) {=0D + if (Is5LevelPaging) {=0D + if (Lvl5PtEntry[Index5].Uint64 !=3D 0) {=0D + DEBUG ((DEBUG_VERBOSE," Lvl5Pt Entry(0x%03x) - 0x%016lx\n", Index= 5, Lvl5PtEntry[Index5].Uint64));=0D + }=0D + if (Lvl5PtEntry[Index5].Uint64 =3D=3D 0) {=0D + continue;=0D + }=0D + Lvl4PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_A= DDRESS(Lvl5PtEntry[Index5].Bits.AddressLo, Lvl5PtEntry[Index5].Bits.Address= Hi);=0D + }=0D +=0D + for (Index4 =3D 0; Index4 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_EN= TRY); Index4++) {=0D + if (Lvl4PtEntry[Index4].Uint64 !=3D 0) {=0D + DEBUG ((DEBUG_VERBOSE," Lvl4Pt Entry(0x%03x) - 0x%016lx\n", Index= 4, Lvl4PtEntry[Index4].Uint64));=0D + }=0D + if (Lvl4PtEntry[Index4].Uint64 =3D=3D 0) {=0D + continue;=0D + }=0D + Lvl3PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_A= DDRESS(Lvl4PtEntry[Index4].Bits.AddressLo, Lvl4PtEntry[Index4].Bits.Address= Hi);=0D + for (Index3 =3D 0; Index3 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_= ENTRY); Index3++) {=0D + if (Lvl3PtEntry[Index3].Uint64 !=3D 0) {=0D + DEBUG ((DEBUG_VERBOSE," Lvl3Pt Entry(0x%03x) - 0x%016lx\n", In= dex3, Lvl3PtEntry[Index3].Uint64));=0D + }=0D + if (Lvl3PtEntry[Index3].Uint64 =3D=3D 0) {=0D + continue;=0D + }=0D +=0D + Lvl2PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS= _ADDRESS(Lvl3PtEntry[Index3].Bits.AddressLo, Lvl3PtEntry[Index3].Bits.Addre= ssHi);=0D + for (Index2 =3D 0; Index2 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGIN= G_ENTRY); Index2++) {=0D + if (Lvl2PtEntry[Index2].Uint64 !=3D 0) {=0D + DEBUG ((DEBUG_VERBOSE," Lvl2Pt Entry(0x%03x) - 0x%016lx\n",= Index2, Lvl2PtEntry[Index2].Uint64));=0D + }=0D + if (Lvl2PtEntry[Index2].Uint64 =3D=3D 0) {=0D + continue;=0D + }=0D + if (Lvl2PtEntry[Index2].Bits.PageSize =3D=3D 0) {=0D + Lvl1PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64= BITS_ADDRESS(Lvl2PtEntry[Index2].Bits.AddressLo, Lvl2PtEntry[Index2].Bits.A= ddressHi);=0D + for (Index1 =3D 0; Index1 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_P= AGING_ENTRY); Index1++) {=0D + if (Lvl1PtEntry[Index1].Uint64 !=3D 0) {=0D + DEBUG ((DEBUG_VERBOSE," Lvl1Pt Entry(0x%03x) - 0x%016= lx\n", Index1, Lvl1PtEntry[Index1].Uint64));=0D + }=0D + }=0D + }=0D + }=0D + }=0D + }=0D + }=0D + DEBUG ((DEBUG_VERBOSE,"=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\= n"));=0D +}=0D +=0D +/**=0D + Invalid page entry.=0D +=0D + @param VtdIndex The VTd engine index.=0D +**/=0D +VOID=0D +InvalidatePageEntry (=0D + IN UINTN VtdIndex=0D + )=0D +{=0D + if (mVtdUnitInformation[VtdIndex].HasDirtyContext || mVtdUnitInformation= [VtdIndex].HasDirtyPages) {=0D + InvalidateVtdIOTLBGlobal (VtdIndex);=0D + }=0D + mVtdUnitInformation[VtdIndex].HasDirtyContext =3D FALSE;=0D + mVtdUnitInformation[VtdIndex].HasDirtyPages =3D FALSE;=0D +}=0D +=0D +#define VTD_PG_R BIT0=0D +#define VTD_PG_W BIT1=0D +#define VTD_PG_X BIT2=0D +#define VTD_PG_EMT (BIT3 | BIT4 | BIT5)=0D +#define VTD_PG_TM (BIT62)=0D +=0D +#define VTD_PG_PS BIT7=0D +=0D +#define PAGE_PROGATE_BITS (VTD_PG_TM | VTD_PG_EMT | VTD_PG_W | VT= D_PG_R)=0D +=0D +#define PAGING_4K_MASK 0xFFF=0D +#define PAGING_2M_MASK 0x1FFFFF=0D +#define PAGING_1G_MASK 0x3FFFFFFF=0D +=0D +#define PAGING_VTD_INDEX_MASK 0x1FF=0D +=0D +#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull=0D +#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull=0D +#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull=0D +=0D +typedef enum {=0D + PageNone,=0D + Page4K,=0D + Page2M,=0D + Page1G,=0D +} PAGE_ATTRIBUTE;=0D +=0D +typedef struct {=0D + PAGE_ATTRIBUTE Attribute;=0D + UINT64 Length;=0D + UINT64 AddressMask;=0D +} PAGE_ATTRIBUTE_TABLE;=0D +=0D +PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] =3D {=0D + {Page4K, SIZE_4KB, PAGING_4K_ADDRESS_MASK_64},=0D + {Page2M, SIZE_2MB, PAGING_2M_ADDRESS_MASK_64},=0D + {Page1G, SIZE_1GB, PAGING_1G_ADDRESS_MASK_64},=0D +};=0D +=0D +/**=0D + Return length according to page attributes.=0D +=0D + @param[in] PageAttributes The page attribute of the page entry.=0D +=0D + @return The length of page entry.=0D +**/=0D +UINTN=0D +PageAttributeToLength (=0D + IN PAGE_ATTRIBUTE PageAttribute=0D + )=0D +{=0D + UINTN Index;=0D + for (Index =3D 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttrib= uteTable[0]); Index++) {=0D + if (PageAttribute =3D=3D mPageAttributeTable[Index].Attribute) {=0D + return (UINTN)mPageAttributeTable[Index].Length;=0D + }=0D + }=0D + return 0;=0D +}=0D +=0D +/**=0D + Return page table entry to match the address.=0D +=0D + @param[in] VtdIndex The index used to identify a VTd e= ngine.=0D + @param[in] SecondLevelPagingEntry The second level paging entry in V= Td table for the device.=0D + @param[in] Address The address to be checked.=0D + @param[in] Is5LevelPaging If it is the 5 level paging.=0D + @param[out] PageAttributes The page attribute of the page ent= ry.=0D +=0D + @return The page entry.=0D +**/=0D +VOID *=0D +GetSecondLevelPageTableEntry (=0D + IN UINTN VtdIndex,=0D + IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,=0D + IN PHYSICAL_ADDRESS Address,=0D + IN BOOLEAN Is5LevelPaging,=0D + OUT PAGE_ATTRIBUTE *PageAttribute=0D + )=0D +{=0D + UINTN Index1;=0D + UINTN Index2;=0D + UINTN Index3;=0D + UINTN Index4;=0D + UINTN Index5;=0D + UINT64 *L1PageTable;=0D + UINT64 *L2PageTable;=0D + UINT64 *L3PageTable;=0D + UINT64 *L4PageTable;=0D + UINT64 *L5PageTable;=0D +=0D + Index5 =3D ((UINTN)RShiftU64 (Address, 48)) & PAGING_VTD_INDEX_MASK;=0D + Index4 =3D ((UINTN)RShiftU64 (Address, 39)) & PAGING_VTD_INDEX_MASK;=0D + Index3 =3D ((UINTN)Address >> 30) & PAGING_VTD_INDEX_MASK;=0D + Index2 =3D ((UINTN)Address >> 21) & PAGING_VTD_INDEX_MASK;=0D + Index1 =3D ((UINTN)Address >> 12) & PAGING_VTD_INDEX_MASK;=0D +=0D + if (Is5LevelPaging) {=0D + L5PageTable =3D (UINT64 *)SecondLevelPagingEntry;=0D + if (L5PageTable[Index5] =3D=3D 0) {=0D + L5PageTable[Index5] =3D (UINT64)(UINTN)AllocateZeroPages (1);=0D + if (L5PageTable[Index5] =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL5 PAGE FAIL (0x%x)!!!!!!\n= ", Index4));=0D + ASSERT(FALSE);=0D + *PageAttribute =3D PageNone;=0D + return NULL;=0D + }=0D + FlushPageTableMemory (VtdIndex, (UINTN)L5PageTable[Index5], SIZE_4KB= );=0D + SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *= )&L5PageTable[Index5], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);= =0D + FlushPageTableMemory (VtdIndex, (UINTN)&L5PageTable[Index5], sizeof(= L5PageTable[Index5]));=0D + }=0D + L4PageTable =3D (UINT64 *)(UINTN)(L5PageTable[Index5] & PAGING_4K_ADDR= ESS_MASK_64);=0D + } else {=0D + L4PageTable =3D (UINT64 *)SecondLevelPagingEntry;=0D + }=0D +=0D + if (L4PageTable[Index4] =3D=3D 0) {=0D + L4PageTable[Index4] =3D (UINT64)(UINTN)AllocateZeroPages (1);=0D + if (L4PageTable[Index4] =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!!\n",= Index4));=0D + ASSERT(FALSE);=0D + *PageAttribute =3D PageNone;=0D + return NULL;=0D + }=0D + FlushPageTableMemory (VtdIndex, (UINTN)L4PageTable[Index4], SIZE_4KB);= =0D + SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&= L4PageTable[Index4], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);=0D + FlushPageTableMemory (VtdIndex, (UINTN)&L4PageTable[Index4], sizeof(L4= PageTable[Index4]));=0D + }=0D +=0D + L3PageTable =3D (UINT64 *)(UINTN)(L4PageTable[Index4] & PAGING_4K_ADDRES= S_MASK_64);=0D + if (L3PageTable[Index3] =3D=3D 0) {=0D + L3PageTable[Index3] =3D (UINT64)(UINTN)AllocateZeroPages (1);=0D + if (L3PageTable[Index3] =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL3 PAGE FAIL (0x%x, 0x%x)!!!!= !!\n", Index4, Index3));=0D + ASSERT(FALSE);=0D + *PageAttribute =3D PageNone;=0D + return NULL;=0D + }=0D + FlushPageTableMemory (VtdIndex, (UINTN)L3PageTable[Index3], SIZE_4KB);= =0D + SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&= L3PageTable[Index3], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);=0D + FlushPageTableMemory (VtdIndex, (UINTN)&L3PageTable[Index3], sizeof(L3= PageTable[Index3]));=0D + }=0D + if ((L3PageTable[Index3] & VTD_PG_PS) !=3D 0) {=0D + // 1G=0D + *PageAttribute =3D Page1G;=0D + return &L3PageTable[Index3];=0D + }=0D +=0D + L2PageTable =3D (UINT64 *)(UINTN)(L3PageTable[Index3] & PAGING_4K_ADDRES= S_MASK_64);=0D + if (L2PageTable[Index2] =3D=3D 0) {=0D + L2PageTable[Index2] =3D Address & PAGING_2M_ADDRESS_MASK_64;=0D + SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&= L2PageTable[Index2], 0);=0D + L2PageTable[Index2] |=3D VTD_PG_PS;=0D + FlushPageTableMemory (VtdIndex, (UINTN)&L2PageTable[Index2], sizeof(L2= PageTable[Index2]));=0D + }=0D + if ((L2PageTable[Index2] & VTD_PG_PS) !=3D 0) {=0D + // 2M=0D + *PageAttribute =3D Page2M;=0D + return &L2PageTable[Index2];=0D + }=0D +=0D + // 4k=0D + L1PageTable =3D (UINT64 *)(UINTN)(L2PageTable[Index2] & PAGING_4K_ADDRES= S_MASK_64);=0D + if ((L1PageTable[Index1] =3D=3D 0) && (Address !=3D 0)) {=0D + *PageAttribute =3D PageNone;=0D + return NULL;=0D + }=0D + *PageAttribute =3D Page4K;=0D + return &L1PageTable[Index1];=0D +}=0D +=0D +/**=0D + Modify memory attributes of page entry.=0D +=0D + @param[in] VtdIndex The index used to identify a VTd engine.=0D + @param[in] PageEntry The page entry.=0D + @param[in] IoMmuAccess The IOMMU access.=0D + @param[out] IsModified TRUE means page table modified. FALSE mean= s page table not modified.=0D +**/=0D +VOID=0D +ConvertSecondLevelPageEntryAttribute (=0D + IN UINTN VtdIndex,=0D + IN VTD_SECOND_LEVEL_PAGING_ENTRY *PageEntry,=0D + IN UINT64 IoMmuAccess,=0D + OUT BOOLEAN *IsModified=0D + )=0D +{=0D + UINT64 CurrentPageEntry;=0D + UINT64 NewPageEntry;=0D +=0D + CurrentPageEntry =3D PageEntry->Uint64;=0D + SetSecondLevelPagingEntryAttribute (PageEntry, IoMmuAccess);=0D + FlushPageTableMemory (VtdIndex, (UINTN)PageEntry, sizeof(*PageEntry));=0D + NewPageEntry =3D PageEntry->Uint64;=0D + if (CurrentPageEntry !=3D NewPageEntry) {=0D + *IsModified =3D TRUE;=0D + DEBUG ((DEBUG_VERBOSE, "ConvertSecondLevelPageEntryAttribute 0x%lx", C= urrentPageEntry));=0D + DEBUG ((DEBUG_VERBOSE, "->0x%lx\n", NewPageEntry));=0D + } else {=0D + *IsModified =3D FALSE;=0D + }=0D +}=0D +=0D +/**=0D + This function returns if there is need to split page entry.=0D +=0D + @param[in] BaseAddress The base address to be checked.=0D + @param[in] Length The length to be checked.=0D + @param[in] PageAttribute The page attribute of the page entry.=0D +=0D + @retval SplitAttributes on if there is need to split page entry.=0D +**/=0D +PAGE_ATTRIBUTE=0D +NeedSplitPage (=0D + IN PHYSICAL_ADDRESS BaseAddress,=0D + IN UINT64 Length,=0D + IN PAGE_ATTRIBUTE PageAttribute=0D + )=0D +{=0D + UINT64 PageEntryLength;=0D +=0D + PageEntryLength =3D PageAttributeToLength (PageAttribute);=0D +=0D + if (((BaseAddress & (PageEntryLength - 1)) =3D=3D 0) && (Length >=3D Pag= eEntryLength)) {=0D + return PageNone;=0D + }=0D +=0D + if (((BaseAddress & PAGING_2M_MASK) !=3D 0) || (Length < SIZE_2MB)) {=0D + return Page4K;=0D + }=0D +=0D + return Page2M;=0D +}=0D +=0D +/**=0D + This function splits one page entry to small page entries.=0D +=0D + @param[in] VtdIndex The index used to identify a VTd engine.=0D + @param[in] PageEntry The page entry to be splitted.=0D + @param[in] PageAttribute The page attribute of the page entry.=0D + @param[in] SplitAttribute How to split the page entry.=0D +=0D + @retval RETURN_SUCCESS The page entry is splitted.=0D + @retval RETURN_UNSUPPORTED The page entry does not support to be = splitted.=0D + @retval RETURN_OUT_OF_RESOURCES No resource to split page entry.=0D +**/=0D +RETURN_STATUS=0D +SplitSecondLevelPage (=0D + IN UINTN VtdIndex,=0D + IN VTD_SECOND_LEVEL_PAGING_ENTRY *PageEntry,=0D + IN PAGE_ATTRIBUTE PageAttribute,=0D + IN PAGE_ATTRIBUTE SplitAttribute=0D + )=0D +{=0D + UINT64 BaseAddress;=0D + UINT64 *NewPageEntry;=0D + UINTN Index;=0D +=0D + ASSERT (PageAttribute =3D=3D Page2M || PageAttribute =3D=3D Page1G);=0D +=0D + if (PageAttribute =3D=3D Page2M) {=0D + //=0D + // Split 2M to 4K=0D + //=0D + ASSERT (SplitAttribute =3D=3D Page4K);=0D + if (SplitAttribute =3D=3D Page4K) {=0D + NewPageEntry =3D AllocateZeroPages (1);=0D + DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));=0D + if (NewPageEntry =3D=3D NULL) {=0D + return RETURN_OUT_OF_RESOURCES;=0D + }=0D + BaseAddress =3D PageEntry->Uint64 & PAGING_2M_ADDRESS_MASK_64;=0D + for (Index =3D 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {=0D + NewPageEntry[Index] =3D (BaseAddress + SIZE_4KB * Index) | (PageEn= try->Uint64 & PAGE_PROGATE_BITS);=0D + }=0D + FlushPageTableMemory (VtdIndex, (UINTN)NewPageEntry, SIZE_4KB);=0D +=0D + PageEntry->Uint64 =3D (UINT64)(UINTN)NewPageEntry;=0D + SetSecondLevelPagingEntryAttribute (PageEntry, EDKII_IOMMU_ACCESS_RE= AD | EDKII_IOMMU_ACCESS_WRITE);=0D + FlushPageTableMemory (VtdIndex, (UINTN)PageEntry, sizeof(*PageEntry)= );=0D + return RETURN_SUCCESS;=0D + } else {=0D + return RETURN_UNSUPPORTED;=0D + }=0D + } else if (PageAttribute =3D=3D Page1G) {=0D + //=0D + // Split 1G to 2M=0D + // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K = to get more compact page table.=0D + //=0D + ASSERT (SplitAttribute =3D=3D Page2M || SplitAttribute =3D=3D Page4K);= =0D + if ((SplitAttribute =3D=3D Page2M || SplitAttribute =3D=3D Page4K)) {= =0D + NewPageEntry =3D AllocateZeroPages (1);=0D + DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));=0D + if (NewPageEntry =3D=3D NULL) {=0D + return RETURN_OUT_OF_RESOURCES;=0D + }=0D + BaseAddress =3D PageEntry->Uint64 & PAGING_1G_ADDRESS_MASK_64;=0D + for (Index =3D 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {=0D + NewPageEntry[Index] =3D (BaseAddress + SIZE_2MB * Index) | VTD_PG_= PS | (PageEntry->Uint64 & PAGE_PROGATE_BITS);=0D + }=0D + FlushPageTableMemory (VtdIndex, (UINTN)NewPageEntry, SIZE_4KB);=0D +=0D + PageEntry->Uint64 =3D (UINT64)(UINTN)NewPageEntry;=0D + SetSecondLevelPagingEntryAttribute (PageEntry, EDKII_IOMMU_ACCESS_RE= AD | EDKII_IOMMU_ACCESS_WRITE);=0D + FlushPageTableMemory (VtdIndex, (UINTN)PageEntry, sizeof(*PageEntry)= );=0D + return RETURN_SUCCESS;=0D + } else {=0D + return RETURN_UNSUPPORTED;=0D + }=0D + } else {=0D + return RETURN_UNSUPPORTED;=0D + }=0D +}=0D +=0D +/**=0D + Set VTd attribute for a system memory on second level page entry=0D +=0D + @param[in] VtdIndex The index used to identify a VTd eng= ine.=0D + @param[in] DomainIdentifier The domain ID of the source.=0D + @param[in] SecondLevelPagingEntry The second level paging entry in VTd= table for the device.=0D + @param[in] BaseAddress The base of device memory address to= be used as the DMA memory.=0D + @param[in] Length The length of device memory address = to be used as the DMA memory.=0D + @param[in] IoMmuAccess The IOMMU access.=0D +=0D + @retval EFI_SUCCESS The IoMmuAccess is set for the memory ran= ge specified by BaseAddress and Length.=0D + @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligne= d.=0D + @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.=0D + @retval EFI_INVALID_PARAMETER Length is 0.=0D + @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combinat= ion of access.=0D + @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not suppor= ted by the IOMMU.=0D + @retval EFI_UNSUPPORTED The IOMMU does not support the memory ran= ge specified by BaseAddress and Length.=0D + @retval EFI_OUT_OF_RESOURCES There are not enough resources available = to modify the IOMMU access.=0D + @retval EFI_DEVICE_ERROR The IOMMU device reported an error while = attempting the operation.=0D +**/=0D +EFI_STATUS=0D +SetSecondLevelPagingAttribute (=0D + IN UINTN VtdIndex,=0D + IN UINT16 DomainIdentifier,=0D + IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,=0D + IN UINT64 BaseAddress,=0D + IN UINT64 Length,=0D + IN UINT64 IoMmuAccess=0D + )=0D +{=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *PageEntry;=0D + PAGE_ATTRIBUTE PageAttribute;=0D + UINTN PageEntryLength;=0D + PAGE_ATTRIBUTE SplitAttribute;=0D + EFI_STATUS Status;=0D + BOOLEAN IsEntryModified;=0D +=0D + DEBUG ((DEBUG_VERBOSE,"SetSecondLevelPagingAttribute (%d) (0x%016lx - 0x= %016lx : %x) \n", VtdIndex, BaseAddress, Length, IoMmuAccess));=0D + DEBUG ((DEBUG_VERBOSE," SecondLevelPagingEntry Base - 0x%x\n", SecondLe= velPagingEntry));=0D +=0D + if (BaseAddress !=3D ALIGN_VALUE(BaseAddress, SIZE_4KB)) {=0D + DEBUG ((DEBUG_ERROR, "SetSecondLevelPagingAttribute - Invalid Alignmen= t\n"));=0D + return EFI_UNSUPPORTED;=0D + }=0D + if (Length !=3D ALIGN_VALUE(Length, SIZE_4KB)) {=0D + DEBUG ((DEBUG_ERROR, "SetSecondLevelPagingAttribute - Invalid Alignmen= t\n"));=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + while (Length !=3D 0) {=0D + PageEntry =3D GetSecondLevelPageTableEntry (VtdIndex, SecondLevelPagin= gEntry, BaseAddress, mVtdUnitInformation[VtdIndex].Is5LevelPaging, &PageAtt= ribute);=0D + if (PageEntry =3D=3D NULL) {=0D + DEBUG ((DEBUG_ERROR, "PageEntry - NULL\n"));=0D + return RETURN_UNSUPPORTED;=0D + }=0D + PageEntryLength =3D PageAttributeToLength (PageAttribute);=0D + SplitAttribute =3D NeedSplitPage (BaseAddress, Length, PageAttribute);= =0D + if (SplitAttribute =3D=3D PageNone) {=0D + ConvertSecondLevelPageEntryAttribute (VtdIndex, PageEntry, IoMmuAcce= ss, &IsEntryModified);=0D + if (IsEntryModified) {=0D + mVtdUnitInformation[VtdIndex].HasDirtyPages =3D TRUE;=0D + }=0D + //=0D + // Convert success, move to next=0D + //=0D + BaseAddress +=3D PageEntryLength;=0D + Length -=3D PageEntryLength;=0D + } else {=0D + Status =3D SplitSecondLevelPage (VtdIndex, PageEntry, PageAttribute,= SplitAttribute);=0D + if (RETURN_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "SplitSecondLevelPage - %r\n", Status));=0D + return RETURN_UNSUPPORTED;=0D + }=0D + mVtdUnitInformation[VtdIndex].HasDirtyPages =3D TRUE;=0D + //=0D + // Just split current page=0D + // Convert success in next around=0D + //=0D + }=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Set VTd attribute for a system memory.=0D +=0D + @param[in] VtdIndex The index used to identify a VTd eng= ine.=0D + @param[in] DomainIdentifier The domain ID of the source.=0D + @param[in] SecondLevelPagingEntry The second level paging entry in VTd= table for the device.=0D + @param[in] BaseAddress The base of device memory address to= be used as the DMA memory.=0D + @param[in] Length The length of device memory address = to be used as the DMA memory.=0D + @param[in] IoMmuAccess The IOMMU access.=0D +=0D + @retval EFI_SUCCESS The IoMmuAccess is set for the memory ran= ge specified by BaseAddress and Length.=0D + @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligne= d.=0D + @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.=0D + @retval EFI_INVALID_PARAMETER Length is 0.=0D + @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combinat= ion of access.=0D + @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not suppor= ted by the IOMMU.=0D + @retval EFI_UNSUPPORTED The IOMMU does not support the memory ran= ge specified by BaseAddress and Length.=0D + @retval EFI_OUT_OF_RESOURCES There are not enough resources available = to modify the IOMMU access.=0D + @retval EFI_DEVICE_ERROR The IOMMU device reported an error while = attempting the operation.=0D +**/=0D +EFI_STATUS=0D +SetPageAttribute (=0D + IN UINTN VtdIndex,=0D + IN UINT16 DomainIdentifier,=0D + IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,=0D + IN UINT64 BaseAddress,=0D + IN UINT64 Length,=0D + IN UINT64 IoMmuAccess=0D + )=0D +{=0D + EFI_STATUS Status;=0D + Status =3D EFI_NOT_FOUND;=0D + if (SecondLevelPagingEntry !=3D NULL) {=0D + Status =3D SetSecondLevelPagingAttribute (VtdIndex, DomainIdentifier, = SecondLevelPagingEntry, BaseAddress, Length, IoMmuAccess);=0D + }=0D + return Status;=0D +}=0D +=0D +/**=0D + Set VTd attribute for a system memory.=0D +=0D + @param[in] Segment The Segment used to identify a VTd engine.= =0D + @param[in] SourceId The SourceId used to identify a VTd engine= and table entry.=0D + @param[in] BaseAddress The base of device memory address to be us= ed as the DMA memory.=0D + @param[in] Length The length of device memory address to be = used as the DMA memory.=0D + @param[in] IoMmuAccess The IOMMU access.=0D +=0D + @retval EFI_SUCCESS The IoMmuAccess is set for the memory ran= ge specified by BaseAddress and Length.=0D + @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligne= d.=0D + @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.=0D + @retval EFI_INVALID_PARAMETER Length is 0.=0D + @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combinat= ion of access.=0D + @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not suppor= ted by the IOMMU.=0D + @retval EFI_UNSUPPORTED The IOMMU does not support the memory ran= ge specified by BaseAddress and Length.=0D + @retval EFI_OUT_OF_RESOURCES There are not enough resources available = to modify the IOMMU access.=0D + @retval EFI_DEVICE_ERROR The IOMMU device reported an error while = attempting the operation.=0D +**/=0D +EFI_STATUS=0D +SetAccessAttribute (=0D + IN UINT16 Segment,=0D + IN VTD_SOURCE_ID SourceId,=0D + IN UINT64 BaseAddress,=0D + IN UINT64 Length,=0D + IN UINT64 IoMmuAccess=0D + )=0D +{=0D + UINTN VtdIndex;=0D + EFI_STATUS Status;=0D + VTD_EXT_CONTEXT_ENTRY *ExtContextEntry;=0D + VTD_CONTEXT_ENTRY *ContextEntry;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;=0D + UINT64 Pt;=0D + UINTN PciDataIndex;=0D + UINT16 DomainIdentifier;=0D +=0D + SecondLevelPagingEntry =3D NULL;=0D +=0D + DEBUG ((DEBUG_VERBOSE,"SetAccessAttribute (S%04x B%02x D%02x F%02x) (0x%= 016lx - 0x%08x, %x)\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, S= ourceId.Bits.Function, BaseAddress, (UINTN)Length, IoMmuAccess));=0D +=0D + VtdIndex =3D FindVtdIndexByPciDevice (Segment, SourceId, &ExtContextEntr= y, &ContextEntry);=0D + if (VtdIndex =3D=3D (UINTN)-1) {=0D + DEBUG ((DEBUG_ERROR,"SetAccessAttribute - Pci device (S%04x B%02x D%02= x F%02x) not found!\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, S= ourceId.Bits.Function));=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + PciDataIndex =3D GetPciDataIndex (VtdIndex, Segment, SourceId);=0D + mVtdUnitInformation[VtdIndex].PciDeviceInfo->PciDeviceData[PciDataIndex]= .AccessCount++;=0D + //=0D + // DomainId should not be 0.=0D + //=0D + DomainIdentifier =3D (UINT16)(PciDataIndex + 1);=0D +=0D + if (ExtContextEntry !=3D NULL) {=0D + if (ExtContextEntry->Bits.Present =3D=3D 0) {=0D + SecondLevelPagingEntry =3D CreateSecondLevelPagingEntry (VtdIndex, 0= , mVtdUnitInformation[VtdIndex].Is5LevelPaging);=0D + DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%= 02x F%02x) New\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, Sour= ceId.Bits.Device, SourceId.Bits.Function));=0D + Pt =3D (UINT64)RShiftU64 ((UINT64)(UINTN)SecondLevelPagingEntry, 12)= ;=0D +=0D + ExtContextEntry->Bits.SecondLevelPageTranslationPointerLo =3D (UINT3= 2) Pt;=0D + ExtContextEntry->Bits.SecondLevelPageTranslationPointerHi =3D (UINT3= 2) RShiftU64(Pt, 20);=0D + ExtContextEntry->Bits.DomainIdentifier =3D DomainIdentifier;=0D + ExtContextEntry->Bits.Present =3D 1;=0D + FlushPageTableMemory (VtdIndex, (UINTN)ExtContextEntry, sizeof(*ExtC= ontextEntry));=0D + VtdLibDumpDmarExtContextEntryTable (NULL, NULL, mVtdUnitInformation[= VtdIndex].ExtRootEntryTable, mVtdUnitInformation[VtdIndex].Is5LevelPaging);= =0D + mVtdUnitInformation[VtdIndex].HasDirtyContext =3D TRUE;=0D + } else {=0D + SecondLevelPagingEntry =3D (VOID *)(UINTN)VTD_64BITS_ADDRESS(ExtCont= extEntry->Bits.SecondLevelPageTranslationPointerLo, ExtContextEntry->Bits.S= econdLevelPageTranslationPointerHi);=0D + DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%= 02x F%02x)\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId= .Bits.Device, SourceId.Bits.Function));=0D + }=0D + } else if (ContextEntry !=3D NULL) {=0D + if (ContextEntry->Bits.Present =3D=3D 0) {=0D + SecondLevelPagingEntry =3D CreateSecondLevelPagingEntry (VtdIndex, 0= , mVtdUnitInformation[VtdIndex].Is5LevelPaging);=0D + DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%= 02x F%02x) New\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, Sour= ceId.Bits.Device, SourceId.Bits.Function));=0D + Pt =3D (UINT64)RShiftU64 ((UINT64)(UINTN)SecondLevelPagingEntry, 12)= ;=0D +=0D + ContextEntry->Bits.SecondLevelPageTranslationPointerLo =3D (UINT32) = Pt;=0D + ContextEntry->Bits.SecondLevelPageTranslationPointerHi =3D (UINT32) = RShiftU64(Pt, 20);=0D + ContextEntry->Bits.DomainIdentifier =3D DomainIdentifier;=0D + ContextEntry->Bits.Present =3D 1;=0D + FlushPageTableMemory (VtdIndex, (UINTN)ContextEntry, sizeof(*Context= Entry));=0D + VtdLibDumpDmarContextEntryTable (NULL, NULL, mVtdUnitInformation[Vtd= Index].RootEntryTable, mVtdUnitInformation[VtdIndex].Is5LevelPaging);=0D + mVtdUnitInformation[VtdIndex].HasDirtyContext =3D TRUE;=0D + } else {=0D + SecondLevelPagingEntry =3D (VOID *)(UINTN)VTD_64BITS_ADDRESS(Context= Entry->Bits.SecondLevelPageTranslationPointerLo, ContextEntry->Bits.SecondL= evelPageTranslationPointerHi);=0D + DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%= 02x F%02x)\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId= .Bits.Device, SourceId.Bits.Function));=0D + }=0D + }=0D +=0D + //=0D + // Do not update FixedSecondLevelPagingEntry=0D + //=0D + if (SecondLevelPagingEntry !=3D mVtdUnitInformation[VtdIndex].FixedSecon= dLevelPagingEntry) {=0D + Status =3D SetPageAttribute (=0D + VtdIndex,=0D + DomainIdentifier,=0D + SecondLevelPagingEntry,=0D + BaseAddress,=0D + Length,=0D + IoMmuAccess=0D + );=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR,"SetPageAttribute - %r\n", Status));=0D + return Status;=0D + }=0D + }=0D +=0D + InvalidatePageEntry (VtdIndex);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Always enable the VTd page attribute for the device.=0D +=0D + @param[in] Segment The Segment used to identify a VTd engine.= =0D + @param[in] SourceId The SourceId used to identify a VTd engine= and table entry.=0D +=0D + @retval EFI_SUCCESS The VTd entry is updated to always enable = all DMA access for the specific device.=0D +**/=0D +EFI_STATUS=0D +AlwaysEnablePageAttribute (=0D + IN UINT16 Segment,=0D + IN VTD_SOURCE_ID SourceId=0D + )=0D +{=0D + UINTN VtdIndex;=0D + VTD_EXT_CONTEXT_ENTRY *ExtContextEntry;=0D + VTD_CONTEXT_ENTRY *ContextEntry;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;=0D + UINT64 Pt;=0D +=0D + DEBUG ((DEBUG_INFO,"AlwaysEnablePageAttribute (S%04x B%02x D%02x F%02x)\= n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Functio= n));=0D +=0D + VtdIndex =3D FindVtdIndexByPciDevice (Segment, SourceId, &ExtContextEntr= y, &ContextEntry);=0D + if (VtdIndex =3D=3D (UINTN)-1) {=0D + DEBUG ((DEBUG_ERROR,"AlwaysEnablePageAttribute - Pci device (S%04x B%0= 2x D%02x F%02x) not found!\n", Segment, SourceId.Bits.Bus, SourceId.Bits.De= vice, SourceId.Bits.Function));=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + if (mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry =3D=3D 0) = {=0D + DEBUG((DEBUG_INFO, "CreateSecondLevelPagingEntry - %d\n", VtdIndex));= =0D + mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry =3D CreateSe= condLevelPagingEntry (VtdIndex, EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCES= S_WRITE, mVtdUnitInformation[VtdIndex].Is5LevelPaging);=0D + }=0D +=0D + SecondLevelPagingEntry =3D mVtdUnitInformation[VtdIndex].FixedSecondLeve= lPagingEntry;=0D + Pt =3D (UINT64)RShiftU64 ((UINT64)(UINTN)SecondLevelPagingEntry, 12);=0D + if (ExtContextEntry !=3D NULL) {=0D + ExtContextEntry->Bits.SecondLevelPageTranslationPointerLo =3D (UINT32)= Pt;=0D + ExtContextEntry->Bits.SecondLevelPageTranslationPointerHi =3D (UINT32)= RShiftU64(Pt, 20);=0D + ExtContextEntry->Bits.DomainIdentifier =3D ((1 << (UINT8)((UINTN)mVtdU= nitInformation[VtdIndex].CapReg.Bits.ND * 2 + 4)) - 1);=0D + ExtContextEntry->Bits.Present =3D 1;=0D + FlushPageTableMemory (VtdIndex, (UINTN)ExtContextEntry, sizeof(*ExtCon= textEntry));=0D + } else if (ContextEntry !=3D NULL) {=0D + ContextEntry->Bits.SecondLevelPageTranslationPointerLo =3D (UINT32) Pt= ;=0D + ContextEntry->Bits.SecondLevelPageTranslationPointerHi =3D (UINT32) RS= hiftU64(Pt, 20);=0D + ContextEntry->Bits.DomainIdentifier =3D ((1 << (UINT8)((UINTN)mVtdUnit= Information[VtdIndex].CapReg.Bits.ND * 2 + 4)) - 1);=0D + ContextEntry->Bits.Present =3D 1;=0D + FlushPageTableMemory (VtdIndex, (UINTN)ContextEntry, sizeof(*ContextEn= try));=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/Tran= slationTableEx.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDx= e/TranslationTableEx.c new file mode 100644 index 000000000..c07afaf2b --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/Translation= TableEx.c @@ -0,0 +1,108 @@ +/** @file=0D +=0D + Copyright (c) 2017 - 2023, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include "DmaProtection.h"=0D +=0D +/**=0D + Create extended context entry.=0D +=0D + @param[in] VtdIndex The index of the VTd engine.=0D +=0D + @retval EFI_SUCCESS The extended context entry is created.=0D + @retval EFI_OUT_OF_RESOURCE No enough resource to create extended conte= xt entry.=0D +**/=0D +EFI_STATUS=0D +CreateExtContextEntry (=0D + IN UINTN VtdIndex=0D + )=0D +{=0D + UINTN Index;=0D + VOID *Buffer;=0D + UINTN RootPages;=0D + UINTN ContextPages;=0D + VTD_EXT_ROOT_ENTRY *ExtRootEntry;=0D + VTD_EXT_CONTEXT_ENTRY *ExtContextEntryTable;=0D + VTD_EXT_CONTEXT_ENTRY *ExtContextEntry;=0D + VTD_SOURCE_ID *PciSourceId;=0D + VTD_SOURCE_ID SourceId;=0D + UINTN MaxBusNumber;=0D + UINTN EntryTablePages;=0D +=0D + MaxBusNumber =3D 0;=0D + for (Index =3D 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo->P= ciDeviceDataNumber; Index++) {=0D + PciSourceId =3D &mVtdUnitInformation[VtdIndex].PciDeviceInfo->PciDevic= eData[Index].PciSourceId;=0D + if (PciSourceId->Bits.Bus > MaxBusNumber) {=0D + MaxBusNumber =3D PciSourceId->Bits.Bus;=0D + }=0D + }=0D + DEBUG ((DEBUG_INFO," MaxBusNumber - 0x%x\n", MaxBusNumber));=0D +=0D + RootPages =3D EFI_SIZE_TO_PAGES (sizeof (VTD_EXT_ROOT_ENTRY) * VTD_ROOT_= ENTRY_NUMBER);=0D + ContextPages =3D EFI_SIZE_TO_PAGES (sizeof (VTD_EXT_CONTEXT_ENTRY) * VTD= _CONTEXT_ENTRY_NUMBER);=0D + EntryTablePages =3D RootPages + ContextPages * (MaxBusNumber + 1);=0D + Buffer =3D AllocateZeroPages (EntryTablePages);=0D + if (Buffer =3D=3D NULL) {=0D + DEBUG ((DEBUG_INFO,"Could not Alloc Root Entry Table.. \n"));=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + mVtdUnitInformation[VtdIndex].ExtRootEntryTable =3D (VTD_EXT_ROOT_ENTRY = *)Buffer;=0D + Buffer =3D (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (RootPages);=0D +=0D + for (Index =3D 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo->P= ciDeviceDataNumber; Index++) {=0D + PciSourceId =3D &mVtdUnitInformation[VtdIndex].PciDeviceInfo->PciDevic= eData[Index].PciSourceId;=0D +=0D + SourceId.Bits.Bus =3D PciSourceId->Bits.Bus;=0D + SourceId.Bits.Device =3D PciSourceId->Bits.Device;=0D + SourceId.Bits.Function =3D PciSourceId->Bits.Function;=0D +=0D + ExtRootEntry =3D &mVtdUnitInformation[VtdIndex].ExtRootEntryTable[Sour= ceId.Index.RootIndex];=0D + if (ExtRootEntry->Bits.LowerPresent =3D=3D 0) {=0D + ExtRootEntry->Bits.LowerContextTablePointerLo =3D (UINT32) RShiftU6= 4 ((UINT64)(UINTN)Buffer, 12);=0D + ExtRootEntry->Bits.LowerContextTablePointerHi =3D (UINT32) RShiftU6= 4 ((UINT64)(UINTN)Buffer, 32);=0D + ExtRootEntry->Bits.LowerPresent =3D 1;=0D + ExtRootEntry->Bits.UpperContextTablePointerLo =3D (UINT32) RShiftU6= 4 ((UINT64)(UINTN)Buffer, 12) + 1;=0D + ExtRootEntry->Bits.UpperContextTablePointerHi =3D (UINT32) RShiftU6= 4 (RShiftU64 ((UINT64)(UINTN)Buffer, 12) + 1, 20);=0D + ExtRootEntry->Bits.UpperPresent =3D 1;=0D + Buffer =3D (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (ContextPages);=0D + }=0D +=0D + ExtContextEntryTable =3D (VTD_EXT_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_AD= DRESS(ExtRootEntry->Bits.LowerContextTablePointerLo, ExtRootEntry->Bits.Low= erContextTablePointerHi) ;=0D + ExtContextEntry =3D &ExtContextEntryTable[SourceId.Index.ContextIndex]= ;=0D + ExtContextEntry->Bits.TranslationType =3D 0;=0D + ExtContextEntry->Bits.FaultProcessingDisable =3D 0;=0D + ExtContextEntry->Bits.Present =3D 0;=0D +=0D + DEBUG ((DEBUG_INFO,"DOMAIN: S%04x, B%02x D%02x F%02x\n", mVtdUnitInfor= mation[VtdIndex].Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId= .Bits.Function));=0D +=0D + mVtdUnitInformation[VtdIndex].Is5LevelPaging =3D FALSE;=0D + if ((mVtdUnitInformation[VtdIndex].CapReg.Bits.SAGAW & BIT3) !=3D 0) {= =0D + mVtdUnitInformation[VtdIndex].Is5LevelPaging =3D TRUE;=0D + if ((mAcpiDmarTable->HostAddressWidth <=3D 48) &&=0D + ((mVtdUnitInformation[VtdIndex].CapReg.Bits.SAGAW & BIT2) !=3D 0= )) {=0D + mVtdUnitInformation[VtdIndex].Is5LevelPaging =3D FALSE;=0D + }=0D + } else if ((mVtdUnitInformation[VtdIndex].CapReg.Bits.SAGAW & BIT2) = =3D=3D 0) {=0D + DEBUG((DEBUG_ERROR, "!!!! Page-table type is not supported on VTD %d= !!!!\n", VtdIndex));=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + if (mVtdUnitInformation[VtdIndex].Is5LevelPaging) {=0D + ExtContextEntry->Bits.AddressWidth =3D 0x3;=0D + DEBUG((DEBUG_INFO, "Using 5-level page-table on VTD %d\n", VtdIndex)= );=0D + } else {=0D + ExtContextEntry->Bits.AddressWidth =3D 0x2;=0D + DEBUG((DEBUG_INFO, "Using 4-level page-table on VTD %d\n", VtdIndex)= );=0D + }=0D +=0D +=0D + }=0D +=0D + FlushPageTableMemory (VtdIndex, (UINTN)mVtdUnitInformation[VtdIndex].Ext= RootEntryTable, EFI_PAGES_TO_SIZE(EntryTablePages));=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/VtdL= og.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/VtdLog.c new file mode 100644 index 000000000..0ac4758ff --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/VtdLog.c @@ -0,0 +1,383 @@ +/** @file=0D +=0D + Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include "DmaProtection.h"=0D +=0D +UINT8 *mVtdLogBuffer =3D NULL;=0D +=0D +UINT8 *mVtdLogDxeFreeBuffer =3D NULL;=0D +UINT32 mVtdLogDxeBufferUsed =3D 0;=0D +=0D +UINT32 mVtdLogPeiPostMemBufferUsed =3D 0;=0D +=0D +UINT8 mVtdLogPeiError =3D 0;=0D +UINT16 mVtdLogDxeError =3D 0;=0D +=0D +/**=0D + Allocate memory buffer for VTd log items.=0D +=0D + @param[in] MemorySize Required memory buffer size.=0D +=0D + @retval Buffer address=0D +=0D +**/=0D +UINT8 *=0D +EFIAPI=0D +VTdLogAllocMemory (=0D + IN CONST UINT32 MemorySize=0D + )=0D +{=0D + UINT8 *Buffer;=0D +=0D + Buffer =3D NULL;=0D + if (mVtdLogDxeFreeBuffer !=3D NULL) {=0D + if ((mVtdLogDxeBufferUsed + MemorySize) <=3D PcdGet32 (PcdVTdDxeLogBuf= ferSize)) {=0D + Buffer =3D mVtdLogDxeFreeBuffer;=0D +=0D + mVtdLogDxeFreeBuffer +=3D MemorySize;=0D + mVtdLogDxeBufferUsed +=3D MemorySize;=0D + } else {=0D + mVtdLogDxeError |=3D VTD_LOG_ERROR_BUFFER_FULL;=0D + }=0D + }=0D + return Buffer;=0D +}=0D +=0D +/**=0D + Add a new VTd log event.=0D +=0D + @param[in] EventType Event type=0D + @param[in] Data1 First parameter=0D + @param[in] Data2 Second parameter=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +VTdLogAddEvent (=0D + IN CONST VTDLOG_EVENT_TYPE EventType,=0D + IN CONST UINT64 Data1,=0D + IN CONST UINT64 Data2=0D + )=0D +{=0D + VTDLOG_EVENT_2PARAM *Item;=0D +=0D + if (PcdGet8 (PcdVTdLogLevel) =3D=3D 0) {=0D + return;=0D + } else if ((PcdGet8 (PcdVTdLogLevel) =3D=3D 1) && (EventType >=3D VTDLOG= _DXE_ADVANCED)) {=0D + return;=0D + }=0D +=0D + Item =3D (VTDLOG_EVENT_2PARAM *) VTdLogAllocMemory (sizeof (VTDLOG_EVENT= _2PARAM));=0D + if (Item !=3D NULL) {=0D + Item->Data1 =3D Data1;=0D + Item->Data2 =3D Data2;=0D +=0D + Item->Header.DataSize =3D sizeof (VTDLOG_EVENT_2PARAM);=0D + Item->Header.LogType =3D (UINT64) 1 << EventType;=0D + Item->Header.Timestamp =3D AsmReadTsc ();=0D + }=0D +}=0D +=0D +/**=0D + Add a new VTd log event with data.=0D +=0D + @param[in] EventType Event type=0D + @param[in] Param parameter=0D + @param[in] Data Data=0D + @param[in] DataSize Data size=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +VTdLogAddDataEvent (=0D + IN CONST VTDLOG_EVENT_TYPE EventType,=0D + IN CONST UINT64 Param,=0D + IN CONST VOID *Data,=0D + IN CONST UINT32 DataSize=0D + )=0D +{=0D + VTDLOG_EVENT_CONTEXT *Item;=0D + UINT32 EventSize;=0D +=0D + if (PcdGet8 (PcdVTdLogLevel) =3D=3D 0) {=0D + return;=0D + } else if ((PcdGet8 (PcdVTdLogLevel) =3D=3D 1) && (EventType >=3D VTDLOG= _DXE_ADVANCED)) {=0D + return;=0D + }=0D +=0D + EventSize =3D sizeof (VTDLOG_EVENT_CONTEXT) + DataSize - 1;=0D +=0D + Item =3D (VTDLOG_EVENT_CONTEXT *) VTdLogAllocMemory (EventSize);=0D + if (Item !=3D NULL) {=0D + Item->Param =3D Param;=0D + CopyMem (Item->Data, Data, DataSize);=0D +=0D + Item->Header.DataSize =3D EventSize;=0D + Item->Header.LogType =3D (UINT64) 1 << EventType;=0D + Item->Header.Timestamp =3D AsmReadTsc ();=0D + }=0D +}=0D + =0D +/**=0D + Get Event Items From Pei Pre-Mem Buffer=0D +=0D + @param[in] Buffer Pre-Memory data buffer.=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback function for each VTd log event= =0D +**/=0D +UINT64=0D +EFIAPI=0D +VTdGetEventItemsFromPeiPreMemBuffer (=0D + IN VTDLOG_PEI_PRE_MEM_INFO *InfoBuffer,=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LOG_HANDLE_EVENT CallbackHandle=0D + )=0D +{=0D + UINTN Index;=0D + UINT64 EventCount;=0D + VTDLOG_EVENT_2PARAM Event;=0D +=0D + if (InfoBuffer =3D=3D NULL) {=0D + return 0;=0D + }=0D +=0D + EventCount =3D 0;=0D + for (Index =3D 0; Index < VTD_LOG_PEI_PRE_MEM_BAR_MAX; Index++) {=0D + if (InfoBuffer[Index].Mode =3D=3D VTD_LOG_PEI_PRE_MEM_NOT_USED) {=0D + continue;=0D + }=0D + if (CallbackHandle) {=0D + Event.Header.DataSize =3D sizeof (VTDLOG_EVENT_2PARAM);=0D + Event.Header.Timestamp =3D 0;=0D +=0D + Event.Header.LogType =3D ((UINT64) 1) << VTDLOG_PEI_PRE_MEM_DMA_PROT= ECT;=0D + Event.Data1 =3D InfoBuffer[Index].BarAddress;=0D + Event.Data2 =3D InfoBuffer[Index].Mode;=0D + Event.Data2 |=3D InfoBuffer[Index].Status<<8;=0D + CallbackHandle (Context, &Event.Header);=0D + }=0D + EventCount++;=0D + }=0D +=0D + return EventCount;=0D +}=0D +=0D +/**=0D + Get Event Items From Pei Post-Mem/Dxe Buffer=0D +=0D + @param[in] Buffer Data buffer.=0D + @param[in] BufferUsed Data buffer used.=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback function for each VTd log eve= nt=0D +**/=0D +UINT64=0D +EFIAPI=0D +VTdGetEventItemsFromBuffer (=0D + IN UINT8 *Buffer,=0D + IN UINT32 BufferUsed,=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LOG_HANDLE_EVENT CallbackHandle=0D + )=0D +{=0D + UINT64 Count;=0D + VTDLOG_EVENT_HEADER *Header;=0D +=0D + Count =3D 0;=0D + if (Buffer !=3D NULL) {=0D + while (BufferUsed > 0) {=0D + Header =3D (VTDLOG_EVENT_HEADER *) Buffer;=0D + if (BufferUsed >=3D Header->DataSize) {=0D + if (CallbackHandle) {=0D + CallbackHandle (Context, Header);=0D + }=0D + Buffer +=3D Header->DataSize;=0D + BufferUsed -=3D Header->DataSize;=0D + Count++;=0D + } else {=0D + BufferUsed =3D 0;=0D + }=0D + }=0D + }=0D +=0D + return Count;=0D +}=0D +=0D +/**=0D + Generate the VTd log state.=0D +=0D + @param[in] EventType Event type=0D + @param[in] Data1 First parameter=0D + @param[in] Data2 Second parameter=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback function for each VTd log eve= nt=0D +**/=0D +VOID=0D +EFIAPI=0D +VTdGenerateStateEvent (=0D + IN VTDLOG_EVENT_TYPE EventType,=0D + IN UINT64 Data1,=0D + IN UINT64 Data2,=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LOG_HANDLE_EVENT CallbackHandle=0D + )=0D +{=0D + VTDLOG_EVENT_2PARAM Item;=0D +=0D + Item.Data1 =3D Data1;=0D + Item.Data2 =3D Data2;=0D +=0D + Item.Header.DataSize =3D sizeof (VTDLOG_EVENT_2PARAM);=0D + Item.Header.LogType =3D (UINT64) 1 << EventType;=0D + Item.Header.Timestamp =3D 0;=0D +=0D + if (CallbackHandle) {=0D + CallbackHandle (Context, &Item.Header);=0D + }=0D +}=0D +=0D +/**=0D + Get the VTd log events.=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback function for each VTd log eve= nt=0D +=0D + @retval UINT32 Number of events=0D +**/=0D +UINT64=0D +EFIAPI=0D +VTdLogGetEvents (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LOG_HANDLE_EVENT CallbackHandle=0D + )=0D +{=0D + UINT64 CountPeiPreMem;=0D + UINT64 CountPeiPostMem;=0D + UINT64 CountDxe;=0D + UINT8 *Buffer;=0D +=0D + if (mVtdLogBuffer =3D=3D NULL) {=0D + return 0;=0D + }=0D +=0D + //=0D + // PEI pre-memory phase=0D + //=0D + Buffer =3D &mVtdLogBuffer[PcdGet32 (PcdVTdDxeLogBufferSize) + PcdGet32 (= PcdVTdPeiPostMemLogBufferSize)];=0D + CountPeiPreMem =3D VTdGetEventItemsFromPeiPreMemBuffer ((VTDLOG_PEI_PRE_= MEM_INFO *) Buffer, Context, CallbackHandle);=0D + DEBUG ((DEBUG_INFO, "Find %d in PEI pre mem phase\n", CountPeiPreMem));= =0D +=0D + //=0D + // PEI post memory phase=0D + //=0D + Buffer =3D &mVtdLogBuffer[PcdGet32 (PcdVTdDxeLogBufferSize)];=0D + CountPeiPostMem =3D VTdGetEventItemsFromBuffer (Buffer, mVtdLogPeiPostMe= mBufferUsed, Context, CallbackHandle);=0D + if (mVtdLogPeiError !=3D 0) {=0D + VTdGenerateStateEvent (VTDLOG_PEI_BASIC, mVtdLogPeiError, 0, Context, = CallbackHandle);=0D + CountPeiPostMem++;=0D + }=0D + DEBUG ((DEBUG_INFO, "Find %d in PEI post mem phase\n", CountPeiPostMem))= ;=0D +=0D + //=0D + // DXE phase=0D + //=0D + Buffer =3D &mVtdLogBuffer[0];=0D + CountDxe =3D VTdGetEventItemsFromBuffer (Buffer, mVtdLogDxeBufferUsed, C= ontext, CallbackHandle);=0D + if (mVtdLogDxeError !=3D 0) {=0D + VTdGenerateStateEvent (VTDLOG_DXE_BASIC, mVtdLogDxeError, 0, Context, = CallbackHandle);=0D + CountDxe++;=0D + }=0D + DEBUG ((DEBUG_INFO, "Find %d in DXE phase\n", CountDxe));=0D +=0D + return CountPeiPreMem + CountPeiPostMem + CountDxe;=0D +}=0D +=0D +EDKII_VTD_LOG_PROTOCOL mIntelVTdLog =3D {=0D + EDKII_VTD_LOG_PROTOCOL_REVISION,=0D + VTdLogGetEvents=0D +};=0D +=0D +/**=0D + Initializes the VTd Log.=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +VTdLogInitialize(=0D + VOID=0D + )=0D +{=0D + UINT32 TotalBufferSize;=0D + EFI_STATUS Status;=0D + VOID *HobPtr;=0D + VTDLOG_PEI_BUFFER_HOB *HobPeiBuffer;=0D + EFI_HANDLE Handle;=0D + UINT32 BufferOffset;=0D +=0D + if (PcdGet8 (PcdVTdLogLevel) =3D=3D 0) {=0D + return;=0D + }=0D +=0D + if (mVtdLogBuffer !=3D NULL) {=0D + return;=0D + }=0D +=0D + TotalBufferSize =3D PcdGet32 (PcdVTdDxeLogBufferSize) + PcdGet32 (PcdVTd= PeiPostMemLogBufferSize) + sizeof (VTDLOG_PEI_PRE_MEM_INFO) * VTD_LOG_PEI_P= RE_MEM_BAR_MAX;=0D +=0D + Status =3D gBS->AllocatePool (EfiBootServicesData, TotalBufferSize, &mVt= dLogBuffer);=0D + if (EFI_ERROR (Status)) {=0D + return;=0D + }=0D +=0D + //=0D + // DXE Buffer=0D + //=0D + if (PcdGet32 (PcdVTdDxeLogBufferSize) > 0) {=0D + mVtdLogDxeFreeBuffer =3D mVtdLogBuffer;=0D + mVtdLogDxeBufferUsed =3D 0;=0D + }=0D +=0D + //=0D + // Get PEI pre-memory buffer offset=0D + //=0D + BufferOffset =3D PcdGet32 (PcdVTdDxeLogBufferSize) + PcdGet32 (PcdVTdPei= PostMemLogBufferSize);=0D +=0D + HobPtr =3D GetFirstGuidHob (&gVTdLogBufferHobGuid);=0D + if (HobPtr !=3D NULL) {=0D + HobPeiBuffer =3D GET_GUID_HOB_DATA (HobPtr);=0D +=0D + //=0D + // Copy PEI pre-memory phase VTd log.=0D + //=0D + CopyMem (&mVtdLogBuffer[BufferOffset], &HobPeiBuffer->PreMemInfo, size= of (VTDLOG_PEI_PRE_MEM_INFO) * VTD_LOG_PEI_PRE_MEM_BAR_MAX);=0D +=0D + //=0D + // Copy PEI post-memory pase VTd log.=0D + //=0D + BufferOffset =3D PcdGet32 (PcdVTdDxeLogBufferSize);=0D + if (PcdGet32 (PcdVTdPeiPostMemLogBufferSize) > 0) {=0D + if (HobPeiBuffer->PostMemBufferUsed > 0) {=0D + mVtdLogPeiPostMemBufferUsed =3D HobPeiBuffer->PostMemBufferUsed;=0D + CopyMem (&mVtdLogBuffer[BufferOffset], (UINT8 *) (UINTN) HobPeiBuf= fer->PostMemBuffer, mVtdLogPeiPostMemBufferUsed);=0D + }=0D + }=0D +=0D + mVtdLogPeiError =3D HobPeiBuffer->VtdLogPeiError;=0D + } else {=0D + //=0D + // Do not find PEI Vtd log, clear PEI pre-memory phase buffer.=0D + //=0D + ZeroMem (&mVtdLogBuffer[BufferOffset], sizeof (VTDLOG_PEI_PRE_MEM_INFO= ) * VTD_LOG_PEI_PRE_MEM_BAR_MAX);=0D + }=0D +=0D + Handle =3D NULL;=0D + Status =3D gBS->InstallMultipleProtocolInterfaces (=0D + &Handle,=0D + &gEdkiiVTdLogProtocolGuid,=0D + &mIntelVTdLog,=0D + NULL=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +}=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/VtdR= eg.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/VtdReg.c new file mode 100644 index 000000000..dd0c49698 --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCoreDxe/VtdReg.c @@ -0,0 +1,757 @@ +/** @file=0D +=0D + Copyright (c) 2017 - 2023, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include "DmaProtection.h"=0D +=0D +#define VTD_CAP_REG_NFR_MAX (256)=0D +=0D +UINTN mVtdUnitNumber =3D 0;=0D +VTD_UNIT_INFORMATION *mVtdUnitInformation =3D NULL;=0D +VTD_REGESTER_INFO *mVtdRegsInfoBuffer =3D NULL;=0D +=0D +BOOLEAN mVtdEnabled;=0D +=0D +/**=0D + Flush VTD page table and context table memory.=0D +=0D + This action is to make sure the IOMMU engine can get final data in memor= y.=0D +=0D + @param[in] VtdIndex The index used to identify a VTd engine.=0D + @param[in] Base The base address of memory to be flushed.= =0D + @param[in] Size The size of memory in bytes to be flushed.= =0D +**/=0D +VOID=0D +FlushPageTableMemory (=0D + IN UINTN VtdIndex,=0D + IN UINTN Base,=0D + IN UINTN Size=0D + )=0D +{=0D + if (mVtdUnitInformation[VtdIndex].ECapReg.Bits.C =3D=3D 0) {=0D + WriteBackDataCacheRange ((VOID *)Base, Size);=0D + }=0D +}=0D +=0D +/**=0D + Perpare cache invalidation interface.=0D +=0D + @param[in] VtdIndex The index used to identify a VTd engine.=0D +=0D + @retval EFI_SUCCESS The operation was successful.=0D + @retval EFI_UNSUPPORTED Invalidation method is not supported.=0D + @retval EFI_OUT_OF_RESOURCES A memory allocation failed.=0D +**/=0D +EFI_STATUS=0D +PerpareCacheInvalidationInterface (=0D + IN UINTN VtdIndex=0D + )=0D +{=0D + UINT32 Reg32;=0D + VTD_IQA_REG IqaReg;=0D + VTD_UNIT_INFORMATION *VtdUnitInfo;=0D + UINTN VtdUnitBaseAddress;=0D +=0D + VtdUnitInfo =3D &mVtdUnitInformation[VtdIndex];=0D + VtdUnitBaseAddress =3D VtdUnitInfo->VtdUnitBaseAddress;=0D +=0D + if (VtdUnitInfo->VerReg.Bits.Major <=3D 5) {=0D + VtdUnitInfo->EnableQueuedInvalidation =3D 0;=0D + DEBUG ((DEBUG_INFO, "Use Register-based Invalidation Interface for eng= ine [%d]\n", VtdIndex));=0D + return EFI_SUCCESS;=0D + }=0D +=0D + if (VtdUnitInfo->ECapReg.Bits.QI =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR, "Hardware does not support queued invalidations i= nterface for engine [%d]\n", VtdIndex));=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + VtdUnitInfo->EnableQueuedInvalidation =3D 1;=0D + DEBUG ((DEBUG_INFO, "Use Queued Invalidation Interface for engine [%d]\n= ", VtdIndex));=0D +=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);=0D + if ((Reg32 & B_GSTS_REG_QIES) !=3D 0) {=0D + DEBUG ((DEBUG_ERROR,"Queued Invalidation Interface was enabled.\n"));= =0D +=0D + VtdLibDisableQueuedInvalidationInterface (VtdUnitBaseAddress);=0D + }=0D +=0D + //=0D + // Initialize the Invalidation Queue Tail Register to zero.=0D + //=0D + MmioWrite64 (VtdUnitBaseAddress + R_IQT_REG, 0);=0D +=0D + //=0D + // Setup the IQ address, size and descriptor width through the Invalidat= ion Queue Address Register=0D + //=0D + if (VtdUnitInfo->QiDescBuffer =3D=3D NULL) {=0D + VtdUnitInfo->QiDescBufferSize =3D (sizeof (QI_256_DESC) * ((UINTN) 1 <= < (VTD_INVALIDATION_QUEUE_SIZE + 7)));=0D + VtdUnitInfo->QiDescBuffer =3D AllocatePages (EFI_SIZE_TO_PAGES (VtdUni= tInfo->QiDescBufferSize));=0D + if (VtdUnitInfo->QiDescBuffer =3D=3D NULL) {=0D + DEBUG ((DEBUG_ERROR,"Could not Alloc Invalidation Queue Buffer.\n"))= ;=0D + VTdLogAddEvent (VTDLOG_DXE_QUEUED_INVALIDATION, VTD_LOG_QI_ERROR_OUT= _OF_RESOURCES, VtdUnitBaseAddress);=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, "Invalidation Queue Buffer Size : %d\n", VtdUnitInfo= ->QiDescBufferSize));=0D + //=0D + // 4KB Aligned address=0D + //=0D + IqaReg.Uint64 =3D (UINT64) (UINTN) VtdUnitInfo->QiDescBuffer;=0D + IqaReg.Bits.DW =3D VTD_QUEUED_INVALIDATION_DESCRIPTOR_WIDTH;=0D + IqaReg.Bits.QS =3D VTD_INVALIDATION_QUEUE_SIZE;=0D + MmioWrite64 (VtdUnitBaseAddress + R_IQA_REG, IqaReg.Uint64);=0D + IqaReg.Uint64 =3D MmioRead64 (VtdUnitBaseAddress + R_IQA_REG);=0D + DEBUG ((DEBUG_INFO, "IQA_REG =3D 0x%lx, IQH_REG =3D 0x%lx\n", IqaReg.Uin= t64, MmioRead64 (VtdUnitBaseAddress + R_IQH_REG)));=0D +=0D + //=0D + // Enable the queued invalidation interface through the Global Command R= egister.=0D + // When enabled, hardware sets the QIES field in the Global Status Regis= ter.=0D + //=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);=0D + Reg32 |=3D B_GMCD_REG_QIE;=0D + MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32);=0D + DEBUG ((DEBUG_INFO, "Enable Queued Invalidation Interface. GCMD_REG =3D = 0x%x\n", Reg32));=0D + do {=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);=0D + } while ((Reg32 & B_GSTS_REG_QIES) =3D=3D 0);=0D +=0D + VTdLogAddEvent (VTDLOG_DXE_QUEUED_INVALIDATION, VTD_LOG_QI_ENABLE, VtdUn= itBaseAddress);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Submit the queued invalidation descriptor to the remapping=0D + hardware unit and wait for its completion.=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D + @param[in] Desc The invalidate descriptor=0D +=0D + @retval EFI_SUCCESS The operation was successful.=0D + @retval RETURN_DEVICE_ERROR A fault is detected.=0D + @retval EFI_INVALID_PARAMETER Parameter is invalid.=0D +**/=0D +EFI_STATUS=0D +SubmitQueuedInvalidationDescriptor (=0D + IN UINTN VtdUnitBaseAddress,=0D + IN QI_256_DESC *Desc=0D + )=0D +{=0D + EFI_STATUS Status;=0D + VTD_REGESTER_QI_INFO RegisterQi;=0D +=0D + Status =3D VtdLibSubmitQueuedInvalidationDescriptor (VtdUnitBaseAddress,= Desc, FALSE);=0D + if (Status =3D=3D EFI_DEVICE_ERROR) {=0D + RegisterQi.BaseAddress =3D VtdUnitBaseAddress;=0D + RegisterQi.FstsReg =3D MmioRead32 (VtdUnitBaseAddress + R_FSTS_REG= );;=0D + RegisterQi.IqercdReg =3D MmioRead64 (VtdUnitBaseAddress + R_IQERCD_R= EG);=0D + VTdLogAddDataEvent (VTDLOG_PEI_REGISTER, VTDLOG_REGISTER_QI, &Register= Qi, sizeof (VTD_REGESTER_QI_INFO));=0D +=0D + MmioWrite32 (VtdUnitBaseAddress + R_FSTS_REG, RegisterQi.FstsReg & (B_= FSTS_REG_IQE | B_FSTS_REG_ITE | B_FSTS_REG_ICE));=0D + }=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + Invalidate VTd context cache.=0D +=0D + @param[in] VtdIndex The index used to identify a VTd engine.=0D +**/=0D +EFI_STATUS=0D +InvalidateContextCache (=0D + IN UINTN VtdIndex=0D + )=0D +{=0D + UINT64 Reg64;=0D + QI_256_DESC QiDesc;=0D +=0D + if (mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation =3D=3D 0) {=0D + //=0D + // Register-based Invalidation=0D + //=0D + Reg64 =3D MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress= + R_CCMD_REG);=0D + if ((Reg64 & B_CCMD_REG_ICC) !=3D 0) {=0D + DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC i= s set for VTD(%d)\n",VtdIndex));=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + Reg64 &=3D ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK));=0D + Reg64 |=3D (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL);=0D + MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD= _REG, Reg64);=0D +=0D + do {=0D + Reg64 =3D MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddre= ss + R_CCMD_REG);=0D + } while ((Reg64 & B_CCMD_REG_ICC) !=3D 0);=0D + } else {=0D + //=0D + // Queued Invalidation=0D + //=0D + QiDesc.Uint64[0] =3D QI_CC_FM(0) | QI_CC_SID(0) | QI_CC_DID(0) | QI_CC= _GRAN(1) | QI_CC_TYPE;=0D + QiDesc.Uint64[1] =3D 0;=0D + QiDesc.Uint64[2] =3D 0;=0D + QiDesc.Uint64[3] =3D 0;=0D +=0D + return SubmitQueuedInvalidationDescriptor(mVtdUnitInformation[VtdIndex= ].VtdUnitBaseAddress, &QiDesc);=0D + }=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Invalidate VTd IOTLB.=0D +=0D + @param[in] VtdIndex The index used to identify a VTd engine.=0D +**/=0D +EFI_STATUS=0D +InvalidateIOTLB (=0D + IN UINTN VtdIndex=0D + )=0D +{=0D + UINT64 Reg64;=0D + QI_256_DESC QiDesc;=0D +=0D + if (mVtdUnitInformation[VtdIndex].EnableQueuedInvalidation =3D=3D 0) {=0D + //=0D + // Register-based Invalidation=0D + //=0D + Reg64 =3D MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress= + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);=0D + if ((Reg64 & B_IOTLB_REG_IVT) !=3D 0) {=0D + DEBUG ((DEBUG_ERROR,"ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set = for VTD(%d)\n", VtdIndex));=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + Reg64 &=3D ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK));=0D + Reg64 |=3D (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL);=0D + MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdU= nitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);=0D +=0D + do {=0D + Reg64 =3D MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddre= ss + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);= =0D + } while ((Reg64 & B_IOTLB_REG_IVT) !=3D 0);=0D + } else {=0D + //=0D + // Queued Invalidation=0D + //=0D + QiDesc.Uint64[0] =3D QI_IOTLB_DID(0) | QI_IOTLB_DR(CAP_READ_DRAIN(mVtd= UnitInformation[VtdIndex].CapReg.Uint64)) | QI_IOTLB_DW(CAP_WRITE_DRAIN(mVt= dUnitInformation[VtdIndex].CapReg.Uint64)) | QI_IOTLB_GRAN(1) | QI_IOTLB_TY= PE;=0D + QiDesc.Uint64[1] =3D QI_IOTLB_ADDR(0) | QI_IOTLB_IH(0) | QI_IOTLB_AM(0= );=0D + QiDesc.Uint64[2] =3D 0;=0D + QiDesc.Uint64[3] =3D 0;=0D +=0D + return SubmitQueuedInvalidationDescriptor(mVtdUnitInformation[VtdIndex= ].VtdUnitBaseAddress, &QiDesc);=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Invalid VTd global IOTLB.=0D +=0D + @param[in] VtdIndex The index of VTd engine.=0D +=0D + @retval EFI_SUCCESS VTd global IOTLB is invalidated.=0D + @retval EFI_DEVICE_ERROR VTd global IOTLB is not invalidated.=0D +**/=0D +EFI_STATUS=0D +InvalidateVtdIOTLBGlobal (=0D + IN UINTN VtdIndex=0D + )=0D +{=0D + if (!mVtdEnabled) {=0D + return EFI_SUCCESS;=0D + }=0D +=0D + DEBUG((DEBUG_VERBOSE, "InvalidateVtdIOTLBGlobal(%d)\n", VtdIndex));=0D +=0D + //=0D + // Write Buffer Flush before invalidation=0D + //=0D + VtdLibFlushWriteBuffer (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress= );=0D +=0D + //=0D + // Invalidate the context cache=0D + //=0D + if (mVtdUnitInformation[VtdIndex].HasDirtyContext) {=0D + InvalidateContextCache (VtdIndex);=0D + }=0D +=0D + //=0D + // Invalidate the IOTLB cache=0D + //=0D + if (mVtdUnitInformation[VtdIndex].HasDirtyContext || mVtdUnitInformation= [VtdIndex].HasDirtyPages) {=0D + InvalidateIOTLB (VtdIndex);=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Prepare VTD configuration.=0D +**/=0D +VOID=0D +PrepareVtdConfig (=0D + VOID=0D + )=0D +{=0D + UINTN Index;=0D + UINTN DomainNumber;=0D + EFI_STATUS Status;=0D +=0D + if (mVtdRegsInfoBuffer =3D=3D NULL) {=0D + mVtdRegsInfoBuffer =3D AllocateZeroPool (sizeof (VTD_REGESTER_INFO) + = sizeof (VTD_UINT128) * VTD_CAP_REG_NFR_MAX);=0D + ASSERT (mVtdRegsInfoBuffer !=3D NULL);=0D + }=0D +=0D + //=0D + // Dump VTd error before DXE phase=0D + //=0D + DumpVtdIfError ();=0D +=0D + for (Index =3D 0; Index < mVtdUnitNumber; Index++) {=0D + DEBUG ((DEBUG_INFO, "Dump VTd Capability (%d)\n", Index));=0D + mVtdUnitInformation[Index].VerReg.Uint32 =3D MmioRead32 (mVtdUnitInfor= mation[Index].VtdUnitBaseAddress + R_VER_REG);=0D + DumpVtdVerRegs (&mVtdUnitInformation[Index].VerReg);=0D + mVtdUnitInformation[Index].CapReg.Uint64 =3D MmioRead64 (mVtdUnitInfor= mation[Index].VtdUnitBaseAddress + R_CAP_REG);=0D + DumpVtdCapRegs (&mVtdUnitInformation[Index].CapReg);=0D + mVtdUnitInformation[Index].ECapReg.Uint64 =3D MmioRead64 (mVtdUnitInfo= rmation[Index].VtdUnitBaseAddress + R_ECAP_REG);=0D + DumpVtdECapRegs (&mVtdUnitInformation[Index].ECapReg);=0D +=0D + if ((mVtdUnitInformation[Index].CapReg.Bits.SLLPS & BIT0) =3D=3D 0) {= =0D + DEBUG((DEBUG_WARN, "!!!! 2MB super page is not supported on VTD %d != !!!\n", Index));=0D + }=0D + if ((mVtdUnitInformation[Index].CapReg.Bits.SAGAW & BIT3) !=3D 0) {=0D + DEBUG((DEBUG_INFO, "Support 5-level page-table on VTD %d\n", Index))= ;=0D + }=0D + if ((mVtdUnitInformation[Index].CapReg.Bits.SAGAW & BIT2) !=3D 0) {=0D + DEBUG((DEBUG_INFO, "Support 4-level page-table on VTD %d\n", Index))= ;=0D + }=0D + if ((mVtdUnitInformation[Index].CapReg.Bits.SAGAW & (BIT3 | BIT2)) =3D= =3D 0) {=0D + DEBUG((DEBUG_ERROR, "!!!! Page-table type 0x%X is not supported on V= TD %d !!!!\n", Index, mVtdUnitInformation[Index].CapReg.Bits.SAGAW));=0D + return ;=0D + }=0D +=0D + DomainNumber =3D (UINTN)1 << (UINT8)((UINTN)mVtdUnitInformation[Index]= .CapReg.Bits.ND * 2 + 4);=0D + if (mVtdUnitInformation[Index].PciDeviceInfo->PciDeviceDataNumber >=3D= DomainNumber) {=0D + DEBUG((DEBUG_ERROR, "!!!! Pci device Number(0x%x) >=3D DomainNumber(= 0x%x) !!!!\n", mVtdUnitInformation[Index].PciDeviceInfo->PciDeviceDataNumbe= r, DomainNumber));=0D + return ;=0D + }=0D +=0D + Status =3D PerpareCacheInvalidationInterface(Index);=0D + if (EFI_ERROR (Status)) {=0D + ASSERT(FALSE);=0D + return;=0D + }=0D + }=0D + return ;=0D +}=0D +=0D +/**=0D + Disable PMR in all VTd engine.=0D +**/=0D +VOID=0D +DisablePmr (=0D + VOID=0D + )=0D +{=0D + UINTN Index;=0D + EFI_STATUS Status;=0D +=0D + DEBUG ((DEBUG_INFO,"DisablePmr\n"));=0D +=0D + for (Index =3D 0; Index < mVtdUnitNumber; Index++) {=0D + Status =3D VtdLibDisablePmr (mVtdUnitInformation[Index].VtdUnitBaseAdd= ress);=0D + VTdLogAddEvent (VTDLOG_DXE_DISABLE_PMR, mVtdUnitInformation[Index].Vtd= UnitBaseAddress, Status);=0D + }=0D +=0D + return ;=0D +}=0D +=0D +/**=0D + Update Root Table Address Register=0D +=0D + @param[in] VtdIndex The index used to identify a VTd engine.=0D + @param[in] EnableADM TRUE - Enable ADM in TTM bits=0D +**/=0D +VOID=0D +UpdateRootTableAddressRegister (=0D + IN UINTN VtdIndex,=0D + IN BOOLEAN EnableADM=0D + )=0D +{=0D + UINT64 Reg64;=0D +=0D + if (mVtdUnitInformation[VtdIndex].ExtRootEntryTable !=3D NULL) {=0D + DEBUG((DEBUG_INFO, "ExtRootEntryTable 0x%x \n", mVtdUnitInformation[Vt= dIndex].ExtRootEntryTable));=0D + Reg64 =3D (UINT64)(UINTN)mVtdUnitInformation[VtdIndex].ExtRootEntryTab= le | (EnableADM ? V_RTADDR_REG_TTM_ADM : BIT11);=0D + } else {=0D + DEBUG((DEBUG_INFO, "RootEntryTable 0x%x \n", mVtdUnitInformation[VtdIn= dex].RootEntryTable));=0D + Reg64 =3D (UINT64)(UINTN)mVtdUnitInformation[VtdIndex].RootEntryTable = | (EnableADM ? V_RTADDR_REG_TTM_ADM : 0);=0D + }=0D + MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_RTADDR= _REG, Reg64);=0D +}=0D +=0D +/**=0D + Enable DMAR translation.=0D +=0D + @retval EFI_SUCCESS DMAR translation is enabled.=0D + @retval EFI_DEVICE_ERROR DMAR translation is not enabled.=0D +**/=0D +EFI_STATUS=0D +EnableDmar (=0D + VOID=0D + )=0D +{=0D + UINTN Index;=0D + UINTN VtdUnitBaseAddress;=0D + BOOLEAN TEWasEnabled;=0D +=0D + for (Index =3D 0; Index < mVtdUnitNumber; Index++) {=0D + VtdUnitBaseAddress =3D mVtdUnitInformation[Index].VtdUnitBaseAddress;= =0D + DEBUG((DEBUG_INFO, ">>>>>>EnableDmar() for engine [%d] BAR [0x%x]\n", = Index, VtdUnitBaseAddress));=0D +=0D + //=0D + // Check TE was enabled or not.=0D + //=0D + TEWasEnabled =3D ((MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG) & B_GS= TS_REG_TE) =3D=3D B_GSTS_REG_TE);=0D +=0D + if (TEWasEnabled && (mVtdUnitInformation[Index].ECapReg.Bits.ADMS =3D= =3D 1) && PcdGetBool (PcdVTdSupportAbortDmaMode)) {=0D + //=0D + // For implementations reporting Enhanced SRTP Support (ESRTPS) fiel= d as=0D + // Clear in the Capability register, software must not modify this f= ield while=0D + // DMA remapping is active (TES=3D1 in Global Status register).=0D + //=0D + if (mVtdUnitInformation[Index].CapReg.Bits.ESRTPS =3D=3D 0) {=0D + VtdLibClearGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_R= EG_TE);=0D + }=0D +=0D + //=0D + // Enable ADM=0D + //=0D + UpdateRootTableAddressRegister (Index, TRUE);=0D +=0D + DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n= "));=0D + VtdLibSetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_S= RTP);=0D +=0D + DEBUG((DEBUG_INFO, "Enable Abort DMA Mode...\n"));=0D + VtdLibSetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_T= E);=0D +=0D + } else {=0D + UpdateRootTableAddressRegister (Index, FALSE);=0D +=0D + DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n= "));=0D + VtdLibSetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_S= RTP);=0D + }=0D +=0D + //=0D + // Write Buffer Flush before invalidation=0D + //=0D + VtdLibFlushWriteBuffer (VtdUnitBaseAddress);=0D +=0D + //=0D + // Invalidate the context cache=0D + //=0D + InvalidateContextCache (Index);=0D +=0D + //=0D + // Invalidate the IOTLB cache=0D + //=0D + InvalidateIOTLB (Index);=0D +=0D + if (TEWasEnabled && (mVtdUnitInformation[Index].ECapReg.Bits.ADMS =3D= =3D 1) && PcdGetBool (PcdVTdSupportAbortDmaMode)) {=0D + if (mVtdUnitInformation[Index].CapReg.Bits.ESRTPS =3D=3D 0) {=0D + VtdLibClearGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_R= EG_TE);=0D + }=0D +=0D + UpdateRootTableAddressRegister (Index, FALSE);=0D +=0D + DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n= "));=0D + VtdLibSetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_S= RTP);=0D + }=0D +=0D + //=0D + // Enable VTd=0D + //=0D + DEBUG ((DEBUG_INFO, "EnableDmar: Waiting B_GSTS_REG_TE ...\n"));=0D + VtdLibSetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_TE)= ;=0D +=0D + DEBUG ((DEBUG_INFO,"VTD (%d) enabled!<<<<<<\n",Index));=0D +=0D + VTdLogAddEvent (VTDLOG_DXE_ENABLE_DMAR, mVtdUnitInformation[Index].Vtd= UnitBaseAddress, 0);=0D + }=0D +=0D + //=0D + // Need disable PMR, since we already setup translation table.=0D + //=0D + DisablePmr ();=0D +=0D + mVtdEnabled =3D TRUE;=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Disable DMAR translation.=0D +=0D + @retval EFI_SUCCESS DMAR translation is disabled.=0D + @retval EFI_DEVICE_ERROR DMAR translation is not disabled.=0D +**/=0D +EFI_STATUS=0D +DisableDmar (=0D + VOID=0D + )=0D +{=0D + UINTN Index;=0D + UINTN SubIndex;=0D + VTD_UNIT_INFORMATION *VtdUnitInfo;=0D +=0D + for (Index =3D 0; Index < mVtdUnitNumber; Index++) {=0D + VtdUnitInfo =3D &mVtdUnitInformation[Index];=0D +=0D + VtdLibDisableDmar (VtdUnitInfo->VtdUnitBaseAddress);=0D + VTdLogAddEvent (VTDLOG_DXE_DISABLE_DMAR, VtdUnitInfo->VtdUnitBaseAddre= ss, 0);=0D +=0D + if (VtdUnitInfo->EnableQueuedInvalidation !=3D 0) {=0D + //=0D + // Disable queued invalidation interface.=0D + //=0D + VtdLibDisableQueuedInvalidationInterface (VtdUnitInfo->VtdUnitBaseAd= dress);=0D + VTdLogAddEvent (VTDLOG_DXE_QUEUED_INVALIDATION, VTD_LOG_QI_DISABLE, = VtdUnitInfo->VtdUnitBaseAddress);=0D +=0D + //=0D + // Free descriptor queue memory=0D + //=0D + if (VtdUnitInfo->QiDescBuffer !=3D NULL) {=0D + FreePages(VtdUnitInfo->QiDescBuffer, EFI_SIZE_TO_PAGES (VtdUnitInf= o->QiDescBufferSize));=0D + VtdUnitInfo->QiDescBuffer =3D NULL;=0D + VtdUnitInfo->QiDescBufferSize =3D 0;=0D + }=0D +=0D + VtdUnitInfo->EnableQueuedInvalidation =3D 0;=0D + }=0D + }=0D +=0D + mVtdEnabled =3D FALSE;=0D +=0D + for (Index =3D 0; Index < mVtdUnitNumber; Index++) {=0D + VtdUnitInfo =3D &mVtdUnitInformation[Index];=0D + DEBUG((DEBUG_INFO, "engine [%d] access\n", Index));=0D + for (SubIndex =3D 0; SubIndex < VtdUnitInfo->PciDeviceInfo->PciDeviceD= ataNumber; SubIndex++) {=0D + DEBUG ((DEBUG_INFO, " PCI S%04X B%02x D%02x F%02x - %d\n",=0D + VtdUnitInfo->Segment,=0D + VtdUnitInfo->PciDeviceInfo->PciDeviceData[Index].PciSourceId.Bits.= Bus,=0D + VtdUnitInfo->PciDeviceInfo->PciDeviceData[Index].PciSourceId.Bits.= Device,=0D + VtdUnitInfo->PciDeviceInfo->PciDeviceData[Index].PciSourceId.Bits.= Function,=0D + VtdUnitInfo->PciDeviceInfo->PciDeviceData[Index].AccessCount=0D + ));=0D + }=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Dump VTd version registers.=0D +=0D + @param[in] VerReg The version register.=0D +**/=0D +VOID=0D +DumpVtdVerRegs (=0D + IN VTD_VER_REG *VerReg=0D + )=0D +{=0D + DEBUG ((DEBUG_INFO, " VerReg - 0x%x\n", VerReg->Uint32));=0D + DEBUG ((DEBUG_INFO, " Major - 0x%x\n", VerReg->Bits.Major));=0D + DEBUG ((DEBUG_INFO, " Minor - 0x%x\n", VerReg->Bits.Minor));=0D +}=0D +=0D +/**=0D + Dump VTd capability registers.=0D +=0D + @param[in] CapReg The capability register.=0D +**/=0D +VOID=0D +DumpVtdCapRegs (=0D + IN VTD_CAP_REG *CapReg=0D + )=0D +{=0D + DEBUG((DEBUG_INFO, " CapReg - 0x%x\n", CapReg->Uint64));=0D + DEBUG((DEBUG_INFO, " ND - 0x%x\n", CapReg->Bits.ND));=0D + DEBUG((DEBUG_INFO, " AFL - 0x%x\n", CapReg->Bits.AFL));=0D + DEBUG((DEBUG_INFO, " RWBF - 0x%x\n", CapReg->Bits.RWBF));=0D + DEBUG((DEBUG_INFO, " PLMR - 0x%x\n", CapReg->Bits.PLMR));=0D + DEBUG((DEBUG_INFO, " PHMR - 0x%x\n", CapReg->Bits.PHMR));=0D + DEBUG((DEBUG_INFO, " CM - 0x%x\n", CapReg->Bits.CM));=0D + DEBUG((DEBUG_INFO, " SAGAW - 0x%x\n", CapReg->Bits.SAGAW));=0D + DEBUG((DEBUG_INFO, " MGAW - 0x%x\n", CapReg->Bits.MGAW));=0D + DEBUG((DEBUG_INFO, " ZLR - 0x%x\n", CapReg->Bits.ZLR));=0D + DEBUG((DEBUG_INFO, " FRO - 0x%x\n", CapReg->Bits.FRO));=0D + DEBUG((DEBUG_INFO, " SLLPS - 0x%x\n", CapReg->Bits.SLLPS));=0D + DEBUG((DEBUG_INFO, " PSI - 0x%x\n", CapReg->Bits.PSI));=0D + DEBUG((DEBUG_INFO, " NFR - 0x%x\n", CapReg->Bits.NFR));=0D + DEBUG((DEBUG_INFO, " MAMV - 0x%x\n", CapReg->Bits.MAMV));=0D + DEBUG((DEBUG_INFO, " DWD - 0x%x\n", CapReg->Bits.DWD));=0D + DEBUG((DEBUG_INFO, " DRD - 0x%x\n", CapReg->Bits.DRD));=0D + DEBUG((DEBUG_INFO, " FL1GP - 0x%x\n", CapReg->Bits.FL1GP));=0D + DEBUG((DEBUG_INFO, " PI - 0x%x\n", CapReg->Bits.PI));=0D +}=0D +=0D +/**=0D + Dump VTd extended capability registers.=0D +=0D + @param[in] ECapReg The extended capability register.=0D +**/=0D +VOID=0D +DumpVtdECapRegs (=0D + IN VTD_ECAP_REG *ECapReg=0D + )=0D +{=0D + DEBUG((DEBUG_INFO, " ECapReg - 0x%lx\n", ECapReg->Uint64));=0D + DEBUG((DEBUG_INFO, " C - 0x%x\n", ECapReg->Bits.C));=0D + DEBUG((DEBUG_INFO, " QI - 0x%x\n", ECapReg->Bits.QI));=0D + DEBUG((DEBUG_INFO, " DT - 0x%x\n", ECapReg->Bits.DT));=0D + DEBUG((DEBUG_INFO, " IR - 0x%x\n", ECapReg->Bits.IR));=0D + DEBUG((DEBUG_INFO, " EIM - 0x%x\n", ECapReg->Bits.EIM));=0D + DEBUG((DEBUG_INFO, " PT - 0x%x\n", ECapReg->Bits.PT));=0D + DEBUG((DEBUG_INFO, " SC - 0x%x\n", ECapReg->Bits.SC));=0D + DEBUG((DEBUG_INFO, " IRO - 0x%x\n", ECapReg->Bits.IRO));=0D + DEBUG((DEBUG_INFO, " MHMV - 0x%x\n", ECapReg->Bits.MHMV));=0D + DEBUG((DEBUG_INFO, " MTS - 0x%x\n", ECapReg->Bits.MTS));=0D + DEBUG((DEBUG_INFO, " NEST - 0x%x\n", ECapReg->Bits.NEST));=0D + DEBUG((DEBUG_INFO, " PASID - 0x%x\n", ECapReg->Bits.PASID));=0D + DEBUG((DEBUG_INFO, " PRS - 0x%x\n", ECapReg->Bits.PRS));=0D + DEBUG((DEBUG_INFO, " ERS - 0x%x\n", ECapReg->Bits.ERS));=0D + DEBUG((DEBUG_INFO, " SRS - 0x%x\n", ECapReg->Bits.SRS));=0D + DEBUG((DEBUG_INFO, " NWFS - 0x%x\n", ECapReg->Bits.NWFS));=0D + DEBUG((DEBUG_INFO, " EAFS - 0x%x\n", ECapReg->Bits.EAFS));=0D + DEBUG((DEBUG_INFO, " PSS - 0x%x\n", ECapReg->Bits.PSS));=0D + DEBUG((DEBUG_INFO, " SMTS - 0x%x\n", ECapReg->Bits.SMTS));=0D + DEBUG((DEBUG_INFO, " ADMS - 0x%x\n", ECapReg->Bits.ADMS));=0D + DEBUG((DEBUG_INFO, " PDS - 0x%x\n", ECapReg->Bits.PDS));=0D +}=0D +=0D +/**=0D + Dump VTd registers.=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D +**/=0D +VOID=0D +DumpVtdRegs (=0D + IN UINTN VtdUnitBaseAddress=0D + )=0D +{=0D + VTD_REGESTER_INFO *VtdRegInfo;=0D + VTD_ECAP_REG ECapReg;=0D + VTD_CAP_REG CapReg;=0D +=0D + if (mVtdRegsInfoBuffer =3D=3D NULL) {=0D + return;=0D + }=0D +=0D + VtdRegInfo =3D mVtdRegsInfoBuffer;=0D + VtdRegInfo->BaseAddress =3D VtdUnitBaseAddress;=0D + VtdRegInfo->VerReg =3D MmioRead32 (VtdUnitBaseAddress + R_VER_REG);= =0D + VtdRegInfo->CapReg =3D MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);= =0D + VtdRegInfo->EcapReg =3D MmioRead64 (VtdUnitBaseAddress + R_ECAP_REG)= ;=0D + VtdRegInfo->GstsReg =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG)= ;=0D + VtdRegInfo->RtaddrReg =3D MmioRead64 (VtdUnitBaseAddress + R_RTADDR_RE= G);=0D + VtdRegInfo->CcmdReg =3D MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG)= ;=0D + VtdRegInfo->FstsReg =3D MmioRead32 (VtdUnitBaseAddress + R_FSTS_REG)= ;=0D + VtdRegInfo->FectlReg =3D MmioRead32 (VtdUnitBaseAddress + R_FECTL_REG= );=0D + VtdRegInfo->FedataReg =3D MmioRead32 (VtdUnitBaseAddress + R_FEDATA_RE= G);=0D + VtdRegInfo->FeaddrReg =3D MmioRead32 (VtdUnitBaseAddress + R_FEADDR_RE= G);=0D + VtdRegInfo->FeuaddrReg =3D MmioRead32 (VtdUnitBaseAddress + R_FEUADDR_R= EG);=0D + VtdRegInfo->IqercdReg =3D MmioRead64 (VtdUnitBaseAddress + R_IQERCD_RE= G);=0D +=0D + CapReg.Uint64 =3D VtdRegInfo->CapReg;=0D + for (VtdRegInfo->FrcdRegNum =3D 0; VtdRegInfo->FrcdRegNum < (UINT16) Cap= Reg.Bits.NFR + 1; VtdRegInfo->FrcdRegNum++) {=0D + VtdRegInfo->FrcdReg[VtdRegInfo->FrcdRegNum].Uint64Lo =3D MmioRead64 (V= tdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (VtdRegInfo->FrcdRegNum * 16)= + R_FRCD_REG));=0D + VtdRegInfo->FrcdReg[VtdRegInfo->FrcdRegNum].Uint64Hi =3D MmioRead64 (V= tdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (VtdRegInfo->FrcdRegNum * 16)= + R_FRCD_REG + sizeof(UINT64)));=0D + }=0D +=0D + ECapReg.Uint64 =3D VtdRegInfo->EcapReg;=0D + VtdRegInfo->IvaReg =3D MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IR= O * 16) + R_IVA_REG);=0D + VtdRegInfo->IotlbReg =3D MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.= IRO * 16) + R_IOTLB_REG);=0D +=0D + DEBUG((DEBUG_INFO, "#### DumpVtdRegs(0x%016lx) Begin ####\n", VtdUnitBas= eAddress));=0D +=0D + VtdLibDumpVtdRegsAll (NULL, NULL, VtdRegInfo);=0D +=0D + DEBUG((DEBUG_INFO, "#### DumpVtdRegs(0x%016lx) End ####\n", VtdUnitBaseA= ddress));=0D +=0D + VTdLogAddDataEvent (VTDLOG_DXE_REGISTER, VTDLOG_REGISTER_ALL, (VOID *) V= tdRegInfo, sizeof (VTD_REGESTER_INFO) + sizeof (VTD_UINT128) * (VtdRegInfo-= >FrcdRegNum - 1));=0D +}=0D +=0D +/**=0D + Dump VTd registers for all VTd engine.=0D +**/=0D +VOID=0D +DumpVtdRegsAll (=0D + VOID=0D + )=0D +{=0D + UINTN VtdIndex;=0D +=0D + for (VtdIndex =3D 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {=0D + DumpVtdRegs (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress);=0D + }=0D +}=0D +=0D +/**=0D + Dump VTd registers if there is error.=0D +**/=0D +VOID=0D +DumpVtdIfError (=0D + VOID=0D + )=0D +{=0D + UINTN Num;=0D + UINTN Index;=0D + VTD_FRCD_REG FrcdReg;=0D + VTD_CAP_REG CapReg;=0D + UINT32 Reg32;=0D + BOOLEAN HasError;=0D +=0D + for (Num =3D 0; Num < mVtdUnitNumber; Num++) {=0D + HasError =3D FALSE;=0D + Reg32 =3D MmioRead32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_= FSTS_REG);=0D + if (Reg32 !=3D 0) {=0D + HasError =3D TRUE;=0D + }=0D + Reg32 =3D MmioRead32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_= FECTL_REG);=0D + if ((Reg32 & BIT30) !=3D 0) {=0D + HasError =3D TRUE;=0D + }=0D +=0D + CapReg.Uint64 =3D MmioRead64 (mVtdUnitInformation[Num].VtdUnitBaseAddr= ess + R_CAP_REG);=0D + for (Index =3D 0; Index < (UINTN)CapReg.Bits.NFR + 1; Index++) {=0D + FrcdReg.Uint64[0] =3D MmioRead64 (mVtdUnitInformation[Num].VtdUnitBa= seAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG));=0D + FrcdReg.Uint64[1] =3D MmioRead64 (mVtdUnitInformation[Num].VtdUnitBa= seAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UI= NT64)));=0D + if (FrcdReg.Bits.F !=3D 0) {=0D + HasError =3D TRUE;=0D + }=0D + }=0D +=0D + if (HasError) {=0D + REPORT_STATUS_CODE (EFI_ERROR_CODE, PcdGet32 (PcdErrorCodeVTdError))= ;=0D + DEBUG((DEBUG_INFO, "\n#### ERROR ####\n"));=0D + DumpVtdRegs (Num);=0D + DEBUG((DEBUG_INFO, "#### ERROR ####\n\n"));=0D + //=0D + // Clear=0D + //=0D + for (Index =3D 0; Index < (UINTN)CapReg.Bits.NFR + 1; Index++) {=0D + FrcdReg.Uint64[1] =3D MmioRead64 (mVtdUnitInformation[Num].VtdUnit= BaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(= UINT64)));=0D + if (FrcdReg.Bits.F !=3D 0) {=0D + //=0D + // Software writes the value read from this field (F) to Clear i= t.=0D + //=0D + MmioWrite64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + ((Cap= Reg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)), FrcdReg.U= int64[1]);=0D + }=0D + }=0D + MmioWrite32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_FSTS_RE= G, MmioRead32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_FSTS_REG));= =0D + }=0D + }=0D +}=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/Dmar= Table.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/DmarTab= le.c new file mode 100644 index 000000000..91c89de47 --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/DmarTable.c @@ -0,0 +1,63 @@ +/** @file=0D +=0D + Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include "IntelVTdCorePei.h"=0D +=0D +/**=0D + Parse DMAR DRHD table.=0D +=0D + @param[in] AcpiDmarTable DMAR ACPI table=0D + @param[in] Callback Callback function for handle DRHD=0D + @param[in] Context Callback function Context=0D +=0D + @return the VTd engine number.=0D +=0D +**/=0D +UINTN=0D +ParseDmarAcpiTableDrhd (=0D + IN EFI_ACPI_DMAR_HEADER *AcpiDmarTable,=0D + IN PROCESS_DRHD_CALLBACK_FUNC Callback,=0D + IN VOID *Context=0D + )=0D +{=0D + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;=0D + UINTN VtdIndex;=0D +=0D + VtdIndex =3D 0;=0D + DmarHeader =3D (EFI_ACPI_DMAR_STRUCTURE_HEADER *) ((UINTN) (AcpiDmarTabl= e + 1));=0D +=0D + while ((UINTN) DmarHeader < (UINTN) AcpiDmarTable + AcpiDmarTable->Heade= r.Length) {=0D + switch (DmarHeader->Type) {=0D + case EFI_ACPI_DMAR_TYPE_DRHD:=0D + if (Callback !=3D NULL) {=0D + Callback (Context, VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *) DmarHea= der);=0D + }=0D + VtdIndex++;=0D + break;=0D + default:=0D + break;=0D + }=0D + DmarHeader =3D (EFI_ACPI_DMAR_STRUCTURE_HEADER *) ((UINTN) DmarHeader = + DmarHeader->Length);=0D + }=0D +=0D + return VtdIndex;=0D +}=0D +=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/Inte= lVTdCorePei.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/I= ntelVTdCorePei.c new file mode 100644 index 000000000..0160c3604 --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/IntelVTdCor= ePei.c @@ -0,0 +1,1099 @@ +/** @file=0D +=0D + Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include "IntelVTdCorePei.h"=0D +=0D +#define VTD_UNIT_MAX 64=0D +=0D +EFI_GUID mVTdInfoGuid =3D {=0D + 0x222f5e30, 0x5cd, 0x49c6, { 0x8a, 0xc, 0x36, 0xd6, 0x58, 0x41, 0xe0, 0x= 82 }=0D +};=0D +=0D +EFI_GUID mDmaBufferInfoGuid =3D {=0D + 0x7b624ec7, 0xfb67, 0x4f9c, { 0xb6, 0xb0, 0x4d, 0xfa, 0x9c, 0x88, 0x20, = 0x39 }=0D +};=0D +=0D +#define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P')=0D +typedef struct {=0D + UINT32 Signature;=0D + EDKII_IOMMU_OPERATION Operation;=0D + UINTN NumberOfBytes;=0D + EFI_PHYSICAL_ADDRESS HostAddress;=0D + EFI_PHYSICAL_ADDRESS DeviceAddress;=0D +} MAP_INFO;=0D +=0D +/**=0D + Allocate memory buffer for VTd log events.=0D +=0D + @param[in] MemorySize Required memory buffer size.=0D +=0D + @retval Buffer address=0D +=0D +**/=0D +UINT8 *=0D +EFIAPI=0D +VTdLogAllocMemory (=0D + IN CONST UINT32 MemorySize=0D + )=0D +{=0D + VOID *HobPtr;=0D + VTDLOG_PEI_BUFFER_HOB *BufferHob;=0D + UINT8 *ReturnBuffer;=0D +=0D + ReturnBuffer =3D NULL;=0D + HobPtr =3D GetFirstGuidHob (&gVTdLogBufferHobGuid);=0D + if (HobPtr !=3D NULL) {=0D + BufferHob =3D GET_GUID_HOB_DATA (HobPtr);=0D +=0D + if (BufferHob->PostMemBuffer !=3D 0) {=0D + //=0D + // Post-memory phase=0D + //=0D + if ((BufferHob->PostMemBufferUsed + MemorySize) < PcdGet32 (PcdVTdPe= iPostMemLogBufferSize)) {=0D + ReturnBuffer =3D &((UINT8 *) (UINTN) BufferHob->PostMemBuffer)[Buf= ferHob->PostMemBufferUsed];=0D + BufferHob->PostMemBufferUsed +=3D MemorySize;=0D + } else {=0D + BufferHob->VtdLogPeiError |=3D VTD_LOG_ERROR_BUFFER_FULL;=0D + }=0D + }=0D + }=0D +=0D + return ReturnBuffer;=0D +}=0D +=0D +/**=0D + Add the VTd log event in post memory phase.=0D +=0D + @param[in] EventType Event type=0D + @param[in] Data1 First parameter=0D + @param[in] Data2 Second parameter=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +VTdLogAddEvent (=0D + IN CONST VTDLOG_EVENT_TYPE EventType,=0D + IN CONST UINT64 Data1,=0D + IN CONST UINT64 Data2=0D + )=0D +{=0D + VTDLOG_EVENT_2PARAM *Item;=0D +=0D + if (PcdGet8 (PcdVTdLogLevel) =3D=3D 0) {=0D + return;=0D + } else if ((PcdGet8 (PcdVTdLogLevel) =3D=3D 1) && (EventType >=3D VTDLOG= _PEI_ADVANCED)) {=0D + return;=0D + }=0D +=0D + Item =3D (VTDLOG_EVENT_2PARAM *) VTdLogAllocMemory (sizeof (VTDLOG_EVENT= _2PARAM));=0D + if (Item !=3D NULL) {=0D + Item->Data1 =3D Data1;=0D + Item->Data2 =3D Data2;=0D + Item->Header.DataSize =3D sizeof (VTDLOG_EVENT_2PARAM);=0D + Item->Header.LogType =3D (UINT64) (1 << EventType);=0D + Item->Header.Timestamp =3D AsmReadTsc ();=0D + }=0D +}=0D +=0D +/**=0D + Add a new VTd log event with data.=0D +=0D + @param[in] EventType Event type=0D + @param[in] Param parameter=0D + @param[in] Data Data=0D + @param[in] DataSize Data size=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +VTdLogAddDataEvent (=0D + IN CONST VTDLOG_EVENT_TYPE EventType,=0D + IN CONST UINT64 Param,=0D + IN CONST VOID *Data,=0D + IN CONST UINT32 DataSize=0D + )=0D +{=0D + VTDLOG_EVENT_CONTEXT *Item;=0D + UINT32 EventSize;=0D +=0D + if (PcdGet8 (PcdVTdLogLevel) =3D=3D 0) {=0D + return;=0D + } else if ((PcdGet8 (PcdVTdLogLevel) =3D=3D 1) && (EventType >=3D VTDLOG= _PEI_ADVANCED)) {=0D + return;=0D + }=0D +=0D + EventSize =3D sizeof (VTDLOG_EVENT_CONTEXT) + DataSize - 1;=0D +=0D + Item =3D (VTDLOG_EVENT_CONTEXT *) VTdLogAllocMemory (EventSize);=0D + if (Item !=3D NULL) {=0D + Item->Param =3D Param;=0D + CopyMem (Item->Data, Data, DataSize);=0D +=0D + Item->Header.DataSize =3D EventSize;=0D + Item->Header.LogType =3D (UINT64) (1 << EventType);=0D + Item->Header.Timestamp =3D AsmReadTsc (); =0D + }=0D +}=0D +/**=0D + Add the VTd log event in pre-memory phase.=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D + @param[in] Mode Pre-memory DMA protection mode.=0D + @param[in] Status Status=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +VTdLogAddPreMemoryEvent (=0D + IN UINTN VtdUnitBaseAddress,=0D + IN UINT8 Mode,=0D + IN UINT8 Status=0D + )=0D +{=0D + VTDLOG_PEI_BUFFER_HOB *BufferHob;=0D + VOID *HobPtr;=0D + UINT8 Index;=0D +=0D + HobPtr =3D GetFirstGuidHob (&gVTdLogBufferHobGuid);=0D + if (HobPtr !=3D NULL) {=0D + BufferHob =3D GET_GUID_HOB_DATA (HobPtr);=0D +=0D + for (Index =3D 0; Index < VTD_LOG_PEI_PRE_MEM_BAR_MAX; Index++) {=0D + if (BufferHob->PreMemInfo[Index].Mode =3D=3D VTD_LOG_PEI_PRE_MEM_NOT= _USED) {=0D + //=0D + // Found a free posttion=0D + //=0D + BufferHob->PreMemInfo[Index].BarAddress =3D (UINT32) VtdUnitBaseAd= dress;=0D + BufferHob->PreMemInfo[Index].Mode =3D Mode;=0D + BufferHob->PreMemInfo[Index].Status =3D Status;=0D + break;=0D + }=0D + }=0D + }=0D +}=0D +=0D +/**=0D + Initializes the VTd Log.=0D +=0D + @param[in] MemoryInitialized TRUE: It is post-memory phase=0D + FALSE: It is pre-memory phase=0D +**/=0D +VOID=0D +EFIAPI=0D +VTdLogInitialize(=0D + BOOLEAN MemoryInitialized=0D + )=0D +{=0D + VTDLOG_PEI_BUFFER_HOB *BufferHob;=0D + VOID *HobPtr;=0D +=0D + if (PcdGet8 (PcdVTdLogLevel) > 0) {=0D + HobPtr =3D GetFirstGuidHob (&gVTdLogBufferHobGuid);=0D + if (HobPtr =3D=3D NULL) {=0D + BufferHob =3D BuildGuidHob (&gVTdLogBufferHobGuid, sizeof (VTDLOG_PE= I_BUFFER_HOB));=0D + ASSERT (BufferHob !=3D NULL);=0D +=0D + ZeroMem (BufferHob, sizeof (VTDLOG_PEI_BUFFER_HOB));=0D + } else {=0D + BufferHob =3D GET_GUID_HOB_DATA (HobPtr);=0D + }=0D +=0D + if (MemoryInitialized) {=0D + if ((BufferHob->PostMemBuffer =3D=3D 0) && (PcdGet32 (PcdVTdPeiPostM= emLogBufferSize) > 0)) {=0D + BufferHob->PostMemBufferUsed =3D 0;=0D + BufferHob->PostMemBuffer =3D (UINTN) AllocateAlignedPages (EFI_SIZ= E_TO_PAGES (PcdGet32 (PcdVTdPeiPostMemLogBufferSize)), sizeof (UINT8));=0D + }=0D + }=0D + }=0D +}=0D +=0D +/**=0D + Set IOMMU attribute for a system memory.=0D +=0D + If the IOMMU PPI exists, the system memory cannot be used=0D + for DMA by default.=0D +=0D + When a device requests a DMA access for a system memory,=0D + the device driver need use SetAttribute() to update the IOMMU=0D + attribute to request DMA access (read and/or write).=0D +=0D + @param[in] This The PPI instance pointer.=0D + @param[in] DeviceHandle The device who initiates the DMA acces= s request.=0D + @param[in] Mapping The mapping value returned from Map().= =0D + @param[in] IoMmuAccess The IOMMU access.=0D +=0D + @retval EFI_SUCCESS The IoMmuAccess is set for the memory = range specified by DeviceAddress and Length.=0D + @retval EFI_INVALID_PARAMETER Mapping is not a value that was return= ed by Map().=0D + @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combi= nation of access.=0D + @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not sup= ported by the IOMMU.=0D + @retval EFI_UNSUPPORTED The IOMMU does not support the memory = range specified by Mapping.=0D + @retval EFI_OUT_OF_RESOURCES There are not enough resources availab= le to modify the IOMMU access.=0D + @retval EFI_DEVICE_ERROR The IOMMU device reported an error whi= le attempting the operation.=0D + @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but D= MA buffer are=0D + not available to be allocated yet.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PeiIoMmuSetAttribute (=0D + IN EDKII_IOMMU_PPI *This,=0D + IN VOID *Mapping,=0D + IN UINT64 IoMmuAccess=0D + )=0D +{=0D + VOID *Hob;=0D + DMA_BUFFER_INFO *DmaBufferInfo;=0D +=0D + //=0D + // check and clear VTd error=0D + //=0D + DumpVtdIfError ();=0D +=0D + DEBUG ((DEBUG_INFO, "PeiIoMmuSetAttribute:\n"));=0D +=0D + Hob =3D GetFirstGuidHob (&mDmaBufferInfoGuid);=0D + DmaBufferInfo =3D GET_GUID_HOB_DATA(Hob);=0D +=0D + if (DmaBufferInfo->DmaBufferCurrentTop =3D=3D 0) {=0D + DEBUG ((DEBUG_INFO, "PeiIoMmuSetAttribute: DmaBufferCurrentTop =3D=3D = 0\n"));=0D + return EFI_NOT_AVAILABLE_YET;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Provides the controller-specific addresses required to access system mem= ory from a=0D + DMA bus master.=0D +=0D + @param [in] This The PPI instance pointer.=0D + @param [in] Operation Indicates if the bus master is going t= o read or write to system memory.=0D + @param [in] HostAddress The system memory address to map to th= e PCI controller.=0D + @param [in] [out] NumberOfBytes On input the number of bytes to map. O= n output the number of bytes=0D + that were mapped.=0D + @param [out] DeviceAddress The resulting map address for the bus = master PCI controller to use to=0D + access the hosts HostAddress.=0D + @param [out] Mapping A resulting value to pass to Unmap().= =0D +=0D + @retval EFI_SUCCESS The range was mapped for the returned = NumberOfBytes.=0D + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a = common buffer.=0D + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.=0D + @retval EFI_OUT_OF_RESOURCES The request could not be completed due= to a lack of resources.=0D + @retval EFI_DEVICE_ERROR The system hardware could not map the = requested address.=0D + @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but D= MA buffer are=0D + not available to be allocated yet.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PeiIoMmuMap (=0D + IN EDKII_IOMMU_PPI *This,=0D + IN EDKII_IOMMU_OPERATION Operation,=0D + IN VOID *HostAddress,=0D + IN OUT UINTN *NumberOfBytes,=0D + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,=0D + OUT VOID **Mapping=0D + )=0D +{=0D + MAP_INFO *MapInfo;=0D + UINTN Length;=0D + VOID *Hob;=0D + DMA_BUFFER_INFO *DmaBufferInfo;=0D +=0D + Hob =3D GetFirstGuidHob (&mDmaBufferInfoGuid);=0D + DmaBufferInfo =3D GET_GUID_HOB_DATA(Hob);=0D +=0D + DEBUG ((DEBUG_INFO, "PeiIoMmuMap - HostAddress - 0x%x, NumberOfBytes - %= x\n", HostAddress, *NumberOfBytes));=0D + DEBUG ((DEBUG_INFO, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBu= fferCurrentTop));=0D + DEBUG ((DEBUG_INFO, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->Dm= aBufferCurrentBottom));=0D + DEBUG ((DEBUG_INFO, " Operation - %x\n", Operation));=0D +=0D + if (DmaBufferInfo->DmaBufferCurrentTop =3D=3D 0) {=0D + return EFI_NOT_AVAILABLE_YET;=0D + }=0D +=0D + if (Operation =3D=3D EdkiiIoMmuOperationBusMasterCommonBuffer ||=0D + Operation =3D=3D EdkiiIoMmuOperationBusMasterCommonBuffer64) {=0D + *DeviceAddress =3D (UINTN) HostAddress;=0D + *Mapping =3D NULL;=0D + return EFI_SUCCESS;=0D + }=0D +=0D + Length =3D *NumberOfBytes + sizeof (MAP_INFO);=0D + if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBuff= erCurrentBottom) {=0D + DEBUG ((DEBUG_ERROR, "PeiIoMmuMap - OUT_OF_RESOURCE\n"));=0D + VTdLogAddEvent (VTDLOG_PEI_VTD_ERROR, VTD_LOG_PEI_VTD_ERROR_PPI_MAP, L= ength);=0D + ASSERT (FALSE);=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + *DeviceAddress =3D DmaBufferInfo->DmaBufferCurrentBottom;=0D + DmaBufferInfo->DmaBufferCurrentBottom +=3D Length;=0D +=0D + MapInfo =3D (VOID *) (UINTN) (*DeviceAddress + *NumberOfBytes);=0D + MapInfo->Signature =3D MAP_INFO_SIGNATURE;=0D + MapInfo->Operation =3D Operation;=0D + MapInfo->NumberOfBytes =3D *NumberOfBytes;=0D + MapInfo->HostAddress =3D (UINTN) HostAddress;=0D + MapInfo->DeviceAddress =3D *DeviceAddress;=0D + *Mapping =3D MapInfo;=0D + DEBUG ((DEBUG_INFO, " Op(%x):DeviceAddress - %x, Mapping - %x\n", Opera= tion, (UINTN) *DeviceAddress, MapInfo));=0D +=0D + //=0D + // If this is a read operation from the Bus Master's point of view,=0D + // then copy the contents of the real buffer into the mapped buffer=0D + // so the Bus Master can read the contents of the real buffer.=0D + //=0D + if (Operation =3D=3D EdkiiIoMmuOperationBusMasterRead ||=0D + Operation =3D=3D EdkiiIoMmuOperationBusMasterRead64) {=0D + CopyMem (=0D + (VOID *) (UINTN) MapInfo->DeviceAddress,=0D + (VOID *) (UINTN) MapInfo->HostAddress,=0D + MapInfo->NumberOfBytes=0D + );=0D + }=0D +=0D + VTdLogAddEvent (VTDLOG_PEI_PPI_MAP, (UINT64) HostAddress, Length);=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Completes the Map() operation and releases any corresponding resources.= =0D +=0D + @param [in] This The PPI instance pointer.=0D + @param [in] Mapping The mapping value returned from Map().= =0D +=0D + @retval EFI_SUCCESS The range was unmapped.=0D + @retval EFI_INVALID_PARAMETER Mapping is not a value that was return= ed by Map().=0D + @retval EFI_DEVICE_ERROR The data was not committed to the targ= et system memory.=0D + @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but D= MA buffer are=0D + not available to be allocated yet.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PeiIoMmuUnmap (=0D + IN EDKII_IOMMU_PPI *This,=0D + IN VOID *Mapping=0D + )=0D +{=0D + MAP_INFO *MapInfo;=0D + UINTN Length;=0D + VOID *Hob;=0D + DMA_BUFFER_INFO *DmaBufferInfo;=0D +=0D + Hob =3D GetFirstGuidHob (&mDmaBufferInfoGuid);=0D + DmaBufferInfo =3D GET_GUID_HOB_DATA(Hob);=0D +=0D + DEBUG ((DEBUG_INFO, "PeiIoMmuUnmap - Mapping - %x\n", Mapping));=0D + DEBUG ((DEBUG_INFO, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBu= fferCurrentTop));=0D + DEBUG ((DEBUG_INFO, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->Dm= aBufferCurrentBottom));=0D +=0D + if (DmaBufferInfo->DmaBufferCurrentTop =3D=3D 0) {=0D + return EFI_NOT_AVAILABLE_YET;=0D + }=0D +=0D + if (Mapping =3D=3D NULL) {=0D + return EFI_SUCCESS;=0D + }=0D +=0D + MapInfo =3D Mapping;=0D + ASSERT (MapInfo->Signature =3D=3D MAP_INFO_SIGNATURE);=0D + DEBUG ((DEBUG_INFO, " Op(%x):DeviceAddress - %x, NumberOfBytes - %x\n",= MapInfo->Operation, (UINTN) MapInfo->DeviceAddress, MapInfo->NumberOfBytes= ));=0D +=0D + //=0D + // If this is a write operation from the Bus Master's point of view,=0D + // then copy the contents of the mapped buffer into the real buffer=0D + // so the processor can read the contents of the real buffer.=0D + //=0D + if (MapInfo->Operation =3D=3D EdkiiIoMmuOperationBusMasterWrite ||=0D + MapInfo->Operation =3D=3D EdkiiIoMmuOperationBusMasterWrite64) {=0D + CopyMem (=0D + (VOID *) (UINTN) MapInfo->HostAddress,=0D + (VOID *) (UINTN) MapInfo->DeviceAddress,=0D + MapInfo->NumberOfBytes=0D + );=0D + }=0D +=0D + Length =3D MapInfo->NumberOfBytes + sizeof (MAP_INFO);=0D + if (DmaBufferInfo->DmaBufferCurrentBottom =3D=3D MapInfo->DeviceAddress = + Length) {=0D + DmaBufferInfo->DmaBufferCurrentBottom -=3D Length;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Allocates pages that are suitable for an OperationBusMasterCommonBuffer = or=0D + OperationBusMasterCommonBuffer64 mapping.=0D +=0D + @param [in] This The PPI instance pointer.=0D + @param [in] MemoryType The type of memory to allocate, EfiBoo= tServicesData or=0D + EfiRuntimeServicesData.=0D + @param [in] Pages The number of pages to allocate.=0D + @param [in] [out] HostAddress A pointer to store the base system mem= ory address of the=0D + allocated range.=0D + @param [in] Attributes The requested bit mask of attributes f= or the allocated range.=0D +=0D + @retval EFI_SUCCESS The requested memory pages were alloca= ted.=0D + @retval EFI_UNSUPPORTED Attributes is unsupported. The only le= gal attribute bits are=0D + MEMORY_WRITE_COMBINE, MEMORY_CACHED an= d DUAL_ADDRESS_CYCLE.=0D + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.=0D + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocate= d.=0D + @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but D= MA buffer are=0D + not available to be allocated yet.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PeiIoMmuAllocateBuffer (=0D + IN EDKII_IOMMU_PPI *This,=0D + IN EFI_MEMORY_TYPE MemoryType,=0D + IN UINTN Pages,=0D + IN OUT VOID **HostAddress,=0D + IN UINT64 Attributes=0D + )=0D +{=0D + UINTN Length;=0D + VOID *Hob;=0D + DMA_BUFFER_INFO *DmaBufferInfo;=0D +=0D + Hob =3D GetFirstGuidHob (&mDmaBufferInfoGuid);=0D + DmaBufferInfo =3D GET_GUID_HOB_DATA(Hob);=0D +=0D + DEBUG ((DEBUG_INFO, "PeiIoMmuAllocateBuffer - page - %x\n", Pages));=0D + DEBUG ((DEBUG_INFO, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBu= fferCurrentTop));=0D + DEBUG ((DEBUG_INFO, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->Dm= aBufferCurrentBottom));=0D +=0D + if (DmaBufferInfo->DmaBufferCurrentTop =3D=3D 0) {=0D + return EFI_NOT_AVAILABLE_YET;=0D + }=0D +=0D + Length =3D EFI_PAGES_TO_SIZE (Pages);=0D + if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBuff= erCurrentBottom) {=0D + DEBUG ((DEBUG_ERROR, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n"));=0D + VTdLogAddEvent (VTDLOG_PEI_VTD_ERROR, VTD_LOG_PEI_VTD_ERROR_PPI_ALLOC,= Length);=0D + ASSERT (FALSE);=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + *HostAddress =3D (VOID *) (UINTN) (DmaBufferInfo->DmaBufferCurrentTop - = Length);=0D + DmaBufferInfo->DmaBufferCurrentTop -=3D Length;=0D +=0D + DEBUG ((DEBUG_INFO, "PeiIoMmuAllocateBuffer - allocate - %x\n", *HostAdd= ress));=0D +=0D + VTdLogAddEvent (VTDLOG_PEI_PPI_ALLOC_BUFFER, (UINT64) (*HostAddress), Le= ngth);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Frees memory that was allocated with AllocateBuffer().=0D +=0D + @param [in] This The PPI instance pointer.=0D + @param [in] Pages The number of pages to free.=0D + @param [in] HostAddress The base system memory address of the = allocated range.=0D +=0D + @retval EFI_SUCCESS The requested memory pages were freed.= =0D + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddr= ess and Pages=0D + was not allocated with AllocateBuffer(= ).=0D + @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but D= MA buffer are=0D + not available to be allocated yet.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PeiIoMmuFreeBuffer (=0D + IN EDKII_IOMMU_PPI *This,=0D + IN UINTN Pages,=0D + IN VOID *HostAddress=0D + )=0D +{=0D + UINTN Length;=0D + VOID *Hob;=0D + DMA_BUFFER_INFO *DmaBufferInfo;=0D +=0D + Hob =3D GetFirstGuidHob (&mDmaBufferInfoGuid);=0D + DmaBufferInfo =3D GET_GUID_HOB_DATA (Hob);=0D +=0D + DEBUG ((DEBUG_INFO, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n", P= ages, HostAddress));=0D + DEBUG ((DEBUG_INFO, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBu= fferCurrentTop));=0D + DEBUG ((DEBUG_INFO, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->Dm= aBufferCurrentBottom));=0D +=0D + if (DmaBufferInfo->DmaBufferCurrentTop =3D=3D 0) {=0D + return EFI_NOT_AVAILABLE_YET;=0D + }=0D +=0D + Length =3D EFI_PAGES_TO_SIZE (Pages);=0D + if ((UINTN)HostAddress =3D=3D DmaBufferInfo->DmaBufferCurrentTop) {=0D + DmaBufferInfo->DmaBufferCurrentTop +=3D Length;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +EDKII_IOMMU_PPI mIoMmuPpi =3D {=0D + EDKII_IOMMU_PPI_REVISION,=0D + PeiIoMmuSetAttribute,=0D + PeiIoMmuMap,=0D + PeiIoMmuUnmap,=0D + PeiIoMmuAllocateBuffer,=0D + PeiIoMmuFreeBuffer,=0D +};=0D +=0D +CONST EFI_PEI_PPI_DESCRIPTOR mIoMmuPpiList =3D {=0D + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,=0D + &gEdkiiIoMmuPpiGuid,=0D + (VOID *) &mIoMmuPpi=0D +};=0D +=0D +/**=0D + Get ACPI DMAT Table from EdkiiVTdInfo PPI=0D +=0D + @retval Address ACPI DMAT Table address=0D + @retval NULL Failed to get ACPI DMAT Table=0D +**/=0D +EFI_ACPI_DMAR_HEADER * GetAcpiDmarTable (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_ACPI_DMAR_HEADER *AcpiDmarTable;=0D +=0D + //=0D + // Get the DMAR table=0D + //=0D + Status =3D PeiServicesLocatePpi (=0D + &gEdkiiVTdInfoPpiGuid,=0D + 0,=0D + NULL,=0D + (VOID **)&AcpiDmarTable=0D + );=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "Fail to get ACPI DMAR Table : %r\n", Status));=0D + AcpiDmarTable =3D NULL;=0D + } else {=0D + VtdLibDumpAcpiDmarDrhd (NULL, NULL, AcpiDmarTable);=0D + }=0D +=0D + return AcpiDmarTable;=0D +}=0D +=0D +/**=0D + Get the VTd engine context information hob.=0D +=0D + @retval The VTd engine context information.=0D +=0D +**/=0D +VTD_INFO *=0D +GetVTdInfoHob (=0D + VOID=0D + )=0D +{=0D + VOID *Hob;=0D + VTD_INFO *VTdInfo;=0D +=0D + Hob =3D GetFirstGuidHob (&mVTdInfoGuid);=0D + if (Hob =3D=3D NULL) {=0D + VTdInfo =3D BuildGuidHob (&mVTdInfoGuid, sizeof (VTD_INFO));=0D + if (VTdInfo !=3D NULL) {=0D + ZeroMem (VTdInfo, sizeof (VTD_INFO));=0D + }=0D + } else {=0D + VTdInfo =3D GET_GUID_HOB_DATA(Hob);=0D + }=0D + return VTdInfo;=0D +}=0D +=0D +/**=0D + Callback function of parse DMAR DRHD table in pre-memory phase.=0D +=0D + @param [in] [out] Context Callback function context.=0D + @param [in] VTdIndex The VTd engine index.=0D + @param [in] DmarDrhd The DRHD table.=0D +=0D +**/=0D +VOID=0D +ProcessDhrdPreMemory (=0D + IN OUT VOID *Context,=0D + IN UINTN VTdIndex,=0D + IN EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd=0D + )=0D +{=0D + DEBUG ((DEBUG_INFO,"VTD (%d) BaseAddress - 0x%016lx\n", VTdIndex, DmarD= rhd->RegisterBaseAddress));=0D +=0D + EnableVTdTranslationProtectionBlockDma ((UINTN) DmarDrhd->RegisterBaseAd= dress);=0D +}=0D +=0D +/**=0D + Callback function of parse DMAR DRHD table in post memory phase.=0D +=0D + @param [in] [out] Context Callback function context.=0D + @param [in] VTdIndex The VTd engine index.=0D + @param [in] DmarDrhd The DRHD table.=0D +=0D +**/=0D +VOID=0D +ProcessDrhdPostMemory (=0D + IN OUT VOID *Context,=0D + IN UINTN VTdIndex,=0D + IN EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd=0D + )=0D +{=0D + VTD_UNIT_INFO *VtdUnitInfo;=0D + UINTN Index;=0D +=0D + VtdUnitInfo =3D (VTD_UNIT_INFO *) Context;=0D +=0D + if (DmarDrhd->RegisterBaseAddress =3D=3D 0) {=0D + DEBUG ((DEBUG_INFO,"VTd Base Address is 0\n"));=0D + ASSERT (FALSE);=0D + return;=0D + }=0D +=0D + for (Index =3D 0; Index < VTD_UNIT_MAX; Index++) {=0D + if (VtdUnitInfo[Index].VtdUnitBaseAddress =3D=3D DmarDrhd->RegisterBas= eAddress) {=0D + DEBUG ((DEBUG_INFO,"Find VTD (%d) [0x%08x] Exist\n", VTdIndex, DmarD= rhd->RegisterBaseAddress));=0D + return;=0D + }=0D + }=0D +=0D + for (VTdIndex =3D 0; VTdIndex < VTD_UNIT_MAX; VTdIndex++) {=0D + if (VtdUnitInfo[VTdIndex].VtdUnitBaseAddress =3D=3D 0) {=0D + VtdUnitInfo[VTdIndex].VtdUnitBaseAddress =3D (UINTN) DmarDrhd->Regis= terBaseAddress;=0D + VtdUnitInfo[VTdIndex].Segment =3D DmarDrhd->SegmentNumber;=0D + VtdUnitInfo[VTdIndex].Flags =3D DmarDrhd->Flags;=0D + VtdUnitInfo[VTdIndex].Done =3D FALSE;=0D +=0D + DEBUG ((DEBUG_INFO,"VTD (%d) BaseAddress - 0x%016lx\n", VTdIndex, D= marDrhd->RegisterBaseAddress));=0D + DEBUG ((DEBUG_INFO," Segment - %d, Flags - 0x%x\n", DmarDrhd->Seg= mentNumber, DmarDrhd->Flags));=0D + return;=0D + }=0D + }=0D +=0D + DEBUG ((DEBUG_INFO,"VtdUnitInfo Table is full\n"));=0D + ASSERT (FALSE);=0D + return;=0D +}=0D +=0D +/**=0D + Initializes the Intel VTd Info in post memory phase.=0D +=0D + @retval EFI_SUCCESS Usb bot driver is successfully initialized= .=0D + @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.=0D +**/=0D +EFI_STATUS=0D +InitVTdInfo (=0D + VOID=0D + )=0D +{=0D + VTD_INFO *VTdInfo;=0D + EFI_ACPI_DMAR_HEADER *AcpiDmarTable;=0D + UINTN VtdUnitNumber;=0D + VTD_UNIT_INFO *VtdUnitInfo;=0D +=0D + VTdInfo =3D GetVTdInfoHob ();=0D + ASSERT (VTdInfo !=3D NULL);=0D +=0D + AcpiDmarTable =3D GetAcpiDmarTable ();=0D + ASSERT (AcpiDmarTable !=3D NULL);=0D +=0D + if (VTdInfo->VtdUnitInfo =3D=3D NULL) {=0D + //=0D + // Genrate a new Vtd Unit Info Table=0D + //=0D + VTdInfo->VtdUnitInfo =3D AllocateZeroPages (EFI_SIZE_TO_PAGES (sizeof = (VTD_UNIT_INFO) * VTD_UNIT_MAX));=0D + if (VTdInfo->VtdUnitInfo =3D=3D NULL) {=0D + DEBUG ((DEBUG_ERROR, "InitVTdInfo - OUT_OF_RESOURCE\n"));=0D + ASSERT (FALSE);=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + }=0D + VtdUnitInfo =3D VTdInfo->VtdUnitInfo;=0D +=0D + if (VTdInfo->HostAddressWidth =3D=3D 0) {=0D + VTdInfo->HostAddressWidth =3D AcpiDmarTable->HostAddressWidth;=0D + }=0D +=0D + if (VTdInfo->HostAddressWidth !=3D AcpiDmarTable->HostAddressWidth) {=0D + DEBUG ((DEBUG_ERROR, "Host Address Width is not match.\n"));=0D + ASSERT (FALSE);=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + //=0D + // Parse the DMAR ACPI Table to the new Vtd Unit Info Table=0D + //=0D + VtdUnitNumber =3D ParseDmarAcpiTableDrhd (AcpiDmarTable, ProcessDrhdPost= Memory, VtdUnitInfo);=0D + if (VtdUnitNumber =3D=3D 0) {=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + for (VTdInfo->VTdEngineCount =3D 0; VTdInfo->VTdEngineCount < VTD_UNIT_M= AX; VTdInfo->VTdEngineCount++) {=0D + if (VtdUnitInfo[VTdInfo->VTdEngineCount].VtdUnitBaseAddress =3D=3D 0) = {=0D + break;=0D + }=0D + }=0D +=0D + VTdInfo->AcpiDmarTable =3D AcpiDmarTable;=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Initializes the Intel VTd DMAR for block all DMA.=0D +=0D + @retval EFI_SUCCESS Driver is successfully initialized.=0D + @retval RETURN_NOT_READY Fail to get VTdInfo Hob .=0D +**/=0D +EFI_STATUS=0D +InitVTdDmarBlockAll (=0D + VOID=0D + )=0D +{=0D + EFI_ACPI_DMAR_HEADER *AcpiDmarTable;=0D +=0D + //=0D + // Get the DMAR table=0D + //=0D + AcpiDmarTable =3D GetAcpiDmarTable ();=0D + ASSERT (AcpiDmarTable !=3D NULL);=0D +=0D + //=0D + // Parse the DMAR table and block all DMA=0D + //=0D + return ParseDmarAcpiTableDrhd (AcpiDmarTable, ProcessDhrdPreMemory, NULL= );=0D +}=0D +=0D +/**=0D + Initializes DMA buffer=0D +=0D + @retval EFI_SUCCESS DMA buffer is successfully initialized.=0D + @retval EFI_INVALID_PARAMETER Invalid DMA buffer size.=0D + @retval EFI_OUT_OF_RESOURCES Can't initialize DMA buffer.=0D +**/=0D +EFI_STATUS=0D +InitDmaBuffer(=0D + VOID=0D + )=0D +{=0D + DMA_BUFFER_INFO *DmaBufferInfo;=0D + VOID *Hob;=0D + VOID *VtdPmrHobPtr;=0D + VTD_PMR_INFO_HOB *VtdPmrHob;=0D +=0D + DEBUG ((DEBUG_INFO, "InitDmaBuffer :\n"));=0D +=0D + Hob =3D GetFirstGuidHob (&mDmaBufferInfoGuid);=0D + ASSERT(Hob !=3D NULL);=0D + DmaBufferInfo =3D GET_GUID_HOB_DATA (Hob);=0D +=0D + /**=0D + When gVtdPmrInfoDataHobGuid exists, it means:=0D + 1. Dma buffer is reserved by memory initialize code=0D + 2. PeiGetVtdPmrAlignmentLib is used to get alignment=0D + 3. Protection regions are determined by the system memory map=0D + 4. Protection regions will be conveyed through VTD_PMR_INFO_HOB=0D +=0D + When gVtdPmrInfoDataHobGuid dosen't exist, it means:=0D + 1. IntelVTdDmarPei driver will calcuate the protected memory alignment= =0D + 2. Dma buffer is reserved by AllocateAlignedPages()=0D + **/=0D +=0D +=0D + if (DmaBufferInfo->DmaBufferSize =3D=3D 0) {=0D + DEBUG ((DEBUG_INFO, " DmaBufferSize is 0\n"));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + if (DmaBufferInfo->DmaBufferBase =3D=3D 0) {=0D + VtdPmrHobPtr =3D GetFirstGuidHob (&gVtdPmrInfoDataHobGuid);=0D + if (VtdPmrHobPtr !=3D NULL) {=0D + //=0D + // Get the protected memory ranges information from the VTd PMR hob= =0D + //=0D + VtdPmrHob =3D GET_GUID_HOB_DATA (VtdPmrHobPtr);=0D +=0D + if ((VtdPmrHob->ProtectedHighBase - VtdPmrHob->ProtectedLowLimit) < = DmaBufferInfo->DmaBufferSize) {=0D + DEBUG ((DEBUG_ERROR, " DmaBufferSize not enough\n"));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + DmaBufferInfo->DmaBufferBase =3D VtdPmrHob->ProtectedLowLimit;=0D + } else {=0D + //=0D + // Allocate memory for DMA buffer=0D + //=0D + DmaBufferInfo->DmaBufferBase =3D (UINTN) AllocateAlignedPages (EFI_S= IZE_TO_PAGES (DmaBufferInfo->DmaBufferSize), 0);=0D + if (DmaBufferInfo->DmaBufferBase =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR, " InitDmaBuffer : OutOfResource\n"));=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + DEBUG ((DEBUG_INFO, "Alloc DMA buffer success.\n"));=0D + }=0D +=0D + DmaBufferInfo->DmaBufferCurrentTop =3D DmaBufferInfo->DmaBufferBase + = DmaBufferInfo->DmaBufferSize;=0D + DmaBufferInfo->DmaBufferCurrentBottom =3D DmaBufferInfo->DmaBufferBase= ;=0D +=0D + DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", DmaBufferInfo-= >DmaBufferSize));=0D + DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", DmaBufferInfo-= >DmaBufferBase));=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, " DmaBufferCurrentTop : 0x%x\n", DmaBufferInfo->D= maBufferCurrentTop));=0D + DEBUG ((DEBUG_INFO, " DmaBufferCurrentBottom : 0x%x\n", DmaBufferInfo->D= maBufferCurrentBottom));=0D +=0D + VTdLogAddEvent (VTDLOG_PEI_PROTECT_MEMORY_RANGE, DmaBufferInfo->DmaBuffe= rCurrentBottom, DmaBufferInfo->DmaBufferCurrentTop);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Initializes the Intel VTd DMAR for DMA buffer.=0D +=0D + @retval EFI_SUCCESS Usb bot driver is successfully initialized= .=0D + @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.=0D + @retval EFI_DEVICE_ERROR DMAR translation is not enabled.=0D +**/=0D +EFI_STATUS=0D +InitVTdDmarForDma (=0D + VOID=0D + )=0D +{=0D + VTD_INFO *VTdInfo;=0D +=0D + EFI_STATUS Status;=0D + EFI_PEI_PPI_DESCRIPTOR *OldDescriptor;=0D + EDKII_IOMMU_PPI *OldIoMmuPpi;=0D +=0D + VTdInfo =3D GetVTdInfoHob ();=0D + ASSERT (VTdInfo !=3D NULL);=0D +=0D + DEBUG ((DEBUG_INFO, "PrepareVtdConfig\n"));=0D + Status =3D PrepareVtdConfig (VTdInfo);=0D + if (EFI_ERROR (Status)) {=0D + ASSERT_EFI_ERROR (Status);=0D + return Status;=0D + }=0D +=0D + // create root entry table=0D + DEBUG ((DEBUG_INFO, "SetupTranslationTable\n"));=0D + Status =3D SetupTranslationTable (VTdInfo);=0D + if (EFI_ERROR (Status)) {=0D + ASSERT_EFI_ERROR (Status);=0D + return Status;=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, "EnableVtdDmar\n"));=0D + Status =3D EnableVTdTranslationProtection(VTdInfo);=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, "Install gEdkiiIoMmuPpiGuid\n"));=0D + // install protocol=0D + //=0D + // (Re)Install PPI.=0D + //=0D + Status =3D PeiServicesLocatePpi (=0D + &gEdkiiIoMmuPpiGuid,=0D + 0,=0D + &OldDescriptor,=0D + (VOID **) &OldIoMmuPpi=0D + );=0D + if (!EFI_ERROR (Status)) {=0D + Status =3D PeiServicesReInstallPpi (OldDescriptor, &mIoMmuPpiList);=0D + } else {=0D + Status =3D PeiServicesInstallPpi (&mIoMmuPpiList);=0D + }=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + This function handles S3 resume task at the end of PEI=0D +=0D + @param[in] PeiServices Pointer to PEI Services Table.=0D + @param[in] NotifyDesc Pointer to the descriptor for the Notifica= tion event that=0D + caused this function to execute.=0D + @param[in] Ppi Pointer to the PPI data associated with th= is function.=0D +=0D + @retval EFI_STATUS Always return EFI_SUCCESS=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +S3EndOfPeiNotify(=0D + IN EFI_PEI_SERVICES **PeiServices,=0D + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,=0D + IN VOID *Ppi=0D + )=0D +{=0D + DEBUG ((DEBUG_INFO, "VTd DMAR PEI S3EndOfPeiNotify\n"));=0D +=0D + if ((PcdGet8 (PcdVTdPolicyPropertyMask) & BIT1) =3D=3D 0) {=0D + DumpVtdIfError ();=0D +=0D + DisableVTdTranslationProtection (GetVTdInfoHob ());=0D + }=0D + return EFI_SUCCESS;=0D +}=0D +=0D +EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc =3D {=0D + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINA= TE_LIST),=0D + &gEfiEndOfPeiSignalPpiGuid,=0D + S3EndOfPeiNotify=0D +};=0D +=0D +/**=0D + This function handles VTd engine setup=0D +=0D + @param[in] PeiServices Pointer to PEI Services Table.=0D + @param[in] NotifyDesc Pointer to the descriptor for the Notifica= tion event that=0D + caused this function to execute.=0D + @param[in] Ppi Pointer to the PPI data associated with th= is function.=0D +=0D + @retval EFI_STATUS Always return EFI_SUCCESS=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +VTdInfoNotify (=0D + IN EFI_PEI_SERVICES **PeiServices,=0D + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,=0D + IN VOID *Ppi=0D + )=0D +{=0D + EFI_STATUS Status;=0D + VOID *MemoryDiscovered;=0D + BOOLEAN MemoryInitialized;=0D +=0D + DEBUG ((DEBUG_INFO, "VTdInfoNotify\n"));=0D +=0D + //=0D + // Check if memory is initialized.=0D + //=0D + MemoryInitialized =3D FALSE;=0D + Status =3D PeiServicesLocatePpi (=0D + &gEfiPeiMemoryDiscoveredPpiGuid,=0D + 0,=0D + NULL,=0D + &MemoryDiscovered=0D + );=0D + if (!EFI_ERROR(Status)) {=0D + MemoryInitialized =3D TRUE;=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, "MemoryInitialized - %x\n", MemoryInitialized));=0D +=0D + if (!MemoryInitialized) {=0D + //=0D + // If the memory is not initialized,=0D + // Protect all system memory=0D + //=0D +=0D + InitVTdDmarBlockAll ();=0D +=0D + //=0D + // Install PPI.=0D + //=0D + Status =3D PeiServicesInstallPpi (&mIoMmuPpiList);=0D + ASSERT_EFI_ERROR(Status);=0D + } else {=0D + //=0D + // If the memory is initialized,=0D + // Allocate DMA buffer and protect rest system memory=0D + //=0D +=0D + VTdLogInitialize (TRUE);=0D +=0D + Status =3D InitDmaBuffer ();=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + //=0D + // NOTE: We need reinit VTdInfo because previous information might be = overriden.=0D + //=0D + Status =3D InitVTdInfo ();=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D InitVTdDmarForDma ();=0D + ASSERT_EFI_ERROR (Status);=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +EFI_PEI_NOTIFY_DESCRIPTOR mVTdInfoNotifyDesc =3D {=0D + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINA= TE_LIST),=0D + &gEdkiiVTdInfoPpiGuid,=0D + VTdInfoNotify=0D +};=0D +=0D +/**=0D + Initializes the Intel VTd DMAR PEIM.=0D +=0D + @param[in] FileHandle Handle of the file being invoked.=0D + @param[in] PeiServices Describes the list of possible PEI Service= s.=0D +=0D + @retval EFI_SUCCESS Usb bot driver is successfully initialized= .=0D + @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +IntelVTdDmarInitialize (=0D + IN EFI_PEI_FILE_HANDLE FileHandle,=0D + IN CONST EFI_PEI_SERVICES **PeiServices=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_BOOT_MODE BootMode;=0D + DMA_BUFFER_INFO *DmaBufferInfo;=0D +=0D + DEBUG ((DEBUG_INFO, "IntelVTdDmarInitialize\n"));=0D +=0D + if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) =3D=3D 0) {=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + VTdLogInitialize (FALSE);=0D +=0D + DmaBufferInfo =3D BuildGuidHob (&mDmaBufferInfoGuid, sizeof (DMA_BUFFER_= INFO));=0D + ASSERT(DmaBufferInfo !=3D NULL);=0D + if (DmaBufferInfo =3D=3D NULL) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + ZeroMem (DmaBufferInfo, sizeof (DMA_BUFFER_INFO));=0D +=0D + PeiServicesGetBootMode (&BootMode);=0D +=0D + if (BootMode =3D=3D BOOT_ON_S3_RESUME) {=0D + DmaBufferInfo->DmaBufferSize =3D PcdGet32 (PcdVTdPeiDmaBufferSizeS3);= =0D + } else {=0D + DmaBufferInfo->DmaBufferSize =3D PcdGet32 (PcdVTdPeiDmaBufferSize);=0D + }=0D +=0D + Status =3D PeiServicesNotifyPpi (&mVTdInfoNotifyDesc);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + //=0D + // Register EndOfPei Notify for S3=0D + //=0D + if (BootMode =3D=3D BOOT_ON_S3_RESUME) {=0D + Status =3D PeiServicesNotifyPpi (&mS3EndOfPeiNotifyDesc);=0D + ASSERT_EFI_ERROR (Status);=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/Inte= lVTdCorePei.h b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/I= ntelVTdCorePei.h new file mode 100644 index 000000000..cca9c7f02 --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/IntelVTdCor= ePei.h @@ -0,0 +1,262 @@ +/** @file=0D + The definition for DMA access Library.=0D +=0D + Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#ifndef __DMA_ACCESS_LIB_H__=0D +#define __DMA_ACCESS_LIB_H__=0D +=0D +#include =0D +=0D +#define VTD_64BITS_ADDRESS(Lo, Hi) (LShiftU64 (Lo, 12) | LShiftU64 (Hi, 32= ))=0D +=0D +//=0D +// Use 256-bit descriptor=0D +// Queue size is 128.=0D +//=0D +#define VTD_QUEUED_INVALIDATION_DESCRIPTOR_WIDTH 1=0D +#define VTD_INVALIDATION_QUEUE_SIZE 0=0D +=0D +typedef struct {=0D + BOOLEAN Done;=0D + UINTN VtdUnitBaseAddress;=0D + UINT16 Segment;=0D + UINT8 Flags;=0D + VTD_VER_REG VerReg;=0D + VTD_CAP_REG CapReg;=0D + VTD_ECAP_REG ECapReg;=0D + BOOLEAN Is5LevelPaging;=0D + UINT8 EnableQueuedInvalidation;=0D + VOID *QiDescBuffer;=0D + UINTN QiDescBufferSize;=0D + UINTN FixedSecondLevelPagingEntry;=0D + UINTN RootEntryTable;=0D + UINTN ExtRootEntryTable;=0D + UINTN RootEntryTablePageSize;=0D + UINTN ExtRootEntryTablePageSize;=0D +} VTD_UNIT_INFO;=0D +=0D +typedef struct {=0D + EFI_ACPI_DMAR_HEADER *AcpiDmarTable;=0D + UINT8 HostAddressWidth;=0D + VTD_REGESTER_THIN_INFO *RegsInfoBuffer;=0D + UINTN VTdEngineCount;=0D + VTD_UNIT_INFO *VtdUnitInfo;=0D +} VTD_INFO;=0D +=0D +typedef struct {=0D + UINTN DmaBufferBase;=0D + UINTN DmaBufferSize;=0D + UINTN DmaBufferCurrentTop;=0D + UINTN DmaBufferCurrentBottom;=0D +} DMA_BUFFER_INFO;=0D +=0D +typedef=0D +VOID=0D +(*PROCESS_DRHD_CALLBACK_FUNC) (=0D + IN OUT VOID *Context,=0D + IN UINTN VTdIndex,=0D + IN EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd=0D + );=0D +=0D +/**=0D + Enable VTd translation table protection for block DMA=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D +=0D + @retval EFI_SUCCESS DMAR translation is enabled.=0D + @retval EFI_DEVICE_ERROR DMAR translation is not enabled.=0D +**/=0D +EFI_STATUS=0D +EnableVTdTranslationProtectionBlockDma (=0D + IN UINTN VtdUnitBaseAddress=0D + );=0D +=0D +/**=0D + Enable VTd translation table protection.=0D +=0D + @param[in] VTdInfo The VTd engine context information.=0D +=0D + @retval EFI_SUCCESS DMAR translation is enabled.=0D + @retval EFI_DEVICE_ERROR DMAR translation is not enabled.=0D +**/=0D +EFI_STATUS=0D +EnableVTdTranslationProtection (=0D + IN VTD_INFO *VTdInfo=0D + );=0D +=0D +/**=0D + Disable VTd translation table protection.=0D +=0D + @param[in] VTdInfo The VTd engine context information.=0D +**/=0D +VOID=0D +DisableVTdTranslationProtection (=0D + IN VTD_INFO *VTdInfo=0D + );=0D +=0D +/**=0D + Parse DMAR DRHD table.=0D +=0D + @param[in] AcpiDmarTable DMAR ACPI table=0D + @param[in] Callback Callback function for handle DRHD=0D + @param[in] Context Callback function Context=0D +=0D + @return the VTd engine number.=0D +=0D +**/=0D +UINTN=0D +ParseDmarAcpiTableDrhd (=0D + IN EFI_ACPI_DMAR_HEADER *AcpiDmarTable,=0D + IN PROCESS_DRHD_CALLBACK_FUNC Callback,=0D + IN VOID *Context=0D + );=0D +=0D +/**=0D + Prepare VTD configuration.=0D +=0D + @param[in] VTdInfo The VTd engine context information.=0D +=0D + @retval EFI_SUCCESS Prepare Vtd config success=0D +**/=0D +EFI_STATUS=0D +PrepareVtdConfig (=0D + IN VTD_INFO *VTdInfo=0D + );=0D +=0D +/**=0D + Setup VTd translation table.=0D +=0D + @param[in] VTdInfo The VTd engine context information.=0D +=0D + @retval EFI_SUCCESS Setup translation table successfully.=0D + @retval EFI_OUT_OF_RESOURCE Setup translation table fail.=0D +**/=0D +EFI_STATUS=0D +SetupTranslationTable (=0D + IN VTD_INFO *VTdInfo=0D + );=0D +=0D +/**=0D + Flush VTD page table and context table memory.=0D +=0D + This action is to make sure the IOMMU engine can get final data in memor= y.=0D +=0D + @param[in] VtdUnitInfo The VTd engine unit information.=0D + @param[in] Base The base address of memory to be flushed.= =0D + @param[in] Size The size of memory in bytes to be flushed.= =0D +**/=0D +VOID=0D +FlushPageTableMemory (=0D + IN VTD_UNIT_INFO *VtdUnitInfo,=0D + IN UINTN Base,=0D + IN UINTN Size=0D + );=0D +=0D +/**=0D + Allocate zero pages.=0D +=0D + @param[in] Pages the number of pages.=0D +=0D + @return the page address.=0D + @retval NULL No resource to allocate pages.=0D +**/=0D +VOID *=0D +EFIAPI=0D +AllocateZeroPages (=0D + IN UINTN Pages=0D + );=0D +=0D +/**=0D + Return the index of PCI data.=0D +=0D + @param[in] VtdUnitInfo The VTd engine unit information.=0D + @param[in] Segment The Segment used to identify a VTd engine.= =0D + @param[in] SourceId The SourceId used to identify a VTd engine= and table entry.=0D +=0D + @return The index of the PCI data.=0D + @retval (UINTN)-1 The PCI data is not found.=0D +**/=0D +UINTN=0D +GetPciDataIndex (=0D + IN VTD_UNIT_INFO *VtdUnitInfo,=0D + IN UINT16 Segment,=0D + IN VTD_SOURCE_ID SourceId=0D + );=0D +=0D +/**=0D + Get the VTd engine context information hob.=0D +=0D + @retval The VTd engine context information.=0D +=0D +**/=0D +VTD_INFO *=0D +GetVTdInfoHob (=0D + VOID=0D + );=0D +=0D +/**=0D + Dump VTd registers if there is error.=0D +**/=0D +VOID=0D +DumpVtdIfError (=0D + VOID=0D + );=0D +=0D +/**=0D + Add the VTd log event in post memory phase.=0D +=0D + @param[in] EventType Event type=0D + @param[in] Data1 First parameter=0D + @param[in] Data2 Second parameter=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +VTdLogAddEvent (=0D + IN CONST VTDLOG_EVENT_TYPE EventType,=0D + IN CONST UINT64 Data1,=0D + IN CONST UINT64 Data2=0D + );=0D +=0D +/**=0D + Add a new VTd log event with data.=0D +=0D + @param[in] EventType Event type=0D + @param[in] Param parameter=0D + @param[in] Data Data=0D + @param[in] DataSize Data size=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +VTdLogAddDataEvent (=0D + IN CONST VTDLOG_EVENT_TYPE EventType,=0D + IN CONST UINT64 Param,=0D + IN CONST VOID *Data,=0D + IN CONST UINT32 DataSize=0D + );=0D +=0D +/**=0D + Add the VTd log event in pre-memory phase.=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D + @param[in] Mode Pre-memory DMA protection mode.=0D + @param[in] Status Status=0D +=0D +**/=0D +VOID=0D +EFIAPI=0D +VTdLogAddPreMemoryEvent (=0D + IN UINTN VtdUnitBaseAddress,=0D + IN UINT8 Mode,=0D + IN UINT8 Status=0D + );=0D +=0D +extern EFI_GUID mVTdInfoGuid;=0D +extern EFI_GUID mDmaBufferInfoGuid;=0D +=0D +#endif=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/Inte= lVTdCorePei.inf b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei= /IntelVTdCorePei.inf new file mode 100644 index 000000000..f756c543c --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/IntelVTdCor= ePei.inf @@ -0,0 +1,70 @@ +## @file=0D +# Component INF file for the Intel VTd DMAR PEIM.=0D +#=0D +# This driver initializes VTd engine based upon EDKII_VTD_INFO_PPI=0D +# and provide DMA protection in PEI.=0D +#=0D +# Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010017=0D + BASE_NAME =3D IntelVTdCorePei=0D + MODULE_UNI_FILE =3D IntelVTdCorePei.uni=0D + FILE_GUID =3D 9311b0cc-5c08-4c0a-bec8-23afab024e48=0D + MODULE_TYPE =3D PEIM=0D + VERSION_STRING =3D 2.0=0D + ENTRY_POINT =3D IntelVTdDmarInitialize=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + MdeModulePkg/MdeModulePkg.dec=0D + IntelSiliconPkg/IntelSiliconPkg.dec=0D +=0D +[Sources]=0D + IntelVTdCorePei.c=0D + IntelVTdCorePei.h=0D + IntelVTdDmar.c=0D + DmarTable.c=0D + TranslationTable.c=0D +=0D +[LibraryClasses]=0D + DebugLib=0D + BaseMemoryLib=0D + BaseLib=0D + PeimEntryPoint=0D + PeiServicesLib=0D + HobLib=0D + IoLib=0D + CacheMaintenanceLib=0D + PciSegmentLib=0D + IntelVTdPeiDxeLib=0D +=0D +[Guids]=0D + gVTdLogBufferHobGuid ## PRODUCES CONSUMES=0D + gVtdPmrInfoDataHobGuid ## CONSUMES=0D +=0D +[Ppis]=0D + gEdkiiIoMmuPpiGuid ## PRODUCES=0D + gEdkiiVTdInfoPpiGuid ## CONSUMES=0D + gEfiPeiMemoryDiscoveredPpiGuid ## CONSUMES=0D + gEfiEndOfPeiSignalPpiGuid ## CONSUMES=0D + gEdkiiVTdNullRootEntryTableGuid ## CONSUMES=0D +=0D +[Pcd]=0D + gIntelSiliconPkgTokenSpaceGuid.PcdVTdPolicyPropertyMask ## CONSUME= S=0D + gIntelSiliconPkgTokenSpaceGuid.PcdVTdPeiDmaBufferSize ## CONSUME= S=0D + gIntelSiliconPkgTokenSpaceGuid.PcdVTdPeiDmaBufferSizeS3 ## CONSUME= S=0D + gIntelSiliconPkgTokenSpaceGuid.PcdVTdSupportAbortDmaMode ## CONSUME= S=0D + gIntelSiliconPkgTokenSpaceGuid.PcdVTdLogLevel ## CONSUME= S=0D + gIntelSiliconPkgTokenSpaceGuid.PcdVTdPeiPostMemLogBufferSize ## CONSUME= S=0D +=0D +[Depex]=0D + gEfiPeiMasterBootModePpiGuid AND=0D + gEdkiiVTdInfoPpiGuid=0D +=0D +[UserExtensions.TianoCore."ExtraFiles"]=0D + IntelVTdCorePeiExtra.uni=0D +=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/Inte= lVTdCorePei.uni b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei= /IntelVTdCorePei.uni new file mode 100644 index 000000000..2b5b260f5 --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/IntelVTdCor= ePei.uni @@ -0,0 +1,14 @@ +// /** @file=0D +// IntelVTdDmarPei Module Localized Abstract and Description Content=0D +//=0D +// Copyright (c) 2020, Intel Corporation. All rights reserved.
=0D +//=0D +// SPDX-License-Identifier: BSD-2-Clause-Patent=0D +//=0D +// **/=0D +=0D +=0D +#string STR_MODULE_ABSTRACT #language en-US "Intel VTd CORE PE= I Driver."=0D +=0D +#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."=0D +=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/Inte= lVTdCorePeiExtra.uni b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCo= rePei/IntelVTdCorePeiExtra.uni new file mode 100644 index 000000000..14848f924 --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/IntelVTdCor= ePeiExtra.uni @@ -0,0 +1,14 @@ +// /** @file=0D +// IntelVTdDmarPei Localized Strings and Content=0D +//=0D +// Copyright (c) 2020, Intel Corporation. All rights reserved.
=0D +//=0D +// SPDX-License-Identifier: BSD-2-Clause-Patent=0D +//=0D +// **/=0D +=0D +#string STR_PROPERTIES_MODULE_NAME=0D +#language en-US=0D +"Intel VTd CORE PEI Driver"=0D +=0D +=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/Inte= lVTdDmar.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/Inte= lVTdDmar.c new file mode 100644 index 000000000..d3876416c --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/IntelVTdDma= r.c @@ -0,0 +1,727 @@ +/** @file=0D +=0D + Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include "IntelVTdCorePei.h"=0D +=0D +#define VTD_CAP_REG_NFR_MAX (256)=0D +=0D +/**=0D + Flush VTD page table and context table memory.=0D +=0D + This action is to make sure the IOMMU engine can get final data in memor= y.=0D +=0D + @param[in] VtdUnitInfo The VTd engine unit information.=0D + @param[in] Base The base address of memory to be flushed.= =0D + @param[in] Size The size of memory in bytes to be flushed.= =0D +**/=0D +VOID=0D +FlushPageTableMemory (=0D + IN VTD_UNIT_INFO *VtdUnitInfo,=0D + IN UINTN Base,=0D + IN UINTN Size=0D + )=0D +{=0D + if (VtdUnitInfo->ECapReg.Bits.C =3D=3D 0) {=0D + WriteBackDataCacheRange ((VOID *) Base, Size);=0D + }=0D +}=0D +=0D +/**=0D + Perpare cache invalidation interface.=0D +=0D + @param[in] VtdUnitInfo The VTd engine unit information.=0D +=0D + @retval EFI_SUCCESS The operation was successful.=0D + @retval EFI_UNSUPPORTED Invalidation method is not supported.=0D + @retval EFI_OUT_OF_RESOURCES A memory allocation failed.=0D +**/=0D +EFI_STATUS=0D +PerpareCacheInvalidationInterface (=0D + IN VTD_UNIT_INFO *VtdUnitInfo=0D + )=0D +{=0D + UINT32 Reg32;=0D + VTD_ECAP_REG ECapReg;=0D + VTD_IQA_REG IqaReg;=0D + UINTN VtdUnitBaseAddress;=0D +=0D + VtdUnitBaseAddress =3D VtdUnitInfo->VtdUnitBaseAddress;=0D +=0D + if (VtdUnitInfo->VerReg.Bits.Major <=3D 5) {=0D + VtdUnitInfo->EnableQueuedInvalidation =3D 0;=0D + DEBUG ((DEBUG_INFO, "Use Register-based Invalidation Interface for eng= ine [0x%x]\n", VtdUnitBaseAddress));=0D + return EFI_SUCCESS;=0D + }=0D +=0D + ECapReg.Uint64 =3D MmioRead64 (VtdUnitBaseAddress + R_ECAP_REG);=0D + if (ECapReg.Bits.QI =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR, "Hardware does not support queued invalidations i= nterface for engine [0x%x]\n", VtdUnitBaseAddress));=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + VtdUnitInfo->EnableQueuedInvalidation =3D 1;=0D + DEBUG ((DEBUG_INFO, "Use Queued Invalidation Interface for engine [0x%x]= \n", VtdUnitBaseAddress));=0D +=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);=0D + if ((Reg32 & B_GSTS_REG_QIES) !=3D 0) {=0D + DEBUG ((DEBUG_INFO,"Queued Invalidation Interface was enabled.\n"));=0D +=0D + VtdLibDisableQueuedInvalidationInterface (VtdUnitBaseAddress);=0D + }=0D +=0D + //=0D + // Initialize the Invalidation Queue Tail Register to zero.=0D + //=0D + MmioWrite64 (VtdUnitBaseAddress + R_IQT_REG, 0);=0D +=0D + //=0D + // Setup the IQ address, size and descriptor width through the Invalidat= ion Queue Address Register=0D + //=0D + if (VtdUnitInfo->QiDescBuffer =3D=3D NULL) {=0D + VtdUnitInfo->QiDescBufferSize =3D (sizeof (QI_256_DESC) * ((UINTN) 1 <= < (VTD_INVALIDATION_QUEUE_SIZE + 7)));=0D + VtdUnitInfo->QiDescBuffer =3D AllocatePages (EFI_SIZE_TO_PAGES (VtdUni= tInfo->QiDescBufferSize));=0D + if (VtdUnitInfo->QiDescBuffer =3D=3D NULL) {=0D + DEBUG ((DEBUG_ERROR,"Could not Alloc Invalidation Queue Buffer.\n"))= ;=0D + VTdLogAddEvent (VTDLOG_PEI_QUEUED_INVALIDATION, VTD_LOG_QI_ERROR_OUT= _OF_RESOURCES, VtdUnitBaseAddress);=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, "Invalidation Queue Buffer Size : %d\n", VtdUnitInfo= ->QiDescBufferSize));=0D + //=0D + // 4KB Aligned address=0D + //=0D + IqaReg.Uint64 =3D (UINT64) (UINTN) VtdUnitInfo->QiDescBuffer;=0D + IqaReg.Bits.DW =3D VTD_QUEUED_INVALIDATION_DESCRIPTOR_WIDTH;=0D + IqaReg.Bits.QS =3D VTD_INVALIDATION_QUEUE_SIZE;=0D + MmioWrite64 (VtdUnitBaseAddress + R_IQA_REG, IqaReg.Uint64);=0D + IqaReg.Uint64 =3D MmioRead64 (VtdUnitBaseAddress + R_IQA_REG);=0D + DEBUG ((DEBUG_INFO, "IQA_REG =3D 0x%lx, IQH_REG =3D 0x%lx\n", IqaReg.Uin= t64, MmioRead64 (VtdUnitBaseAddress + R_IQH_REG)));=0D +=0D + //=0D + // Enable the queued invalidation interface through the Global Command R= egister.=0D + // When enabled, hardware sets the QIES field in the Global Status Regis= ter.=0D + //=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);=0D + Reg32 |=3D B_GMCD_REG_QIE;=0D + MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32);=0D + DEBUG ((DEBUG_INFO, "Enable Queued Invalidation Interface. GCMD_REG =3D = 0x%x\n", Reg32));=0D + do {=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);=0D + } while ((Reg32 & B_GSTS_REG_QIES) =3D=3D 0);=0D +=0D + VTdLogAddEvent (VTDLOG_PEI_QUEUED_INVALIDATION, VTD_LOG_QI_ENABLE, VtdUn= itBaseAddress);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Submit the queued invalidation descriptor to the remapping=0D + hardware unit and wait for its completion.=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D + @param[in] Desc The invalidate descriptor=0D +=0D + @retval EFI_SUCCESS The operation was successful.=0D + @retval RETURN_DEVICE_ERROR A fault is detected.=0D + @retval EFI_INVALID_PARAMETER Parameter is invalid.=0D +**/=0D +EFI_STATUS=0D +SubmitQueuedInvalidationDescriptor (=0D + IN UINTN VtdUnitBaseAddress,=0D + IN QI_256_DESC *Desc=0D + )=0D +{=0D + EFI_STATUS Status;=0D + VTD_REGESTER_QI_INFO RegisterQi;=0D +=0D + Status =3D VtdLibSubmitQueuedInvalidationDescriptor (VtdUnitBaseAddress,= Desc, FALSE);=0D + if (Status =3D=3D EFI_DEVICE_ERROR) {=0D + RegisterQi.BaseAddress =3D VtdUnitBaseAddress;=0D + RegisterQi.FstsReg =3D MmioRead32 (VtdUnitBaseAddress + R_FSTS_REG= );;=0D + RegisterQi.IqercdReg =3D MmioRead64 (VtdUnitBaseAddress + R_IQERCD_R= EG);=0D + VTdLogAddDataEvent (VTDLOG_PEI_REGISTER, VTDLOG_REGISTER_QI, &Register= Qi, sizeof (VTD_REGESTER_QI_INFO));=0D +=0D + MmioWrite32 (VtdUnitBaseAddress + R_FSTS_REG, RegisterQi.FstsReg & (B_= FSTS_REG_IQE | B_FSTS_REG_ITE | B_FSTS_REG_ICE));=0D + }=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + Invalidate VTd context cache.=0D +=0D + @param[in] VtdUnitInfo The VTd engine unit information.=0D +**/=0D +EFI_STATUS=0D +InvalidateContextCache (=0D + IN VTD_UNIT_INFO *VtdUnitInfo=0D + )=0D +{=0D + UINT64 Reg64;=0D + QI_256_DESC QiDesc;=0D +=0D + if (VtdUnitInfo->EnableQueuedInvalidation =3D=3D 0) {=0D + //=0D + // Register-based Invalidation=0D + //=0D + Reg64 =3D MmioRead64 (VtdUnitInfo->VtdUnitBaseAddress + R_CCMD_REG);=0D + if ((Reg64 & B_CCMD_REG_ICC) !=3D 0) {=0D + DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC i= s set for VTD(%x)\n", VtdUnitInfo->VtdUnitBaseAddress));=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + Reg64 &=3D ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK));=0D + Reg64 |=3D (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL);=0D + MmioWrite64 (VtdUnitInfo->VtdUnitBaseAddress + R_CCMD_REG, Reg64);=0D +=0D + do {=0D + Reg64 =3D MmioRead64 (VtdUnitInfo->VtdUnitBaseAddress + R_CCMD_REG);= =0D + } while ((Reg64 & B_CCMD_REG_ICC) !=3D 0);=0D + } else {=0D + //=0D + // Queued Invalidation=0D + //=0D + QiDesc.Uint64[0] =3D QI_CC_FM(0) | QI_CC_SID(0) | QI_CC_DID(0) | QI_CC= _GRAN(1) | QI_CC_TYPE;=0D + QiDesc.Uint64[1] =3D 0;=0D + QiDesc.Uint64[2] =3D 0;=0D + QiDesc.Uint64[3] =3D 0;=0D +=0D + return SubmitQueuedInvalidationDescriptor(VtdUnitInfo->VtdUnitBaseAddr= ess, &QiDesc);=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Invalidate VTd IOTLB.=0D +=0D + @param[in] VtdUnitInfo The VTd engine unit information.=0D +**/=0D +EFI_STATUS=0D +InvalidateIOTLB (=0D + IN VTD_UNIT_INFO *VtdUnitInfo=0D + )=0D +{=0D + UINT64 Reg64;=0D + VTD_ECAP_REG ECapReg;=0D + VTD_CAP_REG CapReg;=0D + QI_256_DESC QiDesc;=0D +=0D + if (VtdUnitInfo->EnableQueuedInvalidation =3D=3D 0) {=0D + //=0D + // Register-based Invalidation=0D + //=0D + ECapReg.Uint64 =3D MmioRead64 (VtdUnitInfo->VtdUnitBaseAddress + R_ECA= P_REG);=0D +=0D + Reg64 =3D MmioRead64 (VtdUnitInfo->VtdUnitBaseAddress + (ECapReg.Bits.= IRO * 16) + R_IOTLB_REG);=0D + if ((Reg64 & B_IOTLB_REG_IVT) !=3D 0) {=0D + DEBUG ((DEBUG_ERROR, "ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is se= t for VTD(%x)\n", VtdUnitInfo->VtdUnitBaseAddress));=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + Reg64 &=3D ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK));=0D + Reg64 |=3D (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL);=0D + MmioWrite64 (VtdUnitInfo->VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16)= + R_IOTLB_REG, Reg64);=0D +=0D + do {=0D + Reg64 =3D MmioRead64 (VtdUnitInfo->VtdUnitBaseAddress + (ECapReg.Bit= s.IRO * 16) + R_IOTLB_REG);=0D + } while ((Reg64 & B_IOTLB_REG_IVT) !=3D 0);=0D + } else {=0D + //=0D + // Queued Invalidation=0D + //=0D + CapReg.Uint64 =3D MmioRead64 (VtdUnitInfo->VtdUnitBaseAddress + R_CAP_= REG);=0D + QiDesc.Uint64[0] =3D QI_IOTLB_DID(0) | QI_IOTLB_DR(CAP_READ_DRAIN(CapR= eg.Uint64)) | QI_IOTLB_DW(CAP_WRITE_DRAIN(CapReg.Uint64)) | QI_IOTLB_GRAN(1= ) | QI_IOTLB_TYPE;=0D + QiDesc.Uint64[1] =3D QI_IOTLB_ADDR(0) | QI_IOTLB_IH(0) | QI_IOTLB_AM(0= );=0D + QiDesc.Uint64[2] =3D 0;=0D + QiDesc.Uint64[3] =3D 0;=0D +=0D + return SubmitQueuedInvalidationDescriptor(VtdUnitInfo->VtdUnitBaseAddr= ess, &QiDesc);=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Enable DMAR translation in pre-mem phase.=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D + @param[in] RtaddrRegValue The value of RTADDR_REG.=0D +=0D + @retval EFI_SUCCESS DMAR translation is enabled.=0D + @retval EFI_DEVICE_ERROR DMAR translation is not enabled.=0D +**/=0D +EFI_STATUS=0D +EnableDmarPreMem (=0D + IN UINTN VtdUnitBaseAddress,=0D + IN UINT64 RtaddrRegValue=0D + )=0D +{=0D + UINT32 Reg32;=0D +=0D + DEBUG ((DEBUG_INFO, ">>>>>>EnableDmarPreMem() for engine [%x] \n", VtdUn= itBaseAddress));=0D +=0D + DEBUG ((DEBUG_INFO, "RTADDR_REG : 0x%016lx \n", RtaddrRegValue));=0D + MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, RtaddrRegValue);=0D +=0D + DEBUG ((DEBUG_INFO, "EnableDmarPreMem: waiting for RTPS bit to be set...= \n"));=0D + VtdLibSetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRTP)= ;=0D +=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);=0D + DEBUG ((DEBUG_INFO, "EnableDmarPreMem: R_GSTS_REG =3D 0x%x \n", Reg32));= =0D +=0D + //=0D + // Write Buffer Flush=0D + //=0D + VtdLibFlushWriteBuffer (VtdUnitBaseAddress);=0D +=0D + //=0D + // Enable VTd=0D + //=0D + VtdLibSetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_TE);= =0D +=0D + DEBUG ((DEBUG_INFO, "VTD () enabled!<<<<<<\n"));=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Enable DMAR translation.=0D +=0D + @param[in] VtdUnitInfo The VTd engine unit information.=0D + @param[in] RootEntryTable The address of the VTd RootEntryTable.=0D +=0D + @retval EFI_SUCCESS DMAR translation is enabled.=0D + @retval EFI_DEVICE_ERROR DMAR translation is not enabled.=0D +**/=0D +EFI_STATUS=0D +EnableDmar (=0D + IN VTD_UNIT_INFO *VtdUnitInfo,=0D + IN UINTN RootEntryTable=0D + )=0D +{=0D + UINTN VtdUnitBaseAddress;=0D + BOOLEAN TEWasEnabled;=0D +=0D + VtdUnitBaseAddress =3D VtdUnitInfo->VtdUnitBaseAddress;=0D +=0D + DEBUG ((DEBUG_INFO, ">>>>>>EnableDmar() for engine [%x] \n", VtdUnitBase= Address));=0D +=0D + //=0D + // Check TE was enabled or not.=0D + //=0D + TEWasEnabled =3D ((MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG) & B_GSTS= _REG_TE) =3D=3D B_GSTS_REG_TE);=0D +=0D + if (TEWasEnabled && (VtdUnitInfo->ECapReg.Bits.ADMS =3D=3D 1) && PcdGetB= ool (PcdVTdSupportAbortDmaMode)) {=0D + //=0D + // For implementations reporting Enhanced SRTP Support (ESRTPS) field = as=0D + // Clear in the Capability register, software must not modify this fie= ld while=0D + // DMA remapping is active (TES=3D1 in Global Status register).=0D + //=0D + if (VtdUnitInfo->CapReg.Bits.ESRTPS =3D=3D 0) {=0D + VtdLibClearGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG= _TE);=0D + }=0D +=0D + //=0D + // Enable ADM=0D + //=0D + MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, (UINT64) (RootEntryTab= le | V_RTADDR_REG_TTM_ADM));=0D +=0D + DEBUG ((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"= ));=0D + VtdLibSetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRT= P);=0D +=0D + DEBUG ((DEBUG_INFO, "Enable Abort DMA Mode...\n"));=0D + VtdLibSetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_TE)= ;=0D +=0D + } else {=0D + DEBUG ((DEBUG_INFO, "RootEntryTable 0x%x \n", RootEntryTable));=0D + MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, (UINT64) RootEntryTabl= e);=0D +=0D + DEBUG ((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"= ));=0D + VtdLibSetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRT= P);=0D + }=0D +=0D + //=0D + // Write Buffer Flush before invalidation=0D + //=0D + VtdLibFlushWriteBuffer (VtdUnitBaseAddress);=0D +=0D + //=0D + // Invalidate the context cache=0D + //=0D + InvalidateContextCache (VtdUnitInfo);=0D +=0D + //=0D + // Invalidate the IOTLB cache=0D + //=0D + InvalidateIOTLB (VtdUnitInfo);=0D +=0D + if (TEWasEnabled && (VtdUnitInfo->ECapReg.Bits.ADMS =3D=3D 1) && PcdGetB= ool (PcdVTdSupportAbortDmaMode)) {=0D + if (VtdUnitInfo->CapReg.Bits.ESRTPS =3D=3D 0) {=0D + VtdLibClearGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG= _TE);=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, "RootEntryTable 0x%x \n", RootEntryTable));=0D + MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, (UINT64) RootEntryTabl= e);=0D +=0D + DEBUG ((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"= ));=0D + VtdLibSetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRT= P);=0D + }=0D +=0D + //=0D + // Enable VTd=0D + //=0D + VtdLibSetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_TE);= =0D +=0D + DEBUG ((DEBUG_INFO, "VTD () enabled!<<<<<<\n"));=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Enable VTd translation table protection for block DMA=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D +=0D + @retval EFI_SUCCESS DMAR translation is enabled.=0D + @retval EFI_DEVICE_ERROR DMAR translation is not enabled.=0D +**/=0D +EFI_STATUS=0D +EnableVTdTranslationProtectionBlockDma (=0D + IN UINTN VtdUnitBaseAddress=0D + )=0D +{=0D + EFI_STATUS Status;=0D + VTD_ECAP_REG ECapReg;=0D + EDKII_VTD_NULL_ROOT_ENTRY_TABLE_PPI *RootEntryTable;=0D + UINT8 Mode;=0D +=0D + DEBUG ((DEBUG_INFO, "EnableVTdTranslationProtectionBlockDma - 0x%08x\n",= VtdUnitBaseAddress));=0D +=0D + DEBUG ((DEBUG_INFO, "PcdVTdSupportAbortDmaMode : %d\n", PcdGetBool (PcdV= TdSupportAbortDmaMode)));=0D +=0D + ECapReg.Uint64 =3D MmioRead64 (VtdUnitBaseAddress + R_ECAP_REG);=0D + DEBUG ((DEBUG_INFO, "ECapReg.ADMS : %d\n", ECapReg.Bits.ADMS));=0D +=0D + if ((ECapReg.Bits.ADMS =3D=3D 1) && PcdGetBool (PcdVTdSupportAbortDmaMod= e)) {=0D + Mode =3D VTD_LOG_PEI_PRE_MEM_ADM;=0D + //=0D + // Use Abort DMA Mode=0D + //=0D + DEBUG ((DEBUG_INFO, "Enable abort DMA mode.\n"));=0D + Status =3D EnableDmarPreMem (VtdUnitBaseAddress, V_RTADDR_REG_TTM_ADM)= ;=0D + } else {=0D + //=0D + // Use Null Root Entry Table=0D + //=0D + Status =3D PeiServicesLocatePpi (=0D + &gEdkiiVTdNullRootEntryTableGuid,=0D + 0,=0D + NULL,=0D + (VOID **)&RootEntryTable=0D + );=0D + if (EFI_ERROR (Status)) {=0D + Mode =3D VTD_LOG_PEI_PRE_MEM_DISABLE;=0D + DEBUG ((DEBUG_ERROR, "Locate Null Root Entry Table Ppi Failed : %r\n= ", Status));=0D + ASSERT (FALSE);=0D + } else {=0D + Mode =3D VTD_LOG_PEI_PRE_MEM_TE;=0D + DEBUG ((DEBUG_INFO, "Block All DMA by TE.\n"));=0D + Status =3D EnableDmarPreMem (VtdUnitBaseAddress, (UINT64) (*RootEntr= yTable));=0D + }=0D + }=0D +=0D + VTdLogAddPreMemoryEvent (VtdUnitBaseAddress, Mode, EFI_ERROR (Status) ? = 0 : 1);=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + Enable VTd translation table protection.=0D +=0D + @param[in] VTdInfo The VTd engine context information.=0D +=0D + @retval EFI_SUCCESS DMAR translation is enabled.=0D + @retval EFI_DEVICE_ERROR DMAR translation is not enabled.=0D +**/=0D +EFI_STATUS=0D +EnableVTdTranslationProtection (=0D + IN VTD_INFO *VTdInfo=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN Index;=0D + VTD_UNIT_INFO *VtdUnitInfo;=0D +=0D + for (Index =3D 0; Index < VTdInfo->VTdEngineCount; Index++) {=0D + VtdUnitInfo =3D &VTdInfo->VtdUnitInfo[Index];=0D + if (VtdUnitInfo->Done) {=0D + DEBUG ((DEBUG_INFO, "EnableVtdDmar (%d) was enabled\n", Index));=0D + continue;=0D + }=0D +=0D + if (VtdUnitInfo->ExtRootEntryTable !=3D 0) {=0D + DEBUG ((DEBUG_INFO, "EnableVtdDmar (%d) ExtRootEntryTable 0x%x\n", I= ndex, VtdUnitInfo->ExtRootEntryTable));=0D + Status =3D EnableDmar (VtdUnitInfo, VtdUnitInfo->ExtRootEntryTable |= BIT11);=0D + } else {=0D + DEBUG ((DEBUG_INFO, "EnableVtdDmar (%d) RootEntryTable 0x%x\n", Inde= x, VtdUnitInfo->RootEntryTable));=0D + Status =3D EnableDmar (VtdUnitInfo, VtdUnitInfo->RootEntryTable);=0D + }=0D +=0D + VTdLogAddEvent (VTDLOG_PEI_POST_MEM_ENABLE_DMA_PROTECT, VTdInfo->VtdUn= itInfo[Index].VtdUnitBaseAddress, Status);=0D +=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "EnableVtdDmar (%d) Failed !\n", Index));=0D + return Status;=0D + }=0D + VtdUnitInfo->Done =3D TRUE;=0D + }=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Disable VTd translation table protection.=0D +=0D + @param[in] VTdInfo The VTd engine context information.=0D +**/=0D +VOID=0D +DisableVTdTranslationProtection (=0D + IN VTD_INFO *VTdInfo=0D + )=0D +{=0D + UINTN Index;=0D + VTD_UNIT_INFO *VtdUnitInfo;=0D +=0D + if (VTdInfo =3D=3D NULL) {=0D + return;=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, "DisableVTdTranslationProtection - %d Vtd Engine\n",= VTdInfo->VTdEngineCount));=0D +=0D + for (Index =3D 0; Index < VTdInfo->VTdEngineCount; Index++) {=0D + VtdUnitInfo =3D &VTdInfo->VtdUnitInfo[Index];=0D +=0D + VtdLibDisableDmar (VtdUnitInfo->VtdUnitBaseAddress);=0D + VTdLogAddEvent (VTDLOG_PEI_POST_MEM_DISABLE_DMA_PROTECT, VtdUnitInfo->= VtdUnitBaseAddress, 0);=0D +=0D + if (VtdUnitInfo->EnableQueuedInvalidation !=3D 0) {=0D + //=0D + // Disable queued invalidation interface.=0D + //=0D + VtdLibDisableQueuedInvalidationInterface (VtdUnitInfo->VtdUnitBaseAd= dress);=0D +=0D + if (VtdUnitInfo->QiDescBuffer !=3D NULL) {=0D + FreePages(VtdUnitInfo->QiDescBuffer, EFI_SIZE_TO_PAGES (VtdUnitInf= o->QiDescBufferSize));=0D + VtdUnitInfo->QiDescBuffer =3D NULL;=0D + VtdUnitInfo->QiDescBufferSize =3D 0;=0D + }=0D +=0D + VtdUnitInfo->EnableQueuedInvalidation =3D 0;=0D + VTdLogAddEvent (VTDLOG_PEI_QUEUED_INVALIDATION, VTD_LOG_QI_DISABLE, = VtdUnitInfo->VtdUnitBaseAddress);=0D + }=0D + }=0D +=0D + return;=0D +}=0D +=0D +/**=0D + Check if VTd engine use 5 level paging.=0D +=0D + @param[in] HostAddressWidth Host Address Width.=0D + @param[in] VtdUnitInfo The VTd engine unit information.=0D + @param[out] Is5LevelPaging Use 5 level paging or not=0D +=0D + @retval EFI_SUCCESS Success=0D + @retval EFI_UNSUPPORTED Feature is not support=0D +=0D +**/=0D +EFI_STATUS=0D +VtdCheckUsing5LevelPaging (=0D + IN UINT8 HostAddressWidth,=0D + IN VTD_CAP_REG CapReg,=0D + OUT BOOLEAN *Is5LevelPaging=0D + )=0D +{=0D + DEBUG ((DEBUG_INFO, " CapReg SAGAW bits : 0x%02x\n", CapReg.Bits.SAGAW)= );=0D +=0D + *Is5LevelPaging =3D FALSE;=0D + if ((CapReg.Bits.SAGAW & BIT3) !=3D 0) {=0D + *Is5LevelPaging =3D TRUE;=0D + if ((HostAddressWidth <=3D 48) &&=0D + ((CapReg.Bits.SAGAW & BIT2) !=3D 0)) {=0D + *Is5LevelPaging =3D FALSE;=0D + } else {=0D + return EFI_UNSUPPORTED;=0D + }=0D + }=0D + if ((CapReg.Bits.SAGAW & (BIT3 | BIT2)) =3D=3D 0) {=0D + return EFI_UNSUPPORTED;=0D + }=0D + DEBUG ((DEBUG_INFO, " Using %d Level Paging\n", *Is5LevelPaging ? 5 : 4= ));=0D + return EFI_SUCCESS;=0D +}=0D +=0D +=0D +/**=0D + Prepare VTD configuration.=0D +=0D + @param[in] VTdInfo The VTd engine context information.=0D +=0D + @retval EFI_SUCCESS Prepare Vtd config success=0D +**/=0D +EFI_STATUS=0D +PrepareVtdConfig (=0D + IN VTD_INFO *VTdInfo=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN Index;=0D + VTD_UNIT_INFO *VtdUnitInfo;=0D + UINTN VtdUnitBaseAddress;=0D +=0D + if (VTdInfo->RegsInfoBuffer =3D=3D NULL) {=0D + VTdInfo->RegsInfoBuffer =3D AllocateZeroPages (EFI_SIZE_TO_PAGES (size= of (VTD_REGESTER_THIN_INFO) + sizeof (VTD_UINT128) * VTD_CAP_REG_NFR_MAX));= =0D + ASSERT (VTdInfo->RegsInfoBuffer !=3D NULL);=0D + }=0D +=0D + for (Index =3D 0; Index < VTdInfo->VTdEngineCount; Index++) {=0D + VtdUnitInfo =3D &VTdInfo->VtdUnitInfo[Index];=0D + if (VtdUnitInfo->Done) {=0D + continue;=0D + }=0D + VtdUnitBaseAddress =3D VtdUnitInfo->VtdUnitBaseAddress;=0D + DEBUG ((DEBUG_INFO, "VTd Engine: 0x%08X\n", VtdUnitBaseAddress));=0D +=0D + VtdUnitInfo->VerReg.Uint32 =3D MmioRead32 (VtdUnitBaseAddress + R_VER_= REG);=0D + VtdUnitInfo->CapReg.Uint64 =3D MmioRead64 (VtdUnitBaseAddress + R_CAP_= REG);=0D + VtdUnitInfo->ECapReg.Uint64 =3D MmioRead64 (VtdUnitBaseAddress + R_ECA= P_REG);=0D + DEBUG ((DEBUG_INFO, " VER_REG : 0x%08X\n", VtdUnitInfo->VerReg.Uint3= 2));=0D + DEBUG ((DEBUG_INFO, " CAP_REG : 0x%016lX\n", VtdUnitInfo->CapReg.Uin= t64));=0D + DEBUG ((DEBUG_INFO, " ECAP_REG : 0x%016lX\n", VtdUnitInfo->ECapReg.Ui= nt64));=0D +=0D + Status =3D VtdCheckUsing5LevelPaging (VTdInfo->HostAddressWidth, VtdUn= itInfo->CapReg, &(VtdUnitInfo->Is5LevelPaging));=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "!!!! Page-table type 0x%X is not supported!!!!= \n", VtdUnitInfo->CapReg.Bits.SAGAW));=0D + return Status;=0D + }=0D +=0D + Status =3D PerpareCacheInvalidationInterface(&VTdInfo->VtdUnitInfo[Ind= ex]);=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Dump VTd registers if there is error.=0D +**/=0D +VOID=0D +DumpVtdIfError (=0D + VOID=0D + )=0D +{=0D + VTD_INFO *VTdInfo;=0D + UINTN Num;=0D + UINTN VtdUnitBaseAddress;=0D + UINT16 Index;=0D + VTD_REGESTER_THIN_INFO *VtdRegInfo;=0D + VTD_FRCD_REG FrcdReg;=0D + VTD_CAP_REG CapReg;=0D + UINT32 FstsReg32;=0D + UINT32 FectlReg32;=0D + BOOLEAN HasError;=0D +=0D + VTdInfo =3D GetVTdInfoHob ();=0D + if (VTdInfo =3D=3D NULL) {=0D + return;=0D + }=0D +=0D + VtdRegInfo =3D VTdInfo->RegsInfoBuffer;=0D + if (VtdRegInfo =3D=3D NULL) {=0D + return;=0D + }=0D +=0D + for (Num =3D 0; Num < VTdInfo->VTdEngineCount; Num++) {=0D + HasError =3D FALSE;=0D + VtdUnitBaseAddress =3D VTdInfo->VtdUnitInfo[Num].VtdUnitBaseAddress;=0D + FstsReg32 =3D MmioRead32 (VtdUnitBaseAddress + R_FSTS_REG);=0D + if (FstsReg32 !=3D 0) {=0D + HasError =3D TRUE;=0D + }=0D + FectlReg32 =3D MmioRead32 (VtdUnitBaseAddress + R_FECTL_REG);=0D + if ((FectlReg32 & BIT30) !=3D 0) {=0D + HasError =3D TRUE;=0D + }=0D +=0D + CapReg.Uint64 =3D MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);=0D + for (Index =3D 0; Index < (UINT16) CapReg.Bits.NFR + 1; Index++) {=0D + FrcdReg.Uint64[0] =3D MmioRead64 (VtdUnitBaseAddress + ((CapReg.Bits= .FRO * 16) + (Index * 16) + R_FRCD_REG));=0D + FrcdReg.Uint64[1] =3D MmioRead64 (VtdUnitBaseAddress + ((CapReg.Bits= .FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)));=0D + if (FrcdReg.Bits.F !=3D 0) {=0D + HasError =3D TRUE;=0D + break;=0D + }=0D + }=0D +=0D + if (HasError) {=0D + DEBUG ((DEBUG_INFO, "\n#### ERROR ####\n"));=0D +=0D + VtdRegInfo->BaseAddress =3D VtdUnitBaseAddress;=0D + VtdRegInfo->GstsReg =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_= REG);=0D + VtdRegInfo->RtaddrReg =3D MmioRead64 (VtdUnitBaseAddress + R_RTADD= R_REG);;=0D + VtdRegInfo->FstsReg =3D FstsReg32;=0D + VtdRegInfo->FectlReg =3D FectlReg32;=0D + VtdRegInfo->IqercdReg =3D MmioRead64 (VtdUnitBaseAddress + R_IQERC= D_REG);=0D +=0D + CapReg.Uint64 =3D MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);=0D + for (Index =3D 0; Index < (UINT16) CapReg.Bits.NFR + 1; Index++) {=0D + VtdRegInfo->FrcdReg[Index].Uint64Lo =3D MmioRead64 (VtdUnitBaseAdd= ress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG));=0D + VtdRegInfo->FrcdReg[Index].Uint64Hi =3D MmioRead64 (VtdUnitBaseAdd= ress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)= ));=0D + }=0D + VtdRegInfo->FrcdRegNum =3D Index;=0D +=0D + DEBUG ((DEBUG_INFO, "\n#### ERROR ####\n"));=0D +=0D + VtdLibDumpVtdRegsThin (NULL, NULL, VtdRegInfo);=0D +=0D + DEBUG ((DEBUG_INFO, "#### ERROR ####\n\n"));=0D +=0D + VTdLogAddDataEvent (VTDLOG_PEI_REGISTER, VTDLOG_REGISTER_THIN, VtdRe= gInfo, sizeof (VTD_REGESTER_THIN_INFO) + sizeof (VTD_UINT128) * (VtdRegInfo= ->FrcdRegNum - 1));=0D +=0D + //=0D + // Clear=0D + //=0D + for (Index =3D 0; Index < (UINT16) CapReg.Bits.NFR + 1; Index++) {=0D + FrcdReg.Uint64[1] =3D MmioRead64 (VtdUnitBaseAddress + ((CapReg.Bi= ts.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)));=0D + if (FrcdReg.Bits.F !=3D 0) {=0D + //=0D + // Software writes the value read from this field (F) to Clear i= t.=0D + //=0D + MmioWrite64 (VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Ind= ex * 16) + R_FRCD_REG + sizeof(UINT64)), FrcdReg.Uint64[1]);=0D + }=0D + }=0D + MmioWrite32 (VtdUnitBaseAddress + R_FSTS_REG, MmioRead32 (VtdUnitBas= eAddress + R_FSTS_REG));=0D + }=0D + }=0D +} \ No newline at end of file diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/Tran= slationTable.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/= TranslationTable.c new file mode 100644 index 000000000..03a4544a0 --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdCorePei/Translation= Table.c @@ -0,0 +1,926 @@ +/** @file=0D +=0D + Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include "IntelVTdCorePei.h"=0D +=0D +#define ALIGN_VALUE_UP(Value, Alignment) (((Value) + (Alignment) - 1) & (= ~((Alignment) - 1)))=0D +#define ALIGN_VALUE_LOW(Value, Alignment) ((Value) & (~((Alignment) - 1)))= =0D +=0D +/**=0D + Allocate zero pages.=0D +=0D + @param[in] Pages the number of pages.=0D +=0D + @return the page address.=0D + @retval NULL No resource to allocate pages.=0D +**/=0D +VOID *=0D +EFIAPI=0D +AllocateZeroPages (=0D + IN UINTN Pages=0D + )=0D +{=0D + VOID *Addr;=0D +=0D + Addr =3D AllocatePages (Pages);=0D + if (Addr =3D=3D NULL) {=0D + return NULL;=0D + }=0D + ZeroMem (Addr, EFI_PAGES_TO_SIZE (Pages));=0D + return Addr;=0D +}=0D +=0D +/**=0D + Set second level paging entry attribute based upon IoMmuAccess.=0D +=0D + @param[in] PtEntry The paging entry.=0D + @param[in] IoMmuAccess The IOMMU access.=0D +**/=0D +VOID=0D +SetSecondLevelPagingEntryAttribute (=0D + IN VTD_SECOND_LEVEL_PAGING_ENTRY *PtEntry,=0D + IN UINT64 IoMmuAccess=0D + )=0D +{=0D + PtEntry->Bits.Read =3D ((IoMmuAccess & EDKII_IOMMU_ACCESS_READ) !=3D 0)= ;=0D + PtEntry->Bits.Write =3D ((IoMmuAccess & EDKII_IOMMU_ACCESS_WRITE) !=3D 0= );=0D + DEBUG ((DEBUG_VERBOSE, "SetSecondLevelPagingEntryAttribute - 0x%x - 0x%x= \n", PtEntry, IoMmuAccess));=0D +}=0D +=0D +/**=0D + Create second level paging entry table.=0D +=0D + @param[in] VtdUnitInfo The VTd engine unit information.=0D + @param[in] SecondLevelPagingEntry The second level paging entry.=0D + @param[in] MemoryBase The base of the memory.=0D + @param[in] MemoryLimit The limit of the memory.=0D + @param[in] IoMmuAccess The IOMMU access.=0D +=0D + @return The second level paging entry.=0D +**/=0D +VTD_SECOND_LEVEL_PAGING_ENTRY *=0D +CreateSecondLevelPagingEntryTable (=0D + IN VTD_UNIT_INFO *VtdUnitInfo,=0D + IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,=0D + IN UINT64 MemoryBase,=0D + IN UINT64 MemoryLimit,=0D + IN UINT64 IoMmuAccess=0D + )=0D +{=0D + UINTN Index5;=0D + UINTN Index4;=0D + UINTN Index3;=0D + UINTN Index2;=0D + UINTN Lvl5Start;=0D + UINTN Lvl5End;=0D + UINTN Lvl4PagesStart;=0D + UINTN Lvl4PagesEnd;=0D + UINTN Lvl4Start;=0D + UINTN Lvl4End;=0D + UINTN Lvl3Start;=0D + UINTN Lvl3End;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl5PtEntry;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl4PtEntry;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl3PtEntry;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl2PtEntry;=0D + UINT64 BaseAddress;=0D + UINT64 EndAddress;=0D + BOOLEAN Is5LevelPaging;=0D +=0D + if (MemoryLimit =3D=3D 0) {=0D + return NULL;=0D + }=0D +=0D + Lvl4PagesStart =3D 0;=0D + Lvl4PagesEnd =3D 0;=0D + Lvl4PtEntry =3D NULL;=0D + Lvl5PtEntry =3D NULL;=0D +=0D + BaseAddress =3D ALIGN_VALUE_LOW (MemoryBase, SIZE_2MB);=0D + EndAddress =3D ALIGN_VALUE_UP (MemoryLimit, SIZE_2MB);=0D + DEBUG ((DEBUG_INFO, "CreateSecondLevelPagingEntryTable: BaseAddress - 0x= %016lx, EndAddress - 0x%016lx\n", BaseAddress, EndAddress));=0D +=0D + if (SecondLevelPagingEntry =3D=3D NULL) {=0D + SecondLevelPagingEntry =3D AllocateZeroPages (1);=0D + if (SecondLevelPagingEntry =3D=3D NULL) {=0D + DEBUG ((DEBUG_ERROR, "Could not Alloc LVL4 or LVL5 PT. \n"));=0D + return NULL;=0D + }=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN) SecondLevelPagingEntry, EFI= _PAGES_TO_SIZE (1));=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, " SecondLevelPagingEntry:0x%016lx\n", (UINT64) (UINT= N) SecondLevelPagingEntry));=0D + //=0D + // If no access is needed, just create not present entry.=0D + //=0D + if (IoMmuAccess =3D=3D 0) {=0D + DEBUG ((DEBUG_INFO, " SecondLevelPagingEntry:0x%016lx Access 0\n", (UI= NT64) (UINTN) SecondLevelPagingEntry));=0D + return SecondLevelPagingEntry;=0D + }=0D +=0D + Is5LevelPaging =3D VtdUnitInfo->Is5LevelPaging;=0D +=0D + if (Is5LevelPaging) {=0D + Lvl5Start =3D RShiftU64 (BaseAddress, 48) & 0x1FF;=0D + Lvl5End =3D RShiftU64 (EndAddress - 1, 48) & 0x1FF;=0D + DEBUG ((DEBUG_INFO, " Lvl5Start - 0x%x, Lvl5End - 0x%x\n", Lvl5Start,= Lvl5End));=0D +=0D + Lvl4Start =3D RShiftU64 (BaseAddress, 39) & 0x1FF;=0D + Lvl4End =3D RShiftU64 (EndAddress - 1, 39) & 0x1FF;=0D +=0D + Lvl4PagesStart =3D (Lvl5Start<<9) | Lvl4Start;=0D + Lvl4PagesEnd =3D (Lvl5End<<9) | Lvl4End;=0D + DEBUG ((DEBUG_INFO, " Lvl4PagesStart - 0x%x, Lvl4PagesEnd - 0x%x\n", = Lvl4PagesStart, Lvl4PagesEnd));=0D +=0D + Lvl5PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *) SecondLevelPagingEnt= ry;=0D + } else {=0D + Lvl5Start =3D RShiftU64 (BaseAddress, 48) & 0x1FF;=0D + Lvl5End =3D Lvl5Start;=0D +=0D + Lvl4Start =3D RShiftU64 (BaseAddress, 39) & 0x1FF;=0D + Lvl4End =3D RShiftU64 (EndAddress - 1, 39) & 0x1FF;=0D + DEBUG ((DEBUG_INFO, " Lvl4Start - 0x%x, Lvl4End - 0x%x\n", Lvl4Start,= Lvl4End));=0D +=0D + Lvl4PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *) SecondLevelPagingEnt= ry;=0D + }=0D +=0D + for (Index5 =3D Lvl5Start; Index5 <=3D Lvl5End; Index5++) {=0D + if (Is5LevelPaging) {=0D + if (Lvl5PtEntry[Index5].Uint64 =3D=3D 0) {=0D + Lvl5PtEntry[Index5].Uint64 =3D (UINT64) (UINTN) AllocateZeroPages = (1);=0D + if (Lvl5PtEntry[Index5].Uint64 =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR, "!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!= !\n", Index5));=0D + ASSERT (FALSE);=0D + return NULL;=0D + }=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN) Lvl5PtEntry[Index5].Uin= t64, SIZE_4KB);=0D + SetSecondLevelPagingEntryAttribute (&Lvl5PtEntry[Index5], EDKII_IO= MMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);=0D + }=0D + Lvl4Start =3D Lvl4PagesStart & 0x1FF;=0D + if (((Index5+1)<<9) > Lvl4PagesEnd) {=0D + Lvl4End =3D SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY) - 1;;=0D + Lvl4PagesStart =3D (Index5+1)<<9;=0D + } else {=0D + Lvl4End =3D Lvl4PagesEnd & 0x1FF;=0D + }=0D + DEBUG ((DEBUG_INFO, " Lvl5(0x%x): Lvl4Start - 0x%x, Lvl4End - 0x%x\= n", Index5, Lvl4Start, Lvl4End));=0D + Lvl4PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *) (UINTN) VTD_64BITS= _ADDRESS(Lvl5PtEntry[Index5].Bits.AddressLo, Lvl5PtEntry[Index5].Bits.Addre= ssHi);=0D + }=0D +=0D + for (Index4 =3D Lvl4Start; Index4 <=3D Lvl4End; Index4++) {=0D + if (Lvl4PtEntry[Index4].Uint64 =3D=3D 0) {=0D + Lvl4PtEntry[Index4].Uint64 =3D (UINT64) (UINTN) AllocateZeroPages = (1);=0D + if (Lvl4PtEntry[Index4].Uint64 =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR, "!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!= !\n", Index4));=0D + ASSERT(FALSE);=0D + return NULL;=0D + }=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN) Lvl4PtEntry[Index4].Uin= t64, SIZE_4KB);=0D + SetSecondLevelPagingEntryAttribute (&Lvl4PtEntry[Index4], EDKII_IO= MMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);=0D + }=0D +=0D + Lvl3Start =3D RShiftU64 (BaseAddress, 30) & 0x1FF;=0D + if (ALIGN_VALUE_LOW(BaseAddress + SIZE_1GB, SIZE_1GB) <=3D EndAddres= s) {=0D + Lvl3End =3D SIZE_4KB / sizeof (VTD_SECOND_LEVEL_PAGING_ENTRY) - 1;= =0D + } else {=0D + Lvl3End =3D RShiftU64 (EndAddress - 1, 30) & 0x1FF;=0D + }=0D + DEBUG ((DEBUG_INFO, " Lvl4(0x%x): Lvl3Start - 0x%x, Lvl3End - 0x%x\= n", Index4, Lvl3Start, Lvl3End));=0D +=0D + Lvl3PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *) (UINTN) VTD_64BITS= _ADDRESS(Lvl4PtEntry[Index4].Bits.AddressLo, Lvl4PtEntry[Index4].Bits.Addre= ssHi);=0D + for (Index3 =3D Lvl3Start; Index3 <=3D Lvl3End; Index3++) {=0D + if (Lvl3PtEntry[Index3].Uint64 =3D=3D 0) {=0D + Lvl3PtEntry[Index3].Uint64 =3D (UINT64) (UINTN) AllocateZeroPage= s (1);=0D + if (Lvl3PtEntry[Index3].Uint64 =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR, "!!!!!! ALLOCATE LVL3 PAGE FAIL (0x%x, 0x= %x)!!!!!!\n", Index4, Index3));=0D + ASSERT(FALSE);=0D + return NULL;=0D + }=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN) Lvl3PtEntry[Index3].U= int64, SIZE_4KB);=0D + SetSecondLevelPagingEntryAttribute (&Lvl3PtEntry[Index3], EDKII_= IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);=0D + }=0D +=0D + Lvl2PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *) (UINTN) VTD_64BI= TS_ADDRESS(Lvl3PtEntry[Index3].Bits.AddressLo, Lvl3PtEntry[Index3].Bits.Add= ressHi);=0D + for (Index2 =3D 0; Index2 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGIN= G_ENTRY); Index2++) {=0D + Lvl2PtEntry[Index2].Uint64 =3D BaseAddress;=0D + SetSecondLevelPagingEntryAttribute (&Lvl2PtEntry[Index2], IoMmuA= ccess);=0D + Lvl2PtEntry[Index2].Bits.PageSize =3D 1;=0D + BaseAddress +=3D SIZE_2MB;=0D + if (BaseAddress >=3D MemoryLimit) {=0D + break;=0D + }=0D + }=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN) Lvl2PtEntry, SIZE_4KB);= =0D + if (BaseAddress >=3D MemoryLimit) {=0D + break;=0D + }=0D + }=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN) &Lvl3PtEntry[Lvl3Start], = (UINTN) &Lvl3PtEntry[Lvl3End + 1] - (UINTN) &Lvl3PtEntry[Lvl3Start]);=0D + if (BaseAddress >=3D MemoryLimit) {=0D + break;=0D + }=0D + }=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN) &Lvl4PtEntry[Lvl4Start], (U= INTN) &Lvl4PtEntry[Lvl4End + 1] - (UINTN) &Lvl4PtEntry[Lvl4Start]);=0D + }=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN) &Lvl5PtEntry[Lvl5Start], (UIN= TN) &Lvl5PtEntry[Lvl5End + 1] - (UINTN) &Lvl5PtEntry[Lvl5Start]);=0D +=0D + DEBUG ((DEBUG_INFO, " SecondLevelPagingEntry:0x%016lx\n", (UINT64) (UINT= N) SecondLevelPagingEntry));=0D + return SecondLevelPagingEntry;=0D +}=0D +=0D +/**=0D + Create context entry.=0D +=0D + @param[in] VtdUnitInfo The VTd engine unit information.=0D +=0D + @retval EFI_SUCCESS The context entry is created.=0D + @retval EFI_OUT_OF_RESOURCE No enough resource to create context entry= .=0D +=0D +**/=0D +EFI_STATUS=0D +CreateContextEntry (=0D + IN VTD_UNIT_INFO *VtdUnitInfo=0D + )=0D +{=0D + UINTN RootPages;=0D + UINTN ContextPages;=0D + UINTN EntryTablePages;=0D + VOID *Buffer;=0D + UINTN RootIndex;=0D + UINTN ContextIndex;=0D + VTD_ROOT_ENTRY *RootEntryBase;=0D + VTD_ROOT_ENTRY *RootEntry;=0D + VTD_CONTEXT_ENTRY *ContextEntryTable;=0D + VTD_CONTEXT_ENTRY *ContextEntry;=0D + VTD_SOURCE_ID SourceId;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;=0D + UINT64 Pt;=0D +=0D + if (VtdUnitInfo->RootEntryTable !=3D 0) {=0D + return EFI_SUCCESS;=0D + }=0D +=0D + RootPages =3D EFI_SIZE_TO_PAGES (sizeof (VTD_ROOT_ENTRY) * VTD_ROOT_ENTR= Y_NUMBER);=0D + ContextPages =3D EFI_SIZE_TO_PAGES (sizeof (VTD_CONTEXT_ENTRY) * VTD_CON= TEXT_ENTRY_NUMBER);=0D + EntryTablePages =3D RootPages + ContextPages * (VTD_ROOT_ENTRY_NUMBER);= =0D + Buffer =3D AllocateZeroPages (EntryTablePages);=0D + if (Buffer =3D=3D NULL) {=0D + DEBUG ((DEBUG_ERROR, "Could not Alloc Root Entry Table.. \n"));=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + DEBUG ((DEBUG_ERROR, "RootEntryTable address - 0x%x\n", Buffer));=0D + VtdUnitInfo->RootEntryTable =3D (UINTN) Buffer;=0D + VtdUnitInfo->RootEntryTablePageSize =3D EntryTablePages;=0D + RootEntryBase =3D (VTD_ROOT_ENTRY *) Buffer;=0D + Buffer =3D (UINT8 *) Buffer + EFI_PAGES_TO_SIZE (RootPages);=0D +=0D + if (VtdUnitInfo->FixedSecondLevelPagingEntry =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR, "FixedSecondLevelPagingEntry is empty\n"));=0D + ASSERT(FALSE);=0D + }=0D +=0D + for (RootIndex =3D 0; RootIndex < VTD_ROOT_ENTRY_NUMBER; RootIndex++) {= =0D + SourceId.Index.RootIndex =3D (UINT8) RootIndex;=0D +=0D + RootEntry =3D &RootEntryBase[SourceId.Index.RootIndex];=0D + RootEntry->Bits.ContextTablePointerLo =3D (UINT32) RShiftU64 ((UINT64= ) (UINTN) Buffer, 12);=0D + RootEntry->Bits.ContextTablePointerHi =3D (UINT32) RShiftU64 ((UINT64= ) (UINTN) Buffer, 32);=0D + RootEntry->Bits.Present =3D 1;=0D + Buffer =3D (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (ContextPages);=0D + ContextEntryTable =3D (VTD_CONTEXT_ENTRY *) (UINTN) VTD_64BITS_ADDRESS= (RootEntry->Bits.ContextTablePointerLo, RootEntry->Bits.ContextTablePointer= Hi);=0D +=0D + for (ContextIndex =3D 0; ContextIndex < VTD_CONTEXT_ENTRY_NUMBER; Cont= extIndex++) {=0D + SourceId.Index.ContextIndex =3D (UINT8) ContextIndex;=0D + ContextEntry =3D &ContextEntryTable[SourceId.Index.ContextIndex];=0D +=0D + ContextEntry->Bits.TranslationType =3D 0;=0D + ContextEntry->Bits.FaultProcessingDisable =3D 0;=0D + ContextEntry->Bits.Present =3D 0;=0D +=0D + ContextEntry->Bits.AddressWidth =3D VtdUnitInfo->Is5LevelPaging ? 0x= 3 : 0x2;=0D +=0D + if (VtdUnitInfo->FixedSecondLevelPagingEntry !=3D 0) {=0D + SecondLevelPagingEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *) VtdUn= itInfo->FixedSecondLevelPagingEntry;=0D + Pt =3D (UINT64)RShiftU64 ((UINT64) (UINTN) SecondLevelPagingEntry,= 12);=0D + ContextEntry->Bits.SecondLevelPageTranslationPointerLo =3D (UINT32= ) Pt;=0D + ContextEntry->Bits.SecondLevelPageTranslationPointerHi =3D (UINT32= ) RShiftU64(Pt, 20);=0D + ContextEntry->Bits.DomainIdentifier =3D ((1 << (UINT8)((UINTN)VtdU= nitInfo->CapReg.Bits.ND * 2 + 4)) - 1);=0D + ContextEntry->Bits.Present =3D 1;=0D + }=0D + }=0D + }=0D +=0D + FlushPageTableMemory (VtdUnitInfo, VtdUnitInfo->RootEntryTable, EFI_PAGE= S_TO_SIZE(EntryTablePages));=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Create extended context entry.=0D +=0D + @param[in] VtdUnitInfo The VTd engine unit information.=0D +=0D + @retval EFI_SUCCESS The extended context entry is created.=0D + @retval EFI_OUT_OF_RESOURCE No enough resource to create extended cont= ext entry.=0D +**/=0D +EFI_STATUS=0D +CreateExtContextEntry (=0D + IN VTD_UNIT_INFO *VtdUnitInfo=0D + )=0D +{=0D + UINTN RootPages;=0D + UINTN ContextPages;=0D + UINTN EntryTablePages;=0D + VOID *Buffer;=0D + UINTN RootIndex;=0D + UINTN ContextIndex;=0D + VTD_EXT_ROOT_ENTRY *ExtRootEntryBase;=0D + VTD_EXT_ROOT_ENTRY *ExtRootEntry;=0D + VTD_EXT_CONTEXT_ENTRY *ExtContextEntryTable;=0D + VTD_EXT_CONTEXT_ENTRY *ExtContextEntry;=0D + VTD_SOURCE_ID SourceId;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;=0D + UINT64 Pt;=0D +=0D + if (VtdUnitInfo->ExtRootEntryTable !=3D 0) {=0D + return EFI_SUCCESS;=0D + }=0D +=0D + RootPages =3D EFI_SIZE_TO_PAGES (sizeof (VTD_EXT_ROOT_ENTRY) * VTD_ROOT_= ENTRY_NUMBER);=0D + ContextPages =3D EFI_SIZE_TO_PAGES (sizeof (VTD_EXT_CONTEXT_ENTRY) * VTD= _CONTEXT_ENTRY_NUMBER);=0D + EntryTablePages =3D RootPages + ContextPages * (VTD_ROOT_ENTRY_NUMBER);= =0D + Buffer =3D AllocateZeroPages (EntryTablePages);=0D + if (Buffer =3D=3D NULL) {=0D + DEBUG ((DEBUG_INFO, "Could not Alloc Root Entry Table !\n"));=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + DEBUG ((DEBUG_ERROR, "ExtRootEntryTable address - 0x%x\n", Buffer));=0D + VtdUnitInfo->ExtRootEntryTable =3D (UINTN) Buffer;=0D + VtdUnitInfo->ExtRootEntryTablePageSize =3D EntryTablePages;=0D + ExtRootEntryBase =3D (VTD_EXT_ROOT_ENTRY *) Buffer;=0D + Buffer =3D (UINT8 *) Buffer + EFI_PAGES_TO_SIZE (RootPages);=0D +=0D + if (VtdUnitInfo->FixedSecondLevelPagingEntry =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR, "FixedSecondLevelPagingEntry is empty\n"));=0D + ASSERT(FALSE);=0D + }=0D +=0D + for (RootIndex =3D 0; RootIndex < VTD_ROOT_ENTRY_NUMBER; RootIndex++) {= =0D + SourceId.Index.RootIndex =3D (UINT8)RootIndex;=0D +=0D + ExtRootEntry =3D &ExtRootEntryBase[SourceId.Index.RootIndex];=0D + ExtRootEntry->Bits.LowerContextTablePointerLo =3D (UINT32) RShiftU64 = ((UINT64) (UINTN) Buffer, 12);=0D + ExtRootEntry->Bits.LowerContextTablePointerHi =3D (UINT32) RShiftU64 = ((UINT64) (UINTN) Buffer, 32);=0D + ExtRootEntry->Bits.LowerPresent =3D 1;=0D + ExtRootEntry->Bits.UpperContextTablePointerLo =3D (UINT32) RShiftU64 = ((UINT64) (UINTN) Buffer, 12) + 1;=0D + ExtRootEntry->Bits.UpperContextTablePointerHi =3D (UINT32) RShiftU64 = (RShiftU64 ((UINT64) (UINTN) Buffer, 12) + 1, 20);=0D + ExtRootEntry->Bits.UpperPresent =3D 1;=0D + Buffer =3D (UINT8 *) Buffer + EFI_PAGES_TO_SIZE (ContextPages);=0D + ExtContextEntryTable =3D (VTD_EXT_CONTEXT_ENTRY *) (UINTN) VTD_64BITS_= ADDRESS (ExtRootEntry->Bits.LowerContextTablePointerLo, ExtRootEntry->Bits.= LowerContextTablePointerHi);=0D +=0D + for (ContextIndex =3D 0; ContextIndex < VTD_CONTEXT_ENTRY_NUMBER; Cont= extIndex++) {=0D + SourceId.Index.ContextIndex =3D (UINT8) ContextIndex;=0D + ExtContextEntry =3D &ExtContextEntryTable[SourceId.Index.ContextInde= x];=0D +=0D + ExtContextEntry->Bits.TranslationType =3D 0;=0D + ExtContextEntry->Bits.FaultProcessingDisable =3D 0;=0D + ExtContextEntry->Bits.Present =3D 0;=0D +=0D + ExtContextEntry->Bits.AddressWidth =3D VtdUnitInfo->Is5LevelPaging ?= 0x3 : 0x2;=0D +=0D + if (VtdUnitInfo->FixedSecondLevelPagingEntry !=3D 0) {=0D + SecondLevelPagingEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *) VtdUn= itInfo->FixedSecondLevelPagingEntry;=0D + Pt =3D (UINT64)RShiftU64 ((UINT64) (UINTN) SecondLevelPagingEntry,= 12);=0D +=0D + ExtContextEntry->Bits.SecondLevelPageTranslationPointerLo =3D (UIN= T32) Pt;=0D + ExtContextEntry->Bits.SecondLevelPageTranslationPointerHi =3D (UIN= T32) RShiftU64(Pt, 20);=0D + ExtContextEntry->Bits.DomainIdentifier =3D ((1 << (UINT8) ((UINTN)= VtdUnitInfo->CapReg.Bits.ND * 2 + 4)) - 1);=0D + ExtContextEntry->Bits.Present =3D 1;=0D + }=0D + }=0D + }=0D +=0D + FlushPageTableMemory (VtdUnitInfo, VtdUnitInfo->ExtRootEntryTable, EFI_P= AGES_TO_SIZE(EntryTablePages));=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +#define VTD_PG_R BIT0=0D +#define VTD_PG_W BIT1=0D +#define VTD_PG_X BIT2=0D +#define VTD_PG_EMT (BIT3 | BIT4 | BIT5)=0D +#define VTD_PG_TM (BIT62)=0D +=0D +#define VTD_PG_PS BIT7=0D +=0D +#define PAGE_PROGATE_BITS (VTD_PG_TM | VTD_PG_EMT | VTD_PG_W | VT= D_PG_R)=0D +=0D +#define PAGING_4K_MASK 0xFFF=0D +#define PAGING_2M_MASK 0x1FFFFF=0D +#define PAGING_1G_MASK 0x3FFFFFFF=0D +=0D +#define PAGING_VTD_INDEX_MASK 0x1FF=0D +=0D +#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull=0D +#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull=0D +#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull=0D +=0D +typedef enum {=0D + PageNone,=0D + Page4K,=0D + Page2M,=0D + Page1G,=0D +} PAGE_ATTRIBUTE;=0D +=0D +typedef struct {=0D + PAGE_ATTRIBUTE Attribute;=0D + UINT64 Length;=0D + UINT64 AddressMask;=0D +} PAGE_ATTRIBUTE_TABLE;=0D +=0D +PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] =3D {=0D + {Page4K, SIZE_4KB, PAGING_4K_ADDRESS_MASK_64},=0D + {Page2M, SIZE_2MB, PAGING_2M_ADDRESS_MASK_64},=0D + {Page1G, SIZE_1GB, PAGING_1G_ADDRESS_MASK_64},=0D +};=0D +=0D +/**=0D + Return length according to page attributes.=0D +=0D + @param[in] PageAttributes The page attribute of the page entry.=0D +=0D + @return The length of page entry.=0D +**/=0D +UINTN=0D +PageAttributeToLength (=0D + IN PAGE_ATTRIBUTE PageAttribute=0D + )=0D +{=0D + UINTN Index;=0D + for (Index =3D 0; Index < sizeof (mPageAttributeTable) / sizeof (mPageAt= tributeTable[0]); Index++) {=0D + if (PageAttribute =3D=3D mPageAttributeTable[Index].Attribute) {=0D + return (UINTN) mPageAttributeTable[Index].Length;=0D + }=0D + }=0D + return 0;=0D +}=0D +=0D +/**=0D + Return page table entry to match the address.=0D +=0D + @param[in] VtdUnitInfo The VTd engine unit information.=0D + @param[in] SecondLevelPagingEntry The second level paging entry in V= Td table for the device.=0D + @param[in] Address The address to be checked.=0D + @param[out] PageAttributes The page attribute of the page ent= ry.=0D +=0D + @return The page entry.=0D +**/=0D +VOID *=0D +GetSecondLevelPageTableEntry (=0D + IN VTD_UNIT_INFO *VtdUnitInfo,=0D + IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,=0D + IN PHYSICAL_ADDRESS Address,=0D + OUT PAGE_ATTRIBUTE *PageAttribute=0D + )=0D +{=0D + UINTN Index1;=0D + UINTN Index2;=0D + UINTN Index3;=0D + UINTN Index4;=0D + UINTN Index5;=0D + UINT64 *L1PageTable;=0D + UINT64 *L2PageTable;=0D + UINT64 *L3PageTable;=0D + UINT64 *L4PageTable;=0D + UINT64 *L5PageTable;=0D + BOOLEAN Is5LevelPaging;=0D +=0D + Index5 =3D ((UINTN) RShiftU64 (Address, 48)) & PAGING_VTD_INDEX_MASK;=0D + Index4 =3D ((UINTN) RShiftU64 (Address, 39)) & PAGING_VTD_INDEX_MASK;=0D + Index3 =3D ((UINTN) Address >> 30) & PAGING_VTD_INDEX_MASK;=0D + Index2 =3D ((UINTN) Address >> 21) & PAGING_VTD_INDEX_MASK;=0D + Index1 =3D ((UINTN) Address >> 12) & PAGING_VTD_INDEX_MASK;=0D +=0D + Is5LevelPaging =3D VtdUnitInfo->Is5LevelPaging;=0D +=0D + if (Is5LevelPaging) {=0D + L5PageTable =3D (UINT64 *) SecondLevelPagingEntry;=0D + if (L5PageTable[Index5] =3D=3D 0) {=0D + L5PageTable[Index5] =3D (UINT64) (UINTN) AllocateZeroPages (1);=0D + if (L5PageTable[Index5] =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR, "!!!!!! ALLOCATE LVL5 PAGE FAIL (0x%x)!!!!!!\= n", Index4));=0D + ASSERT(FALSE);=0D + *PageAttribute =3D PageNone;=0D + return NULL;=0D + }=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN) L5PageTable[Index5], SIZE= _4KB);=0D + SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *= ) &L5PageTable[Index5], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE)= ;=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN) &L5PageTable[Index5], siz= eof(L5PageTable[Index5]));=0D + }=0D + L4PageTable =3D (UINT64 *) (UINTN) (L5PageTable[Index5] & PAGING_4K_AD= DRESS_MASK_64);=0D + } else {=0D + L4PageTable =3D (UINT64 *)SecondLevelPagingEntry;=0D + }=0D +=0D + if (L4PageTable[Index4] =3D=3D 0) {=0D + L4PageTable[Index4] =3D (UINT64) (UINTN) AllocateZeroPages (1);=0D + if (L4PageTable[Index4] =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR, "!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!!\n"= , Index4));=0D + ASSERT(FALSE);=0D + *PageAttribute =3D PageNone;=0D + return NULL;=0D + }=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN) L4PageTable[Index4], SIZE_4= KB);=0D + SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *) = &L4PageTable[Index4], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);= =0D + FlushPageTableMemory (VtdUnitInfo, (UINTN) &L4PageTable[Index4], sizeo= f(L4PageTable[Index4]));=0D + }=0D +=0D + L3PageTable =3D (UINT64 *) (UINTN) (L4PageTable[Index4] & PAGING_4K_ADDR= ESS_MASK_64);=0D + if (L3PageTable[Index3] =3D=3D 0) {=0D + L3PageTable[Index3] =3D (UINT64) (UINTN) AllocateZeroPages (1);=0D + if (L3PageTable[Index3] =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR, "!!!!!! ALLOCATE LVL3 PAGE FAIL (0x%x, 0x%x)!!!= !!!\n", Index4, Index3));=0D + ASSERT(FALSE);=0D + *PageAttribute =3D PageNone;=0D + return NULL;=0D + }=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN) L3PageTable[Index3], SIZE_4= KB);=0D + SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *) = &L3PageTable[Index3], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);= =0D + FlushPageTableMemory (VtdUnitInfo, (UINTN) &L3PageTable[Index3], sizeo= f (L3PageTable[Index3]));=0D + }=0D + if ((L3PageTable[Index3] & VTD_PG_PS) !=3D 0) {=0D + // 1G=0D + *PageAttribute =3D Page1G;=0D + return &L3PageTable[Index3];=0D + }=0D +=0D + L2PageTable =3D (UINT64 *) (UINTN) (L3PageTable[Index3] & PAGING_4K_ADDR= ESS_MASK_64);=0D + if (L2PageTable[Index2] =3D=3D 0) {=0D + L2PageTable[Index2] =3D Address & PAGING_2M_ADDRESS_MASK_64;=0D + SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *) = &L2PageTable[Index2], 0);=0D + L2PageTable[Index2] |=3D VTD_PG_PS;=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN) &L2PageTable[Index2], sizeo= f (L2PageTable[Index2]));=0D + }=0D + if ((L2PageTable[Index2] & VTD_PG_PS) !=3D 0) {=0D + // 2M=0D + *PageAttribute =3D Page2M;=0D + return &L2PageTable[Index2];=0D + }=0D +=0D + // 4k=0D + L1PageTable =3D (UINT64 *) (UINTN) (L2PageTable[Index2] & PAGING_4K_ADDR= ESS_MASK_64);=0D + if ((L1PageTable[Index1] =3D=3D 0) && (Address !=3D 0)) {=0D + *PageAttribute =3D PageNone;=0D + return NULL;=0D + }=0D + *PageAttribute =3D Page4K;=0D + return &L1PageTable[Index1];=0D +}=0D +=0D +/**=0D + Modify memory attributes of page entry.=0D +=0D + @param[in] VtdUnitInfo The VTd engine unit information.=0D + @param[in] PageEntry The page entry.=0D + @param[in] IoMmuAccess The IOMMU access.=0D + @param[out] IsModified TRUE means page table modified. FALSE mean= s page table not modified.=0D +**/=0D +VOID=0D +ConvertSecondLevelPageEntryAttribute (=0D + IN VTD_UNIT_INFO *VtdUnitInfo,=0D + IN VTD_SECOND_LEVEL_PAGING_ENTRY *PageEntry,=0D + IN UINT64 IoMmuAccess,=0D + OUT BOOLEAN *IsModified=0D + )=0D +{=0D + UINT64 CurrentPageEntry;=0D + UINT64 NewPageEntry;=0D +=0D + CurrentPageEntry =3D PageEntry->Uint64;=0D + SetSecondLevelPagingEntryAttribute (PageEntry, IoMmuAccess);=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN) PageEntry, sizeof(*PageEntry)= );=0D + NewPageEntry =3D PageEntry->Uint64;=0D + if (CurrentPageEntry !=3D NewPageEntry) {=0D + *IsModified =3D TRUE;=0D + DEBUG ((DEBUG_VERBOSE, "ConvertSecondLevelPageEntryAttribute 0x%lx", C= urrentPageEntry));=0D + DEBUG ((DEBUG_VERBOSE, "->0x%lx\n", NewPageEntry));=0D + } else {=0D + *IsModified =3D FALSE;=0D + }=0D +}=0D +=0D +/**=0D + This function returns if there is need to split page entry.=0D +=0D + @param[in] BaseAddress The base address to be checked.=0D + @param[in] Length The length to be checked.=0D + @param[in] PageAttribute The page attribute of the page entry.=0D +=0D + @retval SplitAttributes on if there is need to split page entry.=0D +**/=0D +PAGE_ATTRIBUTE=0D +NeedSplitPage (=0D + IN PHYSICAL_ADDRESS BaseAddress,=0D + IN UINT64 Length,=0D + IN PAGE_ATTRIBUTE PageAttribute=0D + )=0D +{=0D + UINT64 PageEntryLength;=0D +=0D + PageEntryLength =3D PageAttributeToLength (PageAttribute);=0D +=0D + if (((BaseAddress & (PageEntryLength - 1)) =3D=3D 0) && (Length >=3D Pag= eEntryLength)) {=0D + return PageNone;=0D + }=0D +=0D + if (((BaseAddress & PAGING_2M_MASK) !=3D 0) || (Length < SIZE_2MB)) {=0D + return Page4K;=0D + }=0D +=0D + return Page2M;=0D +}=0D +=0D +/**=0D + This function splits one page entry to small page entries.=0D +=0D + @param[in] VtdUnitInfo The VTd engine unit information.=0D + @param[in] PageEntry The page entry to be splitted.=0D + @param[in] PageAttribute The page attribute of the page entry.=0D + @param[in] SplitAttribute How to split the page entry.=0D +=0D + @retval RETURN_SUCCESS The page entry is splitted.=0D + @retval RETURN_UNSUPPORTED The page entry does not support to be = splitted.=0D + @retval RETURN_OUT_OF_RESOURCES No resource to split page entry.=0D +**/=0D +RETURN_STATUS=0D +SplitSecondLevelPage (=0D + IN VTD_UNIT_INFO *VtdUnitInfo,=0D + IN VTD_SECOND_LEVEL_PAGING_ENTRY *PageEntry,=0D + IN PAGE_ATTRIBUTE PageAttribute,=0D + IN PAGE_ATTRIBUTE SplitAttribute=0D + )=0D +{=0D + UINT64 BaseAddress;=0D + UINT64 *NewPageEntry;=0D + UINTN Index;=0D +=0D + ASSERT (PageAttribute =3D=3D Page2M || PageAttribute =3D=3D Page1G);=0D +=0D + if (PageAttribute =3D=3D Page2M) {=0D + //=0D + // Split 2M to 4K=0D + //=0D + ASSERT (SplitAttribute =3D=3D Page4K);=0D + if (SplitAttribute =3D=3D Page4K) {=0D + NewPageEntry =3D AllocateZeroPages (1);=0D + DEBUG ((DEBUG_INFO, "Split - 0x%x\n", NewPageEntry));=0D + if (NewPageEntry =3D=3D NULL) {=0D + return RETURN_OUT_OF_RESOURCES;=0D + }=0D + BaseAddress =3D PageEntry->Uint64 & PAGING_2M_ADDRESS_MASK_64;=0D + for (Index =3D 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {=0D + NewPageEntry[Index] =3D (BaseAddress + SIZE_4KB * Index) | (PageEn= try->Uint64 & PAGE_PROGATE_BITS);=0D + }=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN)NewPageEntry, SIZE_4KB);=0D +=0D + PageEntry->Uint64 =3D (UINT64)(UINTN)NewPageEntry;=0D + SetSecondLevelPagingEntryAttribute (PageEntry, EDKII_IOMMU_ACCESS_RE= AD | EDKII_IOMMU_ACCESS_WRITE);=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN)PageEntry, sizeof(*PageEnt= ry));=0D + return RETURN_SUCCESS;=0D + } else {=0D + return RETURN_UNSUPPORTED;=0D + }=0D + } else if (PageAttribute =3D=3D Page1G) {=0D + //=0D + // Split 1G to 2M=0D + // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K = to get more compact page table.=0D + //=0D + ASSERT (SplitAttribute =3D=3D Page2M || SplitAttribute =3D=3D Page4K);= =0D + if ((SplitAttribute =3D=3D Page2M || SplitAttribute =3D=3D Page4K)) {= =0D + NewPageEntry =3D AllocateZeroPages (1);=0D + DEBUG ((DEBUG_INFO, "Split - 0x%x\n", NewPageEntry));=0D + if (NewPageEntry =3D=3D NULL) {=0D + return RETURN_OUT_OF_RESOURCES;=0D + }=0D + BaseAddress =3D PageEntry->Uint64 & PAGING_1G_ADDRESS_MASK_64;=0D + for (Index =3D 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {=0D + NewPageEntry[Index] =3D (BaseAddress + SIZE_2MB * Index) | VTD_PG_= PS | (PageEntry->Uint64 & PAGE_PROGATE_BITS);=0D + }=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN)NewPageEntry, SIZE_4KB);=0D +=0D + PageEntry->Uint64 =3D (UINT64)(UINTN)NewPageEntry;=0D + SetSecondLevelPagingEntryAttribute (PageEntry, EDKII_IOMMU_ACCESS_RE= AD | EDKII_IOMMU_ACCESS_WRITE);=0D + FlushPageTableMemory (VtdUnitInfo, (UINTN)PageEntry, sizeof(*PageEnt= ry));=0D + return RETURN_SUCCESS;=0D + } else {=0D + return RETURN_UNSUPPORTED;=0D + }=0D + } else {=0D + return RETURN_UNSUPPORTED;=0D + }=0D +}=0D +=0D +/**=0D + Set VTd attribute for a system memory on second level page entry=0D +=0D + @param[in] VtdUnitInfo The VTd engine unit information.=0D + @param[in] SecondLevelPagingEntry The second level paging entry in VTd= table for the device.=0D + @param[in] BaseAddress The base of device memory address to= be used as the DMA memory.=0D + @param[in] Length The length of device memory address = to be used as the DMA memory.=0D + @param[in] IoMmuAccess The IOMMU access.=0D +=0D + @retval EFI_SUCCESS The IoMmuAccess is set for the memory ran= ge specified by BaseAddress and Length.=0D + @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligne= d.=0D + @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.=0D + @retval EFI_INVALID_PARAMETER Length is 0.=0D + @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combinat= ion of access.=0D + @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not suppor= ted by the IOMMU.=0D + @retval EFI_UNSUPPORTED The IOMMU does not support the memory ran= ge specified by BaseAddress and Length.=0D + @retval EFI_OUT_OF_RESOURCES There are not enough resources available = to modify the IOMMU access.=0D + @retval EFI_DEVICE_ERROR The IOMMU device reported an error while = attempting the operation.=0D +**/=0D +EFI_STATUS=0D +SetSecondLevelPagingAttribute (=0D + IN VTD_UNIT_INFO *VtdUnitInfo,=0D + IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,=0D + IN UINT64 BaseAddress,=0D + IN UINT64 Length,=0D + IN UINT64 IoMmuAccess=0D + )=0D +{=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *PageEntry;=0D + PAGE_ATTRIBUTE PageAttribute;=0D + UINTN PageEntryLength;=0D + PAGE_ATTRIBUTE SplitAttribute;=0D + EFI_STATUS Status;=0D + BOOLEAN IsEntryModified;=0D +=0D + DEBUG ((DEBUG_INFO, "SetSecondLevelPagingAttribute (0x%016lx - 0x%016lx = : %x) \n", BaseAddress, Length, IoMmuAccess));=0D + DEBUG ((DEBUG_INFO, " SecondLevelPagingEntry Base - 0x%x\n", SecondLeve= lPagingEntry));=0D +=0D + if (BaseAddress !=3D ALIGN_VALUE(BaseAddress, SIZE_4KB)) {=0D + DEBUG ((DEBUG_ERROR, "SetSecondLevelPagingAttribute - Invalid Alignmen= t\n"));=0D + return EFI_UNSUPPORTED;=0D + }=0D + if (Length !=3D ALIGN_VALUE(Length, SIZE_4KB)) {=0D + DEBUG ((DEBUG_ERROR, "SetSecondLevelPagingAttribute - Invalid Alignmen= t\n"));=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + while (Length !=3D 0) {=0D + PageEntry =3D GetSecondLevelPageTableEntry (VtdUnitInfo, SecondLevelPa= gingEntry, BaseAddress, &PageAttribute);=0D + if (PageEntry =3D=3D NULL) {=0D + DEBUG ((DEBUG_ERROR, "PageEntry - NULL\n"));=0D + return RETURN_UNSUPPORTED;=0D + }=0D + PageEntryLength =3D PageAttributeToLength (PageAttribute);=0D + SplitAttribute =3D NeedSplitPage (BaseAddress, Length, PageAttribute);= =0D + if (SplitAttribute =3D=3D PageNone) {=0D + ConvertSecondLevelPageEntryAttribute (VtdUnitInfo, PageEntry, IoMmuA= ccess, &IsEntryModified);=0D + //=0D + // Convert success, move to next=0D + //=0D + BaseAddress +=3D PageEntryLength;=0D + Length -=3D PageEntryLength;=0D + } else {=0D + Status =3D SplitSecondLevelPage (VtdUnitInfo, PageEntry, PageAttribu= te, SplitAttribute);=0D + if (RETURN_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "SplitSecondLevelPage - %r\n", Status));=0D + return RETURN_UNSUPPORTED;=0D + }=0D + //=0D + // Just split current page=0D + // Convert success in next around=0D + //=0D + }=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Create Fixed Second Level Paging Entry.=0D +=0D + @param[in] VtdUnitInfo The VTd engine unit information.=0D +=0D + @retval EFI_SUCCESS Setup translation table successfully.=0D + @retval EFI_OUT_OF_RESOURCES Setup translation table fail.=0D +=0D +**/=0D +EFI_STATUS=0D +CreateFixedSecondLevelPagingEntry (=0D + IN VTD_UNIT_INFO *VtdUnitInfo=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINT64 IoMmuAccess;=0D + UINT64 BaseAddress;=0D + UINT64 Length;=0D + VOID *Hob;=0D + DMA_BUFFER_INFO *DmaBufferInfo;=0D +=0D + if (VtdUnitInfo->FixedSecondLevelPagingEntry !=3D 0) {=0D + return EFI_SUCCESS;=0D + }=0D +=0D + VtdUnitInfo->FixedSecondLevelPagingEntry =3D (UINTN) CreateSecondLevelPa= gingEntryTable (VtdUnitInfo, NULL, 0, SIZE_4GB, 0);=0D + if (VtdUnitInfo->FixedSecondLevelPagingEntry =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR, "FixedSecondLevelPagingEntry is empty\n"));=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + Hob =3D GetFirstGuidHob (&mDmaBufferInfoGuid);=0D + DmaBufferInfo =3D GET_GUID_HOB_DATA (Hob);=0D + BaseAddress =3D DmaBufferInfo->DmaBufferBase;=0D + Length =3D DmaBufferInfo->DmaBufferSize;=0D + IoMmuAccess =3D EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;=0D +=0D + DEBUG ((DEBUG_INFO, " BaseAddress =3D 0x%lx\n", BaseAddress));=0D + DEBUG ((DEBUG_INFO, " Length =3D 0x%lx\n", Length));=0D + DEBUG ((DEBUG_INFO, " IoMmuAccess =3D 0x%lx\n", IoMmuAccess));=0D +=0D + Status =3D SetSecondLevelPagingAttribute (VtdUnitInfo, (VTD_SECOND_LEVEL= _PAGING_ENTRY*) VtdUnitInfo->FixedSecondLevelPagingEntry, BaseAddress, Leng= th, IoMmuAccess);=0D +=0D + return Status;=0D +}=0D +/**=0D + Setup VTd translation table.=0D +=0D + @param[in] VTdInfo The VTd engine context information.=0D +=0D + @retval EFI_SUCCESS Setup translation table successfully.=0D + @retval EFI_OUT_OF_RESOURCES Setup translation table fail.=0D +=0D +**/=0D +EFI_STATUS=0D +SetupTranslationTable (=0D + IN VTD_INFO *VTdInfo=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN Index;=0D + VTD_UNIT_INFO *VtdUnitInfo;=0D +=0D + for (Index =3D 0; Index < VTdInfo->VTdEngineCount; Index++) {=0D + VtdUnitInfo =3D &VTdInfo->VtdUnitInfo[Index];=0D + if (VtdUnitInfo->Done) {=0D + continue;=0D + }=0D +=0D + Status =3D CreateFixedSecondLevelPagingEntry (VtdUnitInfo);=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_INFO, "CreateFixedSecondLevelPagingEntry failed - %r\n= ", Status));=0D + return Status;=0D + }=0D +=0D + if (VtdUnitInfo->ECapReg.Bits.SMTS) {=0D + if (VtdUnitInfo->ECapReg.Bits.DEP_24) {=0D + DEBUG ((DEBUG_ERROR,"ECapReg.bit24 is not zero\n"));=0D + ASSERT(FALSE);=0D + Status =3D EFI_UNSUPPORTED;=0D + } else {=0D + Status =3D CreateContextEntry (VtdUnitInfo);=0D + }=0D + } else {=0D + if (VtdUnitInfo->ECapReg.Bits.DEP_24) {=0D + //=0D + // To compatible with pervious VTd engine=0D + // It was ECS(Extended Context Support) bit.=0D + //=0D + Status =3D CreateExtContextEntry (VtdUnitInfo);=0D + } else {=0D + Status =3D CreateContextEntry (VtdUnitInfo);=0D + }=0D + }=0D +=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D + }=0D + return EFI_SUCCESS;=0D +}=0D +=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Include/Guid/VtdLogDataHob.h b/S= ilicon/Intel/IntelSiliconPkg/Include/Guid/VtdLogDataHob.h new file mode 100644 index 000000000..7863a257a --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Include/Guid/VtdLogDataHob.h @@ -0,0 +1,151 @@ +/** @file=0D + The definition for VTD Log Data Hob.=0D +=0D + Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +=0D +#ifndef _VTD_LOG_DATA_HOB_H_=0D +#define _VTD_LOG_DATA_HOB_H_=0D +=0D +#include =0D +=0D +#define VTDLOG_LOG_TYPE(_id_) ((UINT64) 1 << (_id_))=0D +=0D +typedef enum {=0D + VTDLOG_PEI_BASIC =3D 0, // Start ID for PEI bas= ic log=0D + VTDLOG_PEI_PRE_MEM_DMA_PROTECT =3D 1, // PRE-MEM phase=0D + VTDLOG_PEI_PMR_LOW_MEMORY_RANGE =3D 2,=0D + VTDLOG_PEI_PMR_HIGH_MEMORY_RANGE =3D 3,=0D + VTDLOG_PEI_PROTECT_MEMORY_RANGE =3D 4,=0D + VTDLOG_PEI_POST_MEM_ENABLE_DMA_PROTECT =3D 5,=0D + VTDLOG_PEI_POST_MEM_DISABLE_DMA_PROTECT =3D 6,=0D + VTDLOG_PEI_QUEUED_INVALIDATION =3D 7,=0D + VTDLOG_PEI_REGISTER =3D 8,=0D + VTDLOG_PEI_VTD_ERROR =3D 9,=0D +=0D + VTDLOG_PEI_ADVANCED =3D 16, // Start ID for PEI ad= vanced log=0D + VTDLOG_PEI_PPI_ALLOC_BUFFER =3D 17,=0D + VTDLOG_PEI_PPI_MAP =3D 18,=0D +=0D + VTDLOG_DXE_BASIC =3D 24, // Start ID for DXE ba= sic log=0D + VTDLOG_DXE_DMAR_TABLE =3D 25,=0D + VTDLOG_DXE_SETUP_VTD =3D 26,=0D + VTDLOG_DXE_PCI_DEVICE =3D 27,=0D + VTDLOG_DXE_REGISTER =3D 28,=0D + VTDLOG_DXE_ENABLE_DMAR =3D 29,=0D + VTDLOG_DXE_DISABLE_DMAR =3D 30,=0D + VTDLOG_DXE_DISABLE_PMR =3D 31,=0D + VTDLOG_DXE_INSTALL_IOMMU_PROTOCOL =3D 32,=0D + VTDLOG_DXE_QUEUED_INVALIDATION =3D 33, =0D +=0D + VTDLOG_DXE_ADVANCED =3D 44, // Start ID for DXE ad= vanced log=0D + VTDLOG_DXE_IOMMU_ALLOC_BUFFER =3D 45,=0D + VTDLOG_DXE_IOMMU_FREE_BUFFER =3D 46,=0D + VTDLOG_DXE_IOMMU_MAP =3D 47,=0D + VTDLOG_DXE_IOMMU_UNMAP =3D 48,=0D + VTDLOG_DXE_IOMMU_SET_ATTRIBUTE =3D 49,=0D + VTDLOG_DXE_ROOT_TABLE =3D 50,=0D +} VTDLOG_EVENT_TYPE;=0D +=0D +#define VTD_LOG_PEI_PRE_MEM_BAR_MAX 64=0D +=0D +//=0D +// Code of VTDLOG_PEI_BASIC / VTDLOG_DXE_BASIC=0D +//=0D +#define VTD_LOG_ERROR_BUFFER_FULL (1<<0)=0D +=0D +//=0D +// Code of VTDLOG_PEI_PRE_MEM_DMA_PROTECT_MODE=0D +//=0D +#define VTD_LOG_PEI_PRE_MEM_NOT_USED 0=0D +#define VTD_LOG_PEI_PRE_MEM_DISABLE 1=0D +#define VTD_LOG_PEI_PRE_MEM_ADM 2=0D +#define VTD_LOG_PEI_PRE_MEM_TE 3=0D +#define VTD_LOG_PEI_PRE_MEM_PMR 4=0D +=0D +//=0D +// Code of VTDLOG_PEI_QUEUED_INVALIDATION=0D +//=0D +#define VTD_LOG_QI_DISABLE 0=0D +#define VTD_LOG_QI_ENABLE 1=0D +#define VTD_LOG_QI_ERROR_OUT_OF_RESOURCES 2=0D +=0D +//=0D +// Code of VTDLOG_PEI_VTD_ERROR=0D +//=0D +#define VTD_LOG_PEI_VTD_ERROR_PPI_ALLOC 1=0D +#define VTD_LOG_PEI_VTD_ERROR_PPI_MAP 2=0D +=0D +// Code of VTDLOG_PEI_REGISTER / VTDLOG_DXE_REGISTER=0D +#define VTDLOG_REGISTER_ALL 0=0D +#define VTDLOG_REGISTER_THIN 1=0D +#define VTDLOG_REGISTER_QI 2=0D +=0D +#pragma pack(1)=0D +=0D +//=0D +// Item head=0D +//=0D +typedef struct {=0D + UINT32 DataSize;=0D + UINT64 LogType;=0D + UINT64 Timestamp;=0D +}VTDLOG_EVENT_HEADER;=0D +=0D +//=0D +// Struct for type =3D VTDLOG_PEI_REGISTER=0D +// VTDLOG_DXE_REGISTER=0D +// VTDLOG_DXE_DMAR_TABLE=0D +// VTDLOG_DXE_IOMMU_SET_ATTRIBUTE=0D +// VTDLOG_DXE_PCI_DEVICE=0D +// VTDLOG_DXE_ROOT_TABLE=0D +//=0D +typedef struct {=0D + VTDLOG_EVENT_HEADER Header;=0D + UINT64 Param;=0D + UINT8 Data[1];=0D +} VTDLOG_EVENT_CONTEXT;=0D +=0D +//=0D +// Struct for rest of the types=0D +//=0D +typedef struct {=0D + VTDLOG_EVENT_HEADER Header;=0D + UINT64 Data1;=0D + UINT64 Data2;=0D +}VTDLOG_EVENT_2PARAM;=0D +=0D +//=0D +// Struct for VTd log event=0D +//=0D +typedef union{=0D + VTDLOG_EVENT_HEADER EventHeader;=0D + VTDLOG_EVENT_2PARAM CommenEvent;=0D + VTDLOG_EVENT_CONTEXT ContextEvent;=0D +} VTDLOG_EVENT;=0D +=0D +//=0D +// Information for PEI pre-memory phase=0D +//=0D +typedef struct {=0D + UINT8 Mode;=0D + UINT8 Status;=0D + UINT32 BarAddress;=0D +} VTDLOG_PEI_PRE_MEM_INFO;=0D +=0D +//=0D +// Buffer struct for PEI phase=0D +//=0D +typedef struct {=0D + UINT8 VtdLogPeiError;=0D + VTDLOG_PEI_PRE_MEM_INFO PreMemInfo[VTD_LOG_PEI_PRE_MEM_BAR_MAX];=0D + UINT32 PostMemBufferUsed;=0D + UINT64 PostMemBuffer;=0D +} VTDLOG_PEI_BUFFER_HOB;=0D +=0D +#pragma pack()=0D +=0D +#endif // _VTD_LOG_DATA_HOB_H_=0D +=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Include/Library/IntelVTdPeiDxeLi= b.h b/Silicon/Intel/IntelSiliconPkg/Include/Library/IntelVTdPeiDxeLib.h new file mode 100644 index 000000000..c0a137a77 --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Include/Library/IntelVTdPeiDxeLib.h @@ -0,0 +1,329 @@ +/** @file=0D + Intel VTd library definitions.=0D +=0D + Copyright (c) 2023 Intel Corporation. All rights reserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#ifndef _INTEL_VTD_PEI_DXE_LIB_H_=0D +#define _INTEL_VTD_PEI_DXE_LIB_H_=0D +=0D +//=0D +// Include files=0D +//=0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#if defined (EXT_CALLBACK)=0D + #define _VTDLIB_DEBUG(PrintLevel, ...) = \=0D + do { = \=0D + VtdLogEventCallback (Context, CallbackHandle, PrintLevel, ##__VA_ARG= S__); \=0D + } while (FALSE)=0D + #define VTDLIB_DEBUG(Expression) _VTDLIB_DEBUG Expression=0D +#else=0D + #define VTDLIB_DEBUG(Expression) DEBUG(Expression)=0D +#endif=0D +=0D +#pragma pack(1)=0D +=0D +typedef struct {=0D + UINT8 DeviceType;=0D + VTD_SOURCE_ID PciSourceId;=0D + EDKII_PLATFORM_VTD_PCI_DEVICE_ID PciDeviceId;=0D + // for statistic analysis=0D + UINT64 AccessCount;=0D +} PCI_DEVICE_DATA;=0D +=0D +typedef struct {=0D + BOOLEAN IncludeAllFlag;=0D + UINT16 Segment;=0D + UINT32 PciDeviceDataMaxNumber;=0D + UINT32 PciDeviceDataNumber;=0D + PCI_DEVICE_DATA PciDeviceData[1];=0D +} PCI_DEVICE_INFORMATION;=0D +=0D +typedef struct {=0D + UINT64 Uint64Lo;=0D + UINT64 Uint64Hi;=0D +}VTD_UINT128;=0D +=0D +typedef struct {=0D + UINT64 BaseAddress;=0D + UINT32 VerReg;=0D + UINT64 CapReg;=0D + UINT64 EcapReg;=0D + UINT32 GstsReg;=0D + UINT64 RtaddrReg;=0D + UINT64 CcmdReg;=0D + UINT32 FstsReg;=0D + UINT32 FectlReg;=0D + UINT32 FedataReg;=0D + UINT32 FeaddrReg;=0D + UINT32 FeuaddrReg;=0D + UINT64 IqercdReg;=0D + UINT64 IvaReg;=0D + UINT64 IotlbReg;=0D + UINT16 FrcdRegNum; // Number of FRCD Register= s=0D + VTD_UINT128 FrcdReg[1];=0D +} VTD_REGESTER_INFO;=0D +=0D +typedef struct {=0D + UINT64 BaseAddress;=0D + UINT32 FstsReg;=0D + UINT64 IqercdReg;=0D +} VTD_REGESTER_QI_INFO;=0D +=0D +typedef struct {=0D + UINT64 BaseAddress;=0D + UINT32 GstsReg;=0D + UINT64 RtaddrReg;=0D + UINT32 FstsReg;=0D + UINT32 FectlReg;=0D + UINT64 IqercdReg;=0D + UINT16 FrcdRegNum; // Number of FRCD Register= s=0D + VTD_UINT128 FrcdReg[1];=0D +} VTD_REGESTER_THIN_INFO;=0D +=0D +typedef struct {=0D + VTD_SOURCE_ID SourceId;=0D + EFI_PHYSICAL_ADDRESS DeviceAddress;=0D + UINT64 Length;=0D + UINT64 IoMmuAccess;=0D + EFI_STATUS Status;=0D +} VTD_PROTOCOL_SET_ATTRIBUTE;=0D +=0D +typedef struct {=0D + UINT64 BaseAddress;=0D + UINT64 TableAddress;=0D + BOOLEAN Is5LevelPaging;=0D +} VTD_ROOT_TABLE_INFO;=0D +=0D +#pragma pack()=0D +=0D +/**=0D + Callback function of VTd lib handle strings.=0D +=0D + @param[in] Context Context=0D + @param[in] ErrorLevel The error level of the debug message.= =0D + @param[in] Buffer Event string=0D +**/=0D +typedef=0D +VOID=0D +(EFIAPI *EDKII_VTD_LIB_STRING_CB) (=0D + IN VOID *Context,=0D + IN UINTN ErrorLevel,=0D + IN CHAR8 *Buffer=0D + );=0D +=0D +/**=0D + Dump DMAR ACPI table.=0D +=0D + @param[in] Context Event Context=0D + @param[in out] CallbackHandle Callback Handler=0D + @param[in] Dmar DMAR ACPI table=0D +**/=0D +VOID=0D +VtdLibDumpAcpiDmar (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN EFI_ACPI_DMAR_HEADER *Dmar=0D + );=0D +=0D +/**=0D + Dump DRHD DMAR ACPI table.=0D +=0D + @param[in] Context Event Context=0D + @param[in out] CallbackHandle Callback Handler=0D + @param[in] Dmar DMAR ACPI table=0D +**/=0D +VOID=0D +VtdLibDumpAcpiDmarDrhd (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN EFI_ACPI_DMAR_HEADER *Dmar=0D + );=0D +=0D +/**=0D + Dump the PCI device information managed by this VTd engine.=0D +=0D + @param[in] Context Event Context=0D + @param[in out] CallbackHandle Callback Handler=0D + @param[in] PciDeviceInfo PCI device information=0D +**/=0D +VOID=0D +VtdLibDumpPciDeviceInfo (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN PCI_DEVICE_INFORMATION *PciDeviceInfo=0D + );=0D +=0D +/**=0D + Dump DMAR context entry table.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] RootEntry DMAR root entry.=0D + @param[in] Is5LevelPaging If it is the 5 level paging.=0D +**/=0D +VOID=0D +VtdLibDumpDmarContextEntryTable (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VTD_ROOT_ENTRY *RootEntry,=0D + IN BOOLEAN Is5LevelPaging=0D + );=0D +=0D +/**=0D + Dump DMAR extended context entry table.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] ExtRootEntry DMAR extended root entry.=0D + @param[in] Is5LevelPaging If it is the 5 level paging.=0D +**/=0D +VOID=0D +VtdLibDumpDmarExtContextEntryTable (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VTD_EXT_ROOT_ENTRY *ExtRootEntry,=0D + IN BOOLEAN Is5LevelPaging=0D + );=0D +=0D +/**=0D + Dump VTd registers.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] VtdRegInfo Registers Information=0D +**/=0D +VOID=0D +VtdLibDumpVtdRegsAll (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VTD_REGESTER_INFO *VtdRegInfo=0D + );=0D +=0D +/**=0D + Dump VTd registers.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] VtdRegInfo Registers Information=0D +**/=0D +VOID=0D +VtdLibDumpVtdRegsThin (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VTD_REGESTER_THIN_INFO *VtdRegInfo=0D + );=0D +=0D +/**=0D + Decode log event.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] Event Event struct=0D +=0D + @retval TRUE Decode event success=0D + @retval FALSE Unknown event=0D +**/=0D +BOOLEAN=0D +VtdLibDecodeEvent (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VTDLOG_EVENT *Event=0D + );=0D +=0D +/**=0D + Flush VTd engine write buffer.=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D +**/=0D +VOID=0D +VtdLibFlushWriteBuffer (=0D + IN UINTN VtdUnitBaseAddress=0D + );=0D +=0D +/**=0D + Clear Global Command Register Bits=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D + @param[in] BitMask Bit mask.=0D +**/=0D +VOID=0D +VtdLibClearGlobalCommandRegisterBits (=0D + IN UINTN VtdUnitBaseAddress,=0D + IN UINT32 BitMask=0D + );=0D +=0D +/**=0D + Set Global Command Register Bits=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D + @param[in] BitMask Bit mask.=0D +**/=0D +VOID=0D +VtdLibSetGlobalCommandRegisterBits (=0D + IN UINTN VtdUnitBaseAddress,=0D + IN UINT32 BitMask=0D + );=0D +=0D +/**=0D + Disable DMAR translation.=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D +=0D + @retval EFI_SUCCESS DMAR translation is disabled.=0D +**/=0D +EFI_STATUS=0D +VtdLibDisableDmar (=0D + IN UINTN VtdUnitBaseAddress=0D + );=0D +=0D +/**=0D + Disable PMR.=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D +=0D + @retval EFI_SUCCESS PMR is disabled.=0D + @retval EFI_UNSUPPORTED PMR is not supported.=0D + @retval EFI_NOT_STARTED PMR was not enabled.=0D +**/=0D +EFI_STATUS=0D +VtdLibDisablePmr (=0D + IN UINTN VtdUnitBaseAddress=0D + );=0D +=0D +/**=0D + Disable queued invalidation interface.=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D +**/=0D +VOID=0D +VtdLibDisableQueuedInvalidationInterface (=0D + IN UINTN VtdUnitBaseAddress=0D + );=0D +=0D +/**=0D + Submit the queued invalidation descriptor to the remapping=0D + hardware unit and wait for its completion.=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D + @param[in] Desc The invalidate descriptor=0D + @param[in] ClearFaultBits Clear Error bits=0D +=0D + @retval EFI_SUCCESS The operation was successful.=0D + @retval RETURN_DEVICE_ERROR A fault is detected.=0D + @retval EFI_INVALID_PARAMETER Parameter is invalid.=0D + @retval EFI_DEVICE_ERROR Detect fault, need to clear fault bits= if ClearFaultBits is FALSE=0D +**/=0D +EFI_STATUS=0D +VtdLibSubmitQueuedInvalidationDescriptor (=0D + IN UINTN VtdUnitBaseAddress,=0D + IN VOID *Desc,=0D + IN BOOLEAN ClearFaultBits=0D + );=0D +=0D +#endif=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Include/Protocol/VtdLog.h b/Sili= con/Intel/IntelSiliconPkg/Include/Protocol/VtdLog.h new file mode 100644 index 000000000..7c2894e81 --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Include/Protocol/VtdLog.h @@ -0,0 +1,59 @@ +/** @file=0D + The definition for VTD Log.=0D +=0D + Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#ifndef __VTD_LOG_PROTOCOL_H__=0D +#define __VTD_LOG_PROTOCOL_H__=0D +=0D +#include =0D +=0D +#define EDKII_VTD_LOG_PROTOCOL_GUID \=0D + { \=0D + 0x1e271819, 0xa3ca, 0x481f, { 0xbd, 0xff, 0x92, 0x78, 0x2f, 0x9a, 0x= 99, 0x3c } \=0D + }=0D +=0D +typedef struct _EDKII_VTD_LOG_PROTOCOL EDKII_VTD_LOG_PROTOCOL;=0D +=0D +#define EDKII_VTD_LOG_PROTOCOL_REVISION 0x00010000=0D +=0D +/**=0D + Callback function of each VTd log event.=0D + @param[in] Context Event context=0D + @param[in] Header Event header=0D +=0D + @retval UINT32 Number of events=0D +**/=0D +typedef=0D +VOID=0D +(EFIAPI *EDKII_VTD_LOG_HANDLE_EVENT) (=0D + IN VOID *Context,=0D + IN VTDLOG_EVENT_HEADER *Header=0D + );=0D +=0D +/**=0D + Get the VTd log events.=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback function for each VTd log eve= nt=0D +=0D + @retval UINT32 Number of events=0D +**/=0D +typedef=0D +UINT64=0D +(EFIAPI *EDKII_VTD_LOG_GET_EVENTS) (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LOG_HANDLE_EVENT CallbackHandle=0D + );=0D +=0D +struct _EDKII_VTD_LOG_PROTOCOL {=0D + UINT64 Revision;=0D + EDKII_VTD_LOG_GET_EVENTS GetEvents;=0D +};=0D +=0D +extern EFI_GUID gEdkiiVTdLogProtocolGuid;=0D +=0D +#endif=0D +=0D diff --git a/Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dec b/Silicon/In= tel/IntelSiliconPkg/IntelSiliconPkg.dec index cad22acda..ec8690a8d 100644 --- a/Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dec +++ b/Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dec @@ -73,6 +73,9 @@ ## HOB GUID to get memory information after MRC is done. The hob data wi= ll be used to set the PMR ranges=0D gVtdPmrInfoDataHobGuid =3D {0x6fb61645, 0xf168, 0x46be, { 0x80, 0xec, 0x= b5, 0x02, 0x38, 0x5e, 0xe7, 0xe7 } }=0D =0D + ## HOB GUID to get VTd log data.=0D + gVTdLogBufferHobGuid =3D {0xc8049121, 0xdf91, 0x4dfd, { 0xad, 0xcb, 0x1c= , 0x55, 0x85, 0x09, 0x6d, 0x3b } }=0D +=0D ## Include/Guid/MicrocodeShadowInfoHob.h=0D gEdkiiMicrocodeShadowInfoHobGuid =3D { 0x658903f9, 0xda66, 0x460d, { 0x8= b, 0xb0, 0x9d, 0x2d, 0xdf, 0x65, 0x44, 0x59 } }=0D =0D @@ -119,6 +122,8 @@ gPchSmmSpi2ProtocolGuid =3D { 0x2d1c0c43, 0x20d3, 0x40ae, { 0x99, 0x07, = 0x2d, 0xf0, 0xe7, 0x91, 0x21, 0xa5 } }=0D =0D gEdkiiPlatformVTdPolicyProtocolGuid =3D { 0x3d17e448, 0x466, 0x4e20, { 0= x99, 0x9f, 0xb2, 0xe1, 0x34, 0x88, 0xee, 0x22 }}=0D + gEdkiiVTdLogProtocolGuid =3D { 0x1e271819, 0xa3ca, 0x481f, { 0xbd, 0xff,= 0x92, 0x78, 0x2f, 0x9a, 0x99, 0x3c }}=0D +=0D gIntelDieInfoProtocolGuid =3D { 0xAED8A0A1, 0xFDE6, 0x4CF2, { 0xA3, 0x85= , 0x08, 0xF1, 0x25, 0xF2, 0x40, 0x37 }}=0D =0D ## Protocol for device security policy.=0D @@ -207,3 +212,19 @@ # non-zero: The size of an additional NVS region following the Regular = variable region.
=0D # @Prompt Additional NVS Region Size.=0D gIntelSiliconPkgTokenSpaceGuid.PcdFlashNvStorageAdditionalSize|0x0000000= 0|UINT32|0x0000000F=0D +=0D + ## Declares VTd LOG Output Level.

=0D + # 0 : Disable VTd Log=0D + # 1 : Enable Basic Log=0D + # 2 : Enable All Log=0D + # @Prompt The VTd Log Output Level.=0D + gIntelSiliconPkgTokenSpaceGuid.PcdVTdLogLevel|0x02|UINT8|0x00000017=0D +=0D + ## Declares VTd PEI POST-MEM LOG buffer size.

=0D + # @Prompt The VTd PEI Post-Mem Log buffer size. 8k=0D + gIntelSiliconPkgTokenSpaceGuid.PcdVTdPeiPostMemLogBufferSize|0x00002000|= UINT32|0x00000019=0D +=0D + ## Declares VTd DXE LOG buffer size.

=0D + # @Prompt The VTd DXE Log buffer size. 4M=0D + gIntelSiliconPkgTokenSpaceGuid.PcdVTdDxeLogBufferSize|0x00400000|UINT32|= 0x0000001A=0D +=0D diff --git a/Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dsc b/Silicon/In= tel/IntelSiliconPkg/IntelSiliconPkg.dsc index 170eb480a..c8ff40b38 100644 --- a/Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dsc +++ b/Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dsc @@ -45,6 +45,7 @@ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBoo= tServicesTableLib.inf=0D UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntry= Point.inf=0D VariableFlashInfoLib|MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseV= ariableFlashInfoLib.inf=0D + IntelVTdPeiDxeLib|IntelSiliconPkg/Library/IntelVTdPeiDxeLib/IntelVTdPeiD= xeLib.inf=0D =0D [LibraryClasses.common.PEIM]=0D PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Library/IntelVTdPeiDxeLib/IntelV= TdPeiDxeLib.c b/Silicon/Intel/IntelSiliconPkg/Library/IntelVTdPeiDxeLib/Int= elVTdPeiDxeLib.c new file mode 100644 index 000000000..a5a1e3beb --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Library/IntelVTdPeiDxeLib/IntelVTdPeiDx= eLib.c @@ -0,0 +1,1793 @@ +/** @file=0D + Source code file for Intel VTd PEI DXE library.=0D +=0D +Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D +SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +//=0D +// Define the maximum message length that this library supports=0D +//=0D +#define MAX_STRING_LENGTH (0x100)=0D +=0D +#define VTD_64BITS_ADDRESS(Lo, Hi) (LShiftU64 (Lo, 12) | LShiftU64 (Hi, 32= ))=0D +=0D +/**=0D + Produces a Null-terminated ASCII string in an output buffer based on a N= ull-terminated=0D + ASCII format string and variable argument list.=0D + =0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] ErrorLevel The error level of the debug message.=0D + @param[in] FormatString A Null-terminated ASCII format string.= =0D + @param[in] ... Variable argument list whose contents a= re accessed based on the format string specified by FormatString.=0D +=0D + @return The number of ASCII characters in the produced output buffer not= including the=0D + Null-terminator.=0D +**/=0D +UINTN=0D +EFIAPI=0D +VtdLogEventCallback (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN UINTN ErrorLevel,=0D + IN CONST CHAR8 *FormatString,=0D + ...=0D + )=0D +{=0D + CHAR8 Buffer[MAX_STRING_LENGTH];=0D + VA_LIST Marker;=0D + UINTN NumberOfPrinted;=0D +=0D + if ((CallbackHandle =3D=3D NULL) || (FormatString =3D=3D NULL)) {=0D + return 0;=0D + }=0D +=0D + VA_START (Marker, FormatString);=0D + NumberOfPrinted =3D AsciiVSPrint (Buffer, sizeof (Buffer), FormatString,= Marker);=0D + VA_END (Marker);=0D +=0D + if (NumberOfPrinted > 0) {=0D + CallbackHandle (Context, ErrorLevel, Buffer);=0D + }=0D +=0D + return NumberOfPrinted;=0D +}=0D +=0D +/**=0D + Dump DMAR DeviceScopeEntry.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] DmarDeviceScopeEntry DMAR DeviceScopeEntry=0D +**/=0D +VOID=0D +VtdLibDumpDmarDeviceScopeEntry (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntr= y=0D + )=0D +{=0D + UINTN PciPathNumber;=0D + UINTN PciPathIndex;=0D + EFI_ACPI_DMAR_PCI_PATH *PciPath;=0D +=0D + if (DmarDeviceScopeEntry =3D=3D NULL) {=0D + return;=0D + }=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " *****************************************************************= ********\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " * DMA-Remapping Device Scope Entry Structure = *\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *****************************************************************= ********\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + (sizeof(UINTN) =3D=3D sizeof(UINT64)) ?=0D + " DMAR Device Scope Entry address ...................... 0x%016lx\n= " :=0D + " DMAR Device Scope Entry address ...................... 0x%08x\n",= =0D + DmarDeviceScopeEntry=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " Device Scope Entry Type ............................ 0x%02x\n",= =0D + DmarDeviceScopeEntry->Type=0D + ));=0D + switch (DmarDeviceScopeEntry->Type) {=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " PCI Endpoint Device\n"=0D + ));=0D + break;=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " PCI Sub-hierachy\n"=0D + ));=0D + break;=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC:=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " IOAPIC\n"=0D + ));=0D + break;=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET:=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " MSI Capable HPET\n"=0D + ));=0D + break;=0D + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE:=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " ACPI Namespace Device\n"=0D + ));=0D + break;=0D + default:=0D + break;=0D + }=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " Length ............................................. 0x%02x\n",= =0D + DmarDeviceScopeEntry->Length=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " Enumeration ID ..................................... 0x%02x\n",= =0D + DmarDeviceScopeEntry->EnumerationId=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " Starting Bus Number ................................ 0x%02x\n",= =0D + DmarDeviceScopeEntry->StartBusNumber=0D + ));=0D +=0D + PciPathNumber =3D (DmarDeviceScopeEntry->Length - sizeof(EFI_ACPI_DMAR_D= EVICE_SCOPE_STRUCTURE_HEADER)) / sizeof(EFI_ACPI_DMAR_PCI_PATH);=0D + PciPath =3D (EFI_ACPI_DMAR_PCI_PATH *)(DmarDeviceScopeEntry + 1);=0D + for (PciPathIndex =3D 0; PciPathIndex < PciPathNumber; PciPathIndex++) {= =0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " Device ............................................. 0x%02x\n= ",=0D + PciPath[PciPathIndex].Device=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " Function ........................................... 0x%02x\n= ",=0D + PciPath[PciPathIndex].Function=0D + ));=0D + }=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " *****************************************************************= ********\n\n"=0D + ));=0D +}=0D +=0D +/**=0D + Dump DMAR SIDP table.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] Sidp DMAR SIDP table=0D +**/=0D +VOID=0D +VtdLibDumpDmarSidp (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN EFI_ACPI_DMAR_SIDP_HEADER *Sidp=0D + )=0D +{=0D + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;=0D + INTN SidpLen;=0D +=0D + if (Sidp =3D=3D NULL) {=0D + return;=0D + }=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " *******************************************************************= ********\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " * SoC Integrated Device Property Reporting Structure = *\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " *******************************************************************= ********\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + (sizeof(UINTN) =3D=3D sizeof(UINT64)) ?=0D + " SIDP address ........................................... 0x%016lx\n= " :=0D + " SIDP address ........................................... 0x%08x\n",= =0D + Sidp=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " Type ................................................. 0x%04x\n",= =0D + Sidp->Header.Type=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " Length ............................................... 0x%04x\n",= =0D + Sidp->Header.Length=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " Segment Number ....................................... 0x%04x\n",= =0D + Sidp->SegmentNumber=0D + ));=0D +=0D + SidpLen =3D Sidp->Header.Length - sizeof(EFI_ACPI_DMAR_SIDP_HEADER);=0D + DmarDeviceScopeEntry =3D (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)= (Sidp + 1);=0D + while (SidpLen > 0) {=0D + VtdLibDumpDmarDeviceScopeEntry (Context, CallbackHandle, DmarDeviceSco= peEntry);=0D + SidpLen -=3D DmarDeviceScopeEntry->Length;=0D + DmarDeviceScopeEntry =3D (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER = *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);=0D + }=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " *******************************************************************= ********\n\n"=0D + ));=0D +}=0D +=0D +/**=0D + Dump DMAR SATC table.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] Satc DMAR SATC table=0D +**/=0D +VOID=0D +VtdLibDumpDmarSatc (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN EFI_ACPI_DMAR_SATC_HEADER *Satc=0D + )=0D +{=0D + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;=0D + INTN SatcLen;=0D +=0D + if (Satc =3D=3D NULL) {=0D + return;=0D + }=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *******************************************************************= ********\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " * ACPI Soc Integrated Address Translation Cache reporting Str= ucture *\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *******************************************************************= ********\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + (sizeof(UINTN) =3D=3D sizeof(UINT64)) ?=0D + " SATC address ........................................... 0x%016lx\n= " :=0D + " SATC address ........................................... 0x%08x\n",= =0D + Satc=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Type ................................................. 0x%04x\n",= =0D + Satc->Header.Type=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Length ............................................... 0x%04x\n",= =0D + Satc->Header.Length=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Flags ................................................ 0x%02x\n",= =0D + Satc->Flags=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Segment Number ....................................... 0x%04x\n",= =0D + Satc->SegmentNumber=0D + ));=0D +=0D + SatcLen =3D Satc->Header.Length - sizeof(EFI_ACPI_DMAR_SATC_HEADER);=0D + DmarDeviceScopeEntry =3D (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)= (Satc + 1);=0D + while (SatcLen > 0) {=0D + VtdLibDumpDmarDeviceScopeEntry (Context, CallbackHandle, DmarDeviceSco= peEntry);=0D + SatcLen -=3D DmarDeviceScopeEntry->Length;=0D + DmarDeviceScopeEntry =3D (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER = *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);=0D + }=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *******************************************************************= ********\n\n"=0D + ));=0D +}=0D +=0D +/**=0D + Dump DMAR ANDD table.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] Andd DMAR ANDD table=0D +**/=0D +VOID=0D +VtdLibDumpDmarAndd (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN EFI_ACPI_DMAR_ANDD_HEADER *Andd=0D + )=0D +{=0D + if (Andd =3D=3D NULL) {=0D + return;=0D + }=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *******************************************************************= ********\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " * ACPI Name-space Device Declaration Structure = *\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *******************************************************************= ********\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + (sizeof(UINTN) =3D=3D sizeof(UINT64)) ?=0D + " ANDD address ........................................... 0x%016lx\n= " :=0D + " ANDD address ........................................... 0x%08x\n",= =0D + Andd=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Type ................................................. 0x%04x\n",= =0D + Andd->Header.Type=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Length ............................................... 0x%04x\n",= =0D + Andd->Header.Length=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " ACPI Device Number ................................... 0x%02x\n",= =0D + Andd->AcpiDeviceNumber=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " ACPI Object Name ..................................... '%a'\n",=0D + (Andd + 1)=0D + ));=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *******************************************************************= ********\n\n"=0D + ));=0D +}=0D +=0D +/**=0D + Dump DMAR RHSA table.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] Rhsa DMAR RHSA table=0D +**/=0D +VOID=0D +VtdLibDumpDmarRhsa (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN EFI_ACPI_DMAR_RHSA_HEADER *Rhsa=0D + )=0D +{=0D + if (Rhsa =3D=3D NULL) {=0D + return;=0D + }=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *******************************************************************= ********\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " * Remapping Hardware Status Affinity Structure = *\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *******************************************************************= ********\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + (sizeof(UINTN) =3D=3D sizeof(UINT64)) ?=0D + " RHSA address ........................................... 0x%016lx\n= " :=0D + " RHSA address ........................................... 0x%08x\n",= =0D + Rhsa=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Type ................................................. 0x%04x\n",= =0D + Rhsa->Header.Type=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Length ............................................... 0x%04x\n",= =0D + Rhsa->Header.Length=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Register Base Address ................................ 0x%016lx\n= ",=0D + Rhsa->RegisterBaseAddress=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Proximity Domain ..................................... 0x%08x\n",= =0D + Rhsa->ProximityDomain=0D + ));=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *******************************************************************= ********\n\n"=0D + ));=0D +}=0D +=0D +/**=0D + Dump DMAR ATSR table.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] Atsr DMAR ATSR table=0D +**/=0D +VOID=0D +VtdLibDumpDmarAtsr (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN EFI_ACPI_DMAR_ATSR_HEADER *Atsr=0D + )=0D +{=0D + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;=0D + INTN AtsrLen;=0D +=0D + if (Atsr =3D=3D NULL) {=0D + return;=0D + }=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *******************************************************************= ********\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " * Root Port ATS Capability Reporting Structure = *\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *******************************************************************= ********\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + (sizeof(UINTN) =3D=3D sizeof(UINT64)) ?=0D + " ATSR address ........................................... 0x%016lx\n= " :=0D + " ATSR address ........................................... 0x%08x\n",= =0D + Atsr=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Type ................................................. 0x%04x\n",= =0D + Atsr->Header.Type=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Length ............................................... 0x%04x\n",= =0D + Atsr->Header.Length=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Flags ................................................ 0x%02x\n",= =0D + Atsr->Flags=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " ALL_PORTS .......................................... 0x%02x\n",= =0D + Atsr->Flags & EFI_ACPI_DMAR_ATSR_FLAGS_ALL_PORTS=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Segment Number ....................................... 0x%04x\n",= =0D + Atsr->SegmentNumber=0D + ));=0D +=0D + AtsrLen =3D Atsr->Header.Length - sizeof(EFI_ACPI_DMAR_ATSR_HEADER);=0D + DmarDeviceScopeEntry =3D (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)= (Atsr + 1);=0D + while (AtsrLen > 0) {=0D + VtdLibDumpDmarDeviceScopeEntry (Context, CallbackHandle, DmarDeviceSco= peEntry);=0D + AtsrLen -=3D DmarDeviceScopeEntry->Length;=0D + DmarDeviceScopeEntry =3D (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER = *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);=0D + }=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *******************************************************************= ********\n\n"=0D + ));=0D +}=0D +=0D +/**=0D + Dump DMAR RMRR table.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] Rmrr DMAR RMRR table=0D +**/=0D +VOID=0D +VtdLibDumpDmarRmrr (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr=0D + )=0D +{=0D + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;=0D + INTN RmrrLen;=0D +=0D + if (Rmrr =3D=3D NULL) {=0D + return;=0D + }=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *******************************************************************= ********\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " * Reserved Memory Region Reporting Structure = *\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *******************************************************************= ********\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + (sizeof(UINTN) =3D=3D sizeof(UINT64)) ?=0D + " RMRR address ........................................... 0x%016lx\n= " :=0D + " RMRR address ........................................... 0x%08x\n",= =0D + Rmrr=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Type ................................................. 0x%04x\n",= =0D + Rmrr->Header.Type=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Length ............................................... 0x%04x\n",= =0D + Rmrr->Header.Length=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Segment Number ....................................... 0x%04x\n",= =0D + Rmrr->SegmentNumber=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Reserved Memory Region Base Address .................. 0x%016lx\n= ",=0D + Rmrr->ReservedMemoryRegionBaseAddress=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Reserved Memory Region Limit Address ................. 0x%016lx\n= ",=0D + Rmrr->ReservedMemoryRegionLimitAddress=0D + ));=0D +=0D + RmrrLen =3D Rmrr->Header.Length - sizeof(EFI_ACPI_DMAR_RMRR_HEADER);=0D + DmarDeviceScopeEntry =3D (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)= (Rmrr + 1);=0D + while (RmrrLen > 0) {=0D + VtdLibDumpDmarDeviceScopeEntry (Context, CallbackHandle, DmarDeviceSco= peEntry);=0D + RmrrLen -=3D DmarDeviceScopeEntry->Length;=0D + DmarDeviceScopeEntry =3D (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER = *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);=0D + }=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *******************************************************************= ********\n\n"=0D + ));=0D +}=0D +=0D +/**=0D + Dump DMAR DRHD table.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] Drhd DMAR DRHD table=0D +**/=0D +VOID=0D +VtdLibDumpDmarDrhd (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd=0D + )=0D +{=0D + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;=0D + INTN DrhdLen;=0D +=0D + if (Drhd =3D=3D NULL) {=0D + return;=0D + }=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *******************************************************************= ********\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " * DMA-Remapping Hardware Definition Structure = *\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " *******************************************************************= ********\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + (sizeof(UINTN) =3D=3D sizeof(UINT64)) ?=0D + " DRHD address ........................................... 0x%016lx\n= " :=0D + " DRHD address ........................................... 0x%08x\n",= =0D + Drhd=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Type ................................................. 0x%04x\n",= =0D + Drhd->Header.Type=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Length ............................................... 0x%04x\n",= =0D + Drhd->Header.Length=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO, =0D + " Flags ................................................ 0x%02x\n",= =0D + Drhd->Flags=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " INCLUDE_PCI_ALL .................................... 0x%02x\n",= =0D + Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " Size ................................................. 0x%02x\n",= =0D + Drhd->Size=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " Segment Number ....................................... 0x%04x\n",= =0D + Drhd->SegmentNumber=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " Register Base Address ................................ 0x%016lx\n= ",=0D + Drhd->RegisterBaseAddress=0D + ));=0D +=0D + DrhdLen =3D Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER);=0D + DmarDeviceScopeEntry =3D (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)= (Drhd + 1);=0D + while (DrhdLen > 0) {=0D + VtdLibDumpDmarDeviceScopeEntry (Context, CallbackHandle, DmarDeviceSco= peEntry);=0D + DrhdLen -=3D DmarDeviceScopeEntry->Length;=0D + DmarDeviceScopeEntry =3D (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER = *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);=0D + }=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " *******************************************************************= ********\n\n"=0D + ));=0D +}=0D +=0D +/**=0D + Dump Header of DMAR ACPI table.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] Dmar DMAR ACPI table=0D +**/=0D +VOID=0D +VtdLibDumpAcpiDmarHeader (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN EFI_ACPI_DMAR_HEADER *Dmar=0D + )=0D +{=0D + //=0D + // Dump Dmar table=0D + //=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + "*********************************************************************= ********\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + "* DMAR Table = *\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + "*********************************************************************= ********\n"=0D + ));=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + (sizeof(UINTN) =3D=3D sizeof(UINT64)) ?=0D + "DMAR address ............................................. 0x%016lx\n= " :=0D + "DMAR address ............................................. 0x%08x\n",= =0D + Dmar=0D + ));=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " Table Contents:\n"=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " Host Address Width ................................... 0x%02x\n",= =0D + Dmar->HostAddressWidth=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " Flags ................................................ 0x%02x\n",= =0D + Dmar->Flags=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " INTR_REMAP ......................................... 0x%02x\n",= =0D + Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " X2APIC_OPT_OUT_SET ................................. 0x%02x\n",= =0D + Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT=0D + ));=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + " DMA_CTRL_PLATFORM_OPT_IN_FLAG ...................... 0x%02x\n",= =0D + Dmar->Flags & EFI_ACPI_DMAR_FLAGS_DMA_CTRL_PLATFORM_OPT_IN_FLAG=0D + ));=0D +}=0D +=0D +/**=0D + Dump DMAR ACPI table.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] Dmar DMAR ACPI table=0D +**/=0D +VOID=0D +VtdLibDumpAcpiDmar (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN EFI_ACPI_DMAR_HEADER *Dmar=0D + )=0D +{=0D + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;=0D + INTN DmarLen;=0D +=0D + if (Dmar =3D=3D NULL) {=0D + return;=0D + }=0D +=0D + //=0D + // Dump Dmar table=0D + //=0D + VtdLibDumpAcpiDmarHeader (Context, CallbackHandle, Dmar);=0D +=0D + DmarLen =3D Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER);=0D + DmarHeader =3D (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1);=0D + while (DmarLen > 0) {=0D + switch (DmarHeader->Type) {=0D + case EFI_ACPI_DMAR_TYPE_DRHD:=0D + VtdLibDumpDmarDrhd (Context, CallbackHandle, (EFI_ACPI_DMAR_DRHD_HEA= DER *)DmarHeader);=0D + break;=0D + case EFI_ACPI_DMAR_TYPE_RMRR:=0D + VtdLibDumpDmarRmrr (Context, CallbackHandle, (EFI_ACPI_DMAR_RMRR_HEA= DER *)DmarHeader);=0D + break;=0D + case EFI_ACPI_DMAR_TYPE_ATSR:=0D + VtdLibDumpDmarAtsr (Context, CallbackHandle, (EFI_ACPI_DMAR_ATSR_HEA= DER *)DmarHeader);=0D + break;=0D + case EFI_ACPI_DMAR_TYPE_RHSA:=0D + VtdLibDumpDmarRhsa (Context, CallbackHandle, (EFI_ACPI_DMAR_RHSA_HEA= DER *)DmarHeader);=0D + break;=0D + case EFI_ACPI_DMAR_TYPE_ANDD:=0D + VtdLibDumpDmarAndd (Context, CallbackHandle, (EFI_ACPI_DMAR_ANDD_HEA= DER *)DmarHeader);=0D + break;=0D + case EFI_ACPI_DMAR_TYPE_SATC:=0D + VtdLibDumpDmarSatc (Context, CallbackHandle, (EFI_ACPI_DMAR_SATC_HEA= DER *)DmarHeader);=0D + break;=0D + case EFI_ACPI_DMAR_TYPE_SIDP:=0D + VtdLibDumpDmarSidp (Context, CallbackHandle, (EFI_ACPI_DMAR_SIDP_HEA= DER *)DmarHeader);=0D + break;=0D + default:=0D + break;=0D + }=0D + DmarLen -=3D DmarHeader->Length;=0D + DmarHeader =3D (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + = DmarHeader->Length);=0D + }=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + "*********************************************************************= ********\n\n"=0D + ));=0D +}=0D +=0D +/**=0D + Dump DRHD DMAR ACPI table.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] Dmar DMAR ACPI table=0D +**/=0D +VOID=0D +VtdLibDumpAcpiDmarDrhd (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN EFI_ACPI_DMAR_HEADER *Dmar=0D + )=0D +{=0D + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;=0D + INTN DmarLen;=0D +=0D + if (Dmar =3D=3D NULL) {=0D + return;=0D + }=0D +=0D + //=0D + // Dump Dmar table=0D + //=0D + VtdLibDumpAcpiDmarHeader (Context, CallbackHandle, Dmar);=0D +=0D + DmarLen =3D Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER);=0D + DmarHeader =3D (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1);=0D + while (DmarLen > 0) {=0D + switch (DmarHeader->Type) {=0D + case EFI_ACPI_DMAR_TYPE_DRHD:=0D + VtdLibDumpDmarDrhd (Context, CallbackHandle, (EFI_ACPI_DMAR_DRHD_HEA= DER *)DmarHeader);=0D + break;=0D + default:=0D + break;=0D + }=0D + DmarLen -=3D DmarHeader->Length;=0D + DmarHeader =3D (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + = DmarHeader->Length);=0D + }=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO,=0D + "*********************************************************************= ********\n\n"=0D + ));=0D +}=0D +=0D +/**=0D + Dump the PCI device information managed by this VTd engine.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] PciDeviceInfo VTd Unit Information=0D +**/=0D +VOID=0D +VtdLibDumpPciDeviceInfo (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN PCI_DEVICE_INFORMATION *PciDeviceInfo=0D + )=0D +{=0D + UINTN Index;=0D +=0D + if (PciDeviceInfo !=3D NULL) {=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PCI Device Information (Number 0x%x, Inclu= deAll - %d):\n",=0D + PciDeviceInfo->PciDeviceDataNumber,=0D + PciDeviceInfo->IncludeAllFlag=0D + ));=0D + for (Index =3D 0; Index < PciDeviceInfo->PciDeviceDataNumber; Index++)= {=0D + VTDLIB_DEBUG ((DEBUG_INFO, " S%04x B%02x D%02x F%02x\n",=0D + PciDeviceInfo->Segment,=0D + PciDeviceInfo->PciDeviceData[Index].PciSourceId.Bits.Bus,=0D + PciDeviceInfo->PciDeviceData[Index].PciSourceId.Bits.Device,=0D + PciDeviceInfo->PciDeviceData[Index].PciSourceId.Bits.Function=0D + ));=0D + }=0D + }=0D +}=0D +=0D +/**=0D + Dump DMAR second level paging entry.=0D +=0D + @param[in] Context Event context=0D + @param[in] CallbackHandle Callback handler=0D + @param[in] SecondLevelPagingEntry The second level paging entry.=0D + @param[in] Is5LevelPaging If it is the 5 level paging.=0D +**/=0D +VOID=0D +VtdLibDumpSecondLevelPagingEntry (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VOID *SecondLevelPagingEntry,=0D + IN BOOLEAN Is5LevelPaging=0D + )=0D +{=0D + UINTN Index5;=0D + UINTN Index4;=0D + UINTN Index3;=0D + UINTN Index2;=0D + UINTN Index1;=0D + UINTN Lvl5IndexEnd;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl5PtEntry;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl4PtEntry;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl3PtEntry;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl2PtEntry;=0D + VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl1PtEntry;=0D +=0D + VTDLIB_DEBUG ((DEBUG_VERBOSE, "=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D\n"));=0D + VTDLIB_DEBUG ((DEBUG_VERBOSE, "DMAR Second Level Page Table:\n"));=0D + VTDLIB_DEBUG ((DEBUG_VERBOSE, "SecondLevelPagingEntry Base - 0x%x, Is5Le= velPaging - %d\n", SecondLevelPagingEntry, Is5LevelPaging));=0D +=0D + Lvl5IndexEnd =3D Is5LevelPaging ? SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGIN= G_ENTRY) : 1;=0D + Lvl4PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *)SecondLevelPagingEntry;= =0D + Lvl5PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *)SecondLevelPagingEntry;= =0D +=0D + for (Index5 =3D 0; Index5 < Lvl5IndexEnd; Index5++) {=0D + if (Is5LevelPaging) {=0D + if (Lvl5PtEntry[Index5].Uint64 !=3D 0) {=0D + VTDLIB_DEBUG ((DEBUG_VERBOSE, " Lvl5Pt Entry(0x%03x) - 0x%016lx\n= ", Index5, Lvl5PtEntry[Index5].Uint64));=0D + }=0D + if (Lvl5PtEntry[Index5].Uint64 =3D=3D 0) {=0D + continue;=0D + }=0D + Lvl4PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_A= DDRESS(Lvl5PtEntry[Index5].Bits.AddressLo, Lvl5PtEntry[Index5].Bits.Address= Hi);=0D + }=0D +=0D + for (Index4 =3D 0; Index4 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_EN= TRY); Index4++) {=0D + if (Lvl4PtEntry[Index4].Uint64 !=3D 0) {=0D + VTDLIB_DEBUG ((DEBUG_VERBOSE, " Lvl4Pt Entry(0x%03x) - 0x%016lx\n= ", Index4, Lvl4PtEntry[Index4].Uint64));=0D + }=0D + if (Lvl4PtEntry[Index4].Uint64 =3D=3D 0) {=0D + continue;=0D + }=0D + Lvl3PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_A= DDRESS(Lvl4PtEntry[Index4].Bits.AddressLo, Lvl4PtEntry[Index4].Bits.Address= Hi);=0D + for (Index3 =3D 0; Index3 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_= ENTRY); Index3++) {=0D + if (Lvl3PtEntry[Index3].Uint64 !=3D 0) {=0D + VTDLIB_DEBUG ((DEBUG_VERBOSE, " Lvl3Pt Entry(0x%03x) - 0x%016l= x\n", Index3, Lvl3PtEntry[Index3].Uint64));=0D + }=0D + if (Lvl3PtEntry[Index3].Uint64 =3D=3D 0) {=0D + continue;=0D + }=0D +=0D + Lvl2PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS= _ADDRESS(Lvl3PtEntry[Index3].Bits.AddressLo, Lvl3PtEntry[Index3].Bits.Addre= ssHi);=0D + for (Index2 =3D 0; Index2 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGIN= G_ENTRY); Index2++) {=0D + if (Lvl2PtEntry[Index2].Uint64 !=3D 0) {=0D + VTDLIB_DEBUG ((DEBUG_VERBOSE, " Lvl2Pt Entry(0x%03x) - 0x%0= 16lx\n", Index2, Lvl2PtEntry[Index2].Uint64));=0D + }=0D + if (Lvl2PtEntry[Index2].Uint64 =3D=3D 0) {=0D + continue;=0D + }=0D + if (Lvl2PtEntry[Index2].Bits.PageSize =3D=3D 0) {=0D + Lvl1PtEntry =3D (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64= BITS_ADDRESS(Lvl2PtEntry[Index2].Bits.AddressLo, Lvl2PtEntry[Index2].Bits.A= ddressHi);=0D + for (Index1 =3D 0; Index1 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_P= AGING_ENTRY); Index1++) {=0D + if (Lvl1PtEntry[Index1].Uint64 !=3D 0) {=0D + VTDLIB_DEBUG ((DEBUG_VERBOSE, " Lvl1Pt Entry(0x%03x) = - 0x%016lx\n", Index1, Lvl1PtEntry[Index1].Uint64));=0D + }=0D + }=0D + }=0D + }=0D + }=0D + }=0D + }=0D + VTDLIB_DEBUG ((DEBUG_VERBOSE, "=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D\n"));=0D +}=0D +=0D +/**=0D + Dump DMAR context entry table.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] RootEntry DMAR root entry.=0D + @param[in] Is5LevelPaging If it is the 5 level paging.=0D +**/=0D +VOID=0D +VtdLibDumpDmarContextEntryTable (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VTD_ROOT_ENTRY *RootEntry,=0D + IN BOOLEAN Is5LevelPaging=0D + )=0D +{=0D + UINTN Index;=0D + UINTN Index2;=0D + VTD_CONTEXT_ENTRY *ContextEntry;=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO, "=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\n"));=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DMAR Context Entry Table:\n"));=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO, "RootEntry Address - 0x%x\n", RootEntry));=0D +=0D + for (Index =3D 0; Index < VTD_ROOT_ENTRY_NUMBER; Index++) {=0D + if ((RootEntry[Index].Uint128.Uint64Lo !=3D 0) || (RootEntry[Index].Ui= nt128.Uint64Hi !=3D 0)) {=0D + VTDLIB_DEBUG ((DEBUG_INFO, " RootEntry(0x%02x) B%02x - 0x%016lx %01= 6lx\n",=0D + Index, Index, RootEntry[Index].Uint128.Uint64Hi, RootEntry[Index].= Uint128.Uint64Lo));=0D + }=0D + if (RootEntry[Index].Bits.Present =3D=3D 0) {=0D + continue;=0D + }=0D + ContextEntry =3D (VTD_CONTEXT_ENTRY *) (UINTN) VTD_64BITS_ADDRESS (Roo= tEntry[Index].Bits.ContextTablePointerLo, RootEntry[Index].Bits.ContextTabl= ePointerHi);=0D + for (Index2 =3D 0; Index2 < VTD_CONTEXT_ENTRY_NUMBER; Index2++) {=0D + if ((ContextEntry[Index2].Uint128.Uint64Lo !=3D 0) || (ContextEntry[= Index2].Uint128.Uint64Hi !=3D 0)) {=0D + VTDLIB_DEBUG ((DEBUG_INFO, " ContextEntry(0x%02x) D%02xF%02x - = 0x%016lx %016lx\n",=0D + Index2, Index2 >> 3, Index2 & 0x7, ContextEntry[Index2].Uint128.= Uint64Hi, ContextEntry[Index2].Uint128.Uint64Lo));=0D + }=0D + if (ContextEntry[Index2].Bits.Present =3D=3D 0) {=0D + continue;=0D + }=0D + VtdLibDumpSecondLevelPagingEntry (Context, CallbackHandle, (VOID *) = (UINTN) VTD_64BITS_ADDRESS (ContextEntry[Index2].Bits.SecondLevelPageTransl= ationPointerLo, ContextEntry[Index2].Bits.SecondLevelPageTranslationPointer= Hi), Is5LevelPaging);=0D + }=0D + }=0D + VTDLIB_DEBUG ((DEBUG_INFO, "=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\n"));=0D +}=0D +=0D +/**=0D + Dump DMAR extended context entry table.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] ExtRootEntry DMAR extended root entry.=0D + @param[in] Is5LevelPaging If it is the 5 level paging.=0D +**/=0D +VOID=0D +VtdLibDumpDmarExtContextEntryTable (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VTD_EXT_ROOT_ENTRY *ExtRootEntry,=0D + IN BOOLEAN Is5LevelPaging=0D + )=0D +{=0D + UINTN Index;=0D + UINTN Index2;=0D + VTD_EXT_CONTEXT_ENTRY *ExtContextEntry;=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO, "=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\n"));=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DMAR ExtContext Entry Table:\n"));=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO, "ExtRootEntry Address - 0x%x\n", ExtRootEntry= ));=0D +=0D + for (Index =3D 0; Index < VTD_ROOT_ENTRY_NUMBER; Index++) {=0D + if ((ExtRootEntry[Index].Uint128.Uint64Lo !=3D 0) || (ExtRootEntry[Ind= ex].Uint128.Uint64Hi !=3D 0)) {=0D + VTDLIB_DEBUG ((DEBUG_INFO, " ExtRootEntry(0x%02x) B%02x - 0x%016lx = %016lx\n",=0D + Index, Index, ExtRootEntry[Index].Uint128.Uint64Hi, ExtRootEntry[I= ndex].Uint128.Uint64Lo));=0D + }=0D + if (ExtRootEntry[Index].Bits.LowerPresent =3D=3D 0) {=0D + continue;=0D + }=0D + ExtContextEntry =3D (VTD_EXT_CONTEXT_ENTRY *) (UINTN) VTD_64BITS_ADDRE= SS (ExtRootEntry[Index].Bits.LowerContextTablePointerLo, ExtRootEntry[Index= ].Bits.LowerContextTablePointerHi);=0D + for (Index2 =3D 0; Index2 < VTD_CONTEXT_ENTRY_NUMBER/2; Index2++) {=0D + if ((ExtContextEntry[Index2].Uint256.Uint64_1 !=3D 0) || (ExtContext= Entry[Index2].Uint256.Uint64_2 !=3D 0) ||=0D + (ExtContextEntry[Index2].Uint256.Uint64_3 !=3D 0) || (ExtContext= Entry[Index2].Uint256.Uint64_4 !=3D 0)) {=0D + VTDLIB_DEBUG ((DEBUG_INFO, " ExtContextEntryLower(0x%02x) D%02x= F%02x - 0x%016lx %016lx %016lx %016lx\n",=0D + Index2, Index2 >> 3, Index2 & 0x7, ExtContextEntry[Index2].Uint2= 56.Uint64_4, ExtContextEntry[Index2].Uint256.Uint64_3, ExtContextEntry[Inde= x2].Uint256.Uint64_2, ExtContextEntry[Index2].Uint256.Uint64_1));=0D + }=0D + if (ExtContextEntry[Index2].Bits.Present =3D=3D 0) {=0D + continue;=0D + }=0D + VtdLibDumpSecondLevelPagingEntry (Context, CallbackHandle, (VOID *) = (UINTN) VTD_64BITS_ADDRESS (ExtContextEntry[Index2].Bits.SecondLevelPageTra= nslationPointerLo, ExtContextEntry[Index2].Bits.SecondLevelPageTranslationP= ointerHi), Is5LevelPaging);=0D + }=0D +=0D + if (ExtRootEntry[Index].Bits.UpperPresent =3D=3D 0) {=0D + continue;=0D + }=0D + ExtContextEntry =3D (VTD_EXT_CONTEXT_ENTRY *) (UINTN) VTD_64BITS_ADDRE= SS (ExtRootEntry[Index].Bits.UpperContextTablePointerLo, ExtRootEntry[Index= ].Bits.UpperContextTablePointerHi);=0D + for (Index2 =3D 0; Index2 < VTD_CONTEXT_ENTRY_NUMBER/2; Index2++) {=0D + if ((ExtContextEntry[Index2].Uint256.Uint64_1 !=3D 0) || (ExtContext= Entry[Index2].Uint256.Uint64_2 !=3D 0) ||=0D + (ExtContextEntry[Index2].Uint256.Uint64_3 !=3D 0) || (ExtContext= Entry[Index2].Uint256.Uint64_4 !=3D 0)) {=0D + VTDLIB_DEBUG ((DEBUG_INFO, " ExtContextEntryUpper(0x%02x) D%02x= F%02x - 0x%016lx %016lx %016lx %016lx\n",=0D + Index2, (Index2 + 128) >> 3, (Index2 + 128) & 0x7, ExtContextEnt= ry[Index2].Uint256.Uint64_4, ExtContextEntry[Index2].Uint256.Uint64_3, ExtC= ontextEntry[Index2].Uint256.Uint64_2, ExtContextEntry[Index2].Uint256.Uint6= 4_1));=0D + }=0D + if (ExtContextEntry[Index2].Bits.Present =3D=3D 0) {=0D + continue;=0D + }=0D + }=0D + }=0D + VTDLIB_DEBUG ((DEBUG_INFO, "=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\n"));=0D +}=0D +=0D +/**=0D + Dump VTd FRCD register.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] FrcdRegNum FRCD Register Number=0D + @param[in] FrcdRegTab FRCD Register Table=0D +**/=0D +VOID=0D +VtdLibDumpVtdFrcdRegs (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN UINT16 FrcdRegNum,=0D + IN VTD_UINT128 *FrcdRegTab=0D + )=0D +{=0D + UINT16 Index;=0D + VTD_FRCD_REG FrcdReg;=0D + VTD_SOURCE_ID SourceId;=0D +=0D + for (Index =3D 0; Index < FrcdRegNum; Index++) {=0D + FrcdReg.Uint64[0] =3D FrcdRegTab[Index].Uint64Lo;=0D + FrcdReg.Uint64[1] =3D FrcdRegTab[Index].Uint64Hi;=0D + VTDLIB_DEBUG ((DEBUG_INFO, " FRCD_REG[%d] - 0x%016lx %016lx\n", Index= , FrcdReg.Uint64[1], FrcdReg.Uint64[0]));=0D + if (FrcdReg.Uint64[1] !=3D 0 || FrcdReg.Uint64[0] !=3D 0) {=0D + VTDLIB_DEBUG ((DEBUG_INFO, " Fault Info - 0x%016lx\n", VTD_64BITS= _ADDRESS(FrcdReg.Bits.FILo, FrcdReg.Bits.FIHi)));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " Fault Bit - %d\n", FrcdReg.Bits.F));= =0D + SourceId.Uint16 =3D (UINT16)FrcdReg.Bits.SID;=0D + VTDLIB_DEBUG ((DEBUG_INFO, " Source - B%02x D%02x F%02x\n", Sourc= eId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " Type - 0x%02x\n", (FrcdReg.Bits.T1 <= < 1) | FrcdReg.Bits.T2));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " Reason - %x (Refer to VTd Spec, Appe= ndix A)\n", FrcdReg.Bits.FR));=0D + }=0D + }=0D +}=0D +=0D +/**=0D + Dump VTd registers.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] VtdRegInfo Registers information=0D +**/=0D +VOID=0D +VtdLibDumpVtdRegsAll (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VTD_REGESTER_INFO *VtdRegInfo=0D + )=0D +{=0D + if (VtdRegInfo !=3D NULL) {=0D + VTDLIB_DEBUG ((DEBUG_INFO, "VTd Engine: [0x%016lx]\n", VtdRegInfo->Bas= eAddress));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " VER_REG - 0x%08x\n", VtdRegInfo->V= erReg));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " CAP_REG - 0x%016lx\n", VtdRegInfo->C= apReg));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " ECAP_REG - 0x%016lx\n", VtdRegInfo->E= capReg));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " GSTS_REG - 0x%08x \n", VtdRegInfo->G= stsReg));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " RTADDR_REG - 0x%016lx\n", VtdRegInfo->R= taddrReg));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " CCMD_REG - 0x%016lx\n", VtdRegInfo->C= cmdReg));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " FSTS_REG - 0x%08x\n", VtdRegInfo->F= stsReg));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " FECTL_REG - 0x%08x\n", VtdRegInfo->F= ectlReg));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " FEDATA_REG - 0x%08x\n", VtdRegInfo->F= edataReg));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " FEADDR_REG - 0x%08x\n", VtdRegInfo->F= eaddrReg));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " FEUADDR_REG - 0x%08x\n", VtdRegInfo->F= euaddrReg));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " IQERCD_REG - 0x%016lx\n", VtdRegInfo->I= qercdReg));=0D +=0D + VtdLibDumpVtdFrcdRegs (Context, CallbackHandle, VtdRegInfo->FrcdRegNum= , VtdRegInfo->FrcdReg);=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO, " IVA_REG - 0x%016lx\n", VtdRegInfo->I= vaReg));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " IOTLB_REG - 0x%016lx\n", VtdRegInfo->I= otlbReg));=0D + }=0D +}=0D +=0D +/**=0D + Dump VTd registers.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] VtdRegInfo Registers information=0D +**/=0D +VOID=0D +VtdLibDumpVtdRegsThin (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VTD_REGESTER_THIN_INFO *VtdRegInfo=0D + )=0D +{=0D + if (VtdRegInfo !=3D NULL) {=0D + VTDLIB_DEBUG ((DEBUG_INFO, "VTd Engine: [0x%016lx]\n", VtdRegInfo->Bas= eAddress));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " GSTS_REG - 0x%08x \n", VtdRegInfo->G= stsReg));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " RTADDR_REG - 0x%016lx\n", VtdRegInfo->R= taddrReg));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " FSTS_REG - 0x%08x\n", VtdRegInfo->F= stsReg));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " FECTL_REG - 0x%08x\n", VtdRegInfo->F= ectlReg));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " IQERCD_REG - 0x%016lx\n", VtdRegInfo->I= qercdReg));=0D +=0D + VtdLibDumpVtdFrcdRegs (Context, CallbackHandle, VtdRegInfo->FrcdRegNum= , VtdRegInfo->FrcdReg);=0D + }=0D +}=0D +=0D +/**=0D + Dump VTd registers.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] VtdRegInfo Registers information=0D +**/=0D +VOID=0D +VtdLibDumpVtdRegsQi (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VTD_REGESTER_QI_INFO *VtdRegInfo=0D + )=0D +{=0D + if (VtdRegInfo !=3D NULL) {=0D + VTDLIB_DEBUG ((DEBUG_INFO, "VTd Engine: [0x%016lx]\n", VtdRegInfo->Bas= eAddress));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " FSTS_REG - 0x%08x\n", VtdRegInfo->F= stsReg));=0D + VTDLIB_DEBUG ((DEBUG_INFO, " IQERCD_REG - 0x%016lx\n", VtdRegInfo->I= qercdReg));=0D + }=0D +}=0D +=0D +/**=0D + Dump Vtd PEI pre-mem event.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] Event VTDLOG_EVENT_2PARAM event=0D +=0D +**/=0D +VOID=0D +VtdLibDumpPeiPreMemInfo (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VTDLOG_EVENT_2PARAM *Event=0D + )=0D +{=0D + UINT64 VtdBarAddress;=0D + UINT64 Mode;=0D + UINT64 Status;=0D +=0D + VtdBarAddress =3D Event->Data1;=0D + Mode =3D Event->Data2 & 0xFF;=0D + Status =3D (Event->Data2>>8) & 0xFF;=0D +=0D + switch (Mode) {=0D + case VTD_LOG_PEI_PRE_MEM_DISABLE:=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI (pre-memory): Disabled [0x%016lx] 0x%x= \n", VtdBarAddress, Status));=0D + break;=0D + case VTD_LOG_PEI_PRE_MEM_ADM:=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI (pre-memory): Enable Abort DMA Mode [0= x%016lx] 0x%x\n", VtdBarAddress, Status));=0D + break;=0D + case VTD_LOG_PEI_PRE_MEM_TE:=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI (pre-memory): Enable NULL Root Entry T= able [0x%016lx] 0x%x\n", VtdBarAddress, Status));=0D + break;=0D + case VTD_LOG_PEI_PRE_MEM_PMR:=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI (pre-memory): Enable PMR [0x%016lx] 0x= %x\n", VtdBarAddress, Status));=0D + break;=0D + case VTD_LOG_PEI_PRE_MEM_NOT_USED:=0D + //=0D + // Not used=0D + //=0D + break;=0D + default:=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI (pre-memory): Unknown [0x%016lx] 0x%x\= n", VtdBarAddress, Status));=0D + break;=0D + }=0D +}=0D +=0D +/**=0D + Dump Vtd Queued Invaildation event.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] Event VTDLOG_EVENT_2PARAM event=0D +=0D +**/=0D +VOID=0D +VtdLibDumpQueuedInvaildation (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VTDLOG_EVENT_2PARAM *Event=0D + )=0D +{=0D + switch (Event->Data1) {=0D + case VTD_LOG_QI_DISABLE:=0D + VTDLIB_DEBUG ((DEBUG_INFO, " [0x%016lx] Disable\n", Event->Data2));=0D + break;=0D + case VTD_LOG_QI_ENABLE:=0D + VTDLIB_DEBUG ((DEBUG_INFO, " [0x%016lx] Enable\n", Event->Data2));=0D + break;=0D + case VTD_LOG_QI_ERROR_OUT_OF_RESOURCES:=0D + VTDLIB_DEBUG ((DEBUG_INFO, " [0x%016lx] error - Out of resources\n", E= vent->Data2));=0D + break;=0D + default:=0D + VTDLIB_DEBUG ((DEBUG_INFO, " [0x%016lx] error - (0x%x)\n", Event->Data= 2, Event->Data1));=0D + break;=0D + }=0D +}=0D +=0D +/**=0D + Dump Vtd registers event.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] Event VTDLOG_EVENT_CONTEXT event=0D +=0D +**/=0D +VOID=0D +VtdLibDumpRegisters (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VTDLOG_EVENT_CONTEXT *Event=0D + )=0D +{=0D + switch (Event->Param) {=0D + case VTDLOG_REGISTER_ALL:=0D + VtdLibDumpVtdRegsAll (Context, CallbackHandle, (VTD_REGESTER_INFO *) E= vent->Data);=0D + break;=0D + case VTDLOG_REGISTER_THIN:=0D + VtdLibDumpVtdRegsThin (Context, CallbackHandle, (VTD_REGESTER_THIN_INF= O *) Event->Data);=0D + break;=0D + case VTDLOG_REGISTER_QI:=0D + VtdLibDumpVtdRegsQi (Context, CallbackHandle, (VTD_REGESTER_QI_INFO *)= Event->Data);=0D + break;=0D + default:=0D + VTDLIB_DEBUG ((DEBUG_INFO, " Unknown format (%d)\n", Event->Param));= =0D + break;=0D + }=0D +}=0D +=0D +/**=0D + Dump Vtd PEI Error event.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] Event VTDLOG_EVENT_2PARAM event=0D +=0D +**/=0D +VOID=0D +VtdLibDumpPeiError (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VTDLOG_EVENT_2PARAM *Event=0D + )=0D +{=0D + UINT64 Timestamp;=0D +=0D + Timestamp =3D Event->Header.Timestamp;=0D +=0D + switch (Event->Data1) {=0D + case VTD_LOG_PEI_VTD_ERROR_PPI_ALLOC:=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Error - PPI alloc length [0x%01= 6lx]\n", Timestamp, Event->Data2));=0D + break;=0D + case VTD_LOG_PEI_VTD_ERROR_PPI_MAP:=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Error - PPI map length [0x%016l= x]\n", Timestamp, Event->Data2));=0D + break;=0D + default:=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Error - Unknown (%d) 0x%x\n", T= imestamp, Event->Data1, Event->Data2));=0D + break;=0D + }=0D +}=0D +=0D +/**=0D + Dump Vtd registers event.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] Event VTDLOG_EVENT_CONTEXT event=0D +=0D +**/=0D +VOID=0D +VtdLibDumpSetAttribute (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VTDLOG_EVENT_CONTEXT *Event=0D + )=0D +{=0D + VTD_PROTOCOL_SET_ATTRIBUTE * SetAttributeInfo;=0D +=0D + SetAttributeInfo =3D (VTD_PROTOCOL_SET_ATTRIBUTE *) Event->Data;=0D +=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: SetAttribute SourceId =3D 0x%04x,= Address =3D 0x%lx, Length =3D 0x%lx, IoMmuAccess =3D 0x%lx, %r\n", =0D + Event->Header.Timestamp,=0D + SetAttributeInfo->SourceId.Uint16,=0D + SetAttributeInfo->DeviceAddress,=0D + SetAttributeInfo->Length,=0D + SetAttributeInfo->Status));=0D +}=0D +=0D +=0D +=0D +/**=0D + Dump Vtd Root Table event.=0D +=0D + @param[in] Context Event context=0D + @param[in out] CallbackHandle Callback handler=0D + @param[in] Event VTDLOG_EVENT_CONTEXT event=0D +=0D +**/=0D +VOID=0D +VtdLibDumpRootTable (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VTDLOG_EVENT_CONTEXT *Event=0D + )=0D +{=0D + VTD_ROOT_TABLE_INFO *RootTableInfo;=0D +=0D + RootTableInfo =3D (VTD_ROOT_TABLE_INFO *) Event->Data;=0D + if (Event->Param =3D=3D 0) {=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Root Entry Table [0x%016lx]\n",= Event->Header.Timestamp, RootTableInfo->BaseAddress));=0D + VtdLibDumpDmarContextEntryTable (Context, CallbackHandle, (VTD_ROOT_EN= TRY *) (UINTN) RootTableInfo->TableAddress, RootTableInfo->Is5LevelPaging);= =0D +=0D + } else if (Event->Param =3D=3D 1) {=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Ext Root Entry Table [0x%016lx]= \n", Event->Header.Timestamp, RootTableInfo->BaseAddress));=0D + VtdLibDumpDmarExtContextEntryTable (Context, CallbackHandle, (VTD_EXT_= ROOT_ENTRY *) (UINTN) RootTableInfo->TableAddress, RootTableInfo->Is5Level= Paging);=0D +=0D + } else {=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Unknown Root Table Type (%d)\n"= , Event->Header.Timestamp, Event->Param));=0D + }=0D +}=0D +=0D +/**=0D + Decode log event.=0D +=0D + @param[in] Context Event context=0D + @param[in out] PciDeviceId Callback handler=0D + @param[in] Event Event struct=0D +=0D + @retval TRUE Decode event success=0D + @retval FALSE Unknown event=0D +**/=0D +BOOLEAN=0D +VtdLibDecodeEvent (=0D + IN VOID *Context,=0D + IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle,=0D + IN VTDLOG_EVENT *Event=0D + )=0D +{=0D + BOOLEAN Result;=0D + UINT64 Timestamp;=0D + UINT64 Data1;=0D + UINT64 Data2;=0D +=0D + Result =3D TRUE;=0D + Timestamp =3D Event->EventHeader.Timestamp;=0D + Data1 =3D Event->CommenEvent.Data1;=0D + Data2 =3D Event->CommenEvent.Data2;=0D +=0D + switch (Event->EventHeader.LogType) {=0D + case VTDLOG_LOG_TYPE (VTDLOG_PEI_BASIC):=0D + if (Data1 & VTD_LOG_ERROR_BUFFER_FULL) {=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Info : Log Buffer Full\n", Ti= mestamp));=0D + Data1 &=3D ~VTD_LOG_ERROR_BUFFER_FULL;=0D + }=0D + if (Data1 !=3D 0) {=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Info : 0x%x, 0x%x\n", Timesta= mp, Data1, Data2));=0D + }=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_PEI_PRE_MEM_DMA_PROTECT):=0D + VtdLibDumpPeiPreMemInfo (Context, CallbackHandle, &(Event->CommenEvent= ));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_PEI_PMR_LOW_MEMORY_RANGE):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: PMR Low Memory Range [0x%x, 0x%= x]\n", Timestamp, Data1, Data2));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_PEI_PMR_HIGH_MEMORY_RANGE):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: PMR High Memory Range [0x%016lx= , 0x%016lx]\n", Timestamp, Data1, Data2));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_PEI_PROTECT_MEMORY_RANGE):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Protected DMA Memory Range [0x%= 016lx, 0x%016lx]\n", Timestamp, Data1, Data2));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_PEI_POST_MEM_ENABLE_DMA_PROTECT):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Enable DMA protection [0x%016lx= ] %r\n", Timestamp, Data1, Data2));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_PEI_POST_MEM_DISABLE_DMA_PROTECT):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Disable DMA protection [0x%016l= x]\n", Timestamp, Data1));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_PEI_QUEUED_INVALIDATION):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Queued Invalidation", Timestamp= ));=0D + VtdLibDumpQueuedInvaildation (Context, CallbackHandle, &(Event->Commen= Event));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_PEI_REGISTER):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Dump Registers\n", Timestamp));= =0D + VtdLibDumpRegisters (Context, CallbackHandle, &(Event->ContextEvent));= =0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_PEI_VTD_ERROR):=0D + VtdLibDumpPeiError (Context, CallbackHandle, &(Event->CommenEvent));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_PEI_PPI_ALLOC_BUFFER):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: PPI AllocateBuffer 0x%x, Length= =3D 0x%x\n", Timestamp, Data1, Data2));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_PEI_PPI_MAP):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: PPI Map 0x%x, Length =3D 0x%x\n= ", Timestamp, Data1, Data2));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_DXE_BASIC):=0D + if (Data1 & VTD_LOG_ERROR_BUFFER_FULL) {=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Info : Log Buffer Full\n", Ti= mestamp));=0D + Data1 &=3D ~VTD_LOG_ERROR_BUFFER_FULL;=0D + }=0D + if (Data1 !=3D 0) {=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Info : 0x%x, 0x%x\n", Timesta= mp, Data1, Data2));=0D + }=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_DXE_DMAR_TABLE):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: DMAR Table\n", Timestamp));=0D + VtdLibDumpAcpiDmar (Context, CallbackHandle, (EFI_ACPI_DMAR_HEADER *) = Event->ContextEvent.Data);=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_DXE_SETUP_VTD):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Setup VTd Below/Above 4G Memory= Limit =3D [0x%016lx, 0x%016lx]\n", Timestamp, Data1, Data2));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_DXE_PCI_DEVICE):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: PCI Devices [0x%016lx]\n", Time= stamp, Event->ContextEvent.Param));=0D + VtdLibDumpPciDeviceInfo (Context, CallbackHandle, (PCI_DEVICE_INFORMAT= ION *) Event->ContextEvent.Data);=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_DXE_REGISTER):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Dump Registers\n", Timestamp));= =0D + VtdLibDumpRegisters (Context, CallbackHandle, &(Event->ContextEvent));= =0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_DXE_ENABLE_DMAR):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Enable DMAR [0x%016lx]\n", Time= stamp, Data1));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_DXE_DISABLE_DMAR):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Disable DMAR [0x%016lx]\n", Tim= estamp, Data1));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_DXE_DISABLE_PMR):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Disable PMR [0x%016lx] %r\n", T= imestamp, Data1, Data2));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_DXE_INSTALL_IOMMU_PROTOCOL):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Install IOMMU Protocol %r\n", T= imestamp, Data1));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_DXE_QUEUED_INVALIDATION):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Queued Invalidation", Timestamp= ));=0D + VtdLibDumpQueuedInvaildation (Context, CallbackHandle, &(Event->Commen= Event));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_DXE_ROOT_TABLE):=0D + VtdLibDumpRootTable (Context, CallbackHandle, &(Event->ContextEvent));= =0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_DXE_IOMMU_ALLOC_BUFFER):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: AllocateBuffer 0x%x, Page =3D 0= x%x\n", Timestamp, Data2, Data1));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_DXE_IOMMU_FREE_BUFFER):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: FreeBuffer 0x%x, Page =3D 0x%x\= n", Timestamp, Data2, Data1));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_DXE_IOMMU_MAP):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Map 0x%x, Operation =3D 0x%x\n"= , Timestamp, Data1, Data2));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_DXE_IOMMU_UNMAP):=0D + VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Unmap 0x%x, NumberOfBytes =3D 0= x%x\n", Timestamp, Data2, Data1));=0D + break;=0D + case VTDLOG_LOG_TYPE (VTDLOG_DXE_IOMMU_SET_ATTRIBUTE):=0D + VtdLibDumpSetAttribute (Context, CallbackHandle, &(Event->ContextEvent= ));=0D + break;=0D + default:=0D + VTDLIB_DEBUG ((DEBUG_INFO, "## Unknown VTd Event Type=3D%d Timestamp= =3D%ld Size=3D%d\n", Event->EventHeader.LogType, Event->EventHeader.Timesta= mp, Event->EventHeader.DataSize));=0D + Result =3D FALSE;=0D + break;=0D + }=0D +=0D + return Result;=0D +}=0D +=0D +/**=0D + Flush VTd engine write buffer.=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D +**/=0D +VOID=0D +VtdLibFlushWriteBuffer (=0D + IN UINTN VtdUnitBaseAddress=0D + )=0D +{=0D + UINT32 Reg32;=0D + VTD_CAP_REG CapReg;=0D +=0D + CapReg.Uint64 =3D MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);=0D +=0D + if (CapReg.Bits.RWBF !=3D 0) {=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);=0D + MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_WBF);= =0D + do {=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);=0D + } while ((Reg32 & B_GSTS_REG_WBF) !=3D 0);=0D + }=0D +}=0D +=0D +/**=0D + Clear Global Command Register Bits=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D + @param[in] BitMask Bit mask=0D +**/=0D +VOID=0D +VtdLibClearGlobalCommandRegisterBits (=0D + IN UINTN VtdUnitBaseAddress,=0D + IN UINT32 BitMask=0D + )=0D +{=0D + UINT32 Reg32;=0D + UINT32 Status;=0D + UINT32 Command;=0D +=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);=0D + Status =3D (Reg32 & 0x96FFFFFF); // Reset the one-shot bits=0D + Command =3D (Status & (~BitMask));=0D + MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Command);=0D +=0D + DEBUG ((DEBUG_INFO, "Clear GCMD_REG bits 0x%x.\n", BitMask));=0D +=0D + //=0D + // Poll on Status bit of Global status register to become zero=0D + //=0D + do {=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);=0D + } while ((Reg32 & BitMask) =3D=3D BitMask);=0D + DEBUG ((DEBUG_INFO, "GSTS_REG : 0x%08x \n", Reg32));=0D +}=0D +=0D +/**=0D + Set Global Command Register Bits=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D + @param[in] BitMask Bit mask=0D +**/=0D +VOID=0D +VtdLibSetGlobalCommandRegisterBits (=0D + IN UINTN VtdUnitBaseAddress,=0D + IN UINT32 BitMask=0D + )=0D +{=0D + UINT32 Reg32;=0D + UINT32 Status;=0D + UINT32 Command;=0D +=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);=0D + Status =3D (Reg32 & 0x96FFFFFF); // Reset the one-shot bits=0D + Command =3D (Status | BitMask);=0D + MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Command);=0D +=0D + DEBUG ((DEBUG_INFO, "Set GCMD_REG bits 0x%x.\n", BitMask));=0D +=0D + //=0D + // Poll on Status bit of Global status register to become not zero=0D + //=0D + do {=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);=0D + } while ((Reg32 & BitMask) =3D=3D 0);=0D + DEBUG ((DEBUG_INFO, "GSTS_REG : 0x%08x \n", Reg32));=0D +}=0D +=0D +/**=0D + Disable DMAR translation.=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D +=0D + @retval EFI_SUCCESS DMAR translation is disabled.=0D +**/=0D +EFI_STATUS=0D +VtdLibDisableDmar (=0D + IN UINTN VtdUnitBaseAddress=0D + )=0D +{=0D + UINT32 Reg32;=0D +=0D + DEBUG ((DEBUG_INFO, ">>>>>>DisableDmar() for engine [%x]\n", VtdUnitBase= Address));=0D +=0D + //=0D + // Write Buffer Flush before invalidation=0D + //=0D + VtdLibFlushWriteBuffer (VtdUnitBaseAddress);=0D +=0D + //=0D + // Disable Dmar=0D + //=0D + //=0D + // Set TE (Translation Enable: BIT31) of Global command register to zero= =0D + //=0D + VtdLibClearGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_TE)= ;=0D +=0D + //=0D + // Set SRTP (Set Root Table Pointer: BIT30) of Global command register i= n order to update the root table pointerDisable VTd=0D + //=0D + VtdLibSetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRTP)= ;=0D +=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);=0D + DEBUG ((DEBUG_INFO, "DisableDmar: GSTS_REG - 0x%08x\n", Reg32));=0D +=0D + MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, 0);=0D +=0D + DEBUG ((DEBUG_INFO,"VTD () Disabled!<<<<<<\n"));=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Disable PMR.=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D +=0D + @retval EFI_SUCCESS PMR is disabled.=0D + @retval EFI_UNSUPPORTED PMR is not supported.=0D + @retval EFI_NOT_STARTED PMR was not enabled.=0D +**/=0D +EFI_STATUS=0D +VtdLibDisablePmr (=0D + IN UINTN VtdUnitBaseAddress=0D + )=0D +{=0D + UINT32 Reg32;=0D + VTD_CAP_REG CapReg;=0D + EFI_STATUS Status;=0D +=0D + CapReg.Uint64 =3D MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);=0D + if (CapReg.Bits.PLMR =3D=3D 0 || CapReg.Bits.PHMR =3D=3D 0) {=0D + //=0D + // PMR is not supported=0D + //=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);=0D + if ((Reg32 & BIT0) !=3D 0) {=0D + MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, 0x0);=0D + do {=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);=0D + } while((Reg32 & BIT0) !=3D 0);=0D +=0D + DEBUG ((DEBUG_INFO,"Pmr [0x%016lx] disabled\n", VtdUnitBaseAddress));= =0D + Status =3D EFI_SUCCESS;=0D + } else {=0D + DEBUG ((DEBUG_INFO,"Pmr [0x%016lx] not enabled\n", VtdUnitBaseAddress)= );=0D + Status =3D EFI_NOT_STARTED;=0D + }=0D + return Status;=0D +}=0D +=0D +/**=0D + Disable queued invalidation interface.=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D +**/=0D +VOID=0D +VtdLibDisableQueuedInvalidationInterface (=0D + IN UINTN VtdUnitBaseAddress=0D + )=0D +{=0D + UINT32 Reg32;=0D + QI_256_DESC QiDesc;=0D +=0D + QiDesc.Uint64[0] =3D QI_IWD_TYPE;=0D + QiDesc.Uint64[1] =3D 0;=0D + QiDesc.Uint64[2] =3D 0;=0D + QiDesc.Uint64[3] =3D 0;=0D +=0D + VtdLibSubmitQueuedInvalidationDescriptor (VtdUnitBaseAddress, &QiDesc, T= RUE);=0D +=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);=0D + Reg32 &=3D (~B_GMCD_REG_QIE);=0D + MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32);=0D +=0D + DEBUG ((DEBUG_INFO, "Disable Queued Invalidation Interface. [%x] GCMD_RE= G =3D 0x%x\n", VtdUnitBaseAddress, Reg32));=0D + do {=0D + Reg32 =3D MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);=0D + } while ((Reg32 & B_GSTS_REG_QIES) !=3D 0);=0D +=0D + MmioWrite64 (VtdUnitBaseAddress + R_IQA_REG, 0);=0D +}=0D +=0D +/**=0D + Submit the queued invalidation descriptor to the remapping=0D + hardware unit and wait for its completion.=0D +=0D + @param[in] VtdUnitBaseAddress The base address of the VTd engine.=0D + @param[in] Desc The invalidate descriptor=0D + @param[in] ClearFaultBits Clear Error bits=0D +=0D + @retval EFI_SUCCESS The operation was successful.=0D + @retval EFI_INVALID_PARAMETER Parameter is invalid.=0D + @retval EFI_NOT_READY Queued invalidation is not inited.=0D + @retval EFI_DEVICE_ERROR Detect fault, need to clear fault bits= if ClearFaultBits is FALSE=0D +=0D +**/=0D +EFI_STATUS=0D +VtdLibSubmitQueuedInvalidationDescriptor (=0D + IN UINTN VtdUnitBaseAddress,=0D + IN VOID *Desc,=0D + IN BOOLEAN ClearFaultBits=0D + )=0D +{=0D + UINTN QueueSize;=0D + UINTN QueueTail;=0D + UINTN QueueHead;=0D + QI_DESC *Qi128Desc;=0D + QI_256_DESC *Qi256Desc;=0D + VTD_IQA_REG IqaReg;=0D + VTD_IQT_REG IqtReg;=0D + VTD_IQH_REG IqhReg;=0D + UINT32 FaultReg;=0D + UINT64 IqercdReg;=0D +=0D + if (Desc =3D=3D NULL) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + IqaReg.Uint64 =3D MmioRead64 (VtdUnitBaseAddress + R_IQA_REG);=0D + if (IqaReg.Bits.IQA =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR,"Invalidation Queue Buffer not ready [0x%lx]\n", I= qaReg.Uint64));=0D + return EFI_NOT_READY;=0D + }=0D + IqtReg.Uint64 =3D MmioRead64 (VtdUnitBaseAddress + R_IQT_REG);=0D +=0D + if (IqaReg.Bits.DW =3D=3D 0) {=0D + //=0D + // 128-bit descriptor=0D + //=0D + QueueSize =3D (UINTN) (1 << (IqaReg.Bits.QS + 8));=0D + Qi128Desc =3D (QI_DESC *) (UINTN) (IqaReg.Bits.IQA << VTD_PAGE_SHIFT);= =0D + QueueTail =3D (UINTN) IqtReg.Bits128Desc.QT;=0D + Qi128Desc +=3D QueueTail;=0D + CopyMem (Qi128Desc, Desc, sizeof (QI_DESC));=0D + QueueTail =3D (QueueTail + 1) % QueueSize;=0D +=0D + DEBUG ((DEBUG_VERBOSE, "[0x%x] Submit QI Descriptor 0x%x [0x%016lx, 0x= %016lx]\n",=0D + VtdUnitBaseAddress,=0D + QueueTail,=0D + Qi128Desc->Low,=0D + Qi128Desc->High));=0D +=0D + IqtReg.Bits128Desc.QT =3D QueueTail;=0D + } else {=0D + //=0D + // 256-bit descriptor=0D + //=0D + QueueSize =3D (UINTN) (1 << (IqaReg.Bits.QS + 7));=0D + Qi256Desc =3D (QI_256_DESC *) (UINTN) (IqaReg.Bits.IQA << VTD_PAGE_SHI= FT);=0D + QueueTail =3D (UINTN) IqtReg.Bits256Desc.QT;=0D + Qi256Desc +=3D QueueTail;=0D + CopyMem (Qi256Desc, Desc, sizeof (QI_256_DESC));=0D + QueueTail =3D (QueueTail + 1) % QueueSize;=0D +=0D + DEBUG ((DEBUG_VERBOSE, "[0x%x] Submit QI Descriptor 0x%x [0x%016lx, 0x= %016lx, 0x%016lx, 0x%016lx]\n",=0D + VtdUnitBaseAddress,=0D + QueueTail,=0D + Qi256Desc->Uint64[0],=0D + Qi256Desc->Uint64[1],=0D + Qi256Desc->Uint64[2],=0D + Qi256Desc->Uint64[3]));=0D +=0D + IqtReg.Bits256Desc.QT =3D QueueTail;=0D + }=0D +=0D + //=0D + // Update the HW tail register indicating the presence of new descriptor= s.=0D + //=0D + MmioWrite64 (VtdUnitBaseAddress + R_IQT_REG, IqtReg.Uint64);=0D +=0D + do {=0D + FaultReg =3D MmioRead32 (VtdUnitBaseAddress + R_FSTS_REG);=0D + if (FaultReg & (B_FSTS_REG_IQE | B_FSTS_REG_ITE | B_FSTS_REG_ICE)) {=0D + IqercdReg =3D MmioRead64 (VtdUnitBaseAddress + R_IQERCD_REG);=0D + DEBUG((DEBUG_ERROR, "BAR [0x%016lx] Detect Queue Invalidation Fault = [0x%08x] - IQERCD [0x%016lx]\n", VtdUnitBaseAddress, FaultReg, IqercdReg));= =0D + if (ClearFaultBits) {=0D + FaultReg &=3D (B_FSTS_REG_IQE | B_FSTS_REG_ITE | B_FSTS_REG_ICE);= =0D + MmioWrite32 (VtdUnitBaseAddress + R_FSTS_REG, FaultReg);=0D + }=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + IqhReg.Uint64 =3D MmioRead64 (VtdUnitBaseAddress + R_IQH_REG);=0D + if (IqaReg.Bits.DW =3D=3D 0) {=0D + QueueHead =3D (UINTN) IqhReg.Bits128Desc.QH;=0D + } else {=0D + QueueHead =3D (UINTN) IqhReg.Bits256Desc.QH;=0D + }=0D + } while (QueueTail !=3D QueueHead);=0D +=0D + return EFI_SUCCESS;=0D +}=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Library/IntelVTdPeiDxeLib/IntelV= TdPeiDxeLib.inf b/Silicon/Intel/IntelSiliconPkg/Library/IntelVTdPeiDxeLib/I= ntelVTdPeiDxeLib.inf new file mode 100644 index 000000000..0d6dff5fa --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Library/IntelVTdPeiDxeLib/IntelVTdPeiDx= eLib.inf @@ -0,0 +1,30 @@ +### @file=0D +# Component information file for Intel VTd function library.=0D +#=0D +# Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D +#=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +###=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010005=0D + BASE_NAME =3D IntelVTdPeiDxeLib=0D + FILE_GUID =3D 6cd8b1ea-152d-4cc9-b9b1-f5c692ba63da= =0D + VERSION_STRING =3D 1.0=0D + MODULE_TYPE =3D BASE=0D + LIBRARY_CLASS =3D IntelVTdPeiDxeLib=0D +=0D +[LibraryClasses]=0D + BaseLib=0D + PrintLib=0D + IoLib=0D + CacheMaintenanceLib=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + MdeModulePkg/MdeModulePkg.dec=0D + IntelSiliconPkg/IntelSiliconPkg.dec=0D +=0D +[Sources]=0D + IntelVTdPeiDxeLib.c=0D diff --git a/Silicon/Intel/IntelSiliconPkg/Library/IntelVTdPeiDxeLib/IntelV= TdPeiDxeLibExt.inf b/Silicon/Intel/IntelSiliconPkg/Library/IntelVTdPeiDxeLi= b/IntelVTdPeiDxeLibExt.inf new file mode 100644 index 000000000..9a2b28e12 --- /dev/null +++ b/Silicon/Intel/IntelSiliconPkg/Library/IntelVTdPeiDxeLib/IntelVTdPeiDx= eLibExt.inf @@ -0,0 +1,34 @@ +### @file=0D +# Component information file for Intel VTd function library.=0D +#=0D +# Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D +#=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +###=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010005=0D + BASE_NAME =3D IntelVTdPeiDxeLib=0D + FILE_GUID =3D 6fd8b3aa-852d-6ccA-b9b2-f5c692ba63ca= =0D + VERSION_STRING =3D 1.0=0D + MODULE_TYPE =3D BASE=0D + LIBRARY_CLASS =3D IntelVTdPeiDxeLib=0D +=0D +[LibraryClasses]=0D + BaseLib=0D + PrintLib=0D + IoLib=0D + CacheMaintenanceLib=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + MdeModulePkg/MdeModulePkg.dec=0D + IntelSiliconPkg/IntelSiliconPkg.dec=0D +=0D +[Sources]=0D + IntelVTdPeiDxeLib.c=0D +=0D +[BuildOptions]=0D + *_*_X64_CC_FLAGS =3D -DEXT_CALLBACK=0D +=0D --=20 2.26.2.windows.1