From nobody Tue Feb 10 06:27:01 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+51253+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+51253+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=linaro.org ARC-Seal: i=1; a=rsa-sha256; t=1574723584; cv=none; d=zohomail.com; s=zohoarc; b=FGobICFKNJKLxzKFva82/7plBRWRhaj9hJz5zb2Tq6NL0iCQ6+DIbu5iSJme6D+TEqFiW62MvG+Y/O/kcKq4K242Gi7UiNkGpsv7WQ8yDGPHUalIMQV++89mJyaxHCyfRBEwFqeE+NYWvbFsceRh86EWet+YkDvwtnxSVMHa6tM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1574723584; h=Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:Message-ID:Reply-To:References:Sender:Subject:To; bh=eEEiI4T9xa8yUsbzHTQGs/cj0FUNUJOp/QVnbxPanUg=; b=hHwOvCa/NIQ5lUGo2iVmqgT0F6tEyWKLNOOI3D4vhxvoQpYewcjQVsvHHWR3aDFNpRb5D3KsvbzaKp9e6bxJc1eibyFp+Y3C9SzTlIT1ufy3P399Ce6mrXS09wYGsrPCAt6411h/CHv+W1QB5AINJOGCrmZQV2WQ7WccGD3dLEs= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+51253+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) header.from= Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1574723584146545.3892916368214; Mon, 25 Nov 2019 15:13:04 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id aaaaYY1788612xaaaaaaaaaa; Mon, 25 Nov 2019 15:13:02 -0800 X-Received: from mail-wr1-f44.google.com (mail-wr1-f44.google.com [209.85.221.44]) by mx.groups.io with SMTP id smtpd.web09.4017.1574723581713201369 for ; Mon, 25 Nov 2019 15:13:02 -0800 X-Received: by mail-wr1-f44.google.com with SMTP id n1so20223955wra.10 for ; Mon, 25 Nov 2019 15:13:01 -0800 (PST) X-Gm-Message-State: aaaaaaaaaaaaaaaaaaaaaaaax1787277AA= X-Google-Smtp-Source: APXvYqwdK4TGFCvawyCHUjI8dixR86CyFJUnz9khFbeycZgSe+WrRQZRxjhkyQ3jBLfXsS4wnhKdLA== X-Received: by 2002:adf:a551:: with SMTP id j17mr32639346wrb.18.1574723580003; Mon, 25 Nov 2019 15:13:00 -0800 (PST) X-Received: from e123331-lin.home (lfbn-mar-1-643-104.w90-118.abo.wanadoo.fr. [90.118.215.104]) by smtp.gmail.com with ESMTPSA id y6sm12601488wrr.19.2019.11.25.15.12.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 25 Nov 2019 15:12:59 -0800 (PST) From: "Ard Biesheuvel" To: devel@edk2.groups.io Cc: leif.lindholm@linaro.org, Ard Biesheuvel Subject: [edk2-devel] [PATCH v2 1/2] EmbeddedPkg/NonCoherentDmaLib: implement support for DMA range limits Date: Tue, 26 Nov 2019 00:12:41 +0100 Message-Id: <20191125231242.12193-2-ard.biesheuvel@linaro.org> In-Reply-To: <20191125231242.12193-1-ard.biesheuvel@linaro.org> References: <20191125231242.12193-1-ard.biesheuvel@linaro.org> Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,ard.biesheuvel@linaro.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1574723582; bh=pq5GHRVxxY9xa8FyPUv4sIcZlG3VnudYmekWmFu7DIU=; h=Cc:Date:From:Reply-To:Subject:To; b=c+e2mFNBTNet33bGtUsYyXybi3s7oqeYXmWFxgW4W/lZdn2xUYzoHlmgQPONe0h6Xar cBn6/J1ndfR8Rx5BUnQq8GDxLekKs6rMYA3QfzmWPNDDWbQy7qQHauzgul37S3FCBzbVX Qlh0o4uh2Y7y2N5HNSYbXa0S4D6m0RHNsqg= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Implement support for driving peripherals with limited DMA ranges to NonCoherentDmaLib, by adding a device address limit, and taking it, along with the device offset, into account when allocating or mapping DMA buffers. Signed-off-by: Ard Biesheuvel Acked-by: Leif Lindholm Acked-by: Philippe Mathieu-Daude Reviewed-by: Philippe Mathieu-Daude Tested-by: Pete Batard --- EmbeddedPkg/EmbeddedPkg.dec | 6 + EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c | 165 ++++++++= ++++++++++-- EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf | 1 + 3 files changed, 160 insertions(+), 12 deletions(-) diff --git a/EmbeddedPkg/EmbeddedPkg.dec b/EmbeddedPkg/EmbeddedPkg.dec index 8812a6db7c30..69922802f473 100644 --- a/EmbeddedPkg/EmbeddedPkg.dec +++ b/EmbeddedPkg/EmbeddedPkg.dec @@ -186,6 +186,12 @@ [PcdsFixedAtBuild.common, PcdsDynamic.common] # gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset|0x0|UINT64|0x0000058 =20 + # + # Highest address value supported by the device for DMA addressing. Note + # that this value should be strictly greater than PcdDmaDeviceOffset. + # + gEmbeddedTokenSpaceGuid.PcdDmaDeviceLimit|0xFFFFFFFFFFFFFFFF|UINT64|0x00= 0005A + # # Selection between DT and ACPI as a default # diff --git a/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c b/Em= beddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c index 78220f6358aa..115345765435 100644 --- a/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c +++ b/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c @@ -40,6 +40,8 @@ typedef struct { STATIC EFI_CPU_ARCH_PROTOCOL *mCpu; STATIC LIST_ENTRY UncachedAllocationList; =20 +STATIC PHYSICAL_ADDRESS mDmaHostAddressLimit; + STATIC PHYSICAL_ADDRESS HostToDeviceAddress ( @@ -49,6 +51,102 @@ HostToDeviceAddress ( return (PHYSICAL_ADDRESS)(UINTN)Address + PcdGet64 (PcdDmaDeviceOffset); } =20 +/** + Allocates one or more 4KB pages of a certain memory type at a specified + 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 return= ed. + If Pages is 0, then NULL is returned. If there is not enough memory at t= he + specified alignment remaining to satisfy the request, then NULL is retur= ned. + If Alignment is not a power of two and Alignment is not zero, then ASSER= T(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @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 allocation. + Must be a power of two. + If Alignment is zero, then byte alignment = is + used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +STATIC +VOID * +InternalAllocateAlignedPages ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN UINTN Alignment + ) +{ + 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 NULL; + } + if (Alignment > EFI_PAGE_SIZE) { + // + // Calculate the total number of pages since alignment is larger than = 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 mDmaHostAddressLimit; + Status =3D gBS->AllocatePages (AllocateMaxAddress, MemoryType, RealPag= es, + &Memory); + if (EFI_ERROR (Status)) { + return NULL; + } + 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 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 mDmaHostAddressLimit; + Status =3D gBS->AllocatePages (AllocateMaxAddress, MemoryType, Pages, + &Memory); + if (EFI_ERROR (Status)) { + return NULL; + } + AlignedMemory =3D (UINTN)Memory; + } + return (VOID *)AlignedMemory; +} + /** Provides the DMA controller-specific addresses needed to access system m= emory. =20 @@ -111,7 +209,30 @@ DmaMap ( return EFI_OUT_OF_RESOURCES; } =20 - if (Operation !=3D MapOperationBusMasterRead && + if (((UINTN)HostAddress + *NumberOfBytes) > mDmaHostAddressLimit) { + + if (Operation =3D=3D MapOperationBusMasterCommonBuffer) { + goto CommonBufferError; + } + + AllocSize =3D ALIGN_VALUE (*NumberOfBytes, mCpu->DmaBufferAlignment); + Map->BufferAddress =3D InternalAllocateAlignedPages (EfiBootServicesDa= ta, + EFI_SIZE_TO_PAGES (AllocSize), + mCpu->DmaBufferAlignment); + if (Map->BufferAddress =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto FreeMapInfo; + } + + if (Map->Operation =3D=3D MapOperationBusMasterRead) { + CopyMem (Map->BufferAddress, (VOID *)(UINTN)Map->HostAddress, + *NumberOfBytes); + } + mCpu->FlushDataCache (mCpu, (UINTN)Map->BufferAddress, AllocSize, + EfiCpuFlushTypeWriteBack); + + *DeviceAddress =3D HostToDeviceAddress (Map->BufferAddress); + } else if (Operation !=3D MapOperationBusMasterRead && ((((UINTN)HostAddress & (mCpu->DmaBufferAlignment - 1)) !=3D 0) || ((*NumberOfBytes & (mCpu->DmaBufferAlignment - 1)) !=3D 0))) { =20 @@ -128,12 +249,7 @@ DmaMap ( // on uncached buffers. // if (Operation =3D=3D MapOperationBusMasterCommonBuffer) { - DEBUG ((DEBUG_ERROR, - "%a: Operation type 'MapOperationBusMasterCommonBuffer' is only " - "supported\non memory regions that were allocated using " - "DmaAllocateBuffer ()\n", __FUNCTION__)); - Status =3D EFI_UNSUPPORTED; - goto FreeMapInfo; + goto CommonBufferError; } =20 // @@ -199,6 +315,12 @@ DmaMap ( =20 return EFI_SUCCESS; =20 +CommonBufferError: + DEBUG ((DEBUG_ERROR, + "%a: Operation type 'MapOperationBusMasterCommonBuffer' is only " + "supported\non memory regions that were allocated using " + "DmaAllocateBuffer ()\n", __FUNCTION__)); + Status =3D EFI_UNSUPPORTED; FreeMapInfo: FreePool (Map); =20 @@ -229,6 +351,7 @@ DmaUnmap ( MAP_INFO_INSTANCE *Map; EFI_STATUS Status; VOID *Buffer; + UINTN AllocSize; =20 if (Mapping =3D=3D NULL) { ASSERT (FALSE); @@ -238,7 +361,17 @@ DmaUnmap ( Map =3D (MAP_INFO_INSTANCE *)Mapping; =20 Status =3D EFI_SUCCESS; - if (Map->DoubleBuffer) { + if (((UINTN)Map->HostAddress + Map->NumberOfBytes) > mDmaHostAddressLimi= t) { + AllocSize =3D ALIGN_VALUE (Map->NumberOfBytes, mCpu->DmaBufferAlignmen= t); + if (Map->Operation =3D=3D MapOperationBusMasterWrite) { + mCpu->FlushDataCache (mCpu, (UINTN)Map->BufferAddress, AllocSize, + EfiCpuFlushTypeInvalidate); + CopyMem ((VOID *)(UINTN)Map->HostAddress, Map->BufferAddress, + Map->NumberOfBytes); + } + FreePages (Map->BufferAddress, EFI_SIZE_TO_PAGES (AllocSize)); + } else if (Map->DoubleBuffer) { + ASSERT (Map->Operation =3D=3D MapOperationBusMasterWrite); =20 if (Map->Operation !=3D MapOperationBusMasterWrite) { @@ -335,10 +468,9 @@ DmaAllocateAlignedBuffer ( return EFI_INVALID_PARAMETER; } =20 - if (MemoryType =3D=3D EfiBootServicesData) { - Allocation =3D AllocateAlignedPages (Pages, Alignment); - } else if (MemoryType =3D=3D EfiRuntimeServicesData) { - Allocation =3D AllocateAlignedRuntimePages (Pages, Alignment); + if (MemoryType =3D=3D EfiBootServicesData || + MemoryType =3D=3D EfiRuntimeServicesData) { + Allocation =3D InternalAllocateAlignedPages (MemoryType, Pages, Alignm= ent); } else { return EFI_INVALID_PARAMETER; } @@ -479,6 +611,15 @@ NonCoherentDmaLibConstructor ( { InitializeListHead (&UncachedAllocationList); =20 + // + // Ensure that the combination of DMA addressing offset and limit produc= es + // a sane value. + // + ASSERT (PcdGet64 (PcdDmaDeviceLimit) > PcdGet64 (PcdDmaDeviceOffset)); + + mDmaHostAddressLimit =3D PcdGet64 (PcdDmaDeviceLimit) - + PcdGet64 (PcdDmaDeviceOffset); + // Get the Cpu protocol for later use return gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mC= pu); } diff --git a/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf b/= EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf index 2db751afee91..1a21cfe4ff23 100644 --- a/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf +++ b/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf @@ -38,6 +38,7 @@ [Protocols] =20 [Pcd] gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset + gEmbeddedTokenSpaceGuid.PcdDmaDeviceLimit =20 [Depex] gEfiCpuArchProtocolGuid --=20 2.17.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#51253): https://edk2.groups.io/g/devel/message/51253 Mute This Topic: https://groups.io/mt/61950463/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-