[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [XEN PATCH v3 5/5] xen/arm: ffa: support notification
Hi Jens, > On 26 Apr 2024, at 10:47, Jens Wiklander <jens.wiklander@xxxxxxxxxx> wrote: > > Add support for FF-A notifications, currently limited to an SP (Secure > Partition) sending an asynchronous notification to a guest. > > Guests and Xen itself are made aware of pending notifications with an > interrupt. The interrupt handler retrieves the notifications using the > FF-A ABI and deliver them to their destinations. > > Update ffa_partinfo_domain_init() to return error code like > ffa_notif_domain_init(). > > Signed-off-by: Jens Wiklander <jens.wiklander@xxxxxxxxxx> > --- > v2->v3: > - Add a GUEST_ prefix and move FFA_NOTIF_PEND_INTR_ID and > FFA_SCHEDULE_RECV_INTR_ID to public/arch-arm.h > - Register the Xen SRI handler on each CPU using on_selected_cpus() and > setup_irq() > - Check that the SGI ID retrieved with FFA_FEATURE_SCHEDULE_RECV_INTR > doesn't conflict with static SGI handlers > > v1->v2: > - Addressing review comments > - Change ffa_handle_notification_{bind,unbind,set}() to take struct > cpu_user_regs *regs as argument. > - Update ffa_partinfo_domain_init() and ffa_notif_domain_init() to return > an error code. > - Fixing a bug in handle_features() for FFA_FEATURE_SCHEDULE_RECV_INTR. > --- > xen/arch/arm/irq.c | 2 +- > xen/arch/arm/tee/Makefile | 1 + > xen/arch/arm/tee/ffa.c | 55 ++++- > xen/arch/arm/tee/ffa_notif.c | 378 ++++++++++++++++++++++++++++++++ > xen/arch/arm/tee/ffa_partinfo.c | 9 +- > xen/arch/arm/tee/ffa_private.h | 56 ++++- > xen/include/public/arch-arm.h | 14 ++ > 7 files changed, 507 insertions(+), 8 deletions(-) > create mode 100644 xen/arch/arm/tee/ffa_notif.c > > diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c > index d7306aa64d50..5224898265a5 100644 > --- a/xen/arch/arm/irq.c > +++ b/xen/arch/arm/irq.c > @@ -155,7 +155,7 @@ void __init init_IRQ(void) > { > /* SGIs are always edge-triggered */ > if ( irq < NR_GIC_SGI ) > - local_irqs_type[irq] = DT_IRQ_TYPE_EDGE_RISING; > + local_irqs_type[irq] = IRQ_TYPE_EDGE_RISING; > else > local_irqs_type[irq] = IRQ_TYPE_INVALID; > } > diff --git a/xen/arch/arm/tee/Makefile b/xen/arch/arm/tee/Makefile > index f0112a2f922d..7c0f46f7f446 100644 > --- a/xen/arch/arm/tee/Makefile > +++ b/xen/arch/arm/tee/Makefile > @@ -2,5 +2,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-$(CONFIG_FFA) += ffa_notif.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 5209612963e1..912e905a27bd 100644 > --- a/xen/arch/arm/tee/ffa.c > +++ b/xen/arch/arm/tee/ffa.c > @@ -39,6 +39,9 @@ > * - at most 32 shared memory regions per guest > * o FFA_MSG_SEND_DIRECT_REQ: > * - only supported from a VM to an SP > + * o FFA_NOTIFICATION_*: > + * - only supports global notifications, that is, per vCPU notifications > + * are not supported > * > * There are some large locked sections with ffa_tx_buffer_lock and > * ffa_rx_buffer_lock. Especially the ffa_tx_buffer_lock spinlock used > @@ -194,6 +197,8 @@ out: > > static void handle_features(struct cpu_user_regs *regs) > { > + struct domain *d = current->domain; > + struct ffa_ctx *ctx = d->arch.tee; > uint32_t a1 = get_user_reg(regs, 1); > unsigned int n; > > @@ -240,6 +245,30 @@ static void handle_features(struct cpu_user_regs *regs) > BUILD_BUG_ON(PAGE_SIZE != FFA_PAGE_SIZE); > ffa_set_regs_success(regs, 0, 0); > break; > + case FFA_FEATURE_NOTIF_PEND_INTR: > + if ( ctx->notif.enabled ) > + ffa_set_regs_success(regs, GUEST_FFA_NOTIF_PEND_INTR_ID, 0); > + else > + ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); > + break; > + case FFA_FEATURE_SCHEDULE_RECV_INTR: > + if ( ctx->notif.enabled ) > + ffa_set_regs_success(regs, GUEST_FFA_SCHEDULE_RECV_INTR_ID, 0); > + else > + ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); > + break; > + > + case FFA_NOTIFICATION_BIND: > + case FFA_NOTIFICATION_UNBIND: > + case FFA_NOTIFICATION_GET: > + case FFA_NOTIFICATION_SET: > + case FFA_NOTIFICATION_INFO_GET_32: > + case FFA_NOTIFICATION_INFO_GET_64: > + if ( ctx->notif.enabled ) > + ffa_set_regs_success(regs, 0, 0); > + else > + ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); > + break; > default: > ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); > break; > @@ -305,6 +334,22 @@ static bool ffa_handle_call(struct cpu_user_regs *regs) > get_user_reg(regs, 1)), > get_user_reg(regs, 3)); > break; > + case FFA_NOTIFICATION_BIND: > + e = ffa_handle_notification_bind(regs); > + break; > + case FFA_NOTIFICATION_UNBIND: > + e = ffa_handle_notification_unbind(regs); > + break; > + case FFA_NOTIFICATION_INFO_GET_32: > + case FFA_NOTIFICATION_INFO_GET_64: > + ffa_handle_notification_info_get(regs); > + return true; > + case FFA_NOTIFICATION_GET: > + ffa_handle_notification_get(regs); > + return true; > + case FFA_NOTIFICATION_SET: > + e = ffa_handle_notification_set(regs); > + break; > > default: > gprintk(XENLOG_ERR, "ffa: unhandled fid 0x%x\n", fid); > @@ -322,6 +367,7 @@ static bool ffa_handle_call(struct cpu_user_regs *regs) > static int ffa_domain_init(struct domain *d) > { > struct ffa_ctx *ctx; > + int ret; > > if ( !ffa_version ) > return -ENODEV; > @@ -345,10 +391,11 @@ static int ffa_domain_init(struct domain *d) > * error, so no need for cleanup in this function. > */ > > - if ( !ffa_partinfo_domain_init(d) ) > - return -EIO; > + ret = ffa_partinfo_domain_init(d); > + if ( ret ) > + return ret; > > - return 0; > + return ffa_notif_domain_init(d); > } > > static void ffa_domain_teardown_continue(struct ffa_ctx *ctx, bool first_time) > @@ -423,6 +470,7 @@ static int ffa_domain_teardown(struct domain *d) > return 0; > > ffa_rxtx_domain_destroy(d); > + ffa_notif_domain_destroy(d); > > ffa_domain_teardown_continue(ctx, true /* first_time */); > > @@ -502,6 +550,7 @@ static bool ffa_probe(void) > if ( !ffa_partinfo_init() ) > goto err_rxtx_destroy; > > + ffa_notif_init(); > INIT_LIST_HEAD(&ffa_teardown_head); > init_timer(&ffa_teardown_timer, ffa_teardown_timer_callback, NULL, 0); > > diff --git a/xen/arch/arm/tee/ffa_notif.c b/xen/arch/arm/tee/ffa_notif.c > new file mode 100644 > index 000000000000..6bb0804ee2f8 > --- /dev/null > +++ b/xen/arch/arm/tee/ffa_notif.c > @@ -0,0 +1,378 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * Copyright (C) 2024 Linaro Limited > + */ > + > +#include <xen/const.h> > +#include <xen/list.h> > +#include <xen/spinlock.h> > +#include <xen/types.h> > + > +#include <asm/smccc.h> > +#include <asm/regs.h> > + > +#include "ffa_private.h" > + > +static bool __ro_after_init notif_enabled; > + > +int ffa_handle_notification_bind(struct cpu_user_regs *regs) > +{ > + struct domain *d = current->domain; > + uint32_t src_dst = get_user_reg(regs, 1); > + uint32_t flags = get_user_reg(regs, 2); > + uint32_t bitmap_lo = get_user_reg(regs, 3); > + uint32_t bitmap_hi = get_user_reg(regs, 4); > + > + if ( !notif_enabled ) > + return FFA_RET_NOT_SUPPORTED; > + > + if ( (src_dst & 0xFFFFU) != ffa_get_vm_id(d) ) > + return FFA_RET_INVALID_PARAMETERS; > + > + if ( flags ) /* Only global notifications are supported */ > + return FFA_RET_DENIED; > + > + /* > + * We only support notifications from SP so no need to check the sender > + * endpoint ID, the SPMC will take care of that for us. > + */ > + return ffa_simple_call(FFA_NOTIFICATION_BIND, src_dst, flags, bitmap_hi, > + bitmap_lo); > +} > + > +int ffa_handle_notification_unbind(struct cpu_user_regs *regs) > +{ > + struct domain *d = current->domain; > + uint32_t src_dst = get_user_reg(regs, 1); > + uint32_t bitmap_lo = get_user_reg(regs, 3); > + uint32_t bitmap_hi = get_user_reg(regs, 4); > + > + if ( !notif_enabled ) > + return FFA_RET_NOT_SUPPORTED; > + > + if ( (src_dst & 0xFFFFU) != ffa_get_vm_id(d) ) > + return FFA_RET_INVALID_PARAMETERS; > + > + /* > + * We only support notifications from SP so no need to check the > + * destination endpoint ID, the SPMC will take care of that for us. > + */ > + return ffa_simple_call(FFA_NOTIFICATION_UNBIND, src_dst, 0, bitmap_hi, > + bitmap_lo); > +} > + > +void ffa_handle_notification_info_get(struct cpu_user_regs *regs) > +{ > + struct domain *d = current->domain; > + struct ffa_ctx *ctx = d->arch.tee; > + bool pending_global; > + > + if ( !notif_enabled ) > + { > + ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); > + return; > + } > + > + spin_lock(&ctx->notif.lock); > + pending_global = ctx->notif.secure_pending; > + ctx->notif.secure_pending = false; > + spin_unlock(&ctx->notif.lock); > + > + if ( pending_global ) > + { > + /* A pending global notification for the guest */ > + ffa_set_regs(regs, FFA_SUCCESS_64, 0, > + 1U << FFA_NOTIF_INFO_GET_ID_COUNT_SHIFT, > ffa_get_vm_id(d), > + 0, 0, 0, 0); > + } > + else > + { > + /* Report an error if there where no pending global notification */ > + ffa_set_regs_error(regs, FFA_RET_NO_DATA); > + } > +} > + > +void ffa_handle_notification_get(struct cpu_user_regs *regs) > +{ > + struct domain *d = current->domain; > + uint32_t recv = get_user_reg(regs, 1); > + uint32_t flags = get_user_reg(regs, 2); > + uint32_t w2 = 0; > + uint32_t w3 = 0; > + uint32_t w4 = 0; > + uint32_t w5 = 0; > + uint32_t w6 = 0; > + uint32_t w7 = 0; > + > + if ( !notif_enabled ) > + { > + ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); > + return; > + } > + > + if ( (recv & 0xFFFFU) != ffa_get_vm_id(d) ) > + { > + ffa_set_regs_error(regs, FFA_RET_INVALID_PARAMETERS); > + return; > + } > + > + if ( flags & ( FFA_NOTIF_FLAG_BITMAP_SP | FFA_NOTIF_FLAG_BITMAP_SPM ) ) > + { > + struct arm_smccc_1_2_regs arg = { > + .a0 = FFA_NOTIFICATION_GET, > + .a1 = recv, > + .a2 = flags & ( FFA_NOTIF_FLAG_BITMAP_SP | > + FFA_NOTIF_FLAG_BITMAP_SPM ), > + }; > + struct arm_smccc_1_2_regs resp; > + int32_t e; > + > + arm_smccc_1_2_smc(&arg, &resp); > + e = ffa_get_ret_code(&resp); > + if ( e ) > + { > + ffa_set_regs_error(regs, e); > + return; > + } > + > + if ( flags & FFA_NOTIF_FLAG_BITMAP_SP ) > + { > + w2 = resp.a2; > + w3 = resp.a3; > + } > + > + if ( flags & FFA_NOTIF_FLAG_BITMAP_SPM ) > + w6 = resp.a6; > + } In here you never clean the secure_pending flag but in practice there would be no more pending notification if SP and SPM flags are set so the response to notification_info_get would wrongly say there is something pending. I am not completely sure how this could be handled if both SP and SPM are not set so i would say for now we should at least put a comment in info_get to keep a note of this fact. Do you agree ? > + > + ffa_set_regs(regs, FFA_SUCCESS_32, 0, w2, w3, w4, w5, w6, w7); > +} > + > +int ffa_handle_notification_set(struct cpu_user_regs *regs) > +{ > + struct domain *d = current->domain; > + uint32_t src_dst = get_user_reg(regs, 1); > + uint32_t flags = get_user_reg(regs, 2); > + uint32_t bitmap_lo = get_user_reg(regs, 3); > + uint32_t bitmap_hi = get_user_reg(regs, 4); > + > + if ( !notif_enabled ) > + return FFA_RET_NOT_SUPPORTED; > + > + if ( (src_dst >> 16) != ffa_get_vm_id(d) ) > + return FFA_RET_INVALID_PARAMETERS; > + > + /* Let the SPMC check the destination of the notification */ > + return ffa_simple_call(FFA_NOTIFICATION_SET, src_dst, flags, bitmap_lo, > + bitmap_hi); > +} > + > +/* > + * Extract a 16-bit ID (index n) from the successful return value from > + * FFA_NOTIFICATION_INFO_GET_64 or FFA_NOTIFICATION_INFO_GET_32. IDs are > + * returned in registers 3 to 7 with four IDs per register for 64-bit > + * calling convention and two IDs per register for 32-bit calling > + * convention. > + */ > +static uint16_t get_id_from_resp(struct arm_smccc_1_2_regs *resp, > + unsigned int n) > +{ > + unsigned int ids_per_reg; > + unsigned int reg_idx; > + unsigned int reg_shift; > + > + if ( smccc_is_conv_64(resp->a0) ) > + ids_per_reg = 4; > + else > + ids_per_reg = 2; > + > + reg_idx = n / ids_per_reg + 3; > + reg_shift = ( n % ids_per_reg ) * 16; > + > + switch ( reg_idx ) > + { > + case 3: > + return resp->a3 >> reg_shift; > + case 4: > + return resp->a4 >> reg_shift; > + case 5: > + return resp->a5 >> reg_shift; > + case 6: > + return resp->a6 >> reg_shift; > + case 7: > + return resp->a7 >> reg_shift; > + default: > + ASSERT(0); /* "Can't happen" */ > + return 0; > + } > +} > + > +static void notif_irq_handler(int irq, void *data) > +{ > + const struct arm_smccc_1_2_regs arg = { > + .a0 = FFA_NOTIFICATION_INFO_GET_64, > + }; > + struct arm_smccc_1_2_regs resp; > + unsigned int id_pos; > + unsigned int list_count; > + uint64_t ids_count; > + unsigned int n; > + int32_t res; > + > + do { > + arm_smccc_1_2_smc(&arg, &resp); > + res = ffa_get_ret_code(&resp); > + if ( res ) > + { > + if ( res != FFA_RET_NO_DATA ) > + printk(XENLOG_ERR "ffa: notification info get failed: error > %d\n", > + res); > + return; > + } > + > + ids_count = resp.a2 >> FFA_NOTIF_INFO_GET_ID_LIST_SHIFT; > + list_count = ( resp.a2 >> FFA_NOTIF_INFO_GET_ID_COUNT_SHIFT ) & > + FFA_NOTIF_INFO_GET_ID_COUNT_MASK; > + > + id_pos = 0; > + for ( n = 0; n < list_count; n++ ) > + { > + unsigned int count = ((ids_count >> 2 * n) & 0x3) + 1; > + struct domain *d; > + If a notification is pending for a secure partition at this stage we are not signaling anything so I think this fact should be listed in the limitations to say that we do not signal any secondary scheduler if a notification is pending for a secure partition. > + d = ffa_get_domain_by_vm_id(get_id_from_resp(&resp, id_pos)); > + > + if ( d ) > + { > + struct ffa_ctx *ctx = d->arch.tee; > + > + spin_lock(&ctx->notif.lock); > + ctx->notif.secure_pending = true; > + spin_unlock(&ctx->notif.lock); > + > + /* > + * Since we're only delivering global notification, always > + * deliver to the first vCPU. It doesn't matter which we > + * chose, as long as it's available. > + */ > + vgic_inject_irq(d, d->vcpu[0], GUEST_FFA_NOTIF_PEND_INTR_ID, > + true); > + > + put_domain(d); > + } > + > + id_pos += count; > + } > + > + } while (resp.a2 & FFA_NOTIF_INFO_GET_MORE_FLAG); > +} > + > +static int32_t ffa_notification_bitmap_create(uint16_t vm_id, > + uint32_t vcpu_count) > +{ > + return ffa_simple_call(FFA_NOTIFICATION_BITMAP_CREATE, vm_id, vcpu_count, > + 0, 0); > +} > + > +static int32_t ffa_notification_bitmap_destroy(uint16_t vm_id) > +{ > + return ffa_simple_call(FFA_NOTIFICATION_BITMAP_DESTROY, vm_id, 0, 0, 0); > +} > + > +struct notif_irq_info { > + unsigned int irq; > + int ret; > + struct irqaction *action; > +}; > + > +static void notif_irq_enable(void *info) > +{ > + struct notif_irq_info *irq_info = info; > + > + irq_info->ret = setup_irq(irq_info->irq, 0, irq_info->action); > + if ( irq_info->ret ) > + printk(XENLOG_ERR "ffa: request_irq irq %u failed: error %d\n", > + irq_info->irq, irq_info->ret); > +} > + > +void ffa_notif_init(void) > +{ > + const struct arm_smccc_1_2_regs arg = { > + .a0 = FFA_FEATURES, > + .a1 = FFA_FEATURE_SCHEDULE_RECV_INTR, > + }; > + struct notif_irq_info irq_info = { }; > + struct arm_smccc_1_2_regs resp; > + unsigned int cpu; > + > + arm_smccc_1_2_smc(&arg, &resp); > + if ( resp.a0 != FFA_SUCCESS_32 ) > + return; > + > + irq_info.irq = resp.a2; > + if ( irq_info.irq < GIC_SGI_STATIC_MAX || irq_info.irq >= NR_GIC_SGI ) > + { > + printk(XENLOG_ERR "ffa: notification initialization failed: > conflicting SGI %u\n", > + irq_info.irq); > + return; > + } > + > + /* > + * SGIs are per-CPU so we must enable the IRQ on each CPU. We use an > + * IPI to call notif_irq_enable() on each CPU including the current > + * CPU. The struct irqaction is preallocated since we can't allocate > + * memory while in interrupt context. > + */ > + for_each_online_cpu(cpu) > + { > + irq_info.action = xmalloc(struct irqaction); You allocate one action per cpu but you have only one action pointer in your structure which means you will overload the previously allocated one and lose track. You should have a table of actions in your structure instead unless one action is enough and can be reused on all cpus and in this case you should move out of your loop the allocation part. > + if ( !irq_info.action ) > + { > + irq_info.ret = -ENOMEM; > + break; > + } > + > + *irq_info.action = (struct irqaction){ > + .handler = notif_irq_handler, > + .name = "FF-A notif", > + .free_on_release = 1, > + }; > + > + on_selected_cpus(cpumask_of(cpu), notif_irq_enable, &irq_info, 1); > + if ( irq_info.ret ) > + { > + XFREE(irq_info.action); > + break; > + } > + } > + > + notif_enabled = !irq_info.ret; > +} > + > +int ffa_notif_domain_init(struct domain *d) > +{ > + struct ffa_ctx *ctx = d->arch.tee; > + int32_t res; > + > + if ( !notif_enabled ) > + return 0; > + > + res = ffa_notification_bitmap_create(ffa_get_vm_id(d), d->max_vcpus); > + if ( res ) > + return -ENOMEM; > + > + ctx->notif.enabled = true; > + > + return 0; > +} > + > +void ffa_notif_domain_destroy(struct domain *d) > +{ > + struct ffa_ctx *ctx = d->arch.tee; > + > + if ( ctx->notif.enabled ) > + { > + ffa_notification_bitmap_destroy(ffa_get_vm_id(d)); > + ctx->notif.enabled = false; > + } > +} > diff --git a/xen/arch/arm/tee/ffa_partinfo.c b/xen/arch/arm/tee/ffa_partinfo.c > index dc1059584828..93a03c6bc672 100644 > --- a/xen/arch/arm/tee/ffa_partinfo.c > +++ b/xen/arch/arm/tee/ffa_partinfo.c > @@ -306,7 +306,7 @@ static void vm_destroy_bitmap_init(struct ffa_ctx *ctx, > } > } > > -bool ffa_partinfo_domain_init(struct domain *d) > +int ffa_partinfo_domain_init(struct domain *d) > { > unsigned int count = BITS_TO_LONGS(subscr_vm_destroyed_count); > struct ffa_ctx *ctx = d->arch.tee; > @@ -315,7 +315,7 @@ bool ffa_partinfo_domain_init(struct domain *d) > > ctx->vm_destroy_bitmap = xzalloc_array(unsigned long, count); > if ( !ctx->vm_destroy_bitmap ) > - return false; > + return -ENOMEM; > > for ( n = 0; n < subscr_vm_created_count; n++ ) > { > @@ -330,7 +330,10 @@ bool ffa_partinfo_domain_init(struct domain *d) > } > vm_destroy_bitmap_init(ctx, n); > > - return n == subscr_vm_created_count; > + if ( n != subscr_vm_created_count ) > + return -EIO; > + > + return 0; > } > > bool ffa_partinfo_domain_destroy(struct domain *d) > diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h > index 98236cbf14a3..a59c9887774b 100644 > --- a/xen/arch/arm/tee/ffa_private.h > +++ b/xen/arch/arm/tee/ffa_private.h > @@ -25,6 +25,7 @@ > #define FFA_RET_DENIED -6 > #define FFA_RET_RETRY -7 > #define FFA_RET_ABORTED -8 > +#define FFA_RET_NO_DATA -9 > > /* FFA_VERSION helpers */ > #define FFA_VERSION_MAJOR_SHIFT 16U > @@ -175,6 +176,21 @@ > */ > #define FFA_PARTITION_INFO_GET_COUNT_FLAG BIT(0, U) > > +/* Flags used in calls to FFA_NOTIFICATION_GET interface */ > +#define FFA_NOTIF_FLAG_BITMAP_SP BIT(0, U) > +#define FFA_NOTIF_FLAG_BITMAP_VM BIT(1, U) > +#define FFA_NOTIF_FLAG_BITMAP_SPM BIT(2, U) > +#define FFA_NOTIF_FLAG_BITMAP_HYP BIT(3, U) > + > +#define FFA_NOTIF_INFO_GET_MORE_FLAG BIT(0, U) > +#define FFA_NOTIF_INFO_GET_ID_LIST_SHIFT 12 > +#define FFA_NOTIF_INFO_GET_ID_COUNT_SHIFT 7 > +#define FFA_NOTIF_INFO_GET_ID_COUNT_MASK 0x1F > + > +/* Feature IDs used with FFA_FEATURES */ > +#define FFA_FEATURE_NOTIF_PEND_INTR 0x1U > +#define FFA_FEATURE_SCHEDULE_RECV_INTR 0x2U > + > /* Function IDs */ > #define FFA_ERROR 0x84000060U > #define FFA_SUCCESS_32 0x84000061U > @@ -213,6 +229,27 @@ > #define FFA_MEM_FRAG_TX 0x8400007BU > #define FFA_MSG_SEND 0x8400006EU > #define FFA_MSG_POLL 0x8400006AU > +#define FFA_NOTIFICATION_BITMAP_CREATE 0x8400007DU > +#define FFA_NOTIFICATION_BITMAP_DESTROY 0x8400007EU > +#define FFA_NOTIFICATION_BIND 0x8400007FU > +#define FFA_NOTIFICATION_UNBIND 0x84000080U > +#define FFA_NOTIFICATION_SET 0x84000081U > +#define FFA_NOTIFICATION_GET 0x84000082U > +#define FFA_NOTIFICATION_INFO_GET_32 0x84000083U > +#define FFA_NOTIFICATION_INFO_GET_64 0xC4000083U > + > +struct ffa_ctx_notif { > + bool enabled; > + > + /* Used to serialize access to the rest of this struct */ > + spinlock_t lock; > + > + /* > + * True if domain is reported by FFA_NOTIFICATION_INFO_GET to have > + * pending global notifications. > + */ > + bool secure_pending; > +}; > > struct ffa_ctx { > void *rx; > @@ -228,6 +265,7 @@ struct ffa_ctx { > struct list_head shm_list; > /* Number of allocated shared memory object */ > unsigned int shm_count; > + struct ffa_ctx_notif notif; > /* > * tx_lock is used to serialize access to tx > * rx_lock is used to serialize access to rx > @@ -257,7 +295,7 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs); > int ffa_handle_mem_reclaim(uint64_t handle, uint32_t flags); > > bool ffa_partinfo_init(void); > -bool ffa_partinfo_domain_init(struct domain *d); > +int ffa_partinfo_domain_init(struct domain *d); > bool ffa_partinfo_domain_destroy(struct domain *d); > 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, > @@ -271,12 +309,28 @@ uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t > tx_addr, > uint32_t ffa_handle_rxtx_unmap(void); > int32_t ffa_handle_rx_release(void); > > +void ffa_notif_init(void); > +int ffa_notif_domain_init(struct domain *d); > +void ffa_notif_domain_destroy(struct domain *d); > + > +int ffa_handle_notification_bind(struct cpu_user_regs *regs); > +int ffa_handle_notification_unbind(struct cpu_user_regs *regs); > +void ffa_handle_notification_info_get(struct cpu_user_regs *regs); > +void ffa_handle_notification_get(struct cpu_user_regs *regs); > +int ffa_handle_notification_set(struct cpu_user_regs *regs); > + > static inline uint16_t ffa_get_vm_id(const struct domain *d) > { > /* +1 since 0 is reserved for the hypervisor in FF-A */ > return d->domain_id + 1; > } > > +static inline struct domain *ffa_get_domain_by_vm_id(uint16_t vm_id) > +{ > + /* -1 to match ffa_get_vm_id() */ > + return get_domain_by_id(vm_id - 1); > +} > + I think there is a global discussion to have on using get_domain_by_vm_id or rcu_lock_live_remote_domain_by_id to make sure the domain is not dying when we try to do something with it. It does not need to be done here as there are other places to adapt but i wanted to raise the question. I would like to know what you and also other maintainers think here. @Julien/Michal/Stefano ? > static inline void ffa_set_regs(struct cpu_user_regs *regs, register_t v0, > register_t v1, register_t v2, register_t v3, > register_t v4, register_t v5, register_t v6, > diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h > index e167e14f8df9..1eac9802aa53 100644 > --- a/xen/include/public/arch-arm.h > +++ b/xen/include/public/arch-arm.h > @@ -505,6 +505,7 @@ typedef uint64_t xen_callback_t; > #define GUEST_MAX_VCPUS 128 > > /* Interrupts */ > + > #define GUEST_TIMER_VIRT_PPI 27 > #define GUEST_TIMER_PHYS_S_PPI 29 > #define GUEST_TIMER_PHYS_NS_PPI 30 > @@ -515,6 +516,19 @@ typedef uint64_t xen_callback_t; > #define GUEST_VIRTIO_MMIO_SPI_FIRST 33 > #define GUEST_VIRTIO_MMIO_SPI_LAST 43 > > +/* > + * SGI is the preferred delivery mechanism of FF-A pending notifications or > + * schedule recveive interrupt. SGIs 8-15 are normally not used by a guest > + * as they in a non-virtualized system typically are assigned to the secure > + * world. Here we're free to use SGI 8-15 since they are virtual and have > + * nothing to do with the secure world. > + * > + * For partitioning of SGIs see also Arm Base System Architecture v1.0C, > + * https://developer.arm.com/documentation/den0094/ > + */ > +#define GUEST_FFA_NOTIF_PEND_INTR_ID 8 > +#define GUEST_FFA_SCHEDULE_RECV_INTR_ID 9 > + > /* PSCI functions */ > #define PSCI_cpu_suspend 0 > #define PSCI_cpu_off 1 > -- > 2.34.1 > Cheers Bertrand
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |