diff mbox series

[XEN,5/6] xen/arm: ffa: separate rxtx buffer routines

Message ID 20240325093904.3466092-6-jens.wiklander@linaro.org (mailing list archive)
State New
Headers show
Series FF-A mediator reorganisation | expand

Commit Message

Jens Wiklander March 25, 2024, 9:39 a.m. UTC
Move rxtx buffer routines into a spearate file for easier navigation in
the source code.

Add ffa_rxtx_init(), ffa_rxtx_destroy(), and ffa_rxtx_domain_destroy() to
handle the ffa_rxtx internal things on initialization and teardown.

Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
---
 xen/arch/arm/tee/Makefile      |   1 +
 xen/arch/arm/tee/ffa.c         | 174 +-------------------------
 xen/arch/arm/tee/ffa_private.h |   7 ++
 xen/arch/arm/tee/ffa_rxtx.c    | 216 +++++++++++++++++++++++++++++++++
 4 files changed, 229 insertions(+), 169 deletions(-)
 create mode 100644 xen/arch/arm/tee/ffa_rxtx.c

Comments

Bertrand Marquis March 27, 2024, 1:43 p.m. UTC | #1
Hi Jens,

> On 25 Mar 2024, at 10:39, Jens Wiklander <jens.wiklander@linaro.org> wrote:
> 
> Move rxtx buffer routines into a spearate file for easier navigation in
> the source code.
> 
> Add ffa_rxtx_init(), ffa_rxtx_destroy(), and ffa_rxtx_domain_destroy() to
> handle the ffa_rxtx internal things on initialization and teardown.
> 
> Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>

Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com>

Cheers
Bertrand

