diff mbox series

[1/2] firmware: qcom: tzmem: fix virtual-to-physical address conversion

Message ID 20240730-tzmem-efivars-fix-v1-1-bb78884810b5@linaro.org (mailing list archive)
State Superseded
Headers show
Series firmware: qcom: fix an efivars regression in qseecom | expand

Commit Message

Bartosz Golaszewski July 30, 2024, 3:38 p.m. UTC
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

We currently only correctly convert the virtual address passed by the
caller to qcom_tzmem_to_phys() if it corresponds to the base address of
the chunk. If the user wants to convert some pointer at an offset
relative to that base address, we'll return 0. Let's change the
implementation of qcom_tzmem_to_phys(): iterate over the chunks and try
to call gen_pool_virt_to_phys() just-in-time instead of trying to call
it only once when creating the chunk.

Fixes: 84f5a7b67b61 ("firmware: qcom: add a dedicated TrustZone buffer allocator")
Reported-by: Johan Hovold <johan+linaro@kernel.org>
Closes: https://lore.kernel.org/lkml/20240729095542.21097-1-johan+linaro@kernel.org/
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/firmware/qcom/qcom_tzmem.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

Comments

Andrew Halaney July 30, 2024, 5:20 p.m. UTC | #1
On Tue, Jul 30, 2024 at 05:38:48PM GMT, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> 
> We currently only correctly convert the virtual address passed by the
> caller to qcom_tzmem_to_phys() if it corresponds to the base address of
> the chunk. If the user wants to convert some pointer at an offset
> relative to that base address, we'll return 0. Let's change the
> implementation of qcom_tzmem_to_phys(): iterate over the chunks and try
> to call gen_pool_virt_to_phys() just-in-time instead of trying to call
> it only once when creating the chunk.
> 
> Fixes: 84f5a7b67b61 ("firmware: qcom: add a dedicated TrustZone buffer allocator")
> Reported-by: Johan Hovold <johan+linaro@kernel.org>
> Closes: https://lore.kernel.org/lkml/20240729095542.21097-1-johan+linaro@kernel.org/
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> ---
>  drivers/firmware/qcom/qcom_tzmem.c | 21 +++++++++++++++------
>  1 file changed, 15 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/firmware/qcom/qcom_tzmem.c b/drivers/firmware/qcom/qcom_tzmem.c
> index 17948cfc82e7..1294233a4785 100644
> --- a/drivers/firmware/qcom/qcom_tzmem.c
> +++ b/drivers/firmware/qcom/qcom_tzmem.c
> @@ -40,7 +40,6 @@ struct qcom_tzmem_pool {
>  };
>  
>  struct qcom_tzmem_chunk {
> -	phys_addr_t paddr;
>  	size_t size;
>  	struct qcom_tzmem_pool *owner;
>  };
> @@ -385,7 +384,6 @@ void *qcom_tzmem_alloc(struct qcom_tzmem_pool *pool, size_t size, gfp_t gfp)
>  		return NULL;
>  	}
>  
> -	chunk->paddr = gen_pool_virt_to_phys(pool->genpool, vaddr);
>  	chunk->size = size;
>  	chunk->owner = pool;
>  
> @@ -442,14 +440,25 @@ EXPORT_SYMBOL_GPL(qcom_tzmem_free);
>  phys_addr_t qcom_tzmem_to_phys(void *vaddr)

We should update the kerneldoc here, it currently says:

    /**
     * qcom_tzmem_to_phys() - Map the virtual address of a TZ buffer to physical.
     * @vaddr: Virtual address of the buffer allocated from a TZ memory pool.
     *
     * Can be used in any context. The address must have been returned by a call
     * to qcom_tzmem_alloc().
     *
     * Returns: Physical address of the buffer.
     */
    phys_addr_t qcom_tzmem_to_phys(void *vaddr)

"The address must have been returned by a call to qcom_tzmem_alloc()" is
no longer a strict requirement, it can be within the buffer now.

Otherwise, I believe this should fix the problem you and Johan
highlighted and looks ok to me, thanks for the fix.

Acked-by: Andrew Halaney <ahalaney@redhat.com>
diff mbox series

Patch

diff --git a/drivers/firmware/qcom/qcom_tzmem.c b/drivers/firmware/qcom/qcom_tzmem.c
index 17948cfc82e7..1294233a4785 100644
--- a/drivers/firmware/qcom/qcom_tzmem.c
+++ b/drivers/firmware/qcom/qcom_tzmem.c
@@ -40,7 +40,6 @@  struct qcom_tzmem_pool {
 };
 
 struct qcom_tzmem_chunk {
-	phys_addr_t paddr;
 	size_t size;
 	struct qcom_tzmem_pool *owner;
 };
@@ -385,7 +384,6 @@  void *qcom_tzmem_alloc(struct qcom_tzmem_pool *pool, size_t size, gfp_t gfp)
 		return NULL;
 	}
 
-	chunk->paddr = gen_pool_virt_to_phys(pool->genpool, vaddr);
 	chunk->size = size;
 	chunk->owner = pool;
 
@@ -442,14 +440,25 @@  EXPORT_SYMBOL_GPL(qcom_tzmem_free);
 phys_addr_t qcom_tzmem_to_phys(void *vaddr)
 {
 	struct qcom_tzmem_chunk *chunk;
+	struct radix_tree_iter iter;
+	void __rcu **slot;
+	phys_addr_t ret;
 
 	guard(spinlock_irqsave)(&qcom_tzmem_chunks_lock);
 
-	chunk = radix_tree_lookup(&qcom_tzmem_chunks, (unsigned long)vaddr);
-	if (!chunk)
-		return 0;
+	radix_tree_for_each_slot(slot, &qcom_tzmem_chunks, &iter, 0) {
+		chunk = radix_tree_deref_slot_protected(slot,
+						&qcom_tzmem_chunks_lock);
 
-	return chunk->paddr;
+		ret = gen_pool_virt_to_phys(chunk->owner->genpool,
+					    (unsigned long)vaddr);
+		if (ret == -1)
+			continue;
+
+		return ret;
+	}
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(qcom_tzmem_to_phys);