From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from NAM03-BY2-obe.outbound.protection.outlook.com (mail-by2nam03on0619.outbound.protection.outlook.com [IPv6:2a01:111:f400:fe4a::619]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 42D6620081A7B for ; Mon, 17 Apr 2017 12:33:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amdcloud.onmicrosoft.com; s=selector1-amd-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=RxejRNhf4B6pfpAUVibzc2doyQkZDz7oxSRXdgPRWWE=; b=I3NXsS1g3iI7irl1kba8+DQ0h6lL4ZWWx0qAbymK9uEj2feN9u0qaFfI9j7My3UTH2iHKfZdevHhpumOwNq1Idp2OQUWDIkxeOiYYyDYlLf+PRZjOFZ69GpVwUXsUYhBH+pQPZI098crzpv6d9umhFYU/bKPD4+EHkTvZxmh3Qk= Received: from DM5PR12MB1243.namprd12.prod.outlook.com (10.168.237.22) by DM5PR1201MB0140.namprd12.prod.outlook.com (10.174.106.145) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1019.17; Mon, 17 Apr 2017 19:33:10 +0000 Received: from DM5PR12MB1243.namprd12.prod.outlook.com ([10.168.237.22]) by DM5PR12MB1243.namprd12.prod.outlook.com ([10.168.237.22]) with mapi id 15.01.1034.013; Mon, 17 Apr 2017 19:33:09 +0000 From: "Duran, Leo" To: 'Jiewen Yao' , "edk2-devel@lists.01.org" CC: Ruiyu Ni , "Singh, Brijesh" , Ard Biesheuvel Thread-Topic: [RFC] [PATCH V3 2/3] MdeModulePkg/PciHostBridge: Add IOMMU support. Thread-Index: AQHSrRIFEPrnpPzMekijPNZWz9+dN6HKAv1Q Date: Mon, 17 Apr 2017 19:33:09 +0000 Message-ID: References: <1491289579-15888-1-git-send-email-jiewen.yao@intel.com> <1491289579-15888-3-git-send-email-jiewen.yao@intel.com> In-Reply-To: <1491289579-15888-3-git-send-email-jiewen.yao@intel.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: intel.com; dkim=none (message not signed) header.d=none;intel.com; dmarc=none action=none header.from=amd.com; x-originating-ip: [165.204.77.1] x-microsoft-exchange-diagnostics: 1; DM5PR1201MB0140; 7:XmKJdAhEXgXEuFAiRlxBP9oAcCVplII8jqk2lH0g/gEkI+/iLYlxVlSgjmWGYOU2sWzmI/FVPhdi+6TKFPhq9q/UaO5H4kyNcHbgJfOPCXjgwGz5ShlPxjUxXzdh3HsQxKGZjOlph8GCtFI0zJiJuSDnM65RiCKdnDPfpjx0Z4gdXuwayKUW9euwzIpdGh+N36+UgKlWjwrWhCbS29wteCxh9F8oyOU1k3GAxWDS5WhukF2vN+m959hW4q3/04cwImir6WUGF9lGowDZlpx4NNk2URwPAlyckxMd+jC9cwKfa2QtgAT8skgSlKgkl1Ey43AMh1JRraVmD1JM3t4jBg==; 20:3SV6vTmxrRHPUdEyrjtn3Wr0u42y7RgSOTh6T1qjJsOShvqNmai+KAVixqqy5g1YrU6Y2AZGm3ApEDjsrlwdakxSoahoNQc+CFgfg7AYuNU5BRItOAUsmfQZoeU+tpGH8pLa+02vTIOJupD7e/pDtmZQ6xuctgzyP6BNpbftXCJsqxv3U4uzw7yKJChMMrKULoRgaTNuJzceFTjfaPFUtjpMHL8A/mopAdkuj7TBhFGVpLLcT00NPKVBlZlSeBQC x-forefront-antispam-report: SFV:SKI; SCL:-1SFV:NSPM; SFS:(10009020)(6009001)(39850400002)(39400400002)(39840400002)(39860400002)(39450400003)(377454003)(13464003)(6116002)(7696004)(122556002)(25786009)(50986999)(33656002)(54356999)(102836003)(8676002)(8936002)(77096006)(99286003)(53546009)(76176999)(9686003)(74316002)(55016002)(6436002)(6506006)(38730400002)(2900100001)(54906002)(2906002)(6246003)(53946003)(3660700001)(81166006)(4326008)(3280700002)(86362001)(53936002)(66066001)(5660300001)(2501003)(305945005)(7736002)(189998001)(229853002)(2950100002)(579004)(19627235001); DIR:OUT; SFP:1101; SCL:1; SRVR:DM5PR1201MB0140; H:DM5PR12MB1243.namprd12.prod.outlook.com; FPR:; SPF:None; MLV:sfv; LANG:en; x-ms-office365-filtering-correlation-id: c73b9980-1336-481e-6669-08d485c89473 x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: UriScan:; BCL:0; PCL:0; RULEID:(22001)(2017030254075)(48565401081)(201703131423075)(201703031133081); SRVR:DM5PR1201MB0140; x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:(767451399110)(162533806227266)(228905959029699); x-exchange-antispam-report-cfa-test: BCL:0; PCL:0; RULEID:(6040450)(601004)(2401047)(8121501046)(5005006)(3002001)(10201501046)(93006095)(93001095)(6055026)(6041248)(201703131423075)(201702281528075)(201703061421075)(20161123564025)(20161123562025)(20161123555025)(20161123560025)(6072148); SRVR:DM5PR1201MB0140; BCL:0; PCL:0; RULEID:; SRVR:DM5PR1201MB0140; x-forefront-prvs: 02801ACE41 spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM MIME-Version: 1.0 X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-originalarrivaltime: 17 Apr 2017 19:33:09.4214 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR1201MB0140 Subject: Re: [RFC] [PATCH V3 2/3] MdeModulePkg/PciHostBridge: Add IOMMU support. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 17 Apr 2017 19:33:12 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Hi Yao, Just a couple of quick comments: 1) gIoMmuProtocol is declared (global) by PciHostBridge.c, but it is not in= itialized to NULL. 2) Would it be OK to do a one-time LocateProtocol() of gIoMmuProtocol in I= nitializePciHostBridge()? BTW, besides the global declaration, gIoMmuProtocol is currently not used = by PciHostBridge.c=20 Leo > -----Original Message----- > From: Jiewen Yao [mailto:jiewen.yao@intel.com] > Sent: Tuesday, April 04, 2017 2:06 AM > To: edk2-devel@lists.01.org > Cc: Ruiyu Ni ; Duran, Leo ; > Singh, Brijesh ; Ard Biesheuvel > > Subject: [RFC] [PATCH V3 2/3] MdeModulePkg/PciHostBridge: Add IOMMU > support. >=20 > The responsibility of PciHostBridge is to allocate IOMMU page aligned > memory for Map and AllocateBuffer, because PciHostBridge driver already > handles Map() request to allocate another buffer for DMA read/write. >=20 > If the max address requirement can not be satisfied, PciHostBridge may al= so > allocate any IOMMU page aligned memory and use IOMMU Remapping > feature to map to lower address to satisfy device requirement. >=20 > PciHostBridge does not set IOMMU attribute because it does not know > which device request the DMA. This work is done by PciBus driver. >=20 > Cc: Ruiyu Ni > Cc: Leo Duran > Cc: Brijesh Singh > Cc: Ard Biesheuvel > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Jiewen Yao > --- > MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c | 3 + > MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf | 1 + > MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h | 8 + > MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c | 350 > ++++++++++++++++++-- > 4 files changed, 326 insertions(+), 36 deletions(-) >=20 > diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c > b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c > index 9005dee..35233a7 100644 > --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c > +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c > @@ -28,6 +28,9 @@ GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 > *mPciResourceTypeStr[] =3D { > L"I/O", L"Mem", L"PMem", L"Mem64", L"PMem64", L"Bus" > }; >=20 > +EDKII_IOMMU_PROTOCOL *gIoMmuProtocol; > +UINTN mIoMmuPageSize =3D 1; > + > /** > Ensure the compatibility of an IO space descriptor with the IO apertur= e. >=20 > diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf > b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf > index d8b0439..2d3c8c9 100644 > --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf > +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf > @@ -49,6 +49,7 @@ > gEfiDevicePathProtocolGuid ## BY_START > gEfiPciRootBridgeIoProtocolGuid ## BY_START > gEfiPciHostBridgeResourceAllocationProtocolGuid ## BY_START > + gEdkiiIoMmuProtocolGuid ## CONSUMES >=20 > [Depex] > gEfiCpuIo2ProtocolGuid AND > diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h > b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h > index 13185b4..77c3490 100644 > --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h > +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h > @@ -27,6 +27,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY > KIND, EITHER EXPRESS OR IMPLIED. > #include > #include > #include > +#include > #include > #include > #include > @@ -50,8 +51,11 @@ typedef struct { > EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation; > UINTN NumberOfBytes; > UINTN NumberOfPages; > + UINTN MappedNumberOfBytes; > + UINTN MappedNumberOfPages; > EFI_PHYSICAL_ADDRESS HostAddress; > EFI_PHYSICAL_ADDRESS MappedHostAddress; > + BOOLEAN RemapNonExisting; > } MAP_INFO; > #define MAP_INFO_FROM_LINK(a) CR (a, MAP_INFO, Link, > MAP_INFO_SIGNATURE) >=20 > @@ -575,4 +579,8 @@ RootBridgeIoConfiguration ( >=20 > extern EFI_METRONOME_ARCH_PROTOCOL *mMetronome; > extern EFI_CPU_IO2_PROTOCOL *mCpuIo; > + > +extern EDKII_IOMMU_PROTOCOL *gIoMmuProtocol; > +extern UINTN mIoMmuPageSize; > + > #endif > diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c > b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c > index 8af131b..2a17eb1 100644 > --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c > +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c > @@ -1022,6 +1022,121 @@ RootBridgeIoPciWrite ( } >=20 > /** > + Allocates one or more 4KB pages of a certain memory type at a specifie= d > alignment. > + > + Allocates the number of 4KB pages specified by Pages of a certain > + memory type with an alignment specified by Alignment. The allocated > buffer is returned. If Pages is 0, then NULL is returned. > + If there is not enough memory at the specified alignment remaining to > + satisfy the request, then NULL is returned. > + If Alignment is not a power of two and Alignment is not zero, then > ASSERT(). > + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). > + > + @param Type The type of allocation to perform. > + @param MemoryType The type of memory to allocate. > + @param Pages The number of 4 KB pages to allocate. > + @param Alignment The requested alignment of the allocatio= n. > Must be a power of two. > + If Alignment is zero, then byte alignmen= t is used. > + @param Address Pointer to a physical address. > + > + @return Memory Allocation Status. > + > +**/ > +EFI_STATUS > +InternalAllocateAlignedPagesWithAllocateType ( > + IN EFI_ALLOCATE_TYPE Type, > + IN EFI_MEMORY_TYPE MemoryType, > + IN UINTN Pages, > + IN UINTN Alignment, > + IN OUT EFI_PHYSICAL_ADDRESS *Address > + ) > +{ > + EFI_STATUS Status; > + EFI_PHYSICAL_ADDRESS Memory; > + UINTN AlignedMemory; > + UINTN AlignmentMask; > + UINTN UnalignedPages; > + UINTN RealPages; > + > + // > + // Alignment must be a power of two or zero. > + // > + ASSERT ((Alignment & (Alignment - 1)) =3D=3D 0); > + > + if (Pages =3D=3D 0) { > + return EFI_INVALID_PARAMETER; > + } > + if (Alignment > EFI_PAGE_SIZE) { > + // > + // Calculate the total number of pages since alignment is larger tha= n page > size. > + // > + AlignmentMask =3D Alignment - 1; > + RealPages =3D Pages + EFI_SIZE_TO_PAGES (Alignment); > + // > + // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not > overflow. > + // > + ASSERT (RealPages > Pages); > + > + Memory =3D *Address; > + Status =3D gBS->AllocatePages (Type, MemoryType, RealPages, > &Memory); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + AlignedMemory =3D ((UINTN) Memory + AlignmentMask) & > ~AlignmentMask; > + UnalignedPages =3D EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) > Memory); > + if (UnalignedPages > 0) { > + // > + // Free first unaligned page(s). > + // > + Status =3D gBS->FreePages (Memory, UnalignedPages); > + ASSERT_EFI_ERROR (Status); > + } > + Memory =3D (EFI_PHYSICAL_ADDRESS) (AlignedMemory + > EFI_PAGES_TO_SIZE (Pages)); > + UnalignedPages =3D RealPages - Pages - UnalignedPages; > + if (UnalignedPages > 0) { > + // > + // Free last unaligned page(s). > + // > + Status =3D gBS->FreePages (Memory, UnalignedPages); > + ASSERT_EFI_ERROR (Status); > + } > + } else { > + // > + // Do not over-allocate pages in this case. > + // > + Memory =3D *Address; > + Status =3D gBS->AllocatePages (Type, MemoryType, Pages, &Memory); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + AlignedMemory =3D (UINTN) Memory; > + } > + *Address =3D AlignedMemory; > + return EFI_SUCCESS; > +} > + > +/** > + Return if a value is aligned. > + > + @param Value the value to be checked > + @param Alignment the alignment to be checked with. > + > + @retval TRUE The value is aligned > + @retval FALSE The value is not aligned. > +**/ > +BOOLEAN > +InternalIsAlgined ( > + IN UINTN Value, > + IN UINTN Alignment > + ) > +{ > + if (Value =3D=3D ALIGN_VALUE(Value, Alignment)) { > + return TRUE; > + } else { > + return FALSE; > + } > +} > + > +/** > Provides the PCI controller-specific address needed to access > system memory for DMA. >=20 > @@ -1057,6 +1172,9 @@ RootBridgeIoMap ( > PCI_ROOT_BRIDGE_INSTANCE *RootBridge; > EFI_PHYSICAL_ADDRESS PhysicalAddress; > MAP_INFO *MapInfo; > + EFI_PHYSICAL_ADDRESS MaxAddress; > + BOOLEAN NeedMap; > + BOOLEAN NeedAllocateNonExist= ing; >=20 > if (HostAddress =3D=3D NULL || NumberOfBytes =3D=3D NULL || DeviceAddr= ess =3D=3D > NULL || > Mapping =3D=3D NULL) { > @@ -1072,13 +1190,41 @@ RootBridgeIoMap ( >=20 > RootBridge =3D ROOT_BRIDGE_FROM_THIS (This); >=20 > + if (gIoMmuProtocol =3D=3D NULL) { > + gBS->LocateProtocol ( > + &gEdkiiIoMmuProtocolGuid, > + NULL, > + (VOID **) &gIoMmuProtocol > + ); > + if (gIoMmuProtocol !=3D NULL) { > + gIoMmuProtocol->GetPageSize (gIoMmuProtocol, &mIoMmuPageSize); > + ASSERT ((mIoMmuPageSize & (mIoMmuPageSize - 1)) =3D=3D 0); > + } > + } > + > PhysicalAddress =3D (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress; > + > + MaxAddress =3D (EFI_PHYSICAL_ADDRESS)-1; NeedMap =3D FALSE; > + NeedAllocateNonExisting =3D FALSE; > + > if ((!RootBridge->DmaAbove4G || > (Operation !=3D EfiPciOperationBusMasterRead64 && > Operation !=3D EfiPciOperationBusMasterWrite64 && > Operation !=3D EfiPciOperationBusMasterCommonBuffer64)) && > ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB)) { > + NeedMap =3D TRUE; > + MaxAddress =3D SIZE_4GB - 1; > + } >=20 > + if (gIoMmuProtocol !=3D NULL) { > + if ((!InternalIsAlgined (*NumberOfBytes, mIoMmuPageSize)) || > + (!InternalIsAlgined ((UINTN)HostAddress, mIoMmuPageSize))) { > + NeedMap =3D TRUE; > + } > + } > + > + if (NeedMap) { > // > // If the root bridge or the device cannot handle performing DMA abo= ve > // 4GB but any part of the DMA transfer being mapped is above 4GB, t= hen > @@ -1090,9 +1236,17 @@ RootBridgeIoMap ( > // > // Common Buffer operations can not be remapped. If the common > buffer > // if above 4GB, then it is not possible to generate a mapping, so= return > - // an error. > + // an error if there is no IOMMU. > // > - return EFI_UNSUPPORTED; > + if (gIoMmuProtocol =3D=3D NULL) { > + return EFI_UNSUPPORTED; > + } else { > + // > + // We can try to allocate non-existing memory for below 4GiB add= ress > + // and use IOMMU to remap it. > + // > + NeedAllocateNonExisting =3D TRUE; > + } > } >=20 > // > @@ -1113,21 +1267,81 @@ RootBridgeIoMap ( > MapInfo->NumberOfBytes =3D *NumberOfBytes; > MapInfo->NumberOfPages =3D EFI_SIZE_TO_PAGES (MapInfo- > >NumberOfBytes); > MapInfo->HostAddress =3D PhysicalAddress; > - MapInfo->MappedHostAddress =3D SIZE_4GB - 1; > + MapInfo->MappedHostAddress =3D MaxAddress; > + MapInfo->MappedNumberOfBytes =3D ALIGN_VALUE (MapInfo- > >NumberOfBytes, mIoMmuPageSize); > + MapInfo->MappedNumberOfPages =3D EFI_SIZE_TO_PAGES (MapInfo- > >MappedNumberOfBytes); > + MapInfo->RemapNonExisting =3D FALSE; >=20 > - // > - // Allocate a buffer below 4GB to map the transfer to. > - // > - Status =3D gBS->AllocatePages ( > - AllocateMaxAddress, > - EfiBootServicesData, > - MapInfo->NumberOfPages, > - &MapInfo->MappedHostAddress > - ); > - if (EFI_ERROR (Status)) { > - FreePool (MapInfo); > - *NumberOfBytes =3D 0; > - return Status; > + if (!((Operation =3D=3D EfiPciOperationBusMasterCommonBuffer) || > + (Operation =3D=3D EfiPciOperationBusMasterCommonBuffer64))) { > + // > + // Allocate a buffer below 4GB to map the transfer to. > + // > + Status =3D InternalAllocateAlignedPagesWithAllocateType ( > + AllocateMaxAddress, > + EfiBootServicesData, > + MapInfo->MappedNumberOfPages, > + mIoMmuPageSize, > + &MapInfo->MappedHostAddress > + ); > + if (EFI_ERROR (Status)) { > + if (gIoMmuProtocol =3D=3D NULL) { > + FreePool (MapInfo); > + *NumberOfBytes =3D 0; > + return Status; > + } > + // > + // We can try to allocate non-existing memory for below 4GiB add= ress > + // and use IOMMU to remap it. > + // > + NeedAllocateNonExisting =3D TRUE; > + } > + } > + > + if (NeedAllocateNonExisting) { > + if ((!InternalIsAlgined (*NumberOfBytes, mIoMmuPageSize)) || > + (!InternalIsAlgined ((UINTN)HostAddress, mIoMmuPageSize))) { > + // > + // If original memory is not IOMMU aligned, we cannot remap it. > + // > + FreePool (MapInfo); > + *NumberOfBytes =3D 0; > + return EFI_UNSUPPORTED; > + } > + // > + // If the code runs to here, it means: > + // 1) We need remap a common buffer to below 4G non-existing > memory. > + // 2) We need rempa a read/write buffer to below 4G non-existing > memory. > + // > + MapInfo->MappedHostAddress =3D MaxAddress; > + Status =3D gDS->AllocateMemorySpace ( > + EfiGcdAllocateMaxAddressSearchTopDown, > + EfiGcdMemoryTypeNonExistent, > + mIoMmuPageSize, > + MapInfo->MappedNumberOfBytes, > + &MapInfo->MappedHostAddress, > + gImageHandle, > + RootBridge->Handle > + ); > + if (EFI_ERROR(Status)) { > + FreePool (MapInfo); > + *NumberOfBytes =3D 0; > + return Status; > + } > + Status =3D gIoMmuProtocol->SetRemapAddress ( > + gIoMmuProtocol, > + NULL, > + MapInfo->MappedHostAddress, > + (VOID *)(UINTN)MapInfo->HostAddress, > + MapInfo->MappedNumberOfBytes > + ); > + if (EFI_ERROR(Status)) { > + gDS->FreeMemorySpace (MapInfo->MappedHostAddress, MapInfo- > >MappedNumberOfBytes); > + FreePool (MapInfo); > + *NumberOfBytes =3D 0; > + return Status; > + } > + MapInfo->RemapNonExisting =3D TRUE; > } >=20 > // > @@ -1135,19 +1349,26 @@ RootBridgeIoMap ( > // then copy the contents of the real buffer into the mapped buffer > // so the Bus Master can read the contents of the real buffer. > // > - if (Operation =3D=3D EfiPciOperationBusMasterRead || > - Operation =3D=3D EfiPciOperationBusMasterRead64) { > - CopyMem ( > - (VOID *) (UINTN) MapInfo->MappedHostAddress, > - (VOID *) (UINTN) MapInfo->HostAddress, > - MapInfo->NumberOfBytes > - ); > + // This action can be skipped if there is IOMMU, because PciBus does > + // the action after setting IOMMU attributes. > + // > + if (gIoMmuProtocol =3D=3D NULL) { > + if (Operation =3D=3D EfiPciOperationBusMasterRead || > + Operation =3D=3D EfiPciOperationBusMasterRead64) { > + CopyMem ( > + (VOID *) (UINTN) MapInfo->MappedHostAddress, > + (VOID *) (UINTN) MapInfo->HostAddress, > + MapInfo->NumberOfBytes > + ); > + } > } >=20 > InsertTailList (&RootBridge->Maps, &MapInfo->Link); >=20 > // > // The DeviceAddress is the address of the maped buffer below 4GB > + // NOTE: It can be a valid system memory address. > + // Or a non-existing memory but mapped by IOMMU. > // > *DeviceAddress =3D MapInfo->MappedHostAddress; > // > @@ -1228,19 +1449,42 @@ RootBridgeIoUnmap ( > // then copy the contents of the mapped buffer into the real buffer > // so the processor can read the contents of the real buffer. > // > - if (MapInfo->Operation =3D=3D EfiPciOperationBusMasterWrite || > - MapInfo->Operation =3D=3D EfiPciOperationBusMasterWrite64) { > - CopyMem ( > - (VOID *) (UINTN) MapInfo->HostAddress, > - (VOID *) (UINTN) MapInfo->MappedHostAddress, > - MapInfo->NumberOfBytes > - ); > + // This action can be skipped if there is IOMMU, because PciBus does > + // the action. > + // > + if (gIoMmuProtocol =3D=3D NULL) { > + if (MapInfo->Operation =3D=3D EfiPciOperationBusMasterWrite || > + MapInfo->Operation =3D=3D EfiPciOperationBusMasterWrite64) { > + CopyMem ( > + (VOID *) (UINTN) MapInfo->HostAddress, > + (VOID *) (UINTN) MapInfo->MappedHostAddress, > + MapInfo->NumberOfBytes > + ); > + } > + } > + > + if (gIoMmuProtocol !=3D NULL) { > + // > + // Free GCD non existing memory. > + // > + if (MapInfo->RemapNonExisting) { > + gIoMmuProtocol->SetRemapAddress ( > + gIoMmuProtocol, > + NULL, > + MapInfo->MappedHostAddress, > + (VOID *)(UINTN)MapInfo->MappedHostAddress, > + MapInfo->MappedNumberOfBytes > + ); > + gDS->FreeMemorySpace (MapInfo->MappedHostAddress, MapInfo- > >MappedNumberOfBytes); > + FreePool (Mapping); > + return EFI_SUCCESS; > + } > } >=20 > // > // Free the mapped buffer and the MAP_INFO structure. > // > - gBS->FreePages (MapInfo->MappedHostAddress, MapInfo- > >NumberOfPages); > + gBS->FreePages (MapInfo->MappedHostAddress, > + MapInfo->MappedNumberOfPages); > FreePool (Mapping); > return EFI_SUCCESS; > } > @@ -1285,7 +1529,7 @@ RootBridgeIoAllocateBuffer ( > EFI_STATUS Status; > EFI_PHYSICAL_ADDRESS PhysicalAddress; > PCI_ROOT_BRIDGE_INSTANCE *RootBridge; > - EFI_ALLOCATE_TYPE AllocateType; > + UINTN Size; >=20 > // > // Validate Attributes > @@ -1312,25 +1556,52 @@ RootBridgeIoAllocateBuffer ( >=20 > RootBridge =3D ROOT_BRIDGE_FROM_THIS (This); >=20 > - AllocateType =3D AllocateAnyPages; > + PhysicalAddress =3D (EFI_PHYSICAL_ADDRESS) (-1); > if (!RootBridge->DmaAbove4G || > (Attributes & EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE) =3D=3D 0) { > // > // Limit allocations to memory below 4GB > // > - AllocateType =3D AllocateMaxAddress; > PhysicalAddress =3D (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1); > } > - Status =3D gBS->AllocatePages ( > - AllocateType, > + if (gIoMmuProtocol !=3D NULL) { > + Size =3D EFI_PAGES_TO_SIZE(Pages); > + Size =3D ALIGN_VALUE(EFI_PAGES_TO_SIZE(Pages), mIoMmuPageSize); > + Pages =3D EFI_SIZE_TO_PAGES (Size); > + } > + Status =3D InternalAllocateAlignedPagesWithAllocateType ( > + AllocateMaxAddress, > MemoryType, > Pages, > + mIoMmuPageSize, > &PhysicalAddress > ); > if (!EFI_ERROR (Status)) { > *HostAddress =3D (VOID *) (UINTN) PhysicalAddress; > + return EFI_SUCCESS; > } >=20 > + if (gIoMmuProtocol !=3D NULL) { > + // > + // Try to allocate AnyAddress here. > + // > + // We can try to allocate non-existing memory for below 4GiB address > + // and use IOMMU to remap it later. > + // > + PhysicalAddress =3D (EFI_PHYSICAL_ADDRESS) (-1); > + Status =3D InternalAllocateAlignedPagesWithAllocateType ( > + AllocateMaxAddress, > + MemoryType, > + Pages, > + mIoMmuPageSize, > + &PhysicalAddress > + ); > + if (EFI_ERROR(Status)) { > + return Status; > + } > + *HostAddress =3D (VOID *) (UINTN) PhysicalAddress; > + return EFI_SUCCESS; > + } > return Status; > } >=20 > @@ -1356,6 +1627,13 @@ RootBridgeIoFreeBuffer ( > OUT VOID *HostAddress > ) > { > + UINTN Size; > + > + if (gIoMmuProtocol !=3D NULL) { > + Size =3D EFI_PAGES_TO_SIZE(Pages); > + Size =3D ALIGN_VALUE(EFI_PAGES_TO_SIZE(Pages), mIoMmuPageSize); > + Pages =3D EFI_SIZE_TO_PAGES (Size); > + } > return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, > Pages); } >=20 > -- > 2.7.4.windows.1