> ---
> xen/arch/arm/tee/Makefile      |   1 +
> xen/arch/arm/tee/ffa.c         | 174 +-------------------------
> xen/arch/arm/tee/ffa_private.h |   7 ++
> xen/arch/arm/tee/ffa_rxtx.c    | 216 +++++++++++++++++++++++++++++++++
> 4 files changed, 229 insertions(+), 169 deletions(-)
> create mode 100644 xen/arch/arm/tee/ffa_rxtx.c
> 
> diff --git a/xen/arch/arm/tee/Makefile b/xen/arch/arm/tee/Makefile
> index be644fba8055..f0112a2f922d 100644
> --- a/xen/arch/arm/tee/Makefile
> +++ b/xen/arch/arm/tee/Makefile
> @@ -1,5 +1,6 @@
> obj-$(CONFIG_FFA) += ffa.o
> obj-$(CONFIG_FFA) += ffa_shm.o
> obj-$(CONFIG_FFA) += ffa_partinfo.o
> +obj-$(CONFIG_FFA) += ffa_rxtx.o
> obj-y += tee.o
> obj-$(CONFIG_OPTEE) += optee.o
> diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
> index 7a2803881420..4f7775b8c890 100644
> --- a/xen/arch/arm/tee/ffa.c
> +++ b/xen/arch/arm/tee/ffa.c
> @@ -65,26 +65,6 @@
> 
> #include "ffa_private.h"
> 
> -/*
> - * Structs below ending with _1_0 are defined in FF-A-1.0-REL and
> - * structs ending with _1_1 are defined in FF-A-1.1-REL0.
> - */
> -
> -/* Endpoint RX/TX descriptor */
> -struct ffa_endpoint_rxtx_descriptor_1_0 {
> -    uint16_t sender_id;
> -    uint16_t reserved;
> -    uint32_t rx_range_count;
> -    uint32_t tx_range_count;
> -};
> -
> -struct ffa_endpoint_rxtx_descriptor_1_1 {
> -    uint16_t sender_id;
> -    uint16_t reserved;
> -    uint32_t rx_region_offs;
> -    uint32_t tx_region_offs;
> -};
> -
> /* Negotiated FF-A version to use with the SPMC */
> static uint32_t __ro_after_init ffa_version;
> 
> @@ -145,12 +125,6 @@ static bool check_mandatory_feature(uint32_t id)
>     return !ret;
> }
> 
> -static int32_t ffa_rxtx_map(paddr_t tx_addr, paddr_t rx_addr,
> -                            uint32_t page_count)
> -{
> -    return ffa_simple_call(FFA_RXTX_MAP_64, tx_addr, rx_addr, page_count, 0);
> -}
> -
> static void handle_version(struct cpu_user_regs *regs)
> {
>     struct domain *d = current->domain;
> @@ -166,127 +140,6 @@ static void handle_version(struct cpu_user_regs *regs)
>     ffa_set_regs(regs, vers, 0, 0, 0, 0, 0, 0, 0);
> }
> 
> -static uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr,
> -    register_t rx_addr, uint32_t page_count)
> -{
> -    uint32_t ret = FFA_RET_INVALID_PARAMETERS;
> -    struct domain *d = current->domain;
> -    struct ffa_ctx *ctx = d->arch.tee;
> -    struct page_info *tx_pg;
> -    struct page_info *rx_pg;
> -    p2m_type_t t;
> -    void *rx;
> -    void *tx;
> -
> -    if ( !smccc_is_conv_64(fid) )
> -    {
> -        /*
> -         * Calls using the 32-bit calling convention must ignore the upper
> -         * 32 bits in the argument registers.
> -         */
> -        tx_addr &= UINT32_MAX;
> -        rx_addr &= UINT32_MAX;
> -    }
> -
> -    if ( page_count > FFA_MAX_RXTX_PAGE_COUNT )
> -    {
> -        printk(XENLOG_ERR "ffa: RXTX_MAP: error: %u pages requested (limit %u)\n",
> -               page_count, FFA_MAX_RXTX_PAGE_COUNT);
> -        return FFA_RET_INVALID_PARAMETERS;
> -    }
> -
> -    /* Already mapped */
> -    if ( ctx->rx )
> -        return FFA_RET_DENIED;
> -
> -    tx_pg = get_page_from_gfn(d, gfn_x(gaddr_to_gfn(tx_addr)), &t, P2M_ALLOC);
> -    if ( !tx_pg )
> -        return FFA_RET_INVALID_PARAMETERS;
> -
> -    /* Only normal RW RAM for now */
> -    if ( t != p2m_ram_rw )
> -        goto err_put_tx_pg;
> -
> -    rx_pg = get_page_from_gfn(d, gfn_x(gaddr_to_gfn(rx_addr)), &t, P2M_ALLOC);
> -    if ( !tx_pg )
> -        goto err_put_tx_pg;
> -
> -    /* Only normal RW RAM for now */
> -    if ( t != p2m_ram_rw )
> -        goto err_put_rx_pg;
> -
> -    tx = __map_domain_page_global(tx_pg);
> -    if ( !tx )
> -        goto err_put_rx_pg;
> -
> -    rx = __map_domain_page_global(rx_pg);
> -    if ( !rx )
> -        goto err_unmap_tx;
> -
> -    ctx->rx = rx;
> -    ctx->tx = tx;
> -    ctx->rx_pg = rx_pg;
> -    ctx->tx_pg = tx_pg;
> -    ctx->page_count = page_count;
> -    ctx->rx_is_free = true;
> -    return FFA_RET_OK;
> -
> -err_unmap_tx:
> -    unmap_domain_page_global(tx);
> -err_put_rx_pg:
> -    put_page(rx_pg);
> -err_put_tx_pg:
> -    put_page(tx_pg);
> -
> -    return ret;
> -}
> -
> -static void rxtx_unmap(struct ffa_ctx *ctx)
> -{
> -    unmap_domain_page_global(ctx->rx);
> -    unmap_domain_page_global(ctx->tx);
> -    put_page(ctx->rx_pg);
> -    put_page(ctx->tx_pg);
> -    ctx->rx = NULL;
> -    ctx->tx = NULL;
> -    ctx->rx_pg = NULL;
> -    ctx->tx_pg = NULL;
> -    ctx->page_count = 0;
> -    ctx->rx_is_free = false;
> -}
> -
> -static uint32_t ffa_handle_rxtx_unmap(void)
> -{
> -    struct domain *d = current->domain;
> -    struct ffa_ctx *ctx = d->arch.tee;
> -
> -    if ( !ctx->rx )
> -        return FFA_RET_INVALID_PARAMETERS;
> -
> -    rxtx_unmap(ctx);
> -
> -    return FFA_RET_OK;
> -}
> -
> -static int32_t ffa_handle_rx_release(void)
> -{
> -    int32_t ret = FFA_RET_DENIED;
> -    struct domain *d = current->domain;
> -    struct ffa_ctx *ctx = d->arch.tee;
> -
> -    if ( !spin_trylock(&ctx->rx_lock) )
> -        return FFA_RET_BUSY;
> -
> -    if ( !ctx->page_count || ctx->rx_is_free )
> -        goto out;
> -    ret = FFA_RET_OK;
> -    ctx->rx_is_free = true;
> -out:
> -    spin_unlock(&ctx->rx_lock);
> -
> -    return ret;
> -}
> -
> static void handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid)
> {
>     struct arm_smccc_1_2_regs arg = { .a0 = fid, };
> @@ -522,8 +375,7 @@ static int ffa_domain_teardown(struct domain *d)
>     if ( !ctx )
>         return 0;
> 
> -    if ( ctx->rx )
> -        rxtx_unmap(ctx);
> +    ffa_rxtx_domain_destroy(d);
> 
>     ffa_domain_teardown_continue(ctx, true /* first_time */);
> 
> @@ -538,7 +390,6 @@ static int ffa_relinquish_resources(struct domain *d)
> static bool ffa_probe(void)
> {
>     uint32_t vers;
> -    int e;
>     unsigned int major_vers;
>     unsigned int minor_vers;
> 
> @@ -596,36 +447,21 @@ static bool ffa_probe(void)
>          !check_mandatory_feature(FFA_MSG_SEND_DIRECT_REQ_32) )
>         return false;
> 
> -    ffa_rx = alloc_xenheap_pages(get_order_from_pages(FFA_RXTX_PAGE_COUNT), 0);
> -    if ( !ffa_rx )
> +    if ( !ffa_rxtx_init() )
>         return false;
> 
> -    ffa_tx = alloc_xenheap_pages(get_order_from_pages(FFA_RXTX_PAGE_COUNT), 0);
> -    if ( !ffa_tx )
> -        goto err_free_ffa_rx;
> -
> -    e = ffa_rxtx_map(__pa(ffa_tx), __pa(ffa_rx), FFA_RXTX_PAGE_COUNT);
> -    if ( e )
> -    {
> -        printk(XENLOG_ERR "ffa: Failed to map rxtx: error %d\n", e);
> -        goto err_free_ffa_tx;
> -    }
>     ffa_version = vers;
> 
>     if ( !ffa_partinfo_init() )
> -        goto err_free_ffa_tx;
> +        goto err_rxtx_destroy;
> 
>     INIT_LIST_HEAD(&ffa_teardown_head);
>     init_timer(&ffa_teardown_timer, ffa_teardown_timer_callback, NULL, 0);
> 
>     return true;
> 
> -err_free_ffa_tx:
> -    free_xenheap_pages(ffa_tx, 0);
> -    ffa_tx = NULL;
> -err_free_ffa_rx:
> -    free_xenheap_pages(ffa_rx, 0);
> -    ffa_rx = NULL;
> +err_rxtx_destroy:
> +    ffa_rxtx_destroy();
>     ffa_version = 0;
> 
>     return false;
> diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h
> index 6b32b69cfe90..98236cbf14a3 100644
> --- a/xen/arch/arm/tee/ffa_private.h
> +++ b/xen/arch/arm/tee/ffa_private.h
> @@ -263,6 +263,13 @@ int32_t ffa_handle_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3,
>                                       uint32_t w4, uint32_t w5, uint32_t *count,
>                                       uint32_t *fpi_size);
> 
> +bool ffa_rxtx_init(void);
> +void ffa_rxtx_destroy(void);
> +void ffa_rxtx_domain_destroy(struct domain *d);
> +uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr,
> +     register_t rx_addr, uint32_t page_count);
> +uint32_t ffa_handle_rxtx_unmap(void);
> +int32_t ffa_handle_rx_release(void);
> 
> static inline uint16_t ffa_get_vm_id(const struct domain *d)
> {
> diff --git a/xen/arch/arm/tee/ffa_rxtx.c b/xen/arch/arm/tee/ffa_rxtx.c
> new file mode 100644
> index 000000000000..661764052e67
> --- /dev/null
> +++ b/xen/arch/arm/tee/ffa_rxtx.c
> @@ -0,0 +1,216 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2024  Linaro Limited
> + */
> +
> +#include <xen/const.h>
> +#include <xen/domain_page.h>
> +#include <xen/mm.h>
> +#include <xen/sizes.h>
> +#include <xen/types.h>
> +
> +#include <asm/smccc.h>
> +#include <asm/regs.h>
> +
> +#include "ffa_private.h"
> +
> +/* Endpoint RX/TX descriptor defined in FF-A-1.0-REL */
> +struct ffa_endpoint_rxtx_descriptor_1_0 {
> +    uint16_t sender_id;
> +    uint16_t reserved;
> +    uint32_t rx_range_count;
> +    uint32_t tx_range_count;
> +};
> +
> +/* Endpoint RX/TX descriptor defined in FF-A-1.1-REL0 */
> +struct ffa_endpoint_rxtx_descriptor_1_1 {
> +    uint16_t sender_id;
> +    uint16_t reserved;
> +    uint32_t rx_region_offs;
> +    uint32_t tx_region_offs;
> +};
> +
> +uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr,
> +     register_t rx_addr, uint32_t page_count)
> +{
> +    uint32_t ret = FFA_RET_INVALID_PARAMETERS;
> +    struct domain *d = current->domain;
> +    struct ffa_ctx *ctx = d->arch.tee;
> +    struct page_info *tx_pg;
> +    struct page_info *rx_pg;
> +    p2m_type_t t;
> +    void *rx;
> +    void *tx;
> +
> +    if ( !smccc_is_conv_64(fid) )
> +    {
> +        /*
> +         * Calls using the 32-bit calling convention must ignore the upper
> +         * 32 bits in the argument registers.
> +         */
> +        tx_addr &= UINT32_MAX;
> +        rx_addr &= UINT32_MAX;
> +    }
> +
> +    if ( page_count > FFA_MAX_RXTX_PAGE_COUNT )
> +    {
> +        printk(XENLOG_ERR "ffa: RXTX_MAP: error: %u pages requested (limit %u)\n",
> +               page_count, FFA_MAX_RXTX_PAGE_COUNT);
> +        return FFA_RET_INVALID_PARAMETERS;
> +    }
> +
> +    /* Already mapped */
> +    if ( ctx->rx )
> +        return FFA_RET_DENIED;
> +
> +    tx_pg = get_page_from_gfn(d, gfn_x(gaddr_to_gfn(tx_addr)), &t, P2M_ALLOC);
> +    if ( !tx_pg )
> +        return FFA_RET_INVALID_PARAMETERS;
> +
> +    /* Only normal RW RAM for now */
> +    if ( t != p2m_ram_rw )
> +        goto err_put_tx_pg;
> +
> +    rx_pg = get_page_from_gfn(d, gfn_x(gaddr_to_gfn(rx_addr)), &t, P2M_ALLOC);
> +    if ( !tx_pg )
> +        goto err_put_tx_pg;
> +
> +    /* Only normal RW RAM for now */
> +    if ( t != p2m_ram_rw )
> +        goto err_put_rx_pg;
> +
> +    tx = __map_domain_page_global(tx_pg);
> +    if ( !tx )
> +        goto err_put_rx_pg;
> +
> +    rx = __map_domain_page_global(rx_pg);
> +    if ( !rx )
> +        goto err_unmap_tx;
> +
> +    ctx->rx = rx;
> +    ctx->tx = tx;
> +    ctx->rx_pg = rx_pg;
> +    ctx->tx_pg = tx_pg;
> +    ctx->page_count = page_count;
> +    ctx->rx_is_free = true;
> +    return FFA_RET_OK;
> +
> +err_unmap_tx:
> +    unmap_domain_page_global(tx);
> +err_put_rx_pg:
> +    put_page(rx_pg);
> +err_put_tx_pg:
> +    put_page(tx_pg);
> +
> +    return ret;
> +}
> +
> +static void rxtx_unmap(struct ffa_ctx *ctx)
> +{
> +    unmap_domain_page_global(ctx->rx);
> +    unmap_domain_page_global(ctx->tx);
> +    put_page(ctx->rx_pg);
> +    put_page(ctx->tx_pg);
> +    ctx->rx = NULL;
> +    ctx->tx = NULL;
> +    ctx->rx_pg = NULL;
> +    ctx->tx_pg = NULL;
> +    ctx->page_count = 0;
> +    ctx->rx_is_free = false;
> +}
> +
> +uint32_t ffa_handle_rxtx_unmap(void)
> +{
> +    struct domain *d = current->domain;
> +    struct ffa_ctx *ctx = d->arch.tee;
> +
> +    if ( !ctx->rx )
> +        return FFA_RET_INVALID_PARAMETERS;
> +
> +    rxtx_unmap(ctx);
> +
> +    return FFA_RET_OK;
> +}
> +
> +int32_t ffa_handle_rx_release(void)
> +{
> +    int32_t ret = FFA_RET_DENIED;
> +    struct domain *d = current->domain;
> +    struct ffa_ctx *ctx = d->arch.tee;
> +
> +    if ( !spin_trylock(&ctx->rx_lock) )
> +        return FFA_RET_BUSY;
> +
> +    if ( !ctx->page_count || ctx->rx_is_free )
> +        goto out;
> +    ret = FFA_RET_OK;
> +    ctx->rx_is_free = true;
> +out:
> +    spin_unlock(&ctx->rx_lock);
> +
> +    return ret;
> +}
> +
> +static int32_t ffa_rxtx_map(paddr_t tx_addr, paddr_t rx_addr,
> +                            uint32_t page_count)
> +{
> +    return ffa_simple_call(FFA_RXTX_MAP_64, tx_addr, rx_addr, page_count, 0);
> +}
> +
> +static int32_t ffa_rxtx_unmap(void)
> +{
> +    return ffa_simple_call(FFA_RXTX_UNMAP, 0, 0, 0, 0);
> +}
> +
> +void ffa_rxtx_domain_destroy(struct domain *d)
> +{
> +    struct ffa_ctx *ctx = d->arch.tee;
> +
> +    if ( ctx->rx )
> +        rxtx_unmap(ctx);
> +}
> +
> +void ffa_rxtx_destroy(void)
> +{
> +    bool need_unmap = ffa_tx && ffa_rx;
> +
> +    if ( ffa_tx )
> +    {
> +        free_xenheap_pages(ffa_tx, 0);
> +        ffa_tx = NULL;
> +    }
> +    if ( ffa_rx )
> +    {
> +        free_xenheap_pages(ffa_rx, 0);
> +        ffa_rx = NULL;
> +    }
> +
> +    if ( need_unmap )
> +        ffa_rxtx_unmap();
> +}
> +
> +bool ffa_rxtx_init(void)
> +{
> +    int e;
> +
> +    ffa_rx = alloc_xenheap_pages(get_order_from_pages(FFA_RXTX_PAGE_COUNT), 0);
> +    if ( !ffa_rx )
> +        return false;
> +
> +    ffa_tx = alloc_xenheap_pages(get_order_from_pages(FFA_RXTX_PAGE_COUNT), 0);
> +    if ( !ffa_tx )
> +        goto err;
> +
> +    e = ffa_rxtx_map(__pa(ffa_tx), __pa(ffa_rx), FFA_RXTX_PAGE_COUNT);
> +    if ( e )
> +    {
> +        printk(XENLOG_ERR "ffa: Failed to map rxtx: error %d\n", e);
> +        goto err;
> +    }
> +    return true;
> +
> +err:
> +    ffa_rxtx_destroy();
> +
> +    return false;
> +}
> -- 
> 2.34.1
>
diff mbox series

Patch

diff --git a/xen/arch/arm/tee/Makefile b/xen/arch/arm/tee/Makefile
index be644fba8055..f0112a2f922d 100644
--- a/xen/arch/arm/tee/Makefile
+++ b/xen/arch/arm/tee/Makefile
@@ -1,5 +1,6 @@ 
 obj-$(CONFIG_FFA) += ffa.o
 obj-$(CONFIG_FFA) += ffa_shm.o
 obj-$(CONFIG_FFA) += ffa_partinfo.o
+obj-$(CONFIG_FFA) += ffa_rxtx.o
 obj-y += tee.o
 obj-$(CONFIG_OPTEE) += optee.o
diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 7a2803881420..4f7775b8c890 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -65,26 +65,6 @@ 
 
 #include "ffa_private.h"
 
-/*
- * Structs below ending with _1_0 are defined in FF-A-1.0-REL and
- * structs ending with _1_1 are defined in FF-A-1.1-REL0.
- */
-
-/* Endpoint RX/TX descriptor */
-struct ffa_endpoint_rxtx_descriptor_1_0 {
-    uint16_t sender_id;
-    uint16_t reserved;
-    uint32_t rx_range_count;
-    uint32_t tx_range_count;
-};
-
-struct ffa_endpoint_rxtx_descriptor_1_1 {
-    uint16_t sender_id;
-    uint16_t reserved;
-    uint32_t rx_region_offs;
-    uint32_t tx_region_offs;
-};
-
 /* Negotiated FF-A version to use with the SPMC */
 static uint32_t __ro_after_init ffa_version;
 
@@ -145,12 +125,6 @@  static bool check_mandatory_feature(uint32_t id)
     return !ret;
 }
 
-static int32_t ffa_rxtx_map(paddr_t tx_addr, paddr_t rx_addr,
-                            uint32_t page_count)
-{
-    return ffa_simple_call(FFA_RXTX_MAP_64, tx_addr, rx_addr, page_count, 0);
-}
-
 static void handle_version(struct cpu_user_regs *regs)
 {
     struct domain *d = current->domain;
@@ -166,127 +140,6 @@  static void handle_version(struct cpu_user_regs *regs)
     ffa_set_regs(regs, vers, 0, 0, 0, 0, 0, 0, 0);
 }
 
-static uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr,
-				    register_t rx_addr, uint32_t page_count)
-{
-    uint32_t ret = FFA_RET_INVALID_PARAMETERS;
-    struct domain *d = current->domain;
-    struct ffa_ctx *ctx = d->arch.tee;
-    struct page_info *tx_pg;
-    struct page_info *rx_pg;
-    p2m_type_t t;
-    void *rx;
-    void *tx;
-
-    if ( !smccc_is_conv_64(fid) )
-    {
-        /*
-         * Calls using the 32-bit calling convention must ignore the upper
-         * 32 bits in the argument registers.
-         */
-        tx_addr &= UINT32_MAX;
-        rx_addr &= UINT32_MAX;
-    }
-
-    if ( page_count > FFA_MAX_RXTX_PAGE_COUNT )
-    {
-        printk(XENLOG_ERR "ffa: RXTX_MAP: error: %u pages requested (limit %u)\n",
-               page_count, FFA_MAX_RXTX_PAGE_COUNT);
-        return FFA_RET_INVALID_PARAMETERS;
-    }
-
-    /* Already mapped */
-    if ( ctx->rx )
-        return FFA_RET_DENIED;
-
-    tx_pg = get_page_from_gfn(d, gfn_x(gaddr_to_gfn(tx_addr)), &t, P2M_ALLOC);
-    if ( !tx_pg )
-        return FFA_RET_INVALID_PARAMETERS;
-
-    /* Only normal RW RAM for now */
-    if ( t != p2m_ram_rw )
-        goto err_put_tx_pg;
-
-    rx_pg = get_page_from_gfn(d, gfn_x(gaddr_to_gfn(rx_addr)), &t, P2M_ALLOC);
-    if ( !tx_pg )
-        goto err_put_tx_pg;
-
-    /* Only normal RW RAM for now */
-    if ( t != p2m_ram_rw )
-        goto err_put_rx_pg;
-
-    tx = __map_domain_page_global(tx_pg);
-    if ( !tx )
-        goto err_put_rx_pg;
-
-    rx = __map_domain_page_global(rx_pg);
-    if ( !rx )
-        goto err_unmap_tx;
-
-    ctx->rx = rx;
-    ctx->tx = tx;
-    ctx->rx_pg = rx_pg;
-    ctx->tx_pg = tx_pg;
-    ctx->page_count = page_count;
-    ctx->rx_is_free = true;
-    return FFA_RET_OK;
-
-err_unmap_tx:
-    unmap_domain_page_global(tx);
-err_put_rx_pg:
-    put_page(rx_pg);
-err_put_tx_pg:
-    put_page(tx_pg);
-
-    return ret;
-}
-
-static void rxtx_unmap(struct ffa_ctx *ctx)
-{
-    unmap_domain_page_global(ctx->rx);
-    unmap_domain_page_global(ctx->tx);
-    put_page(ctx->rx_pg);
-    put_page(ctx->tx_pg);
-    ctx->rx = NULL;
-    ctx->tx = NULL;
-    ctx->rx_pg = NULL;
-    ctx->tx_pg = NULL;
-    ctx->page_count = 0;
-    ctx->rx_is_free = false;
-}
-
-static uint32_t ffa_handle_rxtx_unmap(void)
-{
-    struct domain *d = current->domain;
-    struct ffa_ctx *ctx = d->arch.tee;
-
-    if ( !ctx->rx )
-        return FFA_RET_INVALID_PARAMETERS;
-
-    rxtx_unmap(ctx);
-
-    return FFA_RET_OK;
-}
-
-static int32_t ffa_handle_rx_release(void)
-{
-    int32_t ret = FFA_RET_DENIED;
-    struct domain *d = current->domain;
-    struct ffa_ctx *ctx = d->arch.tee;
-
-    if ( !spin_trylock(&ctx->rx_lock) )
-        return FFA_RET_BUSY;
-
-    if ( !ctx->page_count || ctx->rx_is_free )
-        goto out;
-    ret = FFA_RET_OK;
-    ctx->rx_is_free = true;
-out:
-    spin_unlock(&ctx->rx_lock);
-
-    return ret;
-}
-
 static void handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid)
 {
     struct arm_smccc_1_2_regs arg = { .a0 = fid, };
@@ -522,8 +375,7 @@  static int ffa_domain_teardown(struct domain *d)
     if ( !ctx )
         return 0;
 
-    if ( ctx->rx )
-        rxtx_unmap(ctx);
+    ffa_rxtx_domain_destroy(d);
 
     ffa_domain_teardown_continue(ctx, true /* first_time */);
 
@@ -538,7 +390,6 @@  static int ffa_relinquish_resources(struct domain *d)
 static bool ffa_probe(void)
 {
     uint32_t vers;
-    int e;
     unsigned int major_vers;
     unsigned int minor_vers;
 
@@ -596,36 +447,21 @@  static bool ffa_probe(void)
          !check_mandatory_feature(FFA_MSG_SEND_DIRECT_REQ_32) )
         return false;
 
-    ffa_rx = alloc_xenheap_pages(get_order_from_pages(FFA_RXTX_PAGE_COUNT), 0);
-    if ( !ffa_rx )
+    if ( !ffa_rxtx_init() )
         return false;
 
-    ffa_tx = alloc_xenheap_pages(get_order_from_pages(FFA_RXTX_PAGE_COUNT), 0);
-    if ( !ffa_tx )
-        goto err_free_ffa_rx;
-
-    e = ffa_rxtx_map(__pa(ffa_tx), __pa(ffa_rx), FFA_RXTX_PAGE_COUNT);
-    if ( e )
-    {
-        printk(XENLOG_ERR "ffa: Failed to map rxtx: error %d\n", e);
-        goto err_free_ffa_tx;
-    }
     ffa_version = vers;
 
     if ( !ffa_partinfo_init() )
-        goto err_free_ffa_tx;
+        goto err_rxtx_destroy;
 
     INIT_LIST_HEAD(&ffa_teardown_head);
     init_timer(&ffa_teardown_timer, ffa_teardown_timer_callback, NULL, 0);
 
     return true;
 
-err_free_ffa_tx:
-    free_xenheap_pages(ffa_tx, 0);
-    ffa_tx = NULL;
-err_free_ffa_rx:
-    free_xenheap_pages(ffa_rx, 0);
-    ffa_rx = NULL;
+err_rxtx_destroy:
+    ffa_rxtx_destroy();
     ffa_version = 0;
 
     return false;
diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h
index 6b32b69cfe90..98236cbf14a3 100644
--- a/xen/arch/arm/tee/ffa_private.h
+++ b/xen/arch/arm/tee/ffa_private.h
@@ -263,6 +263,13 @@  int32_t ffa_handle_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3,
                                       uint32_t w4, uint32_t w5, uint32_t *count,
                                       uint32_t *fpi_size);
 
+bool ffa_rxtx_init(void);
+void ffa_rxtx_destroy(void);
+void ffa_rxtx_domain_destroy(struct domain *d);
+uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr,
+			     register_t rx_addr, uint32_t page_count);
+uint32_t ffa_handle_rxtx_unmap(void);
+int32_t ffa_handle_rx_release(void);
 
 static inline uint16_t ffa_get_vm_id(const struct domain *d)
 {
diff --git a/xen/arch/arm/tee/ffa_rxtx.c b/xen/arch/arm/tee/ffa_rxtx.c
new file mode 100644
index 000000000000..661764052e67
--- /dev/null
+++ b/xen/arch/arm/tee/ffa_rxtx.c
@@ -0,0 +1,216 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2024  Linaro Limited
+ */
+
+#include <xen/const.h>
+#include <xen/domain_page.h>
+#include <xen/mm.h>
+#include <xen/sizes.h>
+#include <xen/types.h>
+
+#include <asm/smccc.h>
+#include <asm/regs.h>
+
+#include "ffa_private.h"
+
+/* Endpoint RX/TX descriptor defined in FF-A-1.0-REL */
+struct ffa_endpoint_rxtx_descriptor_1_0 {
+    uint16_t sender_id;
+    uint16_t reserved;
+    uint32_t rx_range_count;
+    uint32_t tx_range_count;
+};
+
+/* Endpoint RX/TX descriptor defined in FF-A-1.1-REL0 */
+struct ffa_endpoint_rxtx_descriptor_1_1 {
+    uint16_t sender_id;
+    uint16_t reserved;
+    uint32_t rx_region_offs;
+    uint32_t tx_region_offs;
+};
+
+uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr,
+			     register_t rx_addr, uint32_t page_count)
+{
+    uint32_t ret = FFA_RET_INVALID_PARAMETERS;
+    struct domain *d = current->domain;
+    struct ffa_ctx *ctx = d->arch.tee;
+    struct page_info *tx_pg;
+    struct page_info *rx_pg;
+    p2m_type_t t;
+    void *rx;
+    void *tx;
+
+    if ( !smccc_is_conv_64(fid) )
+    {
+        /*
+         * Calls using the 32-bit calling convention must ignore the upper
+         * 32 bits in the argument registers.
+         */
+        tx_addr &= UINT32_MAX;
+        rx_addr &= UINT32_MAX;
+    }
+
+    if ( page_count > FFA_MAX_RXTX_PAGE_COUNT )
+    {
+        printk(XENLOG_ERR "ffa: RXTX_MAP: error: %u pages requested (limit %u)\n",
+               page_count, FFA_MAX_RXTX_PAGE_COUNT);
+        return FFA_RET_INVALID_PARAMETERS;
+    }
+
+    /* Already mapped */
+    if ( ctx->rx )
+        return FFA_RET_DENIED;
+
+    tx_pg = get_page_from_gfn(d, gfn_x(gaddr_to_gfn(tx_addr)), &t, P2M_ALLOC);
+    if ( !tx_pg )
+        return FFA_RET_INVALID_PARAMETERS;
+
+    /* Only normal RW RAM for now */
+    if ( t != p2m_ram_rw )
+        goto err_put_tx_pg;
+
+    rx_pg = get_page_from_gfn(d, gfn_x(gaddr_to_gfn(rx_addr)), &t, P2M_ALLOC);
+    if ( !tx_pg )
+        goto err_put_tx_pg;
+
+    /* Only normal RW RAM for now */
+    if ( t != p2m_ram_rw )
+        goto err_put_rx_pg;
+
+    tx = __map_domain_page_global(tx_pg);
+    if ( !tx )
+        goto err_put_rx_pg;
+
+    rx = __map_domain_page_global(rx_pg);
+    if ( !rx )
+        goto err_unmap_tx;
+
+    ctx->rx = rx;
+    ctx->tx = tx;
+    ctx->rx_pg = rx_pg;
+    ctx->tx_pg = tx_pg;
+    ctx->page_count = page_count;
+    ctx->rx_is_free = true;
+    return FFA_RET_OK;
+
+err_unmap_tx:
+    unmap_domain_page_global(tx);
+err_put_rx_pg:
+    put_page(rx_pg);
+err_put_tx_pg:
+    put_page(tx_pg);
+
+    return ret;
+}
+
+static void rxtx_unmap(struct ffa_ctx *ctx)
+{
+    unmap_domain_page_global(ctx->rx);
+    unmap_domain_page_global(ctx->tx);
+    put_page(ctx->rx_pg);
+    put_page(ctx->tx_pg);
+    ctx->rx = NULL;
+    ctx->tx = NULL;
+    ctx->rx_pg = NULL;
+    ctx->tx_pg = NULL;
+    ctx->page_count = 0;
+    ctx->rx_is_free = false;
+}
+
+uint32_t ffa_handle_rxtx_unmap(void)
+{
+    struct domain *d = current->domain;
+    struct ffa_ctx *ctx = d->arch.tee;
+
+    if ( !ctx->rx )
+        return FFA_RET_INVALID_PARAMETERS;
+
+    rxtx_unmap(ctx);
+
+    return FFA_RET_OK;
+}
+
+int32_t ffa_handle_rx_release(void)
+{
+    int32_t ret = FFA_RET_DENIED;
+    struct domain *d = current->domain;
+    struct ffa_ctx *ctx = d->arch.tee;
+
+    if ( !spin_trylock(&ctx->rx_lock) )
+        return FFA_RET_BUSY;
+
+    if ( !ctx->page_count || ctx->rx_is_free )
+        goto out;
+    ret = FFA_RET_OK;
+    ctx->rx_is_free = true;
+out:
+    spin_unlock(&ctx->rx_lock);
+
+    return ret;
+}
+
+static int32_t ffa_rxtx_map(paddr_t tx_addr, paddr_t rx_addr,
+                            uint32_t page_count)
+{
+    return ffa_simple_call(FFA_RXTX_MAP_64, tx_addr, rx_addr, page_count, 0);
+}
+
+static int32_t ffa_rxtx_unmap(void)
+{
+    return ffa_simple_call(FFA_RXTX_UNMAP, 0, 0, 0, 0);
+}
+
+void ffa_rxtx_domain_destroy(struct domain *d)
+{
+    struct ffa_ctx *ctx = d->arch.tee;
+
+    if ( ctx->rx )
+        rxtx_unmap(ctx);
+}
+
+void ffa_rxtx_destroy(void)
+{
+    bool need_unmap = ffa_tx && ffa_rx;
+
+    if ( ffa_tx )
+    {
+        free_xenheap_pages(ffa_tx, 0);
+        ffa_tx = NULL;
+    }
+    if ( ffa_rx )
+    {
+        free_xenheap_pages(ffa_rx, 0);
+        ffa_rx = NULL;
+    }
+
+    if ( need_unmap )
+        ffa_rxtx_unmap();
+}
+
+bool ffa_rxtx_init(void)
+{
+    int e;
+
+    ffa_rx = alloc_xenheap_pages(get_order_from_pages(FFA_RXTX_PAGE_COUNT), 0);
+    if ( !ffa_rx )
+        return false;
+
+    ffa_tx = alloc_xenheap_pages(get_order_from_pages(FFA_RXTX_PAGE_COUNT), 0);
+    if ( !ffa_tx )
+        goto err;
+
+    e = ffa_rxtx_map(__pa(ffa_tx), __pa(ffa_rx), FFA_RXTX_PAGE_COUNT);
+    if ( e )
+    {
+        printk(XENLOG_ERR "ffa: Failed to map rxtx: error %d\n", e);
+        goto err;
+    }
+    return true;
+
+err:
+    ffa_rxtx_destroy();
+
+    return false;
+}