Re: [XEN PATCH v5 7/7] xen/arm: ffa: support notification

2024-06-07 Thread Jens Wiklander
Hi,

On Wed, Jun 5, 2024 at 12:45 PM Bertrand Marquis
 wrote:
>
> Hi,
>
> > On 4 Jun 2024, at 12:24, Julien Grall  wrote:
> >
> >
> >
> > On 03/06/2024 10:50, Jens Wiklander wrote:
> >> Hi Julien,
> >
> > Hi Jens,
> >
> >
> >> On Mon, Jun 3, 2024 at 11:12 AM Julien Grall  wrote:
> >>>
> >>> Hi Jens,
> >>>
> >>> On 03/06/2024 10:01, Jens Wiklander wrote:
> >>>> On Fri, May 31, 2024 at 4:28 PM Bertrand Marquis
> >>>>  wrote:
> >>>>>
> >>>>> Hi Jens,
> >>>>>
> >>>>>> On 29 May 2024, at 09:25, Jens Wiklander  
> >>>>>> 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 triggers a tasklet to retrieve 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 
> >>>>>> ---
> >>>>>> v4->v5:
> >>>>>> - Move the freeing of d->arch.tee to the new TEE mediator 
> >>>>>> free_domain_ctx
> >>>>>>   callback to make the context accessible during 
> >>>>>> rcu_lock_domain_by_id()
> >>>>>>   from a tasklet
> >>>>>> - Initialize interrupt handlers for secondary CPUs from the new TEE 
> >>>>>> mediator
> >>>>>>   init_interrupt() callback
> >>>>>> - Restore the ffa_probe() from v3, that is, remove the
> >>>>>>   presmp_initcall(ffa_init) approach and use ffa_probe() as usual now 
> >>>>>> that we
> >>>>>>   have the init_interrupt callback.
> >>>>>> - A tasklet is added to handle the Schedule Receiver interrupt. The 
> >>>>>> tasklet
> >>>>>>   finds each relevant domain with rcu_lock_domain_by_id() which now is 
> >>>>>> enough
> >>>>>>   to guarantee that the FF-A context can be accessed.
> >>>>>> - The notification interrupt handler only schedules the notification
> >>>>>>   tasklet mentioned above
> >>>>>>
> >>>>>> v3->v4:
> >>>>>> - Add another note on FF-A limitations
> >>>>>> - Clear secure_pending in ffa_handle_notification_get() if both SP and 
> >>>>>> SPM
> >>>>>>   bitmaps are retrieved
> >>>>>> - ASSERT that ffa_rcu_lock_domain_by_vm_id() isn't passed the vm_id 
> >>>>>> FF-A
> >>>>>>   uses for Xen itself
> >>>>>> - Replace the get_domain_by_id() call done via 
> >>>>>> ffa_get_domain_by_vm_id() in
> >>>>>>   notif_irq_handler() with a call to 
> >>>>>> rcu_lock_live_remote_domain_by_id() via
> >>>>>>   ffa_rcu_lock_domain_by_vm_id()
> >>>>>> - Remove spinlock in struct ffa_ctx_notif and use atomic functions as 
> >>>>>> needed
> >>>>>>   to access and update the secure_pending field
> >>>>>> - In notif_irq_handler(), look for the first online CPU instead of 
> >>>>>> assuming
> >>>>>>   that the first CPU is online
> >>>>>> - Initialize FF-A via presmp_initcall() before the other CPUs are 
> >>>>>> online,
> >>>>>>   use register_cpu_notifier() to install the interrupt handler
> >>>>>>   notif_irq_handler()
> >>>>>> - Update commit message to reflect recent updates
> >>>>>>
> >>>>>> 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() an

Re: [XEN PATCH v5 7/7] xen/arm: ffa: support notification

2024-06-03 Thread Jens Wiklander
Hi Julien,

On Mon, Jun 3, 2024 at 11:12 AM Julien Grall  wrote:
>
> Hi Jens,
>
> On 03/06/2024 10:01, Jens Wiklander wrote:
> > On Fri, May 31, 2024 at 4:28 PM Bertrand Marquis
> >  wrote:
> >>
> >> Hi Jens,
> >>
> >>> On 29 May 2024, at 09:25, Jens Wiklander  
> >>> 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 triggers a tasklet to retrieve 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 
> >>> ---
> >>> v4->v5:
> >>> - Move the freeing of d->arch.tee to the new TEE mediator free_domain_ctx
> >>>   callback to make the context accessible during rcu_lock_domain_by_id()
> >>>   from a tasklet
> >>> - Initialize interrupt handlers for secondary CPUs from the new TEE 
> >>> mediator
> >>>   init_interrupt() callback
> >>> - Restore the ffa_probe() from v3, that is, remove the
> >>>   presmp_initcall(ffa_init) approach and use ffa_probe() as usual now 
> >>> that we
> >>>   have the init_interrupt callback.
> >>> - A tasklet is added to handle the Schedule Receiver interrupt. The 
> >>> tasklet
> >>>   finds each relevant domain with rcu_lock_domain_by_id() which now is 
> >>> enough
> >>>   to guarantee that the FF-A context can be accessed.
> >>> - The notification interrupt handler only schedules the notification
> >>>   tasklet mentioned above
> >>>
> >>> v3->v4:
> >>> - Add another note on FF-A limitations
> >>> - Clear secure_pending in ffa_handle_notification_get() if both SP and SPM
> >>>   bitmaps are retrieved
> >>> - ASSERT that ffa_rcu_lock_domain_by_vm_id() isn't passed the vm_id FF-A
> >>>   uses for Xen itself
> >>> - Replace the get_domain_by_id() call done via ffa_get_domain_by_vm_id() 
> >>> in
> >>>   notif_irq_handler() with a call to rcu_lock_live_remote_domain_by_id() 
> >>> via
> >>>   ffa_rcu_lock_domain_by_vm_id()
> >>> - Remove spinlock in struct ffa_ctx_notif and use atomic functions as 
> >>> needed
> >>>   to access and update the secure_pending field
> >>> - In notif_irq_handler(), look for the first online CPU instead of 
> >>> assuming
> >>>   that the first CPU is online
> >>> - Initialize FF-A via presmp_initcall() before the other CPUs are online,
> >>>   use register_cpu_notifier() to install the interrupt handler
> >>>   notif_irq_handler()
> >>> - Update commit message to reflect recent updates
> >>>
> >>> 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/tee/Makefile   |   1 +
> >>> xen/arch/arm/tee/ffa.c  |  72 +-
> >>> xen/arch/arm/tee/ffa_notif.c| 409 
> >>> xen/arch/arm/tee/ffa_partinfo.c |   9 +-
> >>> xen/arch/arm/tee/ffa_private.h  |  56 -
> >>> xen/arch/arm/tee/tee.c  |   2 +-
> >>> xen/include/public/arch-arm.h   |  14 ++
> >>> 7 files changed, 548 insertions(+), 15 deletions(-)
> >>> create mode 100644 xen/arch/arm/tee/ffa_notif.c
> >>>
> > [...]
> >>>
> >>&g

Re: [XEN PATCH v5 7/7] xen/arm: ffa: support notification

2024-06-03 Thread Jens Wiklander
Hi Bertrand,

On Fri, May 31, 2024 at 4:28 PM Bertrand Marquis
 wrote:
>
> Hi Jens,
>
> > On 29 May 2024, at 09:25, Jens Wiklander  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 triggers a tasklet to retrieve 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 
> > ---
> > v4->v5:
> > - Move the freeing of d->arch.tee to the new TEE mediator free_domain_ctx
> >  callback to make the context accessible during rcu_lock_domain_by_id()
> >  from a tasklet
> > - Initialize interrupt handlers for secondary CPUs from the new TEE mediator
> >  init_interrupt() callback
> > - Restore the ffa_probe() from v3, that is, remove the
> >  presmp_initcall(ffa_init) approach and use ffa_probe() as usual now that we
> >  have the init_interrupt callback.
> > - A tasklet is added to handle the Schedule Receiver interrupt. The tasklet
> >  finds each relevant domain with rcu_lock_domain_by_id() which now is enough
> >  to guarantee that the FF-A context can be accessed.
> > - The notification interrupt handler only schedules the notification
> >  tasklet mentioned above
> >
> > v3->v4:
> > - Add another note on FF-A limitations
> > - Clear secure_pending in ffa_handle_notification_get() if both SP and SPM
> >  bitmaps are retrieved
> > - ASSERT that ffa_rcu_lock_domain_by_vm_id() isn't passed the vm_id FF-A
> >  uses for Xen itself
> > - Replace the get_domain_by_id() call done via ffa_get_domain_by_vm_id() in
> >  notif_irq_handler() with a call to rcu_lock_live_remote_domain_by_id() via
> >  ffa_rcu_lock_domain_by_vm_id()
> > - Remove spinlock in struct ffa_ctx_notif and use atomic functions as needed
> >  to access and update the secure_pending field
> > - In notif_irq_handler(), look for the first online CPU instead of assuming
> >  that the first CPU is online
> > - Initialize FF-A via presmp_initcall() before the other CPUs are online,
> >  use register_cpu_notifier() to install the interrupt handler
> >  notif_irq_handler()
> > - Update commit message to reflect recent updates
> >
> > 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/tee/Makefile   |   1 +
> > xen/arch/arm/tee/ffa.c  |  72 +-
> > xen/arch/arm/tee/ffa_notif.c| 409 
> > xen/arch/arm/tee/ffa_partinfo.c |   9 +-
> > xen/arch/arm/tee/ffa_private.h  |  56 -
> > xen/arch/arm/tee/tee.c  |   2 +-
> > xen/include/public/arch-arm.h   |  14 ++
> > 7 files changed, 548 insertions(+), 15 deletions(-)
> > create mode 100644 xen/arch/arm/tee/ffa_notif.c
> >
[...]
> >
> > @@ -517,8 +567,10 @@ err_rxtx_destroy:
> > static const struct tee_mediator_ops ffa_ops =
> > {
> > .probe = ffa_probe,
> > +.init_interrupt = ffa_notif_init_interrupt,
>
> With the previous change on init secondary i would suggest to
> have a ffa_init_secondary here actually calling the ffa_notif_init_interrupt.

Yes, that makes sense. I'll update.

>
> > .domain_init = ffa_domain_init,
> > .domain_teardown = ffa_domain_teardown,
> > +.free_domain_ctx = ffa_free_domain_ctx,
> > .relinquish_resources = ffa_relinquish_resources,
> > .handle_call = ffa_handle_call,
> > };
> > diff --git a/xen/arch/arm/tee/ffa_notif.c b/xen/arch/arm/tee/ffa_notif.c
> > new file mode 100644
> > index ..e8e8b62590b3
> > --- /dev/null
> > +++ b/xen/arch/arm/tee/ffa_notif.c
[...]
> > +static void notif_vm_pend_intr(uint16_t vm_id)
> >

[XEN PATCH v5 4/7] xen/arm: allow dynamically assigned SGI handlers

2024-05-29 Thread Jens Wiklander
Updates so request_irq() can be used with a dynamically assigned SGI irq
as input. This prepares for a later patch where an FF-A schedule
receiver interrupt handler is installed for an SGI generated by the
secure world.

>From the Arm Base System Architecture v1.0C [1]:
"The system shall implement at least eight Non-secure SGIs, assigned to
interrupt IDs 0-7."

gic_route_irq_to_xen() don't gic_set_irq_type() for SGIs since they are
always edge triggered.

gic_interrupt() is updated to route the dynamically assigned SGIs to
do_IRQ() instead of do_sgi(). The latter still handles the statically
assigned SGI handlers like for instance GIC_SGI_CALL_FUNCTION.

[1] https://developer.arm.com/documentation/den0094/

Signed-off-by: Jens Wiklander 
---
v3->v4
- Use IRQ_TYPE_EDGE_RISING instead of DT_IRQ_TYPE_EDGE_RISING

v2->v3
- Rename GIC_SGI_MAX to GIC_SGI_STATIC_MAX and rename do_sgi() to
  do_static_sgi()
- Update comment in setup_irq() to mention that SGI irq_desc is banked
- Add ASSERT() in do_IRQ() that the irq isn't an SGI before injecting
  calling vgic_inject_irq()
- Initialize local_irqs_type[] range for SGIs as IRQ_TYPE_EDGE_RISING
- Adding link to the Arm Base System Architecture v1.0C

v1->v2
- Update patch description as requested
---
 xen/arch/arm/gic.c | 12 +++-
 xen/arch/arm/include/asm/gic.h |  2 +-
 xen/arch/arm/irq.c | 18 ++
 3 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index b3467a76ae75..3eaf670fd731 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -38,7 +38,7 @@ const struct gic_hw_operations *gic_hw_ops;
 static void __init __maybe_unused build_assertions(void)
 {
 /* Check our enum gic_sgi only covers SGIs */
-BUILD_BUG_ON(GIC_SGI_MAX > NR_GIC_SGI);
+BUILD_BUG_ON(GIC_SGI_STATIC_MAX > NR_GIC_SGI);
 }
 
 void register_gic_ops(const struct gic_hw_operations *ops)
@@ -117,7 +117,9 @@ void gic_route_irq_to_xen(struct irq_desc *desc, unsigned 
int priority)
 
 desc->handler = gic_hw_ops->gic_host_irq_type;
 
-gic_set_irq_type(desc, desc->arch.type);
+/* SGIs are always edge-triggered, so there is need to set it */
+if ( desc->irq >= NR_GIC_SGI)
+gic_set_irq_type(desc, desc->arch.type);
 gic_set_irq_priority(desc, priority);
 }
 
@@ -322,7 +324,7 @@ void gic_disable_cpu(void)
 gic_hw_ops->disable_interface();
 }
 
-static void do_sgi(struct cpu_user_regs *regs, enum gic_sgi sgi)
+static void do_static_sgi(struct cpu_user_regs *regs, enum gic_sgi sgi)
 {
 struct irq_desc *desc = irq_to_desc(sgi);
 
@@ -367,7 +369,7 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
 /* Reading IRQ will ACK it */
 irq = gic_hw_ops->read_irq();
 
-if ( likely(irq >= 16 && irq < 1020) )
+if ( likely(irq >= GIC_SGI_STATIC_MAX && irq < 1020) )
 {
 isb();
 do_IRQ(regs, irq, is_fiq);
@@ -379,7 +381,7 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
 }
 else if ( unlikely(irq < 16) )
 {
-do_sgi(regs, irq);
+do_static_sgi(regs, irq);
 }
 else
 {
diff --git a/xen/arch/arm/include/asm/gic.h b/xen/arch/arm/include/asm/gic.h
index 03f209529b13..541f0eeb808a 100644
--- a/xen/arch/arm/include/asm/gic.h
+++ b/xen/arch/arm/include/asm/gic.h
@@ -285,7 +285,7 @@ enum gic_sgi {
 GIC_SGI_EVENT_CHECK,
 GIC_SGI_DUMP_STATE,
 GIC_SGI_CALL_FUNCTION,
-GIC_SGI_MAX,
+GIC_SGI_STATIC_MAX,
 };
 
 /* SGI irq mode types */
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index bcce80a4d624..5224898265a5 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -152,7 +152,13 @@ void __init init_IRQ(void)
 
 spin_lock(_irqs_type_lock);
 for ( irq = 0; irq < NR_LOCAL_IRQS; irq++ )
-local_irqs_type[irq] = IRQ_TYPE_INVALID;
+{
+/* SGIs are always edge-triggered */
+if ( irq < NR_GIC_SGI )
+local_irqs_type[irq] = IRQ_TYPE_EDGE_RISING;
+else
+local_irqs_type[irq] = IRQ_TYPE_INVALID;
+}
 spin_unlock(_irqs_type_lock);
 
 BUG_ON(init_local_irq_data(smp_processor_id()) < 0);
@@ -224,9 +230,12 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq, 
int is_fiq)
 
 perfc_incr(irqs);
 
-ASSERT(irq >= 16); /* SGIs do not come down this path */
+/* Statically assigned SGIs do not come down this path */
+ASSERT(irq >= GIC_SGI_STATIC_MAX);
 
-if ( irq < 32 )
+if ( irq < NR_GIC_SGI )
+perfc_incr(ipis);
+else if ( irq < NR_GIC_LOCAL_IRQS )
 perfc_incr(ppis);
 else
 perfc_incr(spis);
@@ -260,6 +269,7 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq, 
int is_fiq)
  * The irq cannot be a PPI, we only support delivery of SPIs to
  * guests

[XEN PATCH v5 6/7] xen/arm: add and call tee_free_domain_ctx()

2024-05-29 Thread Jens Wiklander
Add tee_free_domain_ctx() to the TEE mediator framework.
tee_free_domain_ctx() is called from arch_domain_destroy() to allow late
freeing of the d->arch.tee context. This will simplify access to
d->arch.tee for domains retrieved with rcu_lock_domain_by_id().

Signed-off-by: Jens Wiklander 
---
 xen/arch/arm/domain.c  | 1 +
 xen/arch/arm/include/asm/tee/tee.h | 6 ++
 xen/arch/arm/tee/tee.c | 6 ++
 3 files changed, 13 insertions(+)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 34cbfe699a68..61e46a157ccc 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -837,6 +837,7 @@ int arch_domain_teardown(struct domain *d)
 
 void arch_domain_destroy(struct domain *d)
 {
+tee_free_domain_ctx(d);
 /* IOMMU page table is shared with P2M, always call
  * iommu_domain_destroy() before p2m_final_teardown().
  */
diff --git a/xen/arch/arm/include/asm/tee/tee.h 
b/xen/arch/arm/include/asm/tee/tee.h
index eda8a8aa38f2..2e99a38184be 100644
--- a/xen/arch/arm/include/asm/tee/tee.h
+++ b/xen/arch/arm/include/asm/tee/tee.h
@@ -38,6 +38,7 @@ struct tee_mediator_ops {
  */
 int (*domain_init)(struct domain *d);
 int (*domain_teardown)(struct domain *d);
+void (*free_domain_ctx)(struct domain *d);
 
 /*
  * Called during domain destruction to relinquish resources used
@@ -70,6 +71,7 @@ int tee_domain_teardown(struct domain *d);
 int tee_relinquish_resources(struct domain *d);
 uint16_t tee_get_type(void);
 void init_tee_interrupt(void);
+void tee_free_domain_ctx(struct domain *d);
 
 #define REGISTER_TEE_MEDIATOR(_name, _namestr, _type, _ops) \
 static const struct tee_mediator_desc __tee_desc_##_name __used \
@@ -113,6 +115,10 @@ static inline void init_tee_interrupt(void)
 {
 }
 
+static inline void tee_free_domain_ctx(struct domain *d)
+{
+}
+
 #endif  /* CONFIG_TEE */
 
 #endif /* __ARCH_ARM_TEE_TEE_H__ */
diff --git a/xen/arch/arm/tee/tee.c b/xen/arch/arm/tee/tee.c
index 8117fd55123e..cb65f187f51f 100644
--- a/xen/arch/arm/tee/tee.c
+++ b/xen/arch/arm/tee/tee.c
@@ -102,6 +102,12 @@ void __init init_tee_interrupt(void)
 cur_mediator->ops->init_interrupt();
 }
 
+void tee_free_domain_ctx(struct domain *d)
+{
+if ( cur_mediator && cur_mediator->ops->free_domain_ctx)
+cur_mediator->ops->free_domain_ctx(d);
+}
+
 /*
  * Local variables:
  * mode: C
-- 
2.34.1




[XEN PATCH v5 0/7] FF-A notifications

2024-05-29 Thread Jens Wiklander
Hi,

This patch set adds support for FF-A notifications. We only support
global notifications, per vCPU notifications remain unsupported.

The first three patches are further cleanup and can be merged before the
rest if desired.

A physical SGI is used to make Xen aware of pending FF-A notifications. The
physical SGI is selected by the SPMC in the secure world. Since it must not
already be used by Xen the SPMC is in practice forced to donate one of the
secure SGIs, but that's normally not a problem. The SGI handling in Xen is
updated to support registration of handlers for SGIs that aren't statically
assigned, that is, SGI IDs above GIC_SGI_MAX.

The patch "xen/arm: add and call init_tee_interrupt()" provides a hook for
register the needed per-cpu interrupt handler in "xen/arm: ffa: support
notification".

The patch "xen/arm: add and call tee_free_domain_ctx()" provides a hook for
later freeing of the TEE context. This hook is used in "xen/arm: ffa:
support notification" and avoids the problem with TEE context being freed
while we need to access it when handling a Schedule Receiver interrupt. It
was suggested as an alternative in [1] that the TEE context could be freed
from complete_domain_destroy().

[1] 
https://lore.kernel.org/all/cahua44h4ypoxyt7e6wnh5xjfpitzqjqp9ng4smty4ewhyn+...@mail.gmail.com/

Thanks,
Jens

v4->v5:
- Added two new patches "xen/arm: add and call init_tee_interrupt()" and
  "xen/arm: add and call tee_free_domain_ctx()"
- Updated "xen/arm: ffa: support notification", details in the patch

v3->v4:
- "xen/arm: ffa: support notification" and
  "xen/arm: allow dynamically assigned SGI handlers" updated as requestsed,
  details in each patch.

v2->v3:
- "xen/arm: ffa: support notification" and
  "xen/arm: allow dynamically assigned SGI handlers" updated as requestsed,
  details in each patch.

v1->v2:
- "xen/arm: ffa: support notification" and
  "xen/arm: allow dynamically assigned SGI handlers" updated as requestsed,
  details in each patch.
- Added Bertrands R-B for "xen/arm: ffa: refactor ffa_handle_call()",
  "xen/arm: ffa: use ACCESS_ONCE()", and
  "xen/arm: ffa: simplify ffa_handle_mem_share()"

Jens Wiklander (7):
  xen/arm: ffa: refactor ffa_handle_call()
  xen/arm: ffa: use ACCESS_ONCE()
  xen/arm: ffa: simplify ffa_handle_mem_share()
  xen/arm: allow dynamically assigned SGI handlers
  xen/arm: add and call init_tee_interrupt()
  xen/arm: add and call tee_free_domain_ctx()
  xen/arm: ffa: support notification

 xen/arch/arm/domain.c  |   1 +
 xen/arch/arm/gic.c |  12 +-
 xen/arch/arm/include/asm/gic.h |   2 +-
 xen/arch/arm/include/asm/tee/tee.h |  14 +
 xen/arch/arm/irq.c |  18 +-
 xen/arch/arm/smpboot.c |   2 +
 xen/arch/arm/tee/Makefile  |   1 +
 xen/arch/arm/tee/ffa.c | 100 +--
 xen/arch/arm/tee/ffa_notif.c   | 409 +
 xen/arch/arm/tee/ffa_partinfo.c|   9 +-
 xen/arch/arm/tee/ffa_private.h |  56 +++-
 xen/arch/arm/tee/ffa_shm.c |  33 +--
 xen/arch/arm/tee/tee.c |  14 +-
 xen/include/public/arch-arm.h  |  14 +
 14 files changed, 622 insertions(+), 63 deletions(-)
 create mode 100644 xen/arch/arm/tee/ffa_notif.c

-- 
2.34.1




[XEN PATCH v5 2/7] xen/arm: ffa: use ACCESS_ONCE()

2024-05-29 Thread Jens Wiklander
Replace read_atomic() with ACCESS_ONCE() to match the intended use, that
is, to prevent the compiler from (via optimization) reading shared
memory more than once.

Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
---
 xen/arch/arm/tee/ffa_shm.c | 15 ---
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c
index eed9ad2d2986..75a5b66aeb4c 100644
--- a/xen/arch/arm/tee/ffa_shm.c
+++ b/xen/arch/arm/tee/ffa_shm.c
@@ -7,6 +7,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -171,8 +172,8 @@ static int get_shm_pages(struct domain *d, struct 
ffa_shm_mem *shm,
 
 for ( n = 0; n < range_count; n++ )
 {
-page_count = read_atomic([n].page_count);
-addr = read_atomic([n].address);
+page_count = ACCESS_ONCE(range[n].page_count);
+addr = ACCESS_ONCE(range[n].address);
 for ( m = 0; m < page_count; m++ )
 {
 if ( pg_idx >= shm->page_count )
@@ -527,13 +528,13 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 goto out_unlock;
 
 mem_access = ctx->tx + trans.mem_access_offs;
-if ( read_atomic(_access->access_perm.perm) != FFA_MEM_ACC_RW )
+if ( ACCESS_ONCE(mem_access->access_perm.perm) != FFA_MEM_ACC_RW )
 {
 ret = FFA_RET_NOT_SUPPORTED;
 goto out_unlock;
 }
 
-region_offs = read_atomic(_access->region_offs);
+region_offs = ACCESS_ONCE(mem_access->region_offs);
 if ( sizeof(*region_descr) + region_offs > frag_len )
 {
 ret = FFA_RET_NOT_SUPPORTED;
@@ -541,8 +542,8 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 }
 
 region_descr = ctx->tx + region_offs;
-range_count = read_atomic(_descr->address_range_count);
-page_count = read_atomic(_descr->total_page_count);
+range_count = ACCESS_ONCE(region_descr->address_range_count);
+page_count = ACCESS_ONCE(region_descr->total_page_count);
 
 if ( !page_count )
 {
@@ -557,7 +558,7 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 goto out_unlock;
 }
 shm->sender_id = trans.sender_id;
-shm->ep_id = read_atomic(_access->access_perm.endpoint_id);
+shm->ep_id = ACCESS_ONCE(mem_access->access_perm.endpoint_id);
 
 /*
  * Check that the Composite memory region descriptor fits.
-- 
2.34.1




[XEN PATCH v5 7/7] xen/arm: ffa: support notification

2024-05-29 Thread Jens Wiklander
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 triggers a tasklet to retrieve 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 
---
v4->v5:
- Move the freeing of d->arch.tee to the new TEE mediator free_domain_ctx
  callback to make the context accessible during rcu_lock_domain_by_id()
  from a tasklet
- Initialize interrupt handlers for secondary CPUs from the new TEE mediator
  init_interrupt() callback
- Restore the ffa_probe() from v3, that is, remove the
  presmp_initcall(ffa_init) approach and use ffa_probe() as usual now that we
  have the init_interrupt callback.
- A tasklet is added to handle the Schedule Receiver interrupt. The tasklet
  finds each relevant domain with rcu_lock_domain_by_id() which now is enough
  to guarantee that the FF-A context can be accessed.
- The notification interrupt handler only schedules the notification
  tasklet mentioned above

v3->v4:
- Add another note on FF-A limitations
- Clear secure_pending in ffa_handle_notification_get() if both SP and SPM
  bitmaps are retrieved
- ASSERT that ffa_rcu_lock_domain_by_vm_id() isn't passed the vm_id FF-A
  uses for Xen itself
- Replace the get_domain_by_id() call done via ffa_get_domain_by_vm_id() in
  notif_irq_handler() with a call to rcu_lock_live_remote_domain_by_id() via
  ffa_rcu_lock_domain_by_vm_id()
- Remove spinlock in struct ffa_ctx_notif and use atomic functions as needed
  to access and update the secure_pending field
- In notif_irq_handler(), look for the first online CPU instead of assuming
  that the first CPU is online
- Initialize FF-A via presmp_initcall() before the other CPUs are online,
  use register_cpu_notifier() to install the interrupt handler
  notif_irq_handler()
- Update commit message to reflect recent updates

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/tee/Makefile   |   1 +
 xen/arch/arm/tee/ffa.c  |  72 +-
 xen/arch/arm/tee/ffa_notif.c| 409 
 xen/arch/arm/tee/ffa_partinfo.c |   9 +-
 xen/arch/arm/tee/ffa_private.h  |  56 -
 xen/arch/arm/tee/tee.c  |   2 +-
 xen/include/public/arch-arm.h   |  14 ++
 7 files changed, 548 insertions(+), 15 deletions(-)
 create mode 100644 xen/arch/arm/tee/ffa_notif.c

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..d644ee97cd5b 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -39,6 +39,12 @@
  *   - 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
+ *   - doesn't support signalling the secondary scheduler of pending
+ * notification for secure partitions
+ *   - doesn't support notifications for Xen itself
  *
  * 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 +200,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 +248,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

[XEN PATCH v5 5/7] xen/arm: add and call init_tee_interrupt()

2024-05-29 Thread Jens Wiklander
Add init_tee_interrupt() to the TEE mediator framework and call it from
start_secondary() late enough that per-cpu interrupts can be configured
on CPUs as they are initialized. This is needed in later patches.

Signed-off-by: Jens Wiklander 
---
 xen/arch/arm/include/asm/tee/tee.h | 8 
 xen/arch/arm/smpboot.c | 2 ++
 xen/arch/arm/tee/tee.c | 6 ++
 3 files changed, 16 insertions(+)

diff --git a/xen/arch/arm/include/asm/tee/tee.h 
b/xen/arch/arm/include/asm/tee/tee.h
index da324467e130..eda8a8aa38f2 100644
--- a/xen/arch/arm/include/asm/tee/tee.h
+++ b/xen/arch/arm/include/asm/tee/tee.h
@@ -28,6 +28,9 @@ struct tee_mediator_ops {
  */
 bool (*probe)(void);
 
+/* Initialize eventual interrupt handlers on the secondary CPUs */
+void (*init_interrupt)(void);
+
 /*
  * Called during domain construction if toolstack requests to enable
  * TEE support so mediator can inform TEE about new
@@ -66,6 +69,7 @@ int tee_domain_init(struct domain *d, uint16_t tee_type);
 int tee_domain_teardown(struct domain *d);
 int tee_relinquish_resources(struct domain *d);
 uint16_t tee_get_type(void);
+void init_tee_interrupt(void);
 
 #define REGISTER_TEE_MEDIATOR(_name, _namestr, _type, _ops) \
 static const struct tee_mediator_desc __tee_desc_##_name __used \
@@ -105,6 +109,10 @@ static inline uint16_t tee_get_type(void)
 return XEN_DOMCTL_CONFIG_TEE_NONE;
 }
 
+static inline void init_tee_interrupt(void)
+{
+}
+
 #endif  /* CONFIG_TEE */
 
 #endif /* __ARCH_ARM_TEE_TEE_H__ */
diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c
index 93a10d7721b4..e1c1e20efd98 100644
--- a/xen/arch/arm/smpboot.c
+++ b/xen/arch/arm/smpboot.c
@@ -29,6 +29,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Override macros from asm/page.h to make them work with mfn_t */
 #undef virt_to_mfn
@@ -401,6 +402,7 @@ void asmlinkage start_secondary(void)
  */
 init_maintenance_interrupt();
 init_timer_interrupt();
+init_tee_interrupt();
 
 local_abort_enable();
 
diff --git a/xen/arch/arm/tee/tee.c b/xen/arch/arm/tee/tee.c
index ddd17506a9ff..8117fd55123e 100644
--- a/xen/arch/arm/tee/tee.c
+++ b/xen/arch/arm/tee/tee.c
@@ -96,6 +96,12 @@ static int __init tee_init(void)
 
 __initcall(tee_init);
 
+void __init init_tee_interrupt(void)
+{
+if ( cur_mediator && cur_mediator->ops->init_interrupt)
+cur_mediator->ops->init_interrupt();
+}
+
 /*
  * Local variables:
  * mode: C
-- 
2.34.1




[XEN PATCH v5 3/7] xen/arm: ffa: simplify ffa_handle_mem_share()

2024-05-29 Thread Jens Wiklander
Simplify ffa_handle_mem_share() by removing the start_page_idx and
last_page_idx parameters from get_shm_pages() and check that the number
of pages matches expectations at the end of get_shm_pages().

Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
---
 xen/arch/arm/tee/ffa_shm.c | 18 ++
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c
index 75a5b66aeb4c..370d83ec5cf8 100644
--- a/xen/arch/arm/tee/ffa_shm.c
+++ b/xen/arch/arm/tee/ffa_shm.c
@@ -159,10 +159,9 @@ static int32_t ffa_mem_reclaim(uint32_t handle_lo, 
uint32_t handle_hi,
  */
 static int get_shm_pages(struct domain *d, struct ffa_shm_mem *shm,
  const struct ffa_address_range *range,
- uint32_t range_count, unsigned int start_page_idx,
- unsigned int *last_page_idx)
+ uint32_t range_count)
 {
-unsigned int pg_idx = start_page_idx;
+unsigned int pg_idx = 0;
 gfn_t gfn;
 unsigned int n;
 unsigned int m;
@@ -191,7 +190,9 @@ static int get_shm_pages(struct domain *d, struct 
ffa_shm_mem *shm,
 }
 }
 
-*last_page_idx = pg_idx;
+/* The ranges must add up */
+if ( pg_idx < shm->page_count )
+return FFA_RET_INVALID_PARAMETERS;
 
 return FFA_RET_OK;
 }
@@ -460,7 +461,6 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 struct domain *d = current->domain;
 struct ffa_ctx *ctx = d->arch.tee;
 struct ffa_shm_mem *shm = NULL;
-unsigned int last_page_idx = 0;
 register_t handle_hi = 0;
 register_t handle_lo = 0;
 int ret = FFA_RET_DENIED;
@@ -570,15 +570,9 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 goto out;
 }
 
-ret = get_shm_pages(d, shm, region_descr->address_range_array, range_count,
-0, _page_idx);
+ret = get_shm_pages(d, shm, region_descr->address_range_array, 
range_count);
 if ( ret )
 goto out;
-if ( last_page_idx != shm->page_count )
-{
-ret = FFA_RET_INVALID_PARAMETERS;
-goto out;
-}
 
 /* Note that share_shm() uses our tx buffer */
 spin_lock(_tx_buffer_lock);
-- 
2.34.1




[XEN PATCH v5 1/7] xen/arm: ffa: refactor ffa_handle_call()

2024-05-29 Thread Jens Wiklander
Refactors the large switch block in ffa_handle_call() to use common code
for the simple case where it's either an error code or success with no
further parameters.

Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
---
 xen/arch/arm/tee/ffa.c | 30 ++
 1 file changed, 10 insertions(+), 20 deletions(-)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 8665201e34a9..5209612963e1 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -273,18 +273,10 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 case FFA_RXTX_MAP_64:
 e = ffa_handle_rxtx_map(fid, get_user_reg(regs, 1),
get_user_reg(regs, 2), get_user_reg(regs, 3));
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 case FFA_RXTX_UNMAP:
 e = ffa_handle_rxtx_unmap();
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 case FFA_PARTITION_INFO_GET:
 e = ffa_handle_partition_info_get(get_user_reg(regs, 1),
   get_user_reg(regs, 2),
@@ -299,11 +291,7 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 return true;
 case FFA_RX_RELEASE:
 e = ffa_handle_rx_release();
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 case FFA_MSG_SEND_DIRECT_REQ_32:
 case FFA_MSG_SEND_DIRECT_REQ_64:
 handle_msg_send_direct_req(regs, fid);
@@ -316,17 +304,19 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 e = ffa_handle_mem_reclaim(regpair_to_uint64(get_user_reg(regs, 2),
  get_user_reg(regs, 1)),
get_user_reg(regs, 3));
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 
 default:
 gprintk(XENLOG_ERR, "ffa: unhandled fid 0x%x\n", fid);
 ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED);
 return true;
 }
+
+if ( e )
+ffa_set_regs_error(regs, e);
+else
+ffa_set_regs_success(regs, 0, 0);
+return true;
 }
 
 static int ffa_domain_init(struct domain *d)
-- 
2.34.1




Re: Referencing domain struct from interrupt handler

2024-05-15 Thread Jens Wiklander
On Tue, May 14, 2024 at 9:12 AM Jan Beulich  wrote:
>
> On 08.05.2024 09:10, Jens Wiklander wrote:
> > On Fri, May 3, 2024 at 12:32 PM Jan Beulich  wrote:
> >> Furthermore, is it guaranteed that the IRQ handler won't interrupt code
> >> fiddling with the domain list? I don't think it is, since
> >> domlist_update_lock isn't acquired in an IRQ-safe manner. Looks like
> >> you need to defer the operation on the domain until softirq or tasklet
> >> context.
> >
> > Thanks for the suggestion, I'm testing it as:
> > static DECLARE_TASKLET(notif_sri_tasklet, notif_sri_action, NULL);
> >
> > static void notif_irq_handler(int irq, void *data)
> > {
> > tasklet_schedule(_sri_tasklet);
> > }
> >
> > Where notif_sri_action() does what notif_irq_handler() did before
> > (using rcu_lock_domain_by_id()).
> >
> > I have one more question regarding this.
> >
> > Even with the RCU lock if I understand it correctly, it's possible for
> > domain_kill() to tear down the domain. Or as Julien explained it in
> > another thread [3]:
> >> CPU0: ffa_get_domain_by_vm_id() (return the domain as it is alive)
> >>
> >> CPU1: call domain_kill()
> >> CPU1: teardown is called, free d->arch.tee (the pointer is not set to NULL)
> >>
> >> d->arch.tee is now a dangling pointer
> >>
> >> CPU0: access d->arch.tee
> >>
> >> This implies you may need to gain a global lock (I don't have a better
> >> idea so far) to protect the IRQ handler against domains teardown.
> >
> > I'm trying to address that (now in a tasklet) with:
> > /*
> >  * domain_kill() calls ffa_domain_teardown() which will free
> >  * d->arch.tee, but not set it to NULL. This can happen while holding
> >  * the RCU lock.
> >  *
> >  * domain_lock() will stop rspin_barrier() in domain_kill(), unless
> >  * we're already past rspin_barrier(), but then will d->is_dying be
> >  * non-zero.
> >  */
> > domain_lock(d);
> > if ( !d->is_dying )
> > {
> > struct ffa_ctx *ctx = d->arch.tee;
> >
> > ACCESS_ONCE(ctx->notif.secure_pending) = true;
> > }
> > domain_unlock(d);
> >
> > It seems to work, but I'm worried I'm missing something or abusing
> > domain_lock().
>
> Well. Yes, this is one way of dealing with the issue. Yet as you suspect it
> feels like an abuse of domain_lock(); that function would better be avoided
> whenever possible. (It had some very unhelpful uses long ago.)
>
> Another approach would generally be to do respective cleanup not from
> underneath domain_kill(), but complete_domain_destroy(). It's not really
> clear to me which of the two approaches is better in this case.

Thanks for the feedback. I tried moving the freeing of d->arch.tee to
complete_domain_destroy() while keeping the rest of the cleanup as is.
It works as expected, I'll use this for the next version of the patch
set.

Cheers,
Jens



Re: Referencing domain struct from interrupt handler

2024-05-08 Thread Jens Wiklander
Hi Jan,

On Fri, May 3, 2024 at 12:32 PM Jan Beulich  wrote:
>
> On 03.05.2024 09:45, Jens Wiklander wrote:
> > Hi Xen maintainers,
> >
> > In my patch series [XEN PATCH v4 0/5] FF-A notifications [1] I need to
> > get a reference to a domain struct from a domain ID and keep it from
> > being destroyed while using it in the interrupt handler
> > notif_irq_handler() (introduced in the last patch "[XEN PATCH v4 5/5]
> > xen/arm: ffa: support notification"). In my previous patch set [2] I
> > used get_domain_by_id(), but from the following discussion
> > rcu_lock_live_remote_domain_by_id() seems to be a better choice so
> > that's what I'm using now in the v4 patch set. The domain lock is held
> > during a call to vgic_inject_irq() and unlocked right after.
> >
> > While we're reviewing the patch set in [1] I'd like to check the
> > approach with rcu_lock_live_remote_domain_by_id() here.
> >
> > What do you think? Is using rcu_lock_live_remote_domain_by_id() the
> > best approach?
>
> Is it guaranteed that the IRQ handler won't ever run in the context of a
> vCPU belonging to the domain in question? If not, why the "remote" form
> of the function?

No, that's my mistake.

>
> Furthermore, is it guaranteed that the IRQ handler won't interrupt code
> fiddling with the domain list? I don't think it is, since
> domlist_update_lock isn't acquired in an IRQ-safe manner. Looks like
> you need to defer the operation on the domain until softirq or tasklet
> context.

Thanks for the suggestion, I'm testing it as:
static DECLARE_TASKLET(notif_sri_tasklet, notif_sri_action, NULL);

static void notif_irq_handler(int irq, void *data)
{
tasklet_schedule(_sri_tasklet);
}

Where notif_sri_action() does what notif_irq_handler() did before
(using rcu_lock_domain_by_id()).

I have one more question regarding this.

Even with the RCU lock if I understand it correctly, it's possible for
domain_kill() to tear down the domain. Or as Julien explained it in
another thread [3]:
> CPU0: ffa_get_domain_by_vm_id() (return the domain as it is alive)
>
> CPU1: call domain_kill()
> CPU1: teardown is called, free d->arch.tee (the pointer is not set to NULL)
>
> d->arch.tee is now a dangling pointer
>
> CPU0: access d->arch.tee
>
> This implies you may need to gain a global lock (I don't have a better
> idea so far) to protect the IRQ handler against domains teardown.

I'm trying to address that (now in a tasklet) with:
/*
 * domain_kill() calls ffa_domain_teardown() which will free
 * d->arch.tee, but not set it to NULL. This can happen while holding
 * the RCU lock.
 *
 * domain_lock() will stop rspin_barrier() in domain_kill(), unless
 * we're already past rspin_barrier(), but then will d->is_dying be
 * non-zero.
 */
domain_lock(d);
if ( !d->is_dying )
{
struct ffa_ctx *ctx = d->arch.tee;

ACCESS_ONCE(ctx->notif.secure_pending) = true;
}
domain_unlock(d);

It seems to work, but I'm worried I'm missing something or abusing
domain_lock(). I can do this in v5 of the patch set if that helps to
see what I mean.

[3] 
https://patchew.org/Xen/20240426084723.4149648-1-jens.wiklan...@linaro.org/20240426084723.4149648-6-jens.wiklan...@linaro.org/#c7a672a7-02f8-4d24-b87e-1b8439d7e...@xen.org

Thanks,
Jens

>
> Jan
>
> > [1] 
> > https://patchew.org/Xen/20240502145645.1201613-1-jens.wiklan...@linaro.org/
> > [2] 
> > https://patchew.org/Xen/20240426084723.4149648-1-jens.wiklan...@linaro.org/
> >
> > Thanks,
> > Jens
>



Re: [XEN PATCH v4 5/5] xen/arm: ffa: support notification

2024-05-07 Thread Jens Wiklander
Hi Julien,

On Fri, May 3, 2024 at 4:25 PM Julien Grall  wrote:
>
> Hi Jens,
>
> On 03/05/2024 14:54, Jens Wiklander wrote:
> >>> +static int ffa_setup_irq_callback(struct notifier_block *nfb,
> >>> +  unsigned long action, void *hcpu)
> >>> +{
> >>> +unsigned int cpu = (unsigned long)hcpu;
> >>> +struct notif_irq_info irq_info = { };
> >>> +
> >>> +switch ( action )
> >>> +{
> >>> +case CPU_ONLINE:
> >>
> >> Can't you execute the notifier in CPU_STARTING? This will be called on
> >> the CPU directly, so you should be able to use request_irq(...).
> >
> > I tried that first but it failed with the ASSERT_ALLOC_CONTEXT() in 
> > _xmalloc().
> >
> > I've also tested a three-step solution with CPU_UP_PREPARE,
> > CPU_STARTING, and CPU_UP_CANCELED.
> > My approach here is more direct, but it still suffers from a weakness
> > in error handling even if it seems quite unlikely to run out of heap
> > or for setup_irq() to fail at this stage.
>
> Ah I didn't notice that notify_cpu_starting() is called with IRQ
> disabled. I assumed they would be enabled.
>
> Then I would consider to do:
>
> diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c
> index 6efed876782e..db322672e508 100644
> --- a/xen/arch/arm/smpboot.c
> +++ b/xen/arch/arm/smpboot.c
> @@ -389,6 +389,7 @@ void asmlinkage start_secondary(void)
>*/
>   init_maintenance_interrupt();
>   init_timer_interrupt();
> +init_tee_interrupt();
>
>   local_abort_enable();
>
> And plumb through the TEE subsystem.

I'll use that in the next version, it should remove a lot of complex code.

Thanks,
Jens



Re: [XEN PATCH v4 5/5] xen/arm: ffa: support notification

2024-05-03 Thread Jens Wiklander
Hi Julien,

On Fri, May 3, 2024 at 11:59 AM Julien Grall  wrote:
>
> Hi Jens,
>
> On 02/05/2024 15:56, Jens Wiklander wrote:
> > -static bool ffa_probe(void)
> > +static int __init ffa_init(void)
> >   {
> >   uint32_t vers;
> >   unsigned int major_vers;
> > @@ -460,16 +511,16 @@ static bool ffa_probe(void)
> >   printk(XENLOG_ERR
> >  "ffa: unsupported SMCCC version %#x (need at least %#x)\n",
> >  smccc_ver, ARM_SMCCC_VERSION_1_2);
> > -return false;
> > +return 0;
> >   }
> >
> >   if ( !ffa_get_version() )
> > -return false;
> > +return 0;
> >
> >   if ( vers < FFA_MIN_SPMC_VERSION || vers > FFA_MY_VERSION )
> >   {
> >   printk(XENLOG_ERR "ffa: Incompatible version %#x found\n", vers);
> > -return false;
> > +return 0;
> >   }
> >
> >   major_vers = (vers >> FFA_VERSION_MAJOR_SHIFT) & 
> > FFA_VERSION_MAJOR_MASK;
> > @@ -492,26 +543,33 @@ static bool ffa_probe(void)
> >!check_mandatory_feature(FFA_MEM_SHARE_32) ||
> >!check_mandatory_feature(FFA_MEM_RECLAIM) ||
> >!check_mandatory_feature(FFA_MSG_SEND_DIRECT_REQ_32) )
> > -return false;
> > +return 0;
> >
> >   if ( !ffa_rxtx_init() )
> > -return false;
> > +return 0;
> >
> >   ffa_version = vers;
> >
> >   if ( !ffa_partinfo_init() )
> >   goto err_rxtx_destroy;
> >
> > +ffa_notif_init();
> >   INIT_LIST_HEAD(_teardown_head);
> >   init_timer(_teardown_timer, ffa_teardown_timer_callback, NULL, 0);
> >
> > -return true;
> > +return 0;
> >
> >   err_rxtx_destroy:
> >   ffa_rxtx_destroy();
> >   ffa_version = 0;
> >
> > -return false;
> > +return 0;
> > +}
> > +presmp_initcall(ffa_init);
> I would rather prefer if tee_init() is called from presmp_initcall().
> This would avoid FFA to have to try to initialize itself before all the
> others.

OK, I'll update.

>
> This is what I had in mind with my original request, but I guess I
> wasn't clear enough. Sorry for that.

No worries.

>
> [...]
>
> > +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(, );
> > +res = ffa_get_ret_code();
> > +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;
> > +uint16_t vm_id = get_id_from_resp(, id_pos);
> > +struct domain *d;
> > +
> > +/*
> > + * vm_id == 0 means a notifications pending for Xen itself, but
> > + * we don't support that yet.
> > + */
> > +if (vm_id)
> > +d = ffa_rcu_lock_domain_by_vm_id(vm_id);
>
> I am still unconvinced that this is sufficient. This will prevent
> "struct domain *" to be freed. But ...
>
> > +else
> > +d = NULL;
> > +
> > +if ( d )
> > +{
> > +struct ffa_ctx *ctx = d->arch.tee;
>
> ... I don't think it will protect d->arch.tee to be freed as this is
> happening during teardorwn. You mostly need some other sort of locking
> to avoid d->arch.tee been freed behind your back.

OK, I'll need to work more on this. The outcome of the [1] thread may
affect this too.

[1] https://lists.xenproject.org/archives/html/xen-devel/2024-05/msg00156.html

Referencing domain struct from interrupt handler

2024-05-03 Thread Jens Wiklander
Hi Xen maintainers,

In my patch series [XEN PATCH v4 0/5] FF-A notifications [1] I need to
get a reference to a domain struct from a domain ID and keep it from
being destroyed while using it in the interrupt handler
notif_irq_handler() (introduced in the last patch "[XEN PATCH v4 5/5]
xen/arm: ffa: support notification"). In my previous patch set [2] I
used get_domain_by_id(), but from the following discussion
rcu_lock_live_remote_domain_by_id() seems to be a better choice so
that's what I'm using now in the v4 patch set. The domain lock is held
during a call to vgic_inject_irq() and unlocked right after.

While we're reviewing the patch set in [1] I'd like to check the
approach with rcu_lock_live_remote_domain_by_id() here.

What do you think? Is using rcu_lock_live_remote_domain_by_id() the
best approach?

[1] https://patchew.org/Xen/20240502145645.1201613-1-jens.wiklan...@linaro.org/
[2] https://patchew.org/Xen/20240426084723.4149648-1-jens.wiklan...@linaro.org/

Thanks,
Jens



[XEN PATCH v4 4/5] xen/arm: allow dynamically assigned SGI handlers

2024-05-02 Thread Jens Wiklander
Updates so request_irq() can be used with a dynamically assigned SGI irq
as input. This prepares for a later patch where an FF-A schedule
receiver interrupt handler is installed for an SGI generated by the
secure world.

>From the Arm Base System Architecture v1.0C [1]:
"The system shall implement at least eight Non-secure SGIs, assigned to
interrupt IDs 0-7."

gic_route_irq_to_xen() don't gic_set_irq_type() for SGIs since they are
always edge triggered.

gic_interrupt() is updated to route the dynamically assigned SGIs to
do_IRQ() instead of do_sgi(). The latter still handles the statically
assigned SGI handlers like for instance GIC_SGI_CALL_FUNCTION.

[1] https://developer.arm.com/documentation/den0094/

Signed-off-by: Jens Wiklander 
---
v3->v4
- Use IRQ_TYPE_EDGE_RISING instead of DT_IRQ_TYPE_EDGE_RISING

v2->v3
- Rename GIC_SGI_MAX to GIC_SGI_STATIC_MAX and rename do_sgi() to
  do_static_sgi()
- Update comment in setup_irq() to mention that SGI irq_desc is banked
- Add ASSERT() in do_IRQ() that the irq isn't an SGI before injecting
  calling vgic_inject_irq()
- Initialize local_irqs_type[] range for SGIs as IRQ_TYPE_EDGE_RISING
- Adding link to the Arm Base System Architecture v1.0C

v1->v2
- Update patch description as requested
---
 xen/arch/arm/gic.c | 12 +++-
 xen/arch/arm/include/asm/gic.h |  2 +-
 xen/arch/arm/irq.c | 18 ++
 3 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 44c40e86defe..882768252740 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -38,7 +38,7 @@ const struct gic_hw_operations *gic_hw_ops;
 static void __init __maybe_unused build_assertions(void)
 {
 /* Check our enum gic_sgi only covers SGIs */
-BUILD_BUG_ON(GIC_SGI_MAX > NR_GIC_SGI);
+BUILD_BUG_ON(GIC_SGI_STATIC_MAX > NR_GIC_SGI);
 }
 
 void register_gic_ops(const struct gic_hw_operations *ops)
@@ -117,7 +117,9 @@ void gic_route_irq_to_xen(struct irq_desc *desc, unsigned 
int priority)
 
 desc->handler = gic_hw_ops->gic_host_irq_type;
 
-gic_set_irq_type(desc, desc->arch.type);
+/* SGIs are always edge-triggered, so there is need to set it */
+if ( desc->irq >= NR_GIC_SGI)
+gic_set_irq_type(desc, desc->arch.type);
 gic_set_irq_priority(desc, priority);
 }
 
@@ -330,7 +332,7 @@ void gic_disable_cpu(void)
 gic_hw_ops->disable_interface();
 }
 
-static void do_sgi(struct cpu_user_regs *regs, enum gic_sgi sgi)
+static void do_static_sgi(struct cpu_user_regs *regs, enum gic_sgi sgi)
 {
 struct irq_desc *desc = irq_to_desc(sgi);
 
@@ -375,7 +377,7 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
 /* Reading IRQ will ACK it */
 irq = gic_hw_ops->read_irq();
 
-if ( likely(irq >= 16 && irq < 1020) )
+if ( likely(irq >= GIC_SGI_STATIC_MAX && irq < 1020) )
 {
 isb();
 do_IRQ(regs, irq, is_fiq);
@@ -387,7 +389,7 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
 }
 else if ( unlikely(irq < 16) )
 {
-do_sgi(regs, irq);
+do_static_sgi(regs, irq);
 }
 else
 {
diff --git a/xen/arch/arm/include/asm/gic.h b/xen/arch/arm/include/asm/gic.h
index 03f209529b13..541f0eeb808a 100644
--- a/xen/arch/arm/include/asm/gic.h
+++ b/xen/arch/arm/include/asm/gic.h
@@ -285,7 +285,7 @@ enum gic_sgi {
 GIC_SGI_EVENT_CHECK,
 GIC_SGI_DUMP_STATE,
 GIC_SGI_CALL_FUNCTION,
-GIC_SGI_MAX,
+GIC_SGI_STATIC_MAX,
 };
 
 /* SGI irq mode types */
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index bcce80a4d624..5224898265a5 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -152,7 +152,13 @@ void __init init_IRQ(void)
 
 spin_lock(_irqs_type_lock);
 for ( irq = 0; irq < NR_LOCAL_IRQS; irq++ )
-local_irqs_type[irq] = IRQ_TYPE_INVALID;
+{
+/* SGIs are always edge-triggered */
+if ( irq < NR_GIC_SGI )
+local_irqs_type[irq] = IRQ_TYPE_EDGE_RISING;
+else
+local_irqs_type[irq] = IRQ_TYPE_INVALID;
+}
 spin_unlock(_irqs_type_lock);
 
 BUG_ON(init_local_irq_data(smp_processor_id()) < 0);
@@ -224,9 +230,12 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq, 
int is_fiq)
 
 perfc_incr(irqs);
 
-ASSERT(irq >= 16); /* SGIs do not come down this path */
+/* Statically assigned SGIs do not come down this path */
+ASSERT(irq >= GIC_SGI_STATIC_MAX);
 
-if ( irq < 32 )
+if ( irq < NR_GIC_SGI )
+perfc_incr(ipis);
+else if ( irq < NR_GIC_LOCAL_IRQS )
 perfc_incr(ppis);
 else
 perfc_incr(spis);
@@ -260,6 +269,7 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq, 
int is_fiq)
  * The irq cannot be a PPI, we only support delivery of SPIs to
  * guests

[XEN PATCH v4 2/5] xen/arm: ffa: use ACCESS_ONCE()

2024-05-02 Thread Jens Wiklander
Replace read_atomic() with ACCESS_ONCE() to match the intended use, that
is, to prevent the compiler from (via optimization) reading shared
memory more than once.

Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
---
 xen/arch/arm/tee/ffa_shm.c | 15 ---
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c
index eed9ad2d2986..75a5b66aeb4c 100644
--- a/xen/arch/arm/tee/ffa_shm.c
+++ b/xen/arch/arm/tee/ffa_shm.c
@@ -7,6 +7,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -171,8 +172,8 @@ static int get_shm_pages(struct domain *d, struct 
ffa_shm_mem *shm,
 
 for ( n = 0; n < range_count; n++ )
 {
-page_count = read_atomic([n].page_count);
-addr = read_atomic([n].address);
+page_count = ACCESS_ONCE(range[n].page_count);
+addr = ACCESS_ONCE(range[n].address);
 for ( m = 0; m < page_count; m++ )
 {
 if ( pg_idx >= shm->page_count )
@@ -527,13 +528,13 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 goto out_unlock;
 
 mem_access = ctx->tx + trans.mem_access_offs;
-if ( read_atomic(_access->access_perm.perm) != FFA_MEM_ACC_RW )
+if ( ACCESS_ONCE(mem_access->access_perm.perm) != FFA_MEM_ACC_RW )
 {
 ret = FFA_RET_NOT_SUPPORTED;
 goto out_unlock;
 }
 
-region_offs = read_atomic(_access->region_offs);
+region_offs = ACCESS_ONCE(mem_access->region_offs);
 if ( sizeof(*region_descr) + region_offs > frag_len )
 {
 ret = FFA_RET_NOT_SUPPORTED;
@@ -541,8 +542,8 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 }
 
 region_descr = ctx->tx + region_offs;
-range_count = read_atomic(_descr->address_range_count);
-page_count = read_atomic(_descr->total_page_count);
+range_count = ACCESS_ONCE(region_descr->address_range_count);
+page_count = ACCESS_ONCE(region_descr->total_page_count);
 
 if ( !page_count )
 {
@@ -557,7 +558,7 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 goto out_unlock;
 }
 shm->sender_id = trans.sender_id;
-shm->ep_id = read_atomic(_access->access_perm.endpoint_id);
+shm->ep_id = ACCESS_ONCE(mem_access->access_perm.endpoint_id);
 
 /*
  * Check that the Composite memory region descriptor fits.
-- 
2.34.1




[XEN PATCH v4 0/5] FF-A notifications

2024-05-02 Thread Jens Wiklander
Hi,

This patch set adds support for FF-A notifications. We only support
global notifications, per vCPU notifications remain unsupported.

The first three patches are further cleanup and can be merged before the
rest if desired.

A physical SGI is used to make Xen aware of pending FF-A notifications. The
physical SGI is selected by the SPMC in the secure world. Since it must not
already be used by Xen the SPMC is in practice forced to donate one of the
secure SGIs, but that's normally not a problem. The SGI handling in Xen is
updated to support registration of handlers for SGIs that aren't statically
assigned, that is, SGI IDs above GIC_SGI_MAX.

Two items stand out in the last patch, "xen/arm: ffa: support notification":
- The interrupt handler must be registered for each online CPU, but this
  will usually happen for the secondary CPUs after FF-A has been initialized
  so we may need to take some further action in the error path
- The interrupt handler need to get hold of the domain struct of a guest as
  indicated by the SPMC. In this patch set we use
  rcu_lock_live_remote_domain_by_id() to get a safe reference to the domain
  struct.

Thanks,
Jens

v3->v4:
- "xen/arm: ffa: support notification" and
  "xen/arm: allow dynamically assigned SGI handlers" updated as requestsed,
  details in each patch.

v2->v3:
- "xen/arm: ffa: support notification" and
  "xen/arm: allow dynamically assigned SGI handlers" updated as requestsed,
  details in each patch.

v1->v2:
- "xen/arm: ffa: support notification" and
  "xen/arm: allow dynamically assigned SGI handlers" updated as requestsed,
  details in each patch.
- Added Bertrands R-B for "xen/arm: ffa: refactor ffa_handle_call()",
  "xen/arm: ffa: use ACCESS_ONCE()", and
  "xen/arm: ffa: simplify ffa_handle_mem_share()"

Jens Wiklander (5):
  xen/arm: ffa: refactor ffa_handle_call()
  xen/arm: ffa: use ACCESS_ONCE()
  xen/arm: ffa: simplify ffa_handle_mem_share()
  xen/arm: allow dynamically assigned SGI handlers
  xen/arm: ffa: support notification

 xen/arch/arm/gic.c  |  12 +-
 xen/arch/arm/include/asm/gic.h  |   2 +-
 xen/arch/arm/irq.c  |  18 +-
 xen/arch/arm/tee/Makefile   |   1 +
 xen/arch/arm/tee/ffa.c  | 108 +---
 xen/arch/arm/tee/ffa_notif.c| 453 
 xen/arch/arm/tee/ffa_partinfo.c |   9 +-
 xen/arch/arm/tee/ffa_private.h  |  60 -
 xen/arch/arm/tee/ffa_shm.c  |  33 +--
 xen/include/public/arch-arm.h   |  14 +
 10 files changed, 647 insertions(+), 63 deletions(-)
 create mode 100644 xen/arch/arm/tee/ffa_notif.c

-- 
2.34.1




[XEN PATCH v4 5/5] xen/arm: ffa: support notification

2024-05-02 Thread Jens Wiklander
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().

Initialize FF-A with ffa_init() registered in presmp_initcall().
ffa_probe() just returns the probed version which is 0 if initialization
failed. Early FF-A initialization is needed to install the interrupt
handler on each CPU through a function registered with
register_cpu_notifier().

Signed-off-by: Jens Wiklander 
---
v3->v4:
- Add another note on FF-A limitations
- Clear secure_pending in ffa_handle_notification_get() if both SP and SPM
  bitmaps are retrieved
- ASSERT that ffa_rcu_lock_domain_by_vm_id() isn't passed the vm_id FF-A
  uses for Xen itself
- Replace the get_domain_by_id() call done via ffa_get_domain_by_vm_id() in
  notif_irq_handler() with a call to rcu_lock_live_remote_domain_by_id() via
  ffa_rcu_lock_domain_by_vm_id()
- Remove spinlock in struct ffa_ctx_notif and use atomic functions as needed
  to access and update the secure_pending field
- In notif_irq_handler(), look for the first online CPU instead of assuming
  that the first CPU is online
- Initialize FF-A via presmp_initcall() before the other CPUs are online,
  use register_cpu_notifier() to install the interrupt handler
  notif_irq_handler()
- Update commit message to reflect recent updates

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/tee/Makefile   |   1 +
 xen/arch/arm/tee/ffa.c  |  80 +-
 xen/arch/arm/tee/ffa_notif.c| 453 
 xen/arch/arm/tee/ffa_partinfo.c |   9 +-
 xen/arch/arm/tee/ffa_private.h  |  60 -
 xen/include/public/arch-arm.h   |  14 +
 6 files changed, 602 insertions(+), 15 deletions(-)
 create mode 100644 xen/arch/arm/tee/ffa_notif.c

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..0dc0db9bfca8 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -39,6 +39,12 @@
  *   - 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
+ *   - doesn't support signalling the secondary scheduler of pending
+ * notification for secure partitions
+ *   - doesn't support notifications for Xen itself
  *
  * 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 +200,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 +248,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(re

[XEN PATCH v4 3/5] xen/arm: ffa: simplify ffa_handle_mem_share()

2024-05-02 Thread Jens Wiklander
Simplify ffa_handle_mem_share() by removing the start_page_idx and
last_page_idx parameters from get_shm_pages() and check that the number
of pages matches expectations at the end of get_shm_pages().

Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
---
 xen/arch/arm/tee/ffa_shm.c | 18 ++
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c
index 75a5b66aeb4c..370d83ec5cf8 100644
--- a/xen/arch/arm/tee/ffa_shm.c
+++ b/xen/arch/arm/tee/ffa_shm.c
@@ -159,10 +159,9 @@ static int32_t ffa_mem_reclaim(uint32_t handle_lo, 
uint32_t handle_hi,
  */
 static int get_shm_pages(struct domain *d, struct ffa_shm_mem *shm,
  const struct ffa_address_range *range,
- uint32_t range_count, unsigned int start_page_idx,
- unsigned int *last_page_idx)
+ uint32_t range_count)
 {
-unsigned int pg_idx = start_page_idx;
+unsigned int pg_idx = 0;
 gfn_t gfn;
 unsigned int n;
 unsigned int m;
@@ -191,7 +190,9 @@ static int get_shm_pages(struct domain *d, struct 
ffa_shm_mem *shm,
 }
 }
 
-*last_page_idx = pg_idx;
+/* The ranges must add up */
+if ( pg_idx < shm->page_count )
+return FFA_RET_INVALID_PARAMETERS;
 
 return FFA_RET_OK;
 }
@@ -460,7 +461,6 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 struct domain *d = current->domain;
 struct ffa_ctx *ctx = d->arch.tee;
 struct ffa_shm_mem *shm = NULL;
-unsigned int last_page_idx = 0;
 register_t handle_hi = 0;
 register_t handle_lo = 0;
 int ret = FFA_RET_DENIED;
@@ -570,15 +570,9 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 goto out;
 }
 
-ret = get_shm_pages(d, shm, region_descr->address_range_array, range_count,
-0, _page_idx);
+ret = get_shm_pages(d, shm, region_descr->address_range_array, 
range_count);
 if ( ret )
 goto out;
-if ( last_page_idx != shm->page_count )
-{
-ret = FFA_RET_INVALID_PARAMETERS;
-goto out;
-}
 
 /* Note that share_shm() uses our tx buffer */
 spin_lock(_tx_buffer_lock);
-- 
2.34.1




[XEN PATCH v4 1/5] xen/arm: ffa: refactor ffa_handle_call()

2024-05-02 Thread Jens Wiklander
Refactors the large switch block in ffa_handle_call() to use common code
for the simple case where it's either an error code or success with no
further parameters.

Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
---
 xen/arch/arm/tee/ffa.c | 30 ++
 1 file changed, 10 insertions(+), 20 deletions(-)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 8665201e34a9..5209612963e1 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -273,18 +273,10 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 case FFA_RXTX_MAP_64:
 e = ffa_handle_rxtx_map(fid, get_user_reg(regs, 1),
get_user_reg(regs, 2), get_user_reg(regs, 3));
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 case FFA_RXTX_UNMAP:
 e = ffa_handle_rxtx_unmap();
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 case FFA_PARTITION_INFO_GET:
 e = ffa_handle_partition_info_get(get_user_reg(regs, 1),
   get_user_reg(regs, 2),
@@ -299,11 +291,7 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 return true;
 case FFA_RX_RELEASE:
 e = ffa_handle_rx_release();
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 case FFA_MSG_SEND_DIRECT_REQ_32:
 case FFA_MSG_SEND_DIRECT_REQ_64:
 handle_msg_send_direct_req(regs, fid);
@@ -316,17 +304,19 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 e = ffa_handle_mem_reclaim(regpair_to_uint64(get_user_reg(regs, 2),
  get_user_reg(regs, 1)),
get_user_reg(regs, 3));
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 
 default:
 gprintk(XENLOG_ERR, "ffa: unhandled fid 0x%x\n", fid);
 ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED);
 return true;
 }
+
+if ( e )
+ffa_set_regs_error(regs, e);
+else
+ffa_set_regs_success(regs, 0, 0);
+return true;
 }
 
 static int ffa_domain_init(struct domain *d)
-- 
2.34.1




Re: [XEN PATCH v3 5/5] xen/arm: ffa: support notification

2024-04-29 Thread Jens Wiklander
Hi Julien,

On Fri, Apr 26, 2024 at 7:58 PM Julien Grall  wrote:
>
> Hi Jens,
>
> On 26/04/2024 09:47, Jens Wiklander wrote:
> > +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);
> In v2, you were using request_irq(). But now you seem to be open-coding
> it. Can you explain why?

It's because request_irq() does a memory allocation that can't be done
in interrupt context.
>
> > +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(, );
> > +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)
> Even though we currently don't support CPU hotplug, you want to add a
> CPU Notifier to also register the IRQ when a CPU is onlined
> ffa_notif_init().
>
> For an example, see time.c. We may also want to consider to enable TEE
> in presmp_initcalls() so we don't need to have a for_each_online_cpu().

I was considering that too. I'll update the code.

Thanks,
Jens



Re: [XEN PATCH v3 5/5] xen/arm: ffa: support notification

2024-04-29 Thread Jens Wiklander
Hi Bertrand,

On Mon, Apr 29, 2024 at 9:20 AM Bertrand Marquis
 wrote:
[...]
> >> +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(, );
> >> +res = ffa_get_ret_code();
> >> +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;
> >> +
> >> +d = ffa_get_domain_by_vm_id(get_id_from_resp(, id_pos));
> >
> > Thinking a bit more about the question from Bertrand about get_domain_id() 
> > vs rcu_lock_domain_by_id(). I am actually not sure whether either are ok 
> > here.
> >
> > If I am not mistaken, d->arch.tee will be freed as part of the domain 
> > teardown process. This means you can have the following scenario:
> >
> > CPU0: ffa_get_domain_by_vm_id() (return the domain as it is alive)
> >
> > CPU1: call domain_kill()
> > CPU1: teardown is called, free d->arch.tee (the pointer is not set to NULL)
> >
> > d->arch.tee is now a dangling pointer
> >
> > CPU0: access d->arch.tee
> >
> > This implies you may need to gain a global lock (I don't have a better idea 
> > so far) to protect the IRQ handler against domains teardown.
> >
> > Did I miss anything?
>
> I think you are right which is why I was thinking to use 
> rcu_lock_live_remote_domain_by_id to only get a reference
> to the domain if it is not dying.
>
> From the comment in sched.h:
> /*
>  * rcu_lock_domain_by_id() is more efficient than get_domain_by_id().
>  * This is the preferred function if the returned domain reference
>  * is short lived,  but it cannot be used if the domain reference needs
>  * to be kept beyond the current scope (e.g., across a softirq).
>  * The returned domain reference must be discarded using rcu_unlock_domain().
>  */
>
> Now the question of short lived should be challenged but I do not think we can
> consider the current code as "long lived".
>
> It would be a good idea to start a mailing list thread discussion with other
> maintainers on the subject to confirm.
> @Jens: as i will be off for some time, would you mind doing it ?

Sure, first I'll send out a new patch set with the current comments
addressed. I'll update to use rcu_lock_live_remote_domain_by_id() both
because it makes more sense than the current code, and also to have a
good base for the discussion.

Thanks,
Jens



Re: [XEN PATCH v3 5/5] xen/arm: ffa: support notification

2024-04-29 Thread Jens Wiklander
Hi Julien,

On Fri, Apr 26, 2024 at 9:07 PM Julien Grall  wrote:
>
> Hi Jens,
>
> On 26/04/2024 09:47, Jens Wiklander wrote:
> > 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;
>
> This changes seems unrelated to this patch. This wants to be separate
> (if you actually intended to change it).

I'm sorry, my bad. I meant for this to go into "xen/arm: allow
dynamically assigned SGI handlers".

>
> >   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);
> &

Re: [XEN PATCH v3 5/5] xen/arm: ffa: support notification

2024-04-26 Thread Jens Wiklander
On Fri, Apr 26, 2024 at 2:41 PM Bertrand Marquis
 wrote:
>
> Hi Jens,
>
> > On 26 Apr 2024, at 14:32, Jens Wiklander  wrote:
> >
> > Hi Bertrand,
> >
> > On Fri, Apr 26, 2024 at 2:19 PM Bertrand Marquis
> >  wrote:
> >>
> >> Hi Jens,
> >>
> >>> On 26 Apr 2024, at 14:11, Jens Wiklander  
> >>> wrote:
> >>>
> >>> Hi Bertrand,
> >>>
> >>> On Fri, Apr 26, 2024 at 11:20 AM Bertrand Marquis
> >>>  wrote:
> >>>>
> >>>> Hi Jens,
> >>>>
> >>>>> On 26 Apr 2024, at 10:47, Jens Wiklander  
> >>>>> wrote:
> >>>>>
> > [...]
> >>>>> +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(, );
> >>>>> +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.
> >>>
> >>> That shouldn't be needed because this is done in sequence only one CPU
> >>> at a time.
> >>
> >> Sorry i do not understand here.
> >> You have a loop over each online cpu and on each loop you are assigning
> >> irq_info.action with a newly allocated struct irqaction so you are in 
> >> practice
> >> overloading on cpu 2 the action that was allocated for cpu 1.
> >>
> >> What do you mean by sequence here ?
> >>
> >
> > My understanding is that for_each_online_cpu(cpu) loops over each cpu,
> > one at a time. The call
> > on_selected_cpus(cpumask_of(cpu), notif_irq_enable, _info, 1);
> > returns after notif_irq_enable() has returned on the CPU in question
> > thanks to the "1" (wait) parameter. So once it has returned _info
> > isn't used by the other CPU any longer and we can assign a new value
> > to irq_info.action.
>
> Right so you loose track of what was assigned so you are not able to
> free it.
> If that is wanted then why saving this in irq.action as you will only have
> there the one allocated for the last online cpu.

Wouldn't release_irq() free it? An error here is unlikely, but we may
be left with a few installed struct irqaction if it occurs. I can add
a more elaborate error path if it's worth the added complexity.

Thanks,
Jens



Re: [XEN PATCH v3 5/5] xen/arm: ffa: support notification

2024-04-26 Thread Jens Wiklander
Hi Bertrand,

On Fri, Apr 26, 2024 at 2:19 PM Bertrand Marquis
 wrote:
>
> Hi Jens,
>
> > On 26 Apr 2024, at 14:11, Jens Wiklander  wrote:
> >
> > Hi Bertrand,
> >
> > On Fri, Apr 26, 2024 at 11:20 AM Bertrand Marquis
> >  wrote:
> >>
> >> Hi Jens,
> >>
> >>> On 26 Apr 2024, at 10:47, Jens Wiklander  
> >>> wrote:
> >>>
[...]
> >>> +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(, );
> >>> +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.
> >
> > That shouldn't be needed because this is done in sequence only one CPU
> > at a time.
>
> Sorry i do not understand here.
> You have a loop over each online cpu and on each loop you are assigning
> irq_info.action with a newly allocated struct irqaction so you are in practice
> overloading on cpu 2 the action that was allocated for cpu 1.
>
> What do you mean by sequence here ?
>

My understanding is that for_each_online_cpu(cpu) loops over each cpu,
one at a time. The call
on_selected_cpus(cpumask_of(cpu), notif_irq_enable, _info, 1);
returns after notif_irq_enable() has returned on the CPU in question
thanks to the "1" (wait) parameter. So once it has returned _info
isn't used by the other CPU any longer and we can assign a new value
to irq_info.action.

Thanks,
Jens



Re: [XEN PATCH v3 5/5] xen/arm: ffa: support notification

2024-04-26 Thread Jens Wiklander
Hi Bertrand,

On Fri, Apr 26, 2024 at 11:20 AM Bertrand Marquis
 wrote:
>
> Hi Jens,
>
> > On 26 Apr 2024, at 10:47, Jens Wiklander  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 
> > ---
> > 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_SU

[XEN PATCH v3 5/5] xen/arm: ffa: support notification

2024-04-26 Thread Jens Wiklander
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 
---
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_ge

[XEN PATCH v3 1/5] xen/arm: ffa: refactor ffa_handle_call()

2024-04-26 Thread Jens Wiklander
Refactors the large switch block in ffa_handle_call() to use common code
for the simple case where it's either an error code or success with no
further parameters.

Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
---
 xen/arch/arm/tee/ffa.c | 30 ++
 1 file changed, 10 insertions(+), 20 deletions(-)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 8665201e34a9..5209612963e1 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -273,18 +273,10 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 case FFA_RXTX_MAP_64:
 e = ffa_handle_rxtx_map(fid, get_user_reg(regs, 1),
get_user_reg(regs, 2), get_user_reg(regs, 3));
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 case FFA_RXTX_UNMAP:
 e = ffa_handle_rxtx_unmap();
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 case FFA_PARTITION_INFO_GET:
 e = ffa_handle_partition_info_get(get_user_reg(regs, 1),
   get_user_reg(regs, 2),
@@ -299,11 +291,7 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 return true;
 case FFA_RX_RELEASE:
 e = ffa_handle_rx_release();
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 case FFA_MSG_SEND_DIRECT_REQ_32:
 case FFA_MSG_SEND_DIRECT_REQ_64:
 handle_msg_send_direct_req(regs, fid);
@@ -316,17 +304,19 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 e = ffa_handle_mem_reclaim(regpair_to_uint64(get_user_reg(regs, 2),
  get_user_reg(regs, 1)),
get_user_reg(regs, 3));
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 
 default:
 gprintk(XENLOG_ERR, "ffa: unhandled fid 0x%x\n", fid);
 ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED);
 return true;
 }
+
+if ( e )
+ffa_set_regs_error(regs, e);
+else
+ffa_set_regs_success(regs, 0, 0);
+return true;
 }
 
 static int ffa_domain_init(struct domain *d)
-- 
2.34.1




[XEN PATCH v3 3/5] xen/arm: ffa: simplify ffa_handle_mem_share()

2024-04-26 Thread Jens Wiklander
Simplify ffa_handle_mem_share() by removing the start_page_idx and
last_page_idx parameters from get_shm_pages() and check that the number
of pages matches expectations at the end of get_shm_pages().

Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
---
 xen/arch/arm/tee/ffa_shm.c | 18 ++
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c
index 75a5b66aeb4c..370d83ec5cf8 100644
--- a/xen/arch/arm/tee/ffa_shm.c
+++ b/xen/arch/arm/tee/ffa_shm.c
@@ -159,10 +159,9 @@ static int32_t ffa_mem_reclaim(uint32_t handle_lo, 
uint32_t handle_hi,
  */
 static int get_shm_pages(struct domain *d, struct ffa_shm_mem *shm,
  const struct ffa_address_range *range,
- uint32_t range_count, unsigned int start_page_idx,
- unsigned int *last_page_idx)
+ uint32_t range_count)
 {
-unsigned int pg_idx = start_page_idx;
+unsigned int pg_idx = 0;
 gfn_t gfn;
 unsigned int n;
 unsigned int m;
@@ -191,7 +190,9 @@ static int get_shm_pages(struct domain *d, struct 
ffa_shm_mem *shm,
 }
 }
 
-*last_page_idx = pg_idx;
+/* The ranges must add up */
+if ( pg_idx < shm->page_count )
+return FFA_RET_INVALID_PARAMETERS;
 
 return FFA_RET_OK;
 }
@@ -460,7 +461,6 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 struct domain *d = current->domain;
 struct ffa_ctx *ctx = d->arch.tee;
 struct ffa_shm_mem *shm = NULL;
-unsigned int last_page_idx = 0;
 register_t handle_hi = 0;
 register_t handle_lo = 0;
 int ret = FFA_RET_DENIED;
@@ -570,15 +570,9 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 goto out;
 }
 
-ret = get_shm_pages(d, shm, region_descr->address_range_array, range_count,
-0, _page_idx);
+ret = get_shm_pages(d, shm, region_descr->address_range_array, 
range_count);
 if ( ret )
 goto out;
-if ( last_page_idx != shm->page_count )
-{
-ret = FFA_RET_INVALID_PARAMETERS;
-goto out;
-}
 
 /* Note that share_shm() uses our tx buffer */
 spin_lock(_tx_buffer_lock);
-- 
2.34.1




[XEN PATCH v3 0/5] FF-A notifications

2024-04-26 Thread Jens Wiklander
Hi,

This patch set adds support for FF-A notifications. We only support
global notifications, per vCPU notifications remain unsupported.

The first three patches are further cleanup and can be merged before the
rest if desired.

A physical SGI is used to make Xen aware of pending FF-A notifications. The
physical SGI is selected by the SPMC in the secure world. Since it must not
already be used by Xen the SPMC is in practice forced to donate one of the
secure SGIs, but that's normally not a problem. The SGI handling in Xen is
updated to support registration of handlers for SGIs that aren't statically
assigned, that is, SGI IDs above GIC_SGI_MAX.

Thanks,
Jens

v2->v3:
- "xen/arm: ffa: support notification" and
  "xen/arm: allow dynamically assigned SGI handlers" updated as requestsed,
  details in each patch.

v1->v2:
- "xen/arm: ffa: support notification" and
  "xen/arm: allow dynamically assigned SGI handlers" updated as requestsed,
  details in each patch.
- Added Bertrands R-B for "xen/arm: ffa: refactor ffa_handle_call()",
  "xen/arm: ffa: use ACCESS_ONCE()", and
  "xen/arm: ffa: simplify ffa_handle_mem_share()"

Jens Wiklander (5):
  xen/arm: ffa: refactor ffa_handle_call()
  xen/arm: ffa: use ACCESS_ONCE()
  xen/arm: ffa: simplify ffa_handle_mem_share()
  xen/arm: allow dynamically assigned SGI handlers
  xen/arm: ffa: support notification

 xen/arch/arm/gic.c  |  12 +-
 xen/arch/arm/include/asm/gic.h  |   2 +-
 xen/arch/arm/irq.c  |  18 +-
 xen/arch/arm/tee/Makefile   |   1 +
 xen/arch/arm/tee/ffa.c  |  83 +--
 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/arch/arm/tee/ffa_shm.c  |  33 ++-
 xen/include/public/arch-arm.h   |  14 ++
 10 files changed, 551 insertions(+), 55 deletions(-)
 create mode 100644 xen/arch/arm/tee/ffa_notif.c

-- 
2.34.1




[XEN PATCH v3 4/5] xen/arm: allow dynamically assigned SGI handlers

2024-04-26 Thread Jens Wiklander
Updates so request_irq() can be used with a dynamically assigned SGI irq
as input. This prepares for a later patch where an FF-A schedule
receiver interrupt handler is installed for an SGI generated by the
secure world.

>From the Arm Base System Architecture v1.0C [1]:
"The system shall implement at least eight Non-secure SGIs, assigned to
interrupt IDs 0-7."

gic_route_irq_to_xen() don't gic_set_irq_type() for SGIs since they are
always edge triggered.

gic_interrupt() is updated to route the dynamically assigned SGIs to
do_IRQ() instead of do_sgi(). The latter still handles the statically
assigned SGI handlers like for instance GIC_SGI_CALL_FUNCTION.

[1] https://developer.arm.com/documentation/den0094/

Signed-off-by: Jens Wiklander 
---
v2->v3
- Rename GIC_SGI_MAX to GIC_SGI_STATIC_MAX and rename do_sgi() to
  do_static_sgi()
- Update comment in setup_irq() to mention that SGI irq_desc is banked
- Add ASSERT() in do_IRQ() that the irq isn't an SGI before injecting
  calling vgic_inject_irq()
- Initialize local_irqs_type[] range for SGIs as IRQ_TYPE_EDGE_RISING
- Adding link to the Arm Base System Architecture v1.0C

v1->v2
- Update patch description as requested
---
 xen/arch/arm/gic.c | 12 +++-
 xen/arch/arm/include/asm/gic.h |  2 +-
 xen/arch/arm/irq.c | 18 ++
 3 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 44c40e86defe..882768252740 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -38,7 +38,7 @@ const struct gic_hw_operations *gic_hw_ops;
 static void __init __maybe_unused build_assertions(void)
 {
 /* Check our enum gic_sgi only covers SGIs */
-BUILD_BUG_ON(GIC_SGI_MAX > NR_GIC_SGI);
+BUILD_BUG_ON(GIC_SGI_STATIC_MAX > NR_GIC_SGI);
 }
 
 void register_gic_ops(const struct gic_hw_operations *ops)
@@ -117,7 +117,9 @@ void gic_route_irq_to_xen(struct irq_desc *desc, unsigned 
int priority)
 
 desc->handler = gic_hw_ops->gic_host_irq_type;
 
-gic_set_irq_type(desc, desc->arch.type);
+/* SGIs are always edge-triggered, so there is need to set it */
+if ( desc->irq >= NR_GIC_SGI)
+gic_set_irq_type(desc, desc->arch.type);
 gic_set_irq_priority(desc, priority);
 }
 
@@ -330,7 +332,7 @@ void gic_disable_cpu(void)
 gic_hw_ops->disable_interface();
 }
 
-static void do_sgi(struct cpu_user_regs *regs, enum gic_sgi sgi)
+static void do_static_sgi(struct cpu_user_regs *regs, enum gic_sgi sgi)
 {
 struct irq_desc *desc = irq_to_desc(sgi);
 
@@ -375,7 +377,7 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
 /* Reading IRQ will ACK it */
 irq = gic_hw_ops->read_irq();
 
-if ( likely(irq >= 16 && irq < 1020) )
+if ( likely(irq >= GIC_SGI_STATIC_MAX && irq < 1020) )
 {
 isb();
 do_IRQ(regs, irq, is_fiq);
@@ -387,7 +389,7 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
 }
 else if ( unlikely(irq < 16) )
 {
-do_sgi(regs, irq);
+do_static_sgi(regs, irq);
 }
 else
 {
diff --git a/xen/arch/arm/include/asm/gic.h b/xen/arch/arm/include/asm/gic.h
index 03f209529b13..541f0eeb808a 100644
--- a/xen/arch/arm/include/asm/gic.h
+++ b/xen/arch/arm/include/asm/gic.h
@@ -285,7 +285,7 @@ enum gic_sgi {
 GIC_SGI_EVENT_CHECK,
 GIC_SGI_DUMP_STATE,
 GIC_SGI_CALL_FUNCTION,
-GIC_SGI_MAX,
+GIC_SGI_STATIC_MAX,
 };
 
 /* SGI irq mode types */
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index bcce80a4d624..d7306aa64d50 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -152,7 +152,13 @@ void __init init_IRQ(void)
 
 spin_lock(_irqs_type_lock);
 for ( irq = 0; irq < NR_LOCAL_IRQS; irq++ )
-local_irqs_type[irq] = IRQ_TYPE_INVALID;
+{
+/* SGIs are always edge-triggered */
+if ( irq < NR_GIC_SGI )
+local_irqs_type[irq] = DT_IRQ_TYPE_EDGE_RISING;
+else
+local_irqs_type[irq] = IRQ_TYPE_INVALID;
+}
 spin_unlock(_irqs_type_lock);
 
 BUG_ON(init_local_irq_data(smp_processor_id()) < 0);
@@ -224,9 +230,12 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq, 
int is_fiq)
 
 perfc_incr(irqs);
 
-ASSERT(irq >= 16); /* SGIs do not come down this path */
+/* Statically assigned SGIs do not come down this path */
+ASSERT(irq >= GIC_SGI_STATIC_MAX);
 
-if ( irq < 32 )
+if ( irq < NR_GIC_SGI )
+perfc_incr(ipis);
+else if ( irq < NR_GIC_LOCAL_IRQS )
 perfc_incr(ppis);
 else
 perfc_incr(spis);
@@ -260,6 +269,7 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq, 
int is_fiq)
  * The irq cannot be a PPI, we only support delivery of SPIs to
  * guests.
  */
+ASSERT(irq >= NR_GIC_SGI);
 vgic_inject_irq(info-&

[XEN PATCH v3 2/5] xen/arm: ffa: use ACCESS_ONCE()

2024-04-26 Thread Jens Wiklander
Replace read_atomic() with ACCESS_ONCE() to match the intended use, that
is, to prevent the compiler from (via optimization) reading shared
memory more than once.

Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
---
 xen/arch/arm/tee/ffa_shm.c | 15 ---
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c
index eed9ad2d2986..75a5b66aeb4c 100644
--- a/xen/arch/arm/tee/ffa_shm.c
+++ b/xen/arch/arm/tee/ffa_shm.c
@@ -7,6 +7,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -171,8 +172,8 @@ static int get_shm_pages(struct domain *d, struct 
ffa_shm_mem *shm,
 
 for ( n = 0; n < range_count; n++ )
 {
-page_count = read_atomic([n].page_count);
-addr = read_atomic([n].address);
+page_count = ACCESS_ONCE(range[n].page_count);
+addr = ACCESS_ONCE(range[n].address);
 for ( m = 0; m < page_count; m++ )
 {
 if ( pg_idx >= shm->page_count )
@@ -527,13 +528,13 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 goto out_unlock;
 
 mem_access = ctx->tx + trans.mem_access_offs;
-if ( read_atomic(_access->access_perm.perm) != FFA_MEM_ACC_RW )
+if ( ACCESS_ONCE(mem_access->access_perm.perm) != FFA_MEM_ACC_RW )
 {
 ret = FFA_RET_NOT_SUPPORTED;
 goto out_unlock;
 }
 
-region_offs = read_atomic(_access->region_offs);
+region_offs = ACCESS_ONCE(mem_access->region_offs);
 if ( sizeof(*region_descr) + region_offs > frag_len )
 {
 ret = FFA_RET_NOT_SUPPORTED;
@@ -541,8 +542,8 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 }
 
 region_descr = ctx->tx + region_offs;
-range_count = read_atomic(_descr->address_range_count);
-page_count = read_atomic(_descr->total_page_count);
+range_count = ACCESS_ONCE(region_descr->address_range_count);
+page_count = ACCESS_ONCE(region_descr->total_page_count);
 
 if ( !page_count )
 {
@@ -557,7 +558,7 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 goto out_unlock;
 }
 shm->sender_id = trans.sender_id;
-shm->ep_id = read_atomic(_access->access_perm.endpoint_id);
+shm->ep_id = ACCESS_ONCE(mem_access->access_perm.endpoint_id);
 
 /*
  * Check that the Composite memory region descriptor fits.
-- 
2.34.1




Re: [XEN PATCH v2 5/5] xen/arm: ffa: support notification

2024-04-23 Thread Jens Wiklander
Hi Julien,

On Mon, Apr 22, 2024 at 1:40 PM Julien Grall  wrote:
>
> Hi Jens,
>
> This is not a full review of the code. I will let Bertrand doing it.
>
> On 22/04/2024 08:37, Jens Wiklander wrote:
> > +void ffa_notif_init(void)
> > +{
> > +const struct arm_smccc_1_2_regs arg = {
> > +.a0 = FFA_FEATURES,
> > +.a1 = FFA_FEATURE_SCHEDULE_RECV_INTR,
> > +};
> > +struct arm_smccc_1_2_regs resp;
> > +unsigned int irq;
> > +int ret;
> > +
> > +arm_smccc_1_2_smc(, );
> > +if ( resp.a0 != FFA_SUCCESS_32 )
> > +return;
> > +
> > +irq = resp.a2;
> > +if ( irq >= NR_GIC_SGI )
> > +irq_set_type(irq, IRQ_TYPE_EDGE_RISING);
> > +ret = request_irq(irq, 0, notif_irq_handler, "FF-A notif", NULL);
>
> If I am not mistaken, ffa_notif_init() is only called once on the boot
> CPU. However, request_irq() needs to be called on every CPU so the
> callback is registered every where and the interrupt enabled.
>
> I know the name of the function is rather confusing. So can you confirm
> this is what you expected?

Good catch, no this wasn't what I expected. I'll need to change this.

>
> [...]
>
> > diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h
> > index 98236cbf14a3..ef8ffd4526bd 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
> > @@ -97,6 +98,18 @@
> >*/
> >   #define FFA_MAX_SHM_COUNT   32
> >
> > +/*
> > + * TODO How to manage the available SGIs? SGI 8-15 seem to be entirely
> > + * unused, but that may change.
>
> Are the value below intended for the guests? If so, can they be moved in
> public/arch-arm.h along with the others guest interrupts?

Yes, I'll move it.

>
> > + *
> > + * SGI is the preferred delivery mechanism. 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.
>
> Do you have a pointer to the specification?

There's one at the top of arch/arm/tee/ffa.c,
https://developer.arm.com/documentation/den0077/e
Do you want the link close to the defines when I've moved them to
public/arch-arm.h?
Or is it perhaps better to give a link to "Arm Base System
Architecture v1.0C", https://developer.arm.com/documentation/den0094/
instead?

Thanks,
Jens



Re: [XEN PATCH v2 4/5] xen/arm: allow dynamically assigned SGI handlers

2024-04-23 Thread Jens Wiklander
On Tue, Apr 23, 2024 at 1:05 PM Julien Grall  wrote:
>
>
>
> On 23/04/2024 10:35, Jens Wiklander wrote:
> > Hi Julien,
>
> Hi Jens,
>
> > On Mon, Apr 22, 2024 at 12:57 PM Julien Grall  wrote:
> >>
> >> Hi Jens,
> >>
> >> On 22/04/2024 08:37, Jens Wiklander wrote:
> >>> Updates so request_irq() can be used with a dynamically assigned SGI irq
> >>> as input. This prepares for a later patch where an FF-A schedule
> >>> receiver interrupt handler is installed for an SGI generated by the
> >>> secure world.
> >>
> >> I would like to understand the use-case a bit more. Who is responsible
> >> to decide the SGI number? Is it Xen or the firmware?
> >>
> >> If the later, how can we ever guarantee the ID is not going to clash
> >> with what the OS/hypervisor is using? Is it described in a
> >> specification? If so, please give a pointer.
> >
> > The firmware decides the SGI number. Given that the firmware doesn't
> > know which SGIs Xen is using it typically needs to donate one of the
> > secure SGIs, but that is transparent to Xen.
>
> Right this is my concern. The firmware decides the number, but at the
> same time Xen thinks that all the SGIs are available (AFAIK there is
> only one set).
>
> What I would like to see is some wording from a spec indicating that the
> SGIs ID reserved by the firmware will not be clashing with the one used
> by Xen.
>
> >
> >
> >>
> >>>
> >>> gic_route_irq_to_xen() don't gic_set_irq_type() for SGIs since they are
> >>> always edge triggered.
> >>>
> >>> gic_interrupt() is updated to route the dynamically assigned SGIs to
> >>> do_IRQ() instead of do_sgi(). The latter still handles the statically
> >>> assigned SGI handlers like for instance GIC_SGI_CALL_FUNCTION.
> >>>
> >>> Signed-off-by: Jens Wiklander 
> >>> ---
> >>> v1->v2
> >>> - Update patch description as requested
> >>> ---
> >>>xen/arch/arm/gic.c | 5 +++--
> >>>xen/arch/arm/irq.c | 7 +--
> >>
> >> I am not sure where to write the comment. But I think the comment on top
> >> of irq_set_affinity() in setup_irq() should also be updated.
> >>
> >>>2 files changed, 8 insertions(+), 4 deletions(-)
> >>>
> >>> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> >>> index 44c40e86defe..e9aeb7138455 100644
> >>> --- a/xen/arch/arm/gic.c
> >>> +++ b/xen/arch/arm/gic.c
> >>> @@ -117,7 +117,8 @@ void gic_route_irq_to_xen(struct irq_desc *desc, 
> >>> unsigned int priority)
> >>>
> >>>desc->handler = gic_hw_ops->gic_host_irq_type;
> >>>
> >>> -gic_set_irq_type(desc, desc->arch.type);
> >>> +if ( desc->irq >= NR_GIC_SGI)
> >>> +gic_set_irq_type(desc, desc->arch.type);
> >>
> >> So above, you say that the SGIs are always edge-triggered interrupt. So
> >> I assume desc->arch.type. So are you skipping the call because it is
> >> unnessary or it could do the wrong thing?
> >>
> >> Ideally, the outcome of the answer be part of the comment on top of the
> >> check.
> >
> > gic_set_irq_type() has an assert "ASSERT(type != IRQ_TYPE_INVALID)"
> > which is triggered without this check.
> > So it's both unnecessary and wrong. I suppose we could update the
> > bookkeeping of all SGIs to be edge-triggered instead of
> > IRQ_TYPE_INVALID. It would still be unnecessary though. What do you
> > suggest?
>
> I would rather prefer if we update the book-keeping for all the SGIs.

I'll update the code.

>
> [...]
>
> >>
> >>>{
> >>>isb();
> >>>do_IRQ(regs, irq, is_fiq);
> >>> diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
> >>> index bcce80a4d624..fdb214560978 100644
> >>> --- a/xen/arch/arm/irq.c
> >>> +++ b/xen/arch/arm/irq.c
> >>> @@ -224,9 +224,12 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int 
> >>> irq, int is_fiq)
> >>>
> >>>perfc_incr(irqs);
> >>>
> >>> -ASSERT(irq >= 16); /* SGIs do not come down this path */
> >>> +/* Statically assigned SGIs do not come down this path */
> >>> +ASSERT(irq >= GIC_SGI_MAX);
> >>
> >>
> >> With this ch

Re: [XEN PATCH v2 4/5] xen/arm: allow dynamically assigned SGI handlers

2024-04-23 Thread Jens Wiklander
Hi,

On Tue, Apr 23, 2024 at 4:28 PM Julien Grall  wrote:
>
> Hi Bertrand,
>
> On 23/04/2024 14:23, Bertrand Marquis wrote:
> > Hi Julien,
> >
> >> On 23 Apr 2024, at 14:37, Bertrand Marquis  
> >> wrote:
> >>
> >> Hi Julien,
> >>
> >>> On 23 Apr 2024, at 13:05, Julien Grall  wrote:
> >>>
> >>>
> >>>
> >>> On 23/04/2024 10:35, Jens Wiklander wrote:
> >>>> Hi Julien,
> >>>
> >>> Hi Jens,
> >>>
> >>>> On Mon, Apr 22, 2024 at 12:57 PM Julien Grall  wrote:
> >>>>>
> >>>>> Hi Jens,
> >>>>>
> >>>>> On 22/04/2024 08:37, Jens Wiklander wrote:
> >>>>>> Updates so request_irq() can be used with a dynamically assigned SGI 
> >>>>>> irq
> >>>>>> as input. This prepares for a later patch where an FF-A schedule
> >>>>>> receiver interrupt handler is installed for an SGI generated by the
> >>>>>> secure world.
> >>>>>
> >>>>> I would like to understand the use-case a bit more. Who is responsible
> >>>>> to decide the SGI number? Is it Xen or the firmware?
> >>>>>
> >>>>> If the later, how can we ever guarantee the ID is not going to clash
> >>>>> with what the OS/hypervisor is using? Is it described in a
> >>>>> specification? If so, please give a pointer.
> >>>> The firmware decides the SGI number. Given that the firmware doesn't
> >>>> know which SGIs Xen is using it typically needs to donate one of the
> >>>> secure SGIs, but that is transparent to Xen.
> >>>
> >>> Right this is my concern. The firmware decides the number, but at the 
> >>> same time Xen thinks that all the SGIs are available (AFAIK there is only 
> >>> one set).
> >>>
> >>> What I would like to see is some wording from a spec indicating that the 
> >>> SGIs ID reserved by the firmware will not be clashing with the one used 
> >>> by Xen.
> >>
> >> The idea is that the only SGI reserved for secure are used by the secure 
> >> world (in fact it is the SPMC in the secure world who tells us which SGI 
> >> it will generate).
> >> So in theory that means it will always use an SGI between 8 and 15.
> >>
> >> Now it could make sense in fact to check that the number returned by the 
> >> firmware (or SPMC) is not clashing with Xen as it is a recommendation in 
> >> the spec and
> >> in fact an implementation might do something different.
> >>
> >> Right now there is no spec that will say that it will never clash with the 
> >> one used by Xen as the FF-A spec is not enforcing anything here so it 
> >> would be a good idea
> >> to check and disable FF-A with a proper error message if this happens.
> >
> >
> > After some more digging here is what is recommended by Arm in the Arm Base 
> > System Architecture v1.0C [1]:
> >
> > "The system shall implement at least eight Non-secure SGIs, assigned to 
> > interrupt IDs 0-7."
>
> Thanks! Can we provide a link to the specification in the commit message?

Sure, I'll add a link.

>
> >
> > So basically as long as Xen is using SGIs 0-7 it is safe as those shall 
> > never be used by the secure world.
> > Now i do agree that we should check that whatever is returned by the 
> > firmware is not conflicting with what
> > is used by Xen.
> +1.

That makes sense, I'll add a check.

Thanks,
Jens



Re: [XEN PATCH v2 4/5] xen/arm: allow dynamically assigned SGI handlers

2024-04-23 Thread Jens Wiklander
Hi Julien,

On Mon, Apr 22, 2024 at 12:57 PM Julien Grall  wrote:
>
> Hi Jens,
>
> On 22/04/2024 08:37, Jens Wiklander wrote:
> > Updates so request_irq() can be used with a dynamically assigned SGI irq
> > as input. This prepares for a later patch where an FF-A schedule
> > receiver interrupt handler is installed for an SGI generated by the
> > secure world.
>
> I would like to understand the use-case a bit more. Who is responsible
> to decide the SGI number? Is it Xen or the firmware?
>
> If the later, how can we ever guarantee the ID is not going to clash
> with what the OS/hypervisor is using? Is it described in a
> specification? If so, please give a pointer.

The firmware decides the SGI number. Given that the firmware doesn't
know which SGIs Xen is using it typically needs to donate one of the
secure SGIs, but that is transparent to Xen.


>
> >
> > gic_route_irq_to_xen() don't gic_set_irq_type() for SGIs since they are
> > always edge triggered.
> >
> > gic_interrupt() is updated to route the dynamically assigned SGIs to
> > do_IRQ() instead of do_sgi(). The latter still handles the statically
> > assigned SGI handlers like for instance GIC_SGI_CALL_FUNCTION.
> >
> > Signed-off-by: Jens Wiklander 
> > ---
> > v1->v2
> > - Update patch description as requested
> > ---
> >   xen/arch/arm/gic.c | 5 +++--
> >   xen/arch/arm/irq.c | 7 +--
>
> I am not sure where to write the comment. But I think the comment on top
> of irq_set_affinity() in setup_irq() should also be updated.
>
> >   2 files changed, 8 insertions(+), 4 deletions(-)
> >
> > diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> > index 44c40e86defe..e9aeb7138455 100644
> > --- a/xen/arch/arm/gic.c
> > +++ b/xen/arch/arm/gic.c
> > @@ -117,7 +117,8 @@ void gic_route_irq_to_xen(struct irq_desc *desc, 
> > unsigned int priority)
> >
> >   desc->handler = gic_hw_ops->gic_host_irq_type;
> >
> > -gic_set_irq_type(desc, desc->arch.type);
> > +if ( desc->irq >= NR_GIC_SGI)
> > +gic_set_irq_type(desc, desc->arch.type);
>
> So above, you say that the SGIs are always edge-triggered interrupt. So
> I assume desc->arch.type. So are you skipping the call because it is
> unnessary or it could do the wrong thing?
>
> Ideally, the outcome of the answer be part of the comment on top of the
> check.

gic_set_irq_type() has an assert "ASSERT(type != IRQ_TYPE_INVALID)"
which is triggered without this check.
So it's both unnecessary and wrong. I suppose we could update the
bookkeeping of all SGIs to be edge-triggered instead of
IRQ_TYPE_INVALID. It would still be unnecessary though. What do you
suggest?

>
> >   gic_set_irq_priority(desc, priority);
> >   }
> >
> > @@ -375,7 +376,7 @@ void gic_interrupt(struct cpu_user_regs *regs, int 
> > is_fiq)
> >   /* Reading IRQ will ACK it */
> >   irq = gic_hw_ops->read_irq();
> >
> > -if ( likely(irq >= 16 && irq < 1020) )
> > +if ( likely(irq >= GIC_SGI_MAX && irq < 1020) )
>
> This check is now rather confusing as one could think that do_IRQ()
> would still not be reached for dynamic SGI. I think it would be clearer
> GIC_SGI_MAX needs to be renamed to GIC_SGI_STATIC_MAX and do_sgi() to
> do_static_sgi().

Thanks, I'll update.

>
> >   {
> >   isb();
> >   do_IRQ(regs, irq, is_fiq);
> > diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
> > index bcce80a4d624..fdb214560978 100644
> > --- a/xen/arch/arm/irq.c
> > +++ b/xen/arch/arm/irq.c
> > @@ -224,9 +224,12 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int 
> > irq, int is_fiq)
> >
> >   perfc_incr(irqs);
> >
> > -ASSERT(irq >= 16); /* SGIs do not come down this path */
> > +/* Statically assigned SGIs do not come down this path */
> > +ASSERT(irq >= GIC_SGI_MAX);
>
>
> With this change, I think the path with vgic_inject_irq() now needs to
> gain an ASSERT(irq >= NR_GIC_SGI) because the path is not supposed to be
> taken for SGIs.

I'm sorry, I don't see the connection. If I add
ASSERT(virq >= NR_GIC_SGI);
at the top of vgic_inject_irq() it will panic when injecting a
Schedule Receiver or Notification Pending Interrupt for a guest.


>
> >
> > -if ( irq < 32 )
> > +if ( irq < NR_GIC_SGI )
> > +perfc_incr(ipis);
> > +else if ( irq < NR_GIC_LOCAL_IRQS )
> >   perfc_incr(ppis);
> >   else
> >   perfc_incr(spis);
>

Thanks,
Jens



[XEN PATCH v2 4/5] xen/arm: allow dynamically assigned SGI handlers

2024-04-22 Thread Jens Wiklander
Updates so request_irq() can be used with a dynamically assigned SGI irq
as input. This prepares for a later patch where an FF-A schedule
receiver interrupt handler is installed for an SGI generated by the
secure world.

gic_route_irq_to_xen() don't gic_set_irq_type() for SGIs since they are
always edge triggered.

gic_interrupt() is updated to route the dynamically assigned SGIs to
do_IRQ() instead of do_sgi(). The latter still handles the statically
assigned SGI handlers like for instance GIC_SGI_CALL_FUNCTION.

Signed-off-by: Jens Wiklander 
---
v1->v2
- Update patch description as requested
---
 xen/arch/arm/gic.c | 5 +++--
 xen/arch/arm/irq.c | 7 +--
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 44c40e86defe..e9aeb7138455 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -117,7 +117,8 @@ void gic_route_irq_to_xen(struct irq_desc *desc, unsigned 
int priority)
 
 desc->handler = gic_hw_ops->gic_host_irq_type;
 
-gic_set_irq_type(desc, desc->arch.type);
+if ( desc->irq >= NR_GIC_SGI)
+gic_set_irq_type(desc, desc->arch.type);
 gic_set_irq_priority(desc, priority);
 }
 
@@ -375,7 +376,7 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
 /* Reading IRQ will ACK it */
 irq = gic_hw_ops->read_irq();
 
-if ( likely(irq >= 16 && irq < 1020) )
+if ( likely(irq >= GIC_SGI_MAX && irq < 1020) )
 {
 isb();
 do_IRQ(regs, irq, is_fiq);
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index bcce80a4d624..fdb214560978 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -224,9 +224,12 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq, 
int is_fiq)
 
 perfc_incr(irqs);
 
-ASSERT(irq >= 16); /* SGIs do not come down this path */
+/* Statically assigned SGIs do not come down this path */
+ASSERT(irq >= GIC_SGI_MAX);
 
-if ( irq < 32 )
+if ( irq < NR_GIC_SGI )
+perfc_incr(ipis);
+else if ( irq < NR_GIC_LOCAL_IRQS )
 perfc_incr(ppis);
 else
 perfc_incr(spis);
-- 
2.34.1




[XEN PATCH v2 5/5] xen/arm: ffa: support notification

2024-04-22 Thread Jens Wiklander
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 
---
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/tee/Makefile   |   1 +
 xen/arch/arm/tee/ffa.c  |  55 +-
 xen/arch/arm/tee/ffa_notif.c| 331 
 xen/arch/arm/tee/ffa_partinfo.c |   9 +-
 xen/arch/arm/tee/ffa_private.h  |  68 ++-
 5 files changed, 457 insertions(+), 7 deletions(-)
 create mode 100644 xen/arch/arm/tee/ffa_notif.c

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..aa171c0b61f0 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, 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, 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_doma

[XEN PATCH v2 2/5] xen/arm: ffa: use ACCESS_ONCE()

2024-04-22 Thread Jens Wiklander
Replace read_atomic() with ACCESS_ONCE() to match the intended use, that
is, to prevent the compiler from (via optimization) reading shared
memory more than once.

Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
---
 xen/arch/arm/tee/ffa_shm.c | 15 ---
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c
index eed9ad2d2986..75a5b66aeb4c 100644
--- a/xen/arch/arm/tee/ffa_shm.c
+++ b/xen/arch/arm/tee/ffa_shm.c
@@ -7,6 +7,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -171,8 +172,8 @@ static int get_shm_pages(struct domain *d, struct 
ffa_shm_mem *shm,
 
 for ( n = 0; n < range_count; n++ )
 {
-page_count = read_atomic([n].page_count);
-addr = read_atomic([n].address);
+page_count = ACCESS_ONCE(range[n].page_count);
+addr = ACCESS_ONCE(range[n].address);
 for ( m = 0; m < page_count; m++ )
 {
 if ( pg_idx >= shm->page_count )
@@ -527,13 +528,13 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 goto out_unlock;
 
 mem_access = ctx->tx + trans.mem_access_offs;
-if ( read_atomic(_access->access_perm.perm) != FFA_MEM_ACC_RW )
+if ( ACCESS_ONCE(mem_access->access_perm.perm) != FFA_MEM_ACC_RW )
 {
 ret = FFA_RET_NOT_SUPPORTED;
 goto out_unlock;
 }
 
-region_offs = read_atomic(_access->region_offs);
+region_offs = ACCESS_ONCE(mem_access->region_offs);
 if ( sizeof(*region_descr) + region_offs > frag_len )
 {
 ret = FFA_RET_NOT_SUPPORTED;
@@ -541,8 +542,8 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 }
 
 region_descr = ctx->tx + region_offs;
-range_count = read_atomic(_descr->address_range_count);
-page_count = read_atomic(_descr->total_page_count);
+range_count = ACCESS_ONCE(region_descr->address_range_count);
+page_count = ACCESS_ONCE(region_descr->total_page_count);
 
 if ( !page_count )
 {
@@ -557,7 +558,7 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 goto out_unlock;
 }
 shm->sender_id = trans.sender_id;
-shm->ep_id = read_atomic(_access->access_perm.endpoint_id);
+shm->ep_id = ACCESS_ONCE(mem_access->access_perm.endpoint_id);
 
 /*
  * Check that the Composite memory region descriptor fits.
-- 
2.34.1




[XEN PATCH v2 0/5] FF-A notifications

2024-04-22 Thread Jens Wiklander
Hi,

This patch set adds support for FF-A notifications. We only support
global notifications, per vCPU notifications remain unsupported.

The first three patches are further cleanup and can be merged before the
rest if desired.

A physical SGI is used to make Xen aware of pending FF-A notifications. The
physical SGI is selected by the SPMC in the secure world. Since it must not
already be used by Xen the SPMC is in practice forced to donate one of the
secure SGIs, but that's normally not a problem. The SGI handling in Xen is
updated to support registration of handlers for SGIs that aren't statically
assigned, that is, SGI IDs above GIC_SGI_MAX.

Thanks,
Jens

v1->v2:
- "xen/arm: ffa: support notification" and
  "xen/arm: allow dynamically assigned SGI handlers" updated as requestsed,
  details in each patch.
- Added Bertrands R-B for "xen/arm: ffa: refactor ffa_handle_call()",
  "xen/arm: ffa: use ACCESS_ONCE()", and
  "xen/arm: ffa: simplify ffa_handle_mem_share()"

Jens Wiklander (5):
  xen/arm: ffa: refactor ffa_handle_call()
  xen/arm: ffa: use ACCESS_ONCE()
  xen/arm: ffa: simplify ffa_handle_mem_share()
  xen/arm: allow dynamically assigned SGI handlers
  xen/arm: ffa: support notification

 xen/arch/arm/gic.c  |   5 +-
 xen/arch/arm/irq.c  |   7 +-
 xen/arch/arm/tee/Makefile   |   1 +
 xen/arch/arm/tee/ffa.c  |  83 +---
 xen/arch/arm/tee/ffa_notif.c| 331 
 xen/arch/arm/tee/ffa_partinfo.c |   9 +-
 xen/arch/arm/tee/ffa_private.h  |  68 ++-
 xen/arch/arm/tee/ffa_shm.c  |  33 ++--
 8 files changed, 488 insertions(+), 49 deletions(-)
 create mode 100644 xen/arch/arm/tee/ffa_notif.c

-- 
2.34.1




[XEN PATCH v2 3/5] xen/arm: ffa: simplify ffa_handle_mem_share()

2024-04-22 Thread Jens Wiklander
Simplify ffa_handle_mem_share() by removing the start_page_idx and
last_page_idx parameters from get_shm_pages() and check that the number
of pages matches expectations at the end of get_shm_pages().

Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
---
 xen/arch/arm/tee/ffa_shm.c | 18 ++
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c
index 75a5b66aeb4c..370d83ec5cf8 100644
--- a/xen/arch/arm/tee/ffa_shm.c
+++ b/xen/arch/arm/tee/ffa_shm.c
@@ -159,10 +159,9 @@ static int32_t ffa_mem_reclaim(uint32_t handle_lo, 
uint32_t handle_hi,
  */
 static int get_shm_pages(struct domain *d, struct ffa_shm_mem *shm,
  const struct ffa_address_range *range,
- uint32_t range_count, unsigned int start_page_idx,
- unsigned int *last_page_idx)
+ uint32_t range_count)
 {
-unsigned int pg_idx = start_page_idx;
+unsigned int pg_idx = 0;
 gfn_t gfn;
 unsigned int n;
 unsigned int m;
@@ -191,7 +190,9 @@ static int get_shm_pages(struct domain *d, struct 
ffa_shm_mem *shm,
 }
 }
 
-*last_page_idx = pg_idx;
+/* The ranges must add up */
+if ( pg_idx < shm->page_count )
+return FFA_RET_INVALID_PARAMETERS;
 
 return FFA_RET_OK;
 }
@@ -460,7 +461,6 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 struct domain *d = current->domain;
 struct ffa_ctx *ctx = d->arch.tee;
 struct ffa_shm_mem *shm = NULL;
-unsigned int last_page_idx = 0;
 register_t handle_hi = 0;
 register_t handle_lo = 0;
 int ret = FFA_RET_DENIED;
@@ -570,15 +570,9 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 goto out;
 }
 
-ret = get_shm_pages(d, shm, region_descr->address_range_array, range_count,
-0, _page_idx);
+ret = get_shm_pages(d, shm, region_descr->address_range_array, 
range_count);
 if ( ret )
 goto out;
-if ( last_page_idx != shm->page_count )
-{
-ret = FFA_RET_INVALID_PARAMETERS;
-goto out;
-}
 
 /* Note that share_shm() uses our tx buffer */
 spin_lock(_tx_buffer_lock);
-- 
2.34.1




[XEN PATCH v2 1/5] xen/arm: ffa: refactor ffa_handle_call()

2024-04-22 Thread Jens Wiklander
Refactors the large switch block in ffa_handle_call() to use common code
for the simple case where it's either an error code or success with no
further parameters.

Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
---
 xen/arch/arm/tee/ffa.c | 30 ++
 1 file changed, 10 insertions(+), 20 deletions(-)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 8665201e34a9..5209612963e1 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -273,18 +273,10 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 case FFA_RXTX_MAP_64:
 e = ffa_handle_rxtx_map(fid, get_user_reg(regs, 1),
get_user_reg(regs, 2), get_user_reg(regs, 3));
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 case FFA_RXTX_UNMAP:
 e = ffa_handle_rxtx_unmap();
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 case FFA_PARTITION_INFO_GET:
 e = ffa_handle_partition_info_get(get_user_reg(regs, 1),
   get_user_reg(regs, 2),
@@ -299,11 +291,7 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 return true;
 case FFA_RX_RELEASE:
 e = ffa_handle_rx_release();
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 case FFA_MSG_SEND_DIRECT_REQ_32:
 case FFA_MSG_SEND_DIRECT_REQ_64:
 handle_msg_send_direct_req(regs, fid);
@@ -316,17 +304,19 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 e = ffa_handle_mem_reclaim(regpair_to_uint64(get_user_reg(regs, 2),
  get_user_reg(regs, 1)),
get_user_reg(regs, 3));
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 
 default:
 gprintk(XENLOG_ERR, "ffa: unhandled fid 0x%x\n", fid);
 ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED);
 return true;
 }
+
+if ( e )
+ffa_set_regs_error(regs, e);
+else
+ffa_set_regs_success(regs, 0, 0);
+return true;
 }
 
 static int ffa_domain_init(struct domain *d)
-- 
2.34.1




Re: [XEN PATCH v1 4/5] xen/arm: allow dynamically assigned SGI handlers

2024-04-11 Thread Jens Wiklander
Hi Michal,

On Thu, Apr 11, 2024 at 8:44 AM Michal Orzel  wrote:
>
> Hi Jens,
>
> On 11/04/2024 08:12, Jens Wiklander wrote:
> >
> >
> > Hi Michal,
> >
> > On Wed, Apr 10, 2024 at 3:24 PM Michal Orzel  wrote:
> >>
> >> Hi Jens,
> >>
> >> On 09/04/2024 17:36, Jens Wiklander wrote:
> >>>
> >>>
> >>> Updates so request_irq() can be used with a dynamically assigned SGI irq
> >>> as input.
> >> At this point it would be handy to mention the use case for which you need 
> >> to add this support
> >
> > OK, I'll add something like:
> > This prepares for a later patch where an FF-A schedule receiver
> > interrupt handler is installed for an SGI generated by the secure
> > world.
> ok
>
> >
> >>
> >>>
> >>> gic_route_irq_to_xen() don't gic_set_irq_type() for SGIs since they have
> >>> their type assigned earlier during boot
> >> Could you elaborate more on that? Do you mean that SGIs are always edge 
> >> triggered and there's no need
> >> for setting the type?
> >
> > Yes, see https://developer.arm.com/documentation/ihi0069/h
> > 4.4 Software Generated Interrupts
> > SGIs are typically used for inter-processor communication, and are
> > generated by a write to an SGI register in the
> > GIC. SGIs can be either Group 0 or Group 1 interrupts, and they can
> > support only edge-triggered behavior.
> Exactly. But you wrote "have their type assigned earlier during boot" which 
> is not true.
> There is no write to ICFGR0 in Xen codebase. They are implicitly edge 
> triggered.
> So I would write:
> "... for SGIs since they are always edge triggered"

I'll use that instead.

Thanks,
Jens

>
> ~Michal



Re: [XEN PATCH v1 4/5] xen/arm: allow dynamically assigned SGI handlers

2024-04-11 Thread Jens Wiklander
Hi Michal,

On Wed, Apr 10, 2024 at 3:24 PM Michal Orzel  wrote:
>
> Hi Jens,
>
> On 09/04/2024 17:36, Jens Wiklander wrote:
> >
> >
> > Updates so request_irq() can be used with a dynamically assigned SGI irq
> > as input.
> At this point it would be handy to mention the use case for which you need to 
> add this support

OK, I'll add something like:
This prepares for a later patch where an FF-A schedule receiver
interrupt handler is installed for an SGI generated by the secure
world.

>
> >
> > gic_route_irq_to_xen() don't gic_set_irq_type() for SGIs since they have
> > their type assigned earlier during boot
> Could you elaborate more on that? Do you mean that SGIs are always edge 
> triggered and there's no need
> for setting the type?

Yes, see https://developer.arm.com/documentation/ihi0069/h
4.4 Software Generated Interrupts
SGIs are typically used for inter-processor communication, and are
generated by a write to an SGI register in the
GIC. SGIs can be either Group 0 or Group 1 interrupts, and they can
support only edge-triggered behavior.

How about:
SGI should only be configured as edge triggered.

Thanks,
Jens

>
> >
> > gic_interrupt() is updated to route the dynamically assigned SGIs to
> > do_IRQ() instead of do_sgi(). The latter still handles the statically
> > assigned SGI handlers like for instance GIC_SGI_CALL_FUNCTION.
> >
> > Signed-off-by: Jens Wiklander 
> Other than that, it LGTM:
> Acked-by: Michal Orzel 
>
> but I would like other maintainers (especially Julien) to cross check it.
>
> ~Michal



Re: [XEN PATCH v1 5/5] xen/arm: ffa: support notification

2024-04-10 Thread Jens Wiklander
Hi Bertrand,

On Wed, Apr 10, 2024 at 6:30 PM Bertrand Marquis
 wrote:
>
> Hi Jens,
>
> > On 10 Apr 2024, at 17:45, Jens Wiklander  wrote:
> >
> > On Tue, Apr 9, 2024 at 5:36 PM Jens Wiklander  
> > 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.
> >>
> >> Signed-off-by: Jens Wiklander 
> >> ---
[snip]
> >> +case FFA_FEATURE_NOTIF_PEND_INTR:
> >> +if ( ctx->notif.enabled )
> >> +ffa_set_regs_success(regs, 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, FFA_NOTIF_PEND_INTR_ID, 0);
> >> +else
> >> +ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED);
> >> +break;
> >
> > With the recently posted kernel patch
> > https://lore.kernel.org/all/20240410-ffa_npi_support-v1-3-1a5223391...@arm.com/
> > we need to decide which feature interrupt to return since the kernel
> > will only install a handle for the first it finds. Right now I propose
> > to to not report FFA_FEATURE_SCHEDULE_RECV_INTR. When the time comes
> > to use a secondary scheduler we'll need to report the SRI instead.
>
>
> We just had a meeting with Sudeep to discuss that matter and he agreed that
> he would register the interrupt handler for all the interrupts available so 
> that
> we can keep a model where we will generate SRIs only to a secondary scheduler
> and NPI for notification interrupts (so that the VM does not do a INFO_GET 
> when
> not required).
>
> We will have to report both as any VM could act as secondary scheduler for SPs
> in theory (we might need at some point a parameter for that) but for now those
> should only be generated to Dom0 if there are pending notifications for SPs.

OK, thanks. I'll keep both then.

Cheers,
Jens



Re: [XEN PATCH v1 5/5] xen/arm: ffa: support notification

2024-04-10 Thread Jens Wiklander
Hi Bertrand,

On Wed, Apr 10, 2024 at 5:41 PM Bertrand Marquis
 wrote:
>
> Hi Jens,
>
> > On 10 Apr 2024, at 16:27, Jens Wiklander  wrote:
> >
> > On Wed, Apr 10, 2024 at 9:49 AM Bertrand Marquis
> >  wrote:
> >>
> >> Hi Jens,
> >>
> >>> On 9 Apr 2024, at 17:36, Jens Wiklander  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.
> >>>
> >>> Signed-off-by: Jens Wiklander 
> >>> ---
> >>> xen/arch/arm/tee/Makefile  |   1 +
> >>> xen/arch/arm/tee/ffa.c |  58 ++
> >>> xen/arch/arm/tee/ffa_notif.c   | 319 +
> >>> xen/arch/arm/tee/ffa_private.h |  71 
> >>> 4 files changed, 449 insertions(+)
> >>> create mode 100644 xen/arch/arm/tee/ffa_notif.c
> >>>
> >>> 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..ce9757bfeed1 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, 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, FFA_NOTIF_PEND_INTR_ID, 0);
> >>
> >> This should return the RECV_INTR, not the PEND one.
> >
> > Thanks, I'll fix it.
> >
> >>
> >>> +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);
> >>>  

Re: [XEN PATCH v1 5/5] xen/arm: ffa: support notification

2024-04-10 Thread Jens Wiklander
On Tue, Apr 9, 2024 at 5:36 PM Jens Wiklander  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.
>
> Signed-off-by: Jens Wiklander 
> ---
>  xen/arch/arm/tee/Makefile  |   1 +
>  xen/arch/arm/tee/ffa.c |  58 ++
>  xen/arch/arm/tee/ffa_notif.c   | 319 +
>  xen/arch/arm/tee/ffa_private.h |  71 
>  4 files changed, 449 insertions(+)
>  create mode 100644 xen/arch/arm/tee/ffa_notif.c
>
> 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..ce9757bfeed1 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, 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, FFA_NOTIF_PEND_INTR_ID, 0);
> +else
> +ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED);
> +break;

With the recently posted kernel patch
https://lore.kernel.org/all/20240410-ffa_npi_support-v1-3-1a5223391...@arm.com/
we need to decide which feature interrupt to return since the kernel
will only install a handle for the first it finds. Right now I propose
to to not report FFA_FEATURE_SCHEDULE_RECV_INTR. When the time comes
to use a secondary scheduler we'll need to report the SRI instead.

Cheers,
Jens

> +
> +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,30 @@ 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(get_user_reg(regs, 1),
> + get_user_reg(regs, 2),
> + get_user_reg(regs, 3),
> + get_user_reg(regs, 4));
> +break;
> +case FFA_NOTIFICATION_UNBIND:
> +e = ffa_handle_notification_unbind(get_user_reg(regs, 1),
> +   get_user_reg(regs, 3),
> +   get_user_reg(regs, 4));
> +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(re

Re: [XEN PATCH v1 5/5] xen/arm: ffa: support notification

2024-04-10 Thread Jens Wiklander
On Wed, Apr 10, 2024 at 9:49 AM Bertrand Marquis
 wrote:
>
> Hi Jens,
>
> > On 9 Apr 2024, at 17:36, Jens Wiklander  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.
> >
> > Signed-off-by: Jens Wiklander 
> > ---
> > xen/arch/arm/tee/Makefile  |   1 +
> > xen/arch/arm/tee/ffa.c |  58 ++
> > xen/arch/arm/tee/ffa_notif.c   | 319 +
> > xen/arch/arm/tee/ffa_private.h |  71 
> > 4 files changed, 449 insertions(+)
> > create mode 100644 xen/arch/arm/tee/ffa_notif.c
> >
> > 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..ce9757bfeed1 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, 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, FFA_NOTIF_PEND_INTR_ID, 0);
>
> This should return the RECV_INTR, not the PEND one.

Thanks, I'll fix it.

>
> > +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,30 @@ 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(get_user_reg(regs, 1),
> > + get_user_reg(regs, 2),
> > + get_user_reg(regs, 3),
> > + get_user_reg(regs, 4));
>
> I would suggest to pass regs and handle the get_user_regs in the function.

OK

>
> > +break;
> > +case FFA_NOTIFICATION_UNBIND:
> > +e = ffa_handle_notification_unbind(get_user_reg(regs, 1),
> > +   get_user_reg(regs, 3),
> >

[XEN PATCH v1 2/5] xen/arm: ffa: use ACCESS_ONCE()

2024-04-09 Thread Jens Wiklander
Replace read_atomic() with ACCESS_ONCE() to match the intended use, that
is, to prevent the compiler from (via optimization) reading shared
memory more than once.

Signed-off-by: Jens Wiklander 
---
 xen/arch/arm/tee/ffa_shm.c | 15 ---
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c
index eed9ad2d2986..75a5b66aeb4c 100644
--- a/xen/arch/arm/tee/ffa_shm.c
+++ b/xen/arch/arm/tee/ffa_shm.c
@@ -7,6 +7,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -171,8 +172,8 @@ static int get_shm_pages(struct domain *d, struct 
ffa_shm_mem *shm,
 
 for ( n = 0; n < range_count; n++ )
 {
-page_count = read_atomic([n].page_count);
-addr = read_atomic([n].address);
+page_count = ACCESS_ONCE(range[n].page_count);
+addr = ACCESS_ONCE(range[n].address);
 for ( m = 0; m < page_count; m++ )
 {
 if ( pg_idx >= shm->page_count )
@@ -527,13 +528,13 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 goto out_unlock;
 
 mem_access = ctx->tx + trans.mem_access_offs;
-if ( read_atomic(_access->access_perm.perm) != FFA_MEM_ACC_RW )
+if ( ACCESS_ONCE(mem_access->access_perm.perm) != FFA_MEM_ACC_RW )
 {
 ret = FFA_RET_NOT_SUPPORTED;
 goto out_unlock;
 }
 
-region_offs = read_atomic(_access->region_offs);
+region_offs = ACCESS_ONCE(mem_access->region_offs);
 if ( sizeof(*region_descr) + region_offs > frag_len )
 {
 ret = FFA_RET_NOT_SUPPORTED;
@@ -541,8 +542,8 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 }
 
 region_descr = ctx->tx + region_offs;
-range_count = read_atomic(_descr->address_range_count);
-page_count = read_atomic(_descr->total_page_count);
+range_count = ACCESS_ONCE(region_descr->address_range_count);
+page_count = ACCESS_ONCE(region_descr->total_page_count);
 
 if ( !page_count )
 {
@@ -557,7 +558,7 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 goto out_unlock;
 }
 shm->sender_id = trans.sender_id;
-shm->ep_id = read_atomic(_access->access_perm.endpoint_id);
+shm->ep_id = ACCESS_ONCE(mem_access->access_perm.endpoint_id);
 
 /*
  * Check that the Composite memory region descriptor fits.
-- 
2.34.1




[XEN PATCH v1 3/5] xen/arm: ffa: simplify ffa_handle_mem_share()

2024-04-09 Thread Jens Wiklander
Simplify ffa_handle_mem_share() by removing the start_page_idx and
last_page_idx parameters from get_shm_pages() and check that the number
of pages matches expectations at the end of get_shm_pages().

Signed-off-by: Jens Wiklander 
---
 xen/arch/arm/tee/ffa_shm.c | 18 ++
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c
index 75a5b66aeb4c..370d83ec5cf8 100644
--- a/xen/arch/arm/tee/ffa_shm.c
+++ b/xen/arch/arm/tee/ffa_shm.c
@@ -159,10 +159,9 @@ static int32_t ffa_mem_reclaim(uint32_t handle_lo, 
uint32_t handle_hi,
  */
 static int get_shm_pages(struct domain *d, struct ffa_shm_mem *shm,
  const struct ffa_address_range *range,
- uint32_t range_count, unsigned int start_page_idx,
- unsigned int *last_page_idx)
+ uint32_t range_count)
 {
-unsigned int pg_idx = start_page_idx;
+unsigned int pg_idx = 0;
 gfn_t gfn;
 unsigned int n;
 unsigned int m;
@@ -191,7 +190,9 @@ static int get_shm_pages(struct domain *d, struct 
ffa_shm_mem *shm,
 }
 }
 
-*last_page_idx = pg_idx;
+/* The ranges must add up */
+if ( pg_idx < shm->page_count )
+return FFA_RET_INVALID_PARAMETERS;
 
 return FFA_RET_OK;
 }
@@ -460,7 +461,6 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 struct domain *d = current->domain;
 struct ffa_ctx *ctx = d->arch.tee;
 struct ffa_shm_mem *shm = NULL;
-unsigned int last_page_idx = 0;
 register_t handle_hi = 0;
 register_t handle_lo = 0;
 int ret = FFA_RET_DENIED;
@@ -570,15 +570,9 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
 goto out;
 }
 
-ret = get_shm_pages(d, shm, region_descr->address_range_array, range_count,
-0, _page_idx);
+ret = get_shm_pages(d, shm, region_descr->address_range_array, 
range_count);
 if ( ret )
 goto out;
-if ( last_page_idx != shm->page_count )
-{
-ret = FFA_RET_INVALID_PARAMETERS;
-goto out;
-}
 
 /* Note that share_shm() uses our tx buffer */
 spin_lock(_tx_buffer_lock);
-- 
2.34.1




[XEN PATCH v1 0/5] FF-A notifications

2024-04-09 Thread Jens Wiklander
Hi,

This patch set adds support for FF-A notifications. We only support
global notifications, per vCPU notifications remain unsupported.

The first three patches are further cleanup and can be merged before the
rest if desired.

A physical SGI is used to make Xen aware of pending FF-A notifications. The
physical SGI is selected by the SPMC in the secure world. Since it must not
already be used by Xen the SPMC is in practice forced to donate one of the
secure SGIs, but that's normally not a problem. The SGI handling in Xen is
updated to support registration of handlers for SGIs that aren't statically
assigned, that is, SGI IDs above GIC_SGI_MAX.

Thanks,
Jens

Jens Wiklander (5):
  xen/arm: ffa: refactor ffa_handle_call()
  xen/arm: ffa: use ACCESS_ONCE()
  xen/arm: ffa: simplify ffa_handle_mem_share()
  xen/arm: allow dynamically assigned SGI handlers
  xen/arm: ffa: support notification

 xen/arch/arm/gic.c |   5 +-
 xen/arch/arm/irq.c |   7 +-
 xen/arch/arm/tee/Makefile  |   1 +
 xen/arch/arm/tee/ffa.c |  86 +++--
 xen/arch/arm/tee/ffa_notif.c   | 319 +
 xen/arch/arm/tee/ffa_private.h |  71 
 xen/arch/arm/tee/ffa_shm.c |  33 ++--
 7 files changed, 480 insertions(+), 42 deletions(-)
 create mode 100644 xen/arch/arm/tee/ffa_notif.c

-- 
2.34.1




[XEN PATCH v1 4/5] xen/arm: allow dynamically assigned SGI handlers

2024-04-09 Thread Jens Wiklander
Updates so request_irq() can be used with a dynamically assigned SGI irq
as input.

gic_route_irq_to_xen() don't gic_set_irq_type() for SGIs since they have
their type assigned earlier during boot

gic_interrupt() is updated to route the dynamically assigned SGIs to
do_IRQ() instead of do_sgi(). The latter still handles the statically
assigned SGI handlers like for instance GIC_SGI_CALL_FUNCTION.

Signed-off-by: Jens Wiklander 
---
 xen/arch/arm/gic.c | 5 +++--
 xen/arch/arm/irq.c | 7 +--
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 44c40e86defe..e9aeb7138455 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -117,7 +117,8 @@ void gic_route_irq_to_xen(struct irq_desc *desc, unsigned 
int priority)
 
 desc->handler = gic_hw_ops->gic_host_irq_type;
 
-gic_set_irq_type(desc, desc->arch.type);
+if ( desc->irq >= NR_GIC_SGI)
+gic_set_irq_type(desc, desc->arch.type);
 gic_set_irq_priority(desc, priority);
 }
 
@@ -375,7 +376,7 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
 /* Reading IRQ will ACK it */
 irq = gic_hw_ops->read_irq();
 
-if ( likely(irq >= 16 && irq < 1020) )
+if ( likely(irq >= GIC_SGI_MAX && irq < 1020) )
 {
 isb();
 do_IRQ(regs, irq, is_fiq);
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index bcce80a4d624..fdb214560978 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -224,9 +224,12 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq, 
int is_fiq)
 
 perfc_incr(irqs);
 
-ASSERT(irq >= 16); /* SGIs do not come down this path */
+/* Statically assigned SGIs do not come down this path */
+ASSERT(irq >= GIC_SGI_MAX);
 
-if ( irq < 32 )
+if ( irq < NR_GIC_SGI )
+perfc_incr(ipis);
+else if ( irq < NR_GIC_LOCAL_IRQS )
 perfc_incr(ppis);
 else
 perfc_incr(spis);
-- 
2.34.1




[XEN PATCH v1 5/5] xen/arm: ffa: support notification

2024-04-09 Thread Jens Wiklander
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.

Signed-off-by: Jens Wiklander 
---
 xen/arch/arm/tee/Makefile  |   1 +
 xen/arch/arm/tee/ffa.c |  58 ++
 xen/arch/arm/tee/ffa_notif.c   | 319 +
 xen/arch/arm/tee/ffa_private.h |  71 
 4 files changed, 449 insertions(+)
 create mode 100644 xen/arch/arm/tee/ffa_notif.c

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..ce9757bfeed1 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, 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, FFA_NOTIF_PEND_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,30 @@ 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(get_user_reg(regs, 1),
+ get_user_reg(regs, 2),
+ get_user_reg(regs, 3),
+ get_user_reg(regs, 4));
+break;
+case FFA_NOTIFICATION_UNBIND:
+e = ffa_handle_notification_unbind(get_user_reg(regs, 1),
+   get_user_reg(regs, 3),
+   get_user_reg(regs, 4));
+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(get_user_reg(regs, 1),
+get_user_reg(regs, 2),
+get_user_reg(regs, 3),
+get_user_reg(regs, 4));
+break;
 
 default:
 gprintk(XENLOG_ERR, "ffa: unhandled fid 0x%x\n", fid);
@@ -348,6 +401,9 @@ static int ffa_domain_init(struct domain *d)
 if ( !ffa_partinfo_domain_init(d) )
 return -EIO;
 
+if ( !ffa_notif_domain_init(d) )
+return -ENOMEM;
+
 return 0;
 }
 
@@ -423,6 +479,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 +559,7 @@ static bool ffa_probe(void)
 if ( !ffa_partinfo_init() )
 goto err_rxtx_destr

[XEN PATCH v1 1/5] xen/arm: ffa: refactor ffa_handle_call()

2024-04-09 Thread Jens Wiklander
Refactors the large switch block in ffa_handle_call() to use common code
for the simple case where it's either an error code or success with no
further parameters.

Signed-off-by: Jens Wiklander 
---
 xen/arch/arm/tee/ffa.c | 30 ++
 1 file changed, 10 insertions(+), 20 deletions(-)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 8665201e34a9..5209612963e1 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -273,18 +273,10 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 case FFA_RXTX_MAP_64:
 e = ffa_handle_rxtx_map(fid, get_user_reg(regs, 1),
get_user_reg(regs, 2), get_user_reg(regs, 3));
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 case FFA_RXTX_UNMAP:
 e = ffa_handle_rxtx_unmap();
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 case FFA_PARTITION_INFO_GET:
 e = ffa_handle_partition_info_get(get_user_reg(regs, 1),
   get_user_reg(regs, 2),
@@ -299,11 +291,7 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 return true;
 case FFA_RX_RELEASE:
 e = ffa_handle_rx_release();
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 case FFA_MSG_SEND_DIRECT_REQ_32:
 case FFA_MSG_SEND_DIRECT_REQ_64:
 handle_msg_send_direct_req(regs, fid);
@@ -316,17 +304,19 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 e = ffa_handle_mem_reclaim(regpair_to_uint64(get_user_reg(regs, 2),
  get_user_reg(regs, 1)),
get_user_reg(regs, 3));
-if ( e )
-ffa_set_regs_error(regs, e);
-else
-ffa_set_regs_success(regs, 0, 0);
-return true;
+break;
 
 default:
 gprintk(XENLOG_ERR, "ffa: unhandled fid 0x%x\n", fid);
 ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED);
 return true;
 }
+
+if ( e )
+ffa_set_regs_error(regs, e);
+else
+ffa_set_regs_success(regs, 0, 0);
+return true;
 }
 
 static int ffa_domain_init(struct domain *d)
-- 
2.34.1




[XEN PATCH 3/6] xen/arm: ffa: separate memory sharing routines

2024-03-25 Thread Jens Wiklander
Move memory sharing routines into a separate file for easier navigation
in the source code.

Add ffa_shm_domain_destroy() to isolate the ffa_shm things in
ffa_domain_teardown_continue().

Signed-off-by: Jens Wiklander 
---
 xen/arch/arm/tee/Makefile  |   1 +
 xen/arch/arm/tee/ffa.c | 708 +
 xen/arch/arm/tee/ffa_private.h |  10 +
 xen/arch/arm/tee/ffa_shm.c | 708 +
 4 files changed, 729 insertions(+), 698 deletions(-)
 create mode 100644 xen/arch/arm/tee/ffa_shm.c

diff --git a/xen/arch/arm/tee/Makefile b/xen/arch/arm/tee/Makefile
index 58a1015e40e0..0e683d23aa9d 100644
--- a/xen/arch/arm/tee/Makefile
+++ b/xen/arch/arm/tee/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_FFA) += ffa.o
+obj-$(CONFIG_FFA) += ffa_shm.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 259851f20bdb..db36292dc52f 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -84,92 +84,6 @@ struct ffa_partition_info_1_1 {
 uint8_t uuid[16];
 };
 
-/* Constituent memory region descriptor */
-struct ffa_address_range {
-uint64_t address;
-uint32_t page_count;
-uint32_t reserved;
-};
-
-/* Composite memory region descriptor */
-struct ffa_mem_region {
-uint32_t total_page_count;
-uint32_t address_range_count;
-uint64_t reserved;
-struct ffa_address_range address_range_array[];
-};
-
-/* Memory access permissions descriptor */
-struct ffa_mem_access_perm {
-uint16_t endpoint_id;
-uint8_t perm;
-uint8_t flags;
-};
-
-/* Endpoint memory access descriptor */
-struct ffa_mem_access {
-struct ffa_mem_access_perm access_perm;
-uint32_t region_offs;
-uint64_t reserved;
-};
-
-/* Lend, donate or share memory transaction descriptor */
-struct ffa_mem_transaction_1_0 {
-uint16_t sender_id;
-uint8_t mem_reg_attr;
-uint8_t reserved0;
-uint32_t flags;
-uint64_t handle;
-uint64_t tag;
-uint32_t reserved1;
-uint32_t mem_access_count;
-struct ffa_mem_access mem_access_array[];
-};
-
-struct ffa_mem_transaction_1_1 {
-uint16_t sender_id;
-uint16_t mem_reg_attr;
-uint32_t flags;
-uint64_t handle;
-uint64_t tag;
-uint32_t mem_access_size;
-uint32_t mem_access_count;
-uint32_t mem_access_offs;
-uint8_t reserved[12];
-};
-
-/* Calculate offset of struct ffa_mem_access from start of buffer */
-#define MEM_ACCESS_OFFSET(access_idx) \
-( sizeof(struct ffa_mem_transaction_1_1) + \
-  ( access_idx ) * sizeof(struct ffa_mem_access) )
-
-/* Calculate offset of struct ffa_mem_region from start of buffer */
-#define REGION_OFFSET(access_count, region_idx) \
-( MEM_ACCESS_OFFSET(access_count) + \
-  ( region_idx ) * sizeof(struct ffa_mem_region) )
-
-/* Calculate offset of struct ffa_address_range from start of buffer */
-#define ADDR_RANGE_OFFSET(access_count, region_count, range_idx) \
-( REGION_OFFSET(access_count, region_count) + \
-  ( range_idx ) * sizeof(struct ffa_address_range) )
-
-/*
- * The parts needed from struct ffa_mem_transaction_1_0 or struct
- * ffa_mem_transaction_1_1, used to provide an abstraction of difference in
- * data structures between version 1.0 and 1.1. This is just an internal
- * interface and can be changed without changing any ABI.
- */
-struct ffa_mem_transaction_int {
-uint16_t sender_id;
-uint8_t mem_reg_attr;
-uint8_t flags;
-uint8_t mem_access_size;
-uint8_t mem_access_count;
-uint16_t mem_access_offs;
-uint64_t handle;
-uint64_t tag;
-};
-
 /* Endpoint RX/TX descriptor */
 struct ffa_endpoint_rxtx_descriptor_1_0 {
 uint16_t sender_id;
@@ -185,15 +99,6 @@ struct ffa_endpoint_rxtx_descriptor_1_1 {
 uint32_t tx_region_offs;
 };
 
-struct ffa_shm_mem {
-struct list_head list;
-uint16_t sender_id;
-uint16_t ep_id; /* endpoint, the one lending */
-uint64_t handle;/* FFA_HANDLE_INVALID if not set yet */
-unsigned int page_count;
-struct page_info *pages[];
-};
-
 /* Negotiated FF-A version to use with the SPMC */
 static uint32_t __ro_after_init ffa_version;
 
@@ -212,10 +117,10 @@ static uint16_t subscr_vm_destroyed_count __read_mostly;
  * for calls which uses our RX buffer to deliver a result we must call
  * ffa_rx_release() to let the SPMC know that we're done with the buffer.
  */
-static void *ffa_rx __read_mostly;
-static void *ffa_tx __read_mostly;
-static DEFINE_SPINLOCK(ffa_rx_buffer_lock);
-static DEFINE_SPINLOCK(ffa_tx_buffer_lock);
+void *ffa_rx __read_mostly;
+void *ffa_tx __read_mostly;
+DEFINE_SPINLOCK(ffa_rx_buffer_lock);
+DEFINE_SPINLOCK(ffa_tx_buffer_lock);
 
 
 /* Used to track domains that could not be torn down immediately. */
@@ -297,47 +202,6 @@ static int32_t ffa_rx_release(void)
 return ffa_simple_call(FFA_RX_RELEASE, 0, 0, 0, 0);
 }
 
-static int32_t ffa_mem_share(uint32_t tot_len, uint32_t frag_len

[XEN PATCH 1/6] xen/arm: ffa: rename functions to use ffa_ prefix

2024-03-25 Thread Jens Wiklander
Prepare to separate into modules by renaming functions that will need
new names when becoming non-static in the following commit.

Signed-off-by: Jens Wiklander 
---
 xen/arch/arm/tee/ffa.c | 125 +
 1 file changed, 65 insertions(+), 60 deletions(-)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 9a05dcede17a..0344a0f17e72 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -4,7 +4,7 @@
  *
  * Arm Firmware Framework for ARMv8-A (FF-A) mediator
  *
- * Copyright (C) 2023  Linaro Limited
+ * Copyright (C) 2023-2024  Linaro Limited
  *
  * References:
  * FF-A-1.0-REL: FF-A specification version 1.0 available at
@@ -473,7 +473,7 @@ static bool ffa_get_version(uint32_t *vers)
 return true;
 }
 
-static int32_t get_ffa_ret_code(const struct arm_smccc_1_2_regs *resp)
+static int32_t ffa_get_ret_code(const struct arm_smccc_1_2_regs *resp)
 {
 switch ( resp->a0 )
 {
@@ -504,7 +504,7 @@ static int32_t ffa_simple_call(uint32_t fid, register_t a1, 
register_t a2,
 
 arm_smccc_1_2_smc(, );
 
-return get_ffa_ret_code();
+return ffa_get_ret_code();
 }
 
 static int32_t ffa_features(uint32_t id)
@@ -546,7 +546,7 @@ static int32_t ffa_partition_info_get(uint32_t w1, uint32_t 
w2, uint32_t w3,
 
 arm_smccc_1_2_smc(, );
 
-ret = get_ffa_ret_code();
+ret = ffa_get_ret_code();
 if ( !ret )
 {
 *count = resp.a2;
@@ -654,15 +654,16 @@ static int32_t ffa_direct_req_send_vm(uint16_t sp_id, 
uint16_t vm_id,
 return res;
 }
 
-static uint16_t get_vm_id(const struct domain *d)
+static 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 void 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, register_t v7)
+static 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,
+ register_t v7)
 {
 set_user_reg(regs, 0, v0);
 set_user_reg(regs, 1, v1);
@@ -674,15 +675,15 @@ static void set_regs(struct cpu_user_regs *regs, 
register_t v0, register_t v1,
 set_user_reg(regs, 7, v7);
 }
 
-static void set_regs_error(struct cpu_user_regs *regs, uint32_t error_code)
+static void ffa_set_regs_error(struct cpu_user_regs *regs, uint32_t error_code)
 {
-set_regs(regs, FFA_ERROR, 0, error_code, 0, 0, 0, 0, 0);
+ffa_set_regs(regs, FFA_ERROR, 0, error_code, 0, 0, 0, 0, 0);
 }
 
-static void set_regs_success(struct cpu_user_regs *regs, uint32_t w2,
+static void ffa_set_regs_success(struct cpu_user_regs *regs, uint32_t w2,
  uint32_t w3)
 {
-set_regs(regs, FFA_SUCCESS_32, 0, w2, w3, 0, 0, 0, 0);
+ffa_set_regs(regs, FFA_SUCCESS_32, 0, w2, w3, 0, 0, 0, 0);
 }
 
 static void handle_version(struct cpu_user_regs *regs)
@@ -697,11 +698,11 @@ static void handle_version(struct cpu_user_regs *regs)
 vers = FFA_VERSION_1_1;
 
 ctx->guest_vers = vers;
-set_regs(regs, vers, 0, 0, 0, 0, 0, 0, 0);
+ffa_set_regs(regs, vers, 0, 0, 0, 0, 0, 0, 0);
 }
 
-static uint32_t handle_rxtx_map(uint32_t fid, register_t tx_addr,
-register_t rx_addr, uint32_t page_count)
+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;
@@ -789,7 +790,7 @@ static void rxtx_unmap(struct ffa_ctx *ctx)
 ctx->rx_is_free = false;
 }
 
-static uint32_t handle_rxtx_unmap(void)
+static uint32_t ffa_handle_rxtx_unmap(void)
 {
 struct domain *d = current->domain;
 struct ffa_ctx *ctx = d->arch.tee;
@@ -802,9 +803,10 @@ static uint32_t handle_rxtx_unmap(void)
 return FFA_RET_OK;
 }
 
-static int32_t 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)
+static 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)
 {
 int32_t ret = FFA_RET_DENIED;
 struct domain *d = current->domain;
@@ -883,7 +885,7 @@ out:
 return ret;
 }
 
-static int32_t handle_rx_release(void)
+static int32_t ffa_handle_rx_release(void)
 {
 int32_t ret = FFA_RET_DENIED;
 struct domain *d = current->domain;
@@ -916,7 +918,7 @@ static void handle_msg_send_direct_req(

[XEN PATCH 4/6] xen/arm: ffa: separate partition info get routines

2024-03-25 Thread Jens Wiklander
Move partition info get routines into a separate file for easier
navigation in the source code.

Add ffa_partinfo_init(), ffa_partinfo_domain_init(), and
ffa_partinfo_domain_destroy() to handle the ffa_partinfo internal things
on initialization and teardown.

Signed-off-by: Jens Wiklander 
---
 xen/arch/arm/tee/Makefile   |   1 +
 xen/arch/arm/tee/ffa.c  | 359 +-
 xen/arch/arm/tee/ffa_partinfo.c | 373 
 xen/arch/arm/tee/ffa_private.h  |  14 +-
 4 files changed, 398 insertions(+), 349 deletions(-)
 create mode 100644 xen/arch/arm/tee/ffa_partinfo.c

diff --git a/xen/arch/arm/tee/Makefile b/xen/arch/arm/tee/Makefile
index 0e683d23aa9d..be644fba8055 100644
--- a/xen/arch/arm/tee/Makefile
+++ b/xen/arch/arm/tee/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_FFA) += ffa.o
 obj-$(CONFIG_FFA) += ffa_shm.o
+obj-$(CONFIG_FFA) += ffa_partinfo.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 db36292dc52f..7a2803881420 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -70,20 +70,6 @@
  * structs ending with _1_1 are defined in FF-A-1.1-REL0.
  */
 
-/* Partition information descriptor */
-struct ffa_partition_info_1_0 {
-uint16_t id;
-uint16_t execution_context;
-uint32_t partition_properties;
-};
-
-struct ffa_partition_info_1_1 {
-uint16_t id;
-uint16_t execution_context;
-uint32_t partition_properties;
-uint8_t uuid[16];
-};
-
 /* Endpoint RX/TX descriptor */
 struct ffa_endpoint_rxtx_descriptor_1_0 {
 uint16_t sender_id;
@@ -102,11 +88,6 @@ struct ffa_endpoint_rxtx_descriptor_1_1 {
 /* Negotiated FF-A version to use with the SPMC */
 static uint32_t __ro_after_init ffa_version;
 
-/* SPs subscribing to VM_CREATE and VM_DESTROYED events */
-static uint16_t *subscr_vm_created __read_mostly;
-static uint16_t subscr_vm_created_count __read_mostly;
-static uint16_t *subscr_vm_destroyed __read_mostly;
-static uint16_t subscr_vm_destroyed_count __read_mostly;
 
 /*
  * Our rx/tx buffers shared with the SPMC. FFA_RXTX_PAGE_COUNT is the
@@ -170,90 +151,6 @@ static int32_t ffa_rxtx_map(paddr_t tx_addr, paddr_t 
rx_addr,
 return ffa_simple_call(FFA_RXTX_MAP_64, tx_addr, rx_addr, page_count, 0);
 }
 
-static int32_t ffa_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)
-{
-const struct arm_smccc_1_2_regs arg = {
-.a0 = FFA_PARTITION_INFO_GET,
-.a1 = w1,
-.a2 = w2,
-.a3 = w3,
-.a4 = w4,
-.a5 = w5,
-};
-struct arm_smccc_1_2_regs resp;
-uint32_t ret;
-
-arm_smccc_1_2_smc(, );
-
-ret = ffa_get_ret_code();
-if ( !ret )
-{
-*count = resp.a2;
-*fpi_size = resp.a3;
-}
-
-return ret;
-}
-
-static int32_t ffa_rx_release(void)
-{
-return ffa_simple_call(FFA_RX_RELEASE, 0, 0, 0, 0);
-}
-
-static int32_t ffa_direct_req_send_vm(uint16_t sp_id, uint16_t vm_id,
-  uint8_t msg)
-{
-uint32_t exp_resp = FFA_MSG_FLAG_FRAMEWORK;
-unsigned int retry_count = 0;
-int32_t res;
-
-if ( msg == FFA_MSG_SEND_VM_CREATED )
-exp_resp |= FFA_MSG_RESP_VM_CREATED;
-else if ( msg == FFA_MSG_SEND_VM_DESTROYED )
-exp_resp |= FFA_MSG_RESP_VM_DESTROYED;
-else
-return FFA_RET_INVALID_PARAMETERS;
-
-do {
-const struct arm_smccc_1_2_regs arg = {
-.a0 = FFA_MSG_SEND_DIRECT_REQ_32,
-.a1 = sp_id,
-.a2 = FFA_MSG_FLAG_FRAMEWORK | msg,
-.a5 = vm_id,
-};
-struct arm_smccc_1_2_regs resp;
-
-arm_smccc_1_2_smc(, );
-if ( resp.a0 != FFA_MSG_SEND_DIRECT_RESP_32 || resp.a2 != exp_resp )
-{
-/*
- * This is an invalid response, likely due to some error in the
- * implementation of the ABI.
- */
-return FFA_RET_INVALID_PARAMETERS;
-}
-res = resp.a3;
-if ( ++retry_count > 10 )
-{
-/*
- * TODO
- * FFA_RET_INTERRUPTED means that the SPMC has a pending
- * non-secure interrupt, we need a way of delivering that
- * non-secure interrupt.
- * FFA_RET_RETRY is the SP telling us that it's temporarily
- * blocked from handling the direct request, we need a generic
- * way to deal with this.
- * For now in both cases, give up after a few retries.
- */
-return res;
-}
-} while ( res == FFA_RET_INTERRUPTED || res == FFA_RET_RETRY );
-
-return res;
-}
-
 static void handle_version(struct cpu_user_regs *regs)
 {
 struct domain *d = current->domain;
@@ -371,88 +268,6 @@ static uint32_t ffa_handle_rxtx_unmap(void)
 return FFA_

[XEN PATCH 6/6] xen/arm: ffa: support FFA_FEATURES

2024-03-25 Thread Jens Wiklander
Add support for the mandatory FF-A ABI function FFA_FEATURES.

Signed-off-by: Jens Wiklander 
---
 xen/arch/arm/tee/ffa.c | 57 ++
 1 file changed, 57 insertions(+)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 4f7775b8c890..8665201e34a9 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -192,6 +192,60 @@ out:
  resp.a7 & mask);
 }
 
+static void handle_features(struct cpu_user_regs *regs)
+{
+uint32_t a1 = get_user_reg(regs, 1);
+unsigned int n;
+
+for ( n = 2; n <= 7; n++ )
+{
+if ( get_user_reg(regs, n) )
+{
+ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED);
+return;
+}
+}
+
+switch ( a1 )
+{
+case FFA_ERROR:
+case FFA_VERSION:
+case FFA_SUCCESS_32:
+case FFA_SUCCESS_64:
+case FFA_FEATURES:
+case FFA_ID_GET:
+case FFA_RX_RELEASE:
+case FFA_RXTX_UNMAP:
+case FFA_MEM_RECLAIM:
+case FFA_PARTITION_INFO_GET:
+case FFA_MSG_SEND_DIRECT_REQ_32:
+case FFA_MSG_SEND_DIRECT_REQ_64:
+ffa_set_regs_success(regs, 0, 0);
+break;
+case FFA_MEM_SHARE_64:
+case FFA_MEM_SHARE_32:
+/*
+ * We currently don't support dynamically allocated buffers. Report
+ * that with 0 in bit[0] of w2.
+ */
+ffa_set_regs_success(regs, 0, 0);
+break;
+case FFA_RXTX_MAP_64:
+case FFA_RXTX_MAP_32:
+/*
+ * We currently support 4k pages only, report that as 00 in
+ * bit[0:1] in w0. This needs to be revised if Xen page size
+ * differs from FFA_PAGE_SIZE (SZ_4K).
+ */
+BUILD_BUG_ON(PAGE_SIZE != FFA_PAGE_SIZE);
+ffa_set_regs_success(regs, 0, 0);
+break;
+default:
+ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED);
+break;
+}
+}
+
 static bool ffa_handle_call(struct cpu_user_regs *regs)
 {
 uint32_t fid = get_user_reg(regs, 0);
@@ -212,6 +266,9 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 case FFA_ID_GET:
 ffa_set_regs_success(regs, ffa_get_vm_id(d), 0);
 return true;
+case FFA_FEATURES:
+handle_features(regs);
+return true;
 case FFA_RXTX_MAP_32:
 case FFA_RXTX_MAP_64:
 e = ffa_handle_rxtx_map(fid, get_user_reg(regs, 1),
-- 
2.34.1




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

2024-03-25 Thread Jens Wiklander
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 
---
 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)), , 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)), , 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 r

[XEN PATCH 0/6] FF-A mediator reorganisation

2024-03-25 Thread Jens Wiklander
Hi,

The FF-A mediator is reorganized into modules for easier maintenance and to
prepare for future changes. This patch set is not expected add any changed
behaviour, except for the "xen/arm: ffa: support FFA_FEATURES" patch.

Thanks,
Jens

Jens Wiklander (6):
  xen/arm: ffa: rename functions to use ffa_ prefix
  xen/arm: ffa: move common things to ffa_private.h
  xen/arm: ffa: separate memory sharing routines
  xen/arm: ffa: separate partition info get routines
  xen/arm: ffa: separate rxtx buffer routines
  xen/arm: ffa: support FFA_FEATURES

 xen/arch/arm/tee/Makefile   |3 +
 xen/arch/arm/tee/ffa.c  | 1629 ++-
 xen/arch/arm/tee/ffa_partinfo.c |  373 +++
 xen/arch/arm/tee/ffa_private.h  |  347 +++
 xen/arch/arm/tee/ffa_rxtx.c |  216 
 xen/arch/arm/tee/ffa_shm.c  |  708 ++
 6 files changed, 1750 insertions(+), 1526 deletions(-)
 create mode 100644 xen/arch/arm/tee/ffa_partinfo.c
 create mode 100644 xen/arch/arm/tee/ffa_private.h
 create mode 100644 xen/arch/arm/tee/ffa_rxtx.c
 create mode 100644 xen/arch/arm/tee/ffa_shm.c

-- 
2.34.1




[XEN PATCH 2/6] xen/arm: ffa: move common things to ffa_private.h

2024-03-25 Thread Jens Wiklander
Prepare to separate ffa.c into modules by moving common things into the
new internal header file ffa_private.h.

Signed-off-by: Jens Wiklander 
---
 xen/arch/arm/tee/ffa.c | 298 +-
 xen/arch/arm/tee/ffa_private.h | 318 +
 2 files changed, 319 insertions(+), 297 deletions(-)
 create mode 100644 xen/arch/arm/tee/ffa_private.h

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 0344a0f17e72..259851f20bdb 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -63,204 +63,7 @@
 #include 
 #include 
 
-/* Error codes */
-#define FFA_RET_OK  0
-#define FFA_RET_NOT_SUPPORTED   -1
-#define FFA_RET_INVALID_PARAMETERS  -2
-#define FFA_RET_NO_MEMORY   -3
-#define FFA_RET_BUSY-4
-#define FFA_RET_INTERRUPTED -5
-#define FFA_RET_DENIED  -6
-#define FFA_RET_RETRY   -7
-#define FFA_RET_ABORTED -8
-
-/* FFA_VERSION helpers */
-#define FFA_VERSION_MAJOR_SHIFT 16U
-#define FFA_VERSION_MAJOR_MASK  0x7FFFU
-#define FFA_VERSION_MINOR_SHIFT 0U
-#define FFA_VERSION_MINOR_MASK  0xU
-#define MAKE_FFA_VERSION(major, minor)  \
-major) & FFA_VERSION_MAJOR_MASK) << FFA_VERSION_MAJOR_SHIFT) | \
- ((minor) & FFA_VERSION_MINOR_MASK))
-
-#define FFA_VERSION_1_0 MAKE_FFA_VERSION(1, 0)
-#define FFA_VERSION_1_1 MAKE_FFA_VERSION(1, 1)
-/* The minimal FF-A version of the SPMC that can be supported */
-#define FFA_MIN_SPMC_VERSIONFFA_VERSION_1_1
-
-/*
- * This is the version we want to use in communication with guests and SPs.
- * During negotiation with a guest or a SP we may need to lower it for
- * that particular guest or SP.
- */
-#define FFA_MY_VERSION_MAJOR1U
-#define FFA_MY_VERSION_MINOR1U
-#define FFA_MY_VERSION  MAKE_FFA_VERSION(FFA_MY_VERSION_MAJOR, \
- FFA_MY_VERSION_MINOR)
-
-/*
- * The FF-A specification explicitly works with 4K pages as a measure of
- * memory size, for example, FFA_RXTX_MAP takes one parameter "RX/TX page
- * count" which is the number of contiguous 4K pages allocated. Xen may use
- * a different page size depending on the configuration to avoid confusion
- * with PAGE_SIZE use a special define when it's a page size as in the FF-A
- * specification.
- */
-#define FFA_PAGE_SIZE   SZ_4K
-
-/*
- * The number of pages used for each of the RX and TX buffers shared with
- * the SPMC.
- */
-#define FFA_RXTX_PAGE_COUNT 1
-
-/*
- * Limit the number of pages RX/TX buffers guests can map.
- * TODO support a larger number.
- */
-#define FFA_MAX_RXTX_PAGE_COUNT 1
-
-/*
- * Limit for shared buffer size. Please note that this define limits
- * number of pages.
- *
- * FF-A doesn't have any direct requirements on GlobalPlatform or vice
- * versa, but an implementation can very well use FF-A in order to provide
- * a GlobalPlatform interface on top.
- *
- * Global Platform specification for TEE requires that any TEE
- * implementation should allow to share buffers with size of at least
- * 512KB, defined in TEEC-1.0C page 24, Table 4-1,
- * TEEC_CONFIG_SHAREDMEM_MAX_SIZE.
- * Due to overhead which can be hard to predict exactly, double this number
- * to give a safe margin.
- */
-#define FFA_MAX_SHM_PAGE_COUNT  (2 * SZ_512K / FFA_PAGE_SIZE)
-
-/*
- * Limits the number of shared buffers that guest can have at once. This
- * is to prevent case, when guests trick XEN into exhausting its own
- * memory by allocating many small buffers. This value has been chosen
- * arbitrarily.
- */
-#define FFA_MAX_SHM_COUNT   32
-
-/*
- * The time we wait until trying to tear down a domain again if it was
- * blocked initially.
- */
-#define FFA_CTX_TEARDOWN_DELAY  SECONDS(1)
-
-/* FF-A-1.1-REL0 section 10.9.2 Memory region handle, page 167 */
-#define FFA_HANDLE_HYP_FLAG BIT(63, ULL)
-#define FFA_HANDLE_INVALID  0xULL
-
-/*
- * Memory attributes: Normal memory, Write-Back cacheable, Inner shareable
- * Defined in FF-A-1.1-REL0 Table 10.18 at page 175.
- */
-#define FFA_NORMAL_MEM_REG_ATTR 0x2fU
-/*
- * Memory access permissions: Read-write
- * Defined in FF-A-1.1-REL0 Table 10.15 at page 168.
- */
-#define FFA_MEM_ACC_RW  0x2U
-
-/* FF-A-1.1-REL0 section 10.11.4 Flags usage, page 184-187 */
-/* Clear memory before mapping in receiver */
-#define FFA_MEMORY_REGION_FLAG_CLEARBIT(0, U)
-/* Relayer may time slice this operation */
-#define FFA_MEMORY_REGION_FLAG_TIME_SLICE   BIT(1, U)
-/* Clear memory after receiver relinquishes it */
-#define FFA_MEMORY_REGION_FLAG_CLEAR_RELINQUISH BIT(2, U)
-/* Share memory transaction */
-#define FFA_MEMORY_REGION_TRANSACTION_TYPE_SHARE (1U << 3)
-
-/*
- * Flags and field values used fo

[XEN PATCH v5] xen/arm: ffa: reclaim shared memory on guest destroy

2024-02-13 Thread Jens Wiklander
When an FF-A enabled guest is destroyed it may leave behind memory
shared with SPs. This memory must be reclaimed before it's reused or an
SP may make changes to memory used by a new unrelated guest. So when the
domain is teared down add FF-A requests to reclaim all remaining shared
memory.

SPs in the secure world are notified using VM_DESTROYED that a guest has
been destroyed. An SP is supposed to relinquish all shared memory to allow
reclaiming the memory. The relinquish operation may need to be delayed if
the shared memory is for instance part of a DMA operation.

The domain reference counter is increased when the first FF-A shared
memory is registered and the counter is decreased again when the last
shared memory is reclaimed. If FF-A shared memory registrations remain
at the end of of ffa_domain_teardown() a timer is set to try to reclaim
the shared memory every second until the memory is reclaimed.

A few minor style fixes with a removed empty line here and an added new
line there.

Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
---
v5:
- Move the put_domain() call after the spinlock section in dec_ctx_shm_count()
- Move the get_knownalive_domain() call into the else statement in
  inc_ctx_shm_count() to make sure it's only performed if ctx->shm_count
  is to be increased

v4:
- Retry FFA_MSG_SEND_VM_DESTROYED on the returned errors
  FFA_RET_INTERRUPTED and FFA_RET_RETRY even after all shared memory
  handles has been reclaimed.
- Retry ffa_mem_reclaim() only on temporary returned errors, permanent
  errors like FFA_RET_INVALID_PARAMETERS is dealt with in recovery mode
  instead since the SPMC isn't expected to use that error under normal
  circumstances.

v3:
- Mentioning in the commit message that there are some style fixes
- Addressing review comments
- Refactor the ffa_domain_teardown() path to let
  ffa_domain_teardown_continue() do most of the work.

v2:
- Update commit message to match the new implementation
- Using a per domain bitfield to keep track of which SPs has been notified
  with VM_DESTROYED
- Holding a domain reference counter to keep the domain as a zombie domain
  while there still is shared memory registrations remaining to be reclaimed
- Using a timer to retry reclaiming remaining shared memory registrations
---
 xen/arch/arm/tee/ffa.c | 295 ++---
 1 file changed, 245 insertions(+), 50 deletions(-)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 0793c1c7585d..9a05dcede17a 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -54,6 +54,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -144,6 +145,12 @@
  */
 #define FFA_MAX_SHM_COUNT   32
 
+/*
+ * The time we wait until trying to tear down a domain again if it was
+ * blocked initially.
+ */
+#define FFA_CTX_TEARDOWN_DELAY  SECONDS(1)
+
 /* FF-A-1.1-REL0 section 10.9.2 Memory region handle, page 167 */
 #define FFA_HANDLE_HYP_FLAG BIT(63, ULL)
 #define FFA_HANDLE_INVALID  0xULL
@@ -384,11 +391,6 @@ struct ffa_ctx {
 unsigned int page_count;
 /* FF-A version used by the guest */
 uint32_t guest_vers;
-/*
- * Number of SPs that we have sent a VM created signal to, used in
- * ffa_domain_teardown() to know which SPs need to be signalled.
- */
-uint16_t create_signal_count;
 bool rx_is_free;
 /* Used shared memory objects, struct ffa_shm_mem */
 struct list_head shm_list;
@@ -402,6 +404,15 @@ struct ffa_ctx {
 spinlock_t tx_lock;
 spinlock_t rx_lock;
 spinlock_t lock;
+/* Used if domain can't be torn down immediately */
+struct domain *teardown_d;
+struct list_head teardown_list;
+s_time_t teardown_expire;
+/*
+ * Used for ffa_domain_teardown() to keep track of which SPs should be
+ * notified that this guest is being destroyed.
+ */
+unsigned long vm_destroy_bitmap[];
 };
 
 struct ffa_shm_mem {
@@ -436,6 +447,12 @@ static void *ffa_tx __read_mostly;
 static DEFINE_SPINLOCK(ffa_rx_buffer_lock);
 static DEFINE_SPINLOCK(ffa_tx_buffer_lock);
 
+
+/* Used to track domains that could not be torn down immediately. */
+static struct timer ffa_teardown_timer;
+static struct list_head ffa_teardown_head;
+static DEFINE_SPINLOCK(ffa_teardown_lock);
+
 static bool ffa_get_version(uint32_t *vers)
 {
 const struct arm_smccc_1_2_regs arg = {
@@ -853,7 +870,6 @@ static int32_t handle_partition_info_get(uint32_t w1, 
uint32_t w2, uint32_t w3,
 goto out_rx_release;
 }
 
-
 memcpy(ctx->rx, ffa_rx, sz);
 }
 ctx->rx_is_free = false;
@@ -992,53 +1008,83 @@ static void put_shm_pages(struct ffa_shm_mem *shm)
 }
 }
 
-static bool inc_ctx_shm_count(struct ffa_ctx *ctx)
+static bool inc_ctx_shm_count(struct domain *d, struct ffa_ctx *ctx)
 {
 bool ret = true;
 
 spin_lock(>lock);
-if (ctx->shm_count >= FFA_MAX_SHM_COUN

Re: [XEN PATCH v4] xen/arm: ffa: reclaim shared memory on guest destroy

2024-02-05 Thread Jens Wiklander
On Mon, Feb 5, 2024 at 5:54 PM Andrew Cooper  wrote:
>
> On 05/02/2024 3:49 pm, Jens Wiklander wrote:
> > diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
> > index 0793c1c7585d..bbb6b819ee2b 100644
> > --- a/xen/arch/arm/tee/ffa.c
> > +++ b/xen/arch/arm/tee/ffa.c
> > @@ -992,53 +1008,75 @@ static void put_shm_pages(struct ffa_shm_mem *shm)
> >  }
> >  }
> >
> > -static bool inc_ctx_shm_count(struct ffa_ctx *ctx)
> > +static bool inc_ctx_shm_count(struct domain *d, struct ffa_ctx *ctx)
> >  {
> >  bool ret = true;
> >
> >  spin_lock(>lock);
> > +
> > +/*
> > + * If this is the first shm added, increase the domain reference
> > + * counter as we need to keep domain around a bit longer to reclaim the
> > + * shared memory in the teardown path.
> > + */
> > +if ( !ctx->shm_count )
> > +get_knownalive_domain(d);
> > +
> >  if (ctx->shm_count >= FFA_MAX_SHM_COUNT)
> >  ret = false;
> >  else
> >  ctx->shm_count++;
> > +
> >  spin_unlock(>lock);
>
> This is subtle.  It reads as if there is a reference leak.  There really
> will be one if FFA_MAX_SHM_COUNT happens to be 0.
>
> You could add a BUILD_BUG_ON(), but IMO it would be far clearer to
> follow if you moved the get_knownalive_domain() into the else clause.

I see your point, I'll fix it in the next version.

>
> >
> >  return ret;
> >  }
> >
> > -static void dec_ctx_shm_count(struct ffa_ctx *ctx)
> > +static void dec_ctx_shm_count(struct domain *d, struct ffa_ctx *ctx)
> >  {
> >  spin_lock(>lock);
> > +
> >  ASSERT(ctx->shm_count > 0);
> >  ctx->shm_count--;
> > +
> > +/*
> > + * If this was the last shm removed, let go of the domain reference we
> > + * took in inc_ctx_shm_count() above.
> > + */
> > +if ( !ctx->shm_count )
> > +put_domain(d);
> > +
> >  spin_unlock(>lock);
>
> You want a local bool called drop_ref, set within the lock, and move the
> put_domain() down here.  put_domain() is potentially a large operation.

OK, I'll fix it in the next version.

Thanks,
Jens



[XEN PATCH v4] xen/arm: ffa: reclaim shared memory on guest destroy

2024-02-05 Thread Jens Wiklander
When an FF-A enabled guest is destroyed it may leave behind memory
shared with SPs. This memory must be reclaimed before it's reused or an
SP may make changes to memory used by a new unrelated guest. So when the
domain is teared down add FF-A requests to reclaim all remaining shared
memory.

SPs in the secure world are notified using VM_DESTROYED that a guest has
been destroyed. An SP is supposed to relinquish all shared memory to allow
reclaiming the memory. The relinquish operation may need to be delayed if
the shared memory is for instance part of a DMA operation.

The domain reference counter is increased when the first FF-A shared
memory is registered and the counter is decreased again when the last
shared memory is reclaimed. If FF-A shared memory registrations remain
at the end of of ffa_domain_teardown() a timer is set to try to reclaim
the shared memory every second until the memory is reclaimed.

A few minor style fixes with a removed empty line here and an added new
line there.

Signed-off-by: Jens Wiklander 
---

v4:
- Retry FFA_MSG_SEND_VM_DESTROYED on the returned errors
  FFA_RET_INTERRUPTED and FFA_RET_RETRY even after all shared memory
  handles has been reclaimed.
- Retry ffa_mem_reclaim() only on temporary returned errors, permanent
  errors like FFA_RET_INVALID_PARAMETERS is dealt with in recovery mode
  instead since the SPMC isn't expected to use that error under normal
  circumstances.

v3:
- Mentioning in the commit message that there are some style fixes
- Addressing review comments
- Refactor the ffa_domain_teardown() path to let
  ffa_domain_teardown_continue() do most of the work.

v2:
- Update commit message to match the new implementation
- Using a per domain bitfield to keep track of which SPs has been notified
  with VM_DESTROYED
- Holding a domain reference counter to keep the domain as a zombie domain
  while there still is shared memory registrations remaining to be reclaimed
- Using a timer to retry reclaiming remaining shared memory registrations
---
 xen/arch/arm/tee/ffa.c | 285 ++---
 1 file changed, 236 insertions(+), 49 deletions(-)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 0793c1c7585d..bbb6b819ee2b 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -54,6 +54,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -144,6 +145,12 @@
  */
 #define FFA_MAX_SHM_COUNT   32
 
+/*
+ * The time we wait until trying to tear down a domain again if it was
+ * blocked initially.
+ */
+#define FFA_CTX_TEARDOWN_DELAY  SECONDS(1)
+
 /* FF-A-1.1-REL0 section 10.9.2 Memory region handle, page 167 */
 #define FFA_HANDLE_HYP_FLAG BIT(63, ULL)
 #define FFA_HANDLE_INVALID  0xULL
@@ -384,11 +391,6 @@ struct ffa_ctx {
 unsigned int page_count;
 /* FF-A version used by the guest */
 uint32_t guest_vers;
-/*
- * Number of SPs that we have sent a VM created signal to, used in
- * ffa_domain_teardown() to know which SPs need to be signalled.
- */
-uint16_t create_signal_count;
 bool rx_is_free;
 /* Used shared memory objects, struct ffa_shm_mem */
 struct list_head shm_list;
@@ -402,6 +404,15 @@ struct ffa_ctx {
 spinlock_t tx_lock;
 spinlock_t rx_lock;
 spinlock_t lock;
+/* Used if domain can't be torn down immediately */
+struct domain *teardown_d;
+struct list_head teardown_list;
+s_time_t teardown_expire;
+/*
+ * Used for ffa_domain_teardown() to keep track of which SPs should be
+ * notified that this guest is being destroyed.
+ */
+unsigned long vm_destroy_bitmap[];
 };
 
 struct ffa_shm_mem {
@@ -436,6 +447,12 @@ static void *ffa_tx __read_mostly;
 static DEFINE_SPINLOCK(ffa_rx_buffer_lock);
 static DEFINE_SPINLOCK(ffa_tx_buffer_lock);
 
+
+/* Used to track domains that could not be torn down immediately. */
+static struct timer ffa_teardown_timer;
+static struct list_head ffa_teardown_head;
+static DEFINE_SPINLOCK(ffa_teardown_lock);
+
 static bool ffa_get_version(uint32_t *vers)
 {
 const struct arm_smccc_1_2_regs arg = {
@@ -853,7 +870,6 @@ static int32_t handle_partition_info_get(uint32_t w1, 
uint32_t w2, uint32_t w3,
 goto out_rx_release;
 }
 
-
 memcpy(ctx->rx, ffa_rx, sz);
 }
 ctx->rx_is_free = false;
@@ -992,53 +1008,75 @@ static void put_shm_pages(struct ffa_shm_mem *shm)
 }
 }
 
-static bool inc_ctx_shm_count(struct ffa_ctx *ctx)
+static bool inc_ctx_shm_count(struct domain *d, struct ffa_ctx *ctx)
 {
 bool ret = true;
 
 spin_lock(>lock);
+
+/*
+ * If this is the first shm added, increase the domain reference
+ * counter as we need to keep domain around a bit longer to reclaim the
+ * shared memory in the teardown path.
+ */
+if ( !ctx->shm_count )
+get_knownalive_domain(d);
+
 if (ctx->shm_count >= FFA_MAX_SHM_COUNT)
  

Re: [XEN PATCH v3] xen/arm: ffa: reclaim shared memory on guest destroy

2024-02-05 Thread Jens Wiklander
Hi Bertrand,

On Thu, Feb 1, 2024 at 2:57 PM Bertrand Marquis
 wrote:
>
> Hi Jens,
>
> > On 17 Jan 2024, at 12:06, Jens Wiklander  wrote:
> >
> > When an FF-A enabled guest is destroyed it may leave behind memory
> > shared with SPs. This memory must be reclaimed before it's reused or an
> > SP may make changes to memory used by a new unrelated guest. So when the
> > domain is teared down add FF-A requests to reclaim all remaining shared
> > memory.
> >
> > SPs in the secure world are notified using VM_DESTROYED that a guest has
> > been destroyed. An SP is supposed to relinquish all shared memory to allow
> > reclaiming the memory. The relinquish operation may need to be delayed if
> > the shared memory is for instance part of a DMA operation.
> >
> > The domain reference counter is increased when the first FF-A shared
> > memory is registered and the counter is decreased again when the last
> > shared memory is reclaimed. If FF-A shared memory registrations remain
> > at the end of of ffa_domain_teardown() a timer is set to try to reclaim
> > the shared memory every second until the memory is reclaimed.
> >
> > A few minor style fixes with a removed empty line here and an added new
> > line there.
> >
> > Signed-off-by: Jens Wiklander 
> > ---
> >
> > v3:
> > - Mentioning in the commit message that there are some style fixes
> > - Addressing review comments
> > - Refactor the ffa_domain_teardown() path to let
> >  ffa_domain_teardown_continue() do most of the work.
> >
> > v2:
> > - Update commit message to match the new implementation
> > - Using a per domain bitfield to keep track of which SPs has been notified
> >  with VM_DESTROYED
> > - Holding a domain reference counter to keep the domain as a zombie domain
> >  while there still is shared memory registrations remaining to be reclaimed
> > - Using a timer to retry reclaiming remaining shared memory registrations
> > ---
> > xen/arch/arm/tee/ffa.c | 253 +
> > 1 file changed, 204 insertions(+), 49 deletions(-)
> >
> > diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
> > index 0793c1c7585d..80ebbf4f01c6 100644
> > --- a/xen/arch/arm/tee/ffa.c
> > +++ b/xen/arch/arm/tee/ffa.c
> > @@ -54,6 +54,7 @@
> > #include 
> > #include 
> > #include 
> > +#include 
> > #include 
> >
> > #include 
> > @@ -144,6 +145,12 @@
> >  */
> > #define FFA_MAX_SHM_COUNT   32
> >
> > +/*
> > + * The time we wait until trying to tear down a domain again if it was
> > + * blocked initially.
> > + */
> > +#define FFA_CTX_TEARDOWN_DELAY  SECONDS(1)
> > +
> > /* FF-A-1.1-REL0 section 10.9.2 Memory region handle, page 167 */
> > #define FFA_HANDLE_HYP_FLAG BIT(63, ULL)
> > #define FFA_HANDLE_INVALID  0xULL
> > @@ -384,11 +391,6 @@ struct ffa_ctx {
> > unsigned int page_count;
> > /* FF-A version used by the guest */
> > uint32_t guest_vers;
> > -/*
> > - * Number of SPs that we have sent a VM created signal to, used in
> > - * ffa_domain_teardown() to know which SPs need to be signalled.
> > - */
> > -uint16_t create_signal_count;
> > bool rx_is_free;
> > /* Used shared memory objects, struct ffa_shm_mem */
> > struct list_head shm_list;
> > @@ -402,6 +404,15 @@ struct ffa_ctx {
> > spinlock_t tx_lock;
> > spinlock_t rx_lock;
> > spinlock_t lock;
> > +/* Used if domain can't be torn down immediately */
> > +struct domain *teardown_d;
> > +struct list_head teardown_list;
> > +s_time_t teardown_expire;
> > +/*
> > + * Used for ffa_domain_teardown() to keep track of which SPs should be
> > + * notified that this guest is being destroyed.
> > + */
> > +unsigned long vm_destroy_bitmap[];
> > };
> >
> > struct ffa_shm_mem {
> > @@ -436,6 +447,12 @@ static void *ffa_tx __read_mostly;
> > static DEFINE_SPINLOCK(ffa_rx_buffer_lock);
> > static DEFINE_SPINLOCK(ffa_tx_buffer_lock);
> >
> > +
> > +/* Used to track domains that could not be torn down immediately. */
> > +static struct timer ffa_teardown_timer;
> > +static struct list_head ffa_teardown_head;
> > +static DEFINE_SPINLOCK(ffa_teardown_lock);
> > +
> > static bool ffa_get_version(uint32_t *vers)
> > {
> > const struct arm_smccc_1_2_regs arg = {
> > @@ -853,7 +870,6 @@ static

[XEN PATCH v3] xen/arm: ffa: reclaim shared memory on guest destroy

2024-01-17 Thread Jens Wiklander
When an FF-A enabled guest is destroyed it may leave behind memory
shared with SPs. This memory must be reclaimed before it's reused or an
SP may make changes to memory used by a new unrelated guest. So when the
domain is teared down add FF-A requests to reclaim all remaining shared
memory.

SPs in the secure world are notified using VM_DESTROYED that a guest has
been destroyed. An SP is supposed to relinquish all shared memory to allow
reclaiming the memory. The relinquish operation may need to be delayed if
the shared memory is for instance part of a DMA operation.

The domain reference counter is increased when the first FF-A shared
memory is registered and the counter is decreased again when the last
shared memory is reclaimed. If FF-A shared memory registrations remain
at the end of of ffa_domain_teardown() a timer is set to try to reclaim
the shared memory every second until the memory is reclaimed.

A few minor style fixes with a removed empty line here and an added new
line there.

Signed-off-by: Jens Wiklander 
---

v3:
- Mentioning in the commit message that there are some style fixes
- Addressing review comments
- Refactor the ffa_domain_teardown() path to let
  ffa_domain_teardown_continue() do most of the work.

v2:
- Update commit message to match the new implementation
- Using a per domain bitfield to keep track of which SPs has been notified
  with VM_DESTROYED
- Holding a domain reference counter to keep the domain as a zombie domain
  while there still is shared memory registrations remaining to be reclaimed
- Using a timer to retry reclaiming remaining shared memory registrations
---
 xen/arch/arm/tee/ffa.c | 253 +
 1 file changed, 204 insertions(+), 49 deletions(-)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 0793c1c7585d..80ebbf4f01c6 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -54,6 +54,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -144,6 +145,12 @@
  */
 #define FFA_MAX_SHM_COUNT   32
 
+/*
+ * The time we wait until trying to tear down a domain again if it was
+ * blocked initially.
+ */
+#define FFA_CTX_TEARDOWN_DELAY  SECONDS(1)
+
 /* FF-A-1.1-REL0 section 10.9.2 Memory region handle, page 167 */
 #define FFA_HANDLE_HYP_FLAG BIT(63, ULL)
 #define FFA_HANDLE_INVALID  0xULL
@@ -384,11 +391,6 @@ struct ffa_ctx {
 unsigned int page_count;
 /* FF-A version used by the guest */
 uint32_t guest_vers;
-/*
- * Number of SPs that we have sent a VM created signal to, used in
- * ffa_domain_teardown() to know which SPs need to be signalled.
- */
-uint16_t create_signal_count;
 bool rx_is_free;
 /* Used shared memory objects, struct ffa_shm_mem */
 struct list_head shm_list;
@@ -402,6 +404,15 @@ struct ffa_ctx {
 spinlock_t tx_lock;
 spinlock_t rx_lock;
 spinlock_t lock;
+/* Used if domain can't be torn down immediately */
+struct domain *teardown_d;
+struct list_head teardown_list;
+s_time_t teardown_expire;
+/*
+ * Used for ffa_domain_teardown() to keep track of which SPs should be
+ * notified that this guest is being destroyed.
+ */
+unsigned long vm_destroy_bitmap[];
 };
 
 struct ffa_shm_mem {
@@ -436,6 +447,12 @@ static void *ffa_tx __read_mostly;
 static DEFINE_SPINLOCK(ffa_rx_buffer_lock);
 static DEFINE_SPINLOCK(ffa_tx_buffer_lock);
 
+
+/* Used to track domains that could not be torn down immediately. */
+static struct timer ffa_teardown_timer;
+static struct list_head ffa_teardown_head;
+static DEFINE_SPINLOCK(ffa_teardown_lock);
+
 static bool ffa_get_version(uint32_t *vers)
 {
 const struct arm_smccc_1_2_regs arg = {
@@ -853,7 +870,6 @@ static int32_t handle_partition_info_get(uint32_t w1, 
uint32_t w2, uint32_t w3,
 goto out_rx_release;
 }
 
-
 memcpy(ctx->rx, ffa_rx, sz);
 }
 ctx->rx_is_free = false;
@@ -992,53 +1008,75 @@ static void put_shm_pages(struct ffa_shm_mem *shm)
 }
 }
 
-static bool inc_ctx_shm_count(struct ffa_ctx *ctx)
+static bool inc_ctx_shm_count(struct domain *d, struct ffa_ctx *ctx)
 {
 bool ret = true;
 
 spin_lock(>lock);
+
+/*
+ * If this is the first shm added, increase the domain reference
+ * counter as we need to keep domain around a bit longer to reclaim the
+ * shared memory in the teardown path.
+ */
+if ( !ctx->shm_count )
+get_knownalive_domain(d);
+
 if (ctx->shm_count >= FFA_MAX_SHM_COUNT)
 ret = false;
 else
 ctx->shm_count++;
+
 spin_unlock(>lock);
 
 return ret;
 }
 
-static void dec_ctx_shm_count(struct ffa_ctx *ctx)
+static void dec_ctx_shm_count(struct domain *d, struct ffa_ctx *ctx)
 {
 spin_lock(>lock);
+
 ASSERT(ctx->shm_count > 0);
 ctx->shm_count--;
+
+/*
+ * If this was the last shm remove

Re: [XEN PATCH v2] xen/arm: ffa: reclaim shared memory on guest destroy

2024-01-17 Thread Jens Wiklander
Hi Bertrand,

On Mon, Jan 15, 2024 at 12:15 PM Bertrand Marquis
 wrote:
>
> Hi Jens,
>
> Very sorry for the long delay.
>
> > On 13 Dec 2023, at 12:25, Jens Wiklander  wrote:
> >
> > When an FF-A enabled guest is destroyed it may leave behind memory
> > shared with SPs. This memory must be reclaimed before it's reused or an
> > SP may make changes to memory used by a new unrelated guest. So when the
> > domain is teared down add FF-A requests to reclaim all remaining shared
> > memory.
> >
> > SPs in the secure world are notified using VM_DESTROYED that a guest has
> > been destroyed. An SP is supposed to relinquish all shared memory to allow
> > reclaiming the memory. The relinquish operation may need to be delayed if
> > the shared memory is for instance part of a DMA operation.
> >
> > The domain reference counter is increased when the first FF-A shared
> > memory is registered and the counter is decreased again when the last
> > shared memory is reclaimed. If FF-A shared memory registrations remain
> > at the end of of ffa_domain_teardown() a timer is set to try to reclaim
> > the shared memory every second until the memory is reclaimed.
> >
> > Signed-off-by: Jens Wiklander 
> > ---
> > Hi,
> >
> > This is a follow-up to the RFC patch. In this patch, I take an explicit
> > reference on the domain when FF-A shared memory is registered. I've
> > discovered that it might not be strictly necessary until all the shared
> > pages are released with put_page() they also keep a reference to the
> > domain.
> >
> > I'm not entirely sure what is the status of the shared memory when the
> > domain has turned into a zombie. We still hold references on the shared
> > pages until put_page() is called on each. Is that enough to guarantee that
> > they will not be reused?
> >
> > Thanks,
> > Jens
> >
> > v2:
> > - Update commit message to match the new implementation
> > - Using a per domain bitfield to keep track of which SPs has been notified
> >  with VM_DESTROYED
> > - Holding a domain reference counter to keep the domain as a zombie domain
> >  while there still is shared memory registrations remaining to be reclaimed
> > - Using a timer to retry reclaiming remaining shared memory registrations
> >
> > ---
> > xen/arch/arm/tee/ffa.c | 270 ++---
> > 1 file changed, 224 insertions(+), 46 deletions(-)
> >
> > diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
> > index 183528d13388..22906a6e1cff 100644
> > --- a/xen/arch/arm/tee/ffa.c
> > +++ b/xen/arch/arm/tee/ffa.c
> > @@ -54,6 +54,7 @@
> > #include 
> > #include 
> > #include 
> > +#include 
> > #include 
> >
> > #include 
> > @@ -384,11 +385,6 @@ struct ffa_ctx {
> > unsigned int page_count;
> > /* FF-A version used by the guest */
> > uint32_t guest_vers;
> > -/*
> > - * Number of SPs that we have sent a VM created signal to, used in
> > - * ffa_domain_teardown() to know which SPs need to be signalled.
> > - */
> > -uint16_t create_signal_count;
> > bool rx_is_free;
> > /* Used shared memory objects, struct ffa_shm_mem */
> > struct list_head shm_list;
> > @@ -402,6 +398,15 @@ struct ffa_ctx {
> > spinlock_t tx_lock;
> > spinlock_t rx_lock;
> > spinlock_t lock;
> > +/* Used if domain can't be teared down immediately */
> > +struct domain *teardown_d;
> > +struct list_head teardown_list;
> > +s_time_t teardown_expire;
> > +/*
> > + * Used for ffa_domain_teardown() to keep track of which SPs should be
> > + * notified that this guest is being destroyed.
> > + */
> > +unsigned long vm_destroy_bitmap[];
> > };
> >
> > struct ffa_shm_mem {
> > @@ -436,6 +441,12 @@ static void *ffa_tx __read_mostly;
> > static DEFINE_SPINLOCK(ffa_rx_buffer_lock);
> > static DEFINE_SPINLOCK(ffa_tx_buffer_lock);
> >
> > +
> > +/* Used if domain can't be teared down immediately */
>
> Please adapt the comment as this for all domains.
> Suggest: Used to track domains that could not be teared down immediately.

I'll update.

>
> > +static struct timer ffa_teardown_timer;
> > +static struct list_head ffa_teardown_head;
> > +static DEFINE_SPINLOCK(ffa_teardown_lock);
> > +
> > static bool ffa_get_version(uint32_t *vers)
> > {
> > const struct arm_smccc_1_2_regs arg = {
> > @@ -850,7 +861,6 @@ static int32_t han

[XEN PATCH v2] xen/arm: ffa: reclaim shared memory on guest destroy

2023-12-13 Thread Jens Wiklander
When an FF-A enabled guest is destroyed it may leave behind memory
shared with SPs. This memory must be reclaimed before it's reused or an
SP may make changes to memory used by a new unrelated guest. So when the
domain is teared down add FF-A requests to reclaim all remaining shared
memory.

SPs in the secure world are notified using VM_DESTROYED that a guest has
been destroyed. An SP is supposed to relinquish all shared memory to allow
reclaiming the memory. The relinquish operation may need to be delayed if
the shared memory is for instance part of a DMA operation.

The domain reference counter is increased when the first FF-A shared
memory is registered and the counter is decreased again when the last
shared memory is reclaimed. If FF-A shared memory registrations remain
at the end of of ffa_domain_teardown() a timer is set to try to reclaim
the shared memory every second until the memory is reclaimed.

Signed-off-by: Jens Wiklander 
---
Hi,

This is a follow-up to the RFC patch. In this patch, I take an explicit
reference on the domain when FF-A shared memory is registered. I've
discovered that it might not be strictly necessary until all the shared
pages are released with put_page() they also keep a reference to the
domain.

I'm not entirely sure what is the status of the shared memory when the
domain has turned into a zombie. We still hold references on the shared
pages until put_page() is called on each. Is that enough to guarantee that
they will not be reused?

Thanks,
Jens

v2:
- Update commit message to match the new implementation
- Using a per domain bitfield to keep track of which SPs has been notified
  with VM_DESTROYED
- Holding a domain reference counter to keep the domain as a zombie domain
  while there still is shared memory registrations remaining to be reclaimed
- Using a timer to retry reclaiming remaining shared memory registrations

---
 xen/arch/arm/tee/ffa.c | 270 ++---
 1 file changed, 224 insertions(+), 46 deletions(-)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 183528d13388..22906a6e1cff 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -54,6 +54,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -384,11 +385,6 @@ struct ffa_ctx {
 unsigned int page_count;
 /* FF-A version used by the guest */
 uint32_t guest_vers;
-/*
- * Number of SPs that we have sent a VM created signal to, used in
- * ffa_domain_teardown() to know which SPs need to be signalled.
- */
-uint16_t create_signal_count;
 bool rx_is_free;
 /* Used shared memory objects, struct ffa_shm_mem */
 struct list_head shm_list;
@@ -402,6 +398,15 @@ struct ffa_ctx {
 spinlock_t tx_lock;
 spinlock_t rx_lock;
 spinlock_t lock;
+/* Used if domain can't be teared down immediately */
+struct domain *teardown_d;
+struct list_head teardown_list;
+s_time_t teardown_expire;
+/*
+ * Used for ffa_domain_teardown() to keep track of which SPs should be
+ * notified that this guest is being destroyed.
+ */
+unsigned long vm_destroy_bitmap[];
 };
 
 struct ffa_shm_mem {
@@ -436,6 +441,12 @@ static void *ffa_tx __read_mostly;
 static DEFINE_SPINLOCK(ffa_rx_buffer_lock);
 static DEFINE_SPINLOCK(ffa_tx_buffer_lock);
 
+
+/* Used if domain can't be teared down immediately */
+static struct timer ffa_teardown_timer;
+static struct list_head ffa_teardown_head;
+static DEFINE_SPINLOCK(ffa_teardown_lock);
+
 static bool ffa_get_version(uint32_t *vers)
 {
 const struct arm_smccc_1_2_regs arg = {
@@ -850,7 +861,6 @@ static int32_t handle_partition_info_get(uint32_t w1, 
uint32_t w2, uint32_t w3,
 goto out_rx_release;
 }
 
-
 memcpy(ctx->rx, ffa_rx, sz);
 }
 ctx->rx_is_free = false;
@@ -989,53 +999,75 @@ static void put_shm_pages(struct ffa_shm_mem *shm)
 }
 }
 
-static bool inc_ctx_shm_count(struct ffa_ctx *ctx)
+static bool inc_ctx_shm_count(struct domain *d, struct ffa_ctx *ctx)
 {
 bool ret = true;
 
 spin_lock(>lock);
+
+/*
+ * If this is the first shm added, increase the domain reference
+ * counter as we may need to domain around a bit longer to reclaim the
+ * shared memory in the teardown path.
+ */
+if ( !ctx->shm_count )
+get_knownalive_domain(d);
+
 if (ctx->shm_count >= FFA_MAX_SHM_COUNT)
 ret = false;
 else
 ctx->shm_count++;
+
 spin_unlock(>lock);
 
 return ret;
 }
 
-static void dec_ctx_shm_count(struct ffa_ctx *ctx)
+static void dec_ctx_shm_count(struct domain *d, struct ffa_ctx *ctx)
 {
 spin_lock(>lock);
+
 ASSERT(ctx->shm_count > 0);
 ctx->shm_count--;
+
+/*
+ * If this was the last shm removed, let go of the domain reference we
+ * took in inc_ctx_shm_count() above.
+ */
+if ( !ctx->shm_count )
+put_domain(d);
+
 spin_unlock(

[XEN PATCH] xen/arm: ffa: return FFA_RET_NOT_SUPPORTED on unhandled calls

2023-12-13 Thread Jens Wiklander
Until now has an unsupported FF-A request been reported back with
ARM_SMCCC_ERR_UNKNOWN_FUNCTION in register x0. A FF-A caller would
rather expect FFA_ERROR in x0 and FFA_RET_NOT_SUPPORTED in x2 so update
ffa_handle_call() to return true and with the cpu_user_regs updated.

Fixes: 38846de2176b ("xen/arm: tee: add a primitive FF-A mediator")
Signed-off-by: Jens Wiklander 
---
 xen/arch/arm/tee/ffa.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 183528d13388..98905fec7967 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -1477,7 +1477,8 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 
 default:
 gprintk(XENLOG_ERR, "ffa: unhandled fid 0x%x\n", fid);
-return false;
+set_regs_error(regs, FFA_RET_NOT_SUPPORTED);
+return true;
 }
 }
 
-- 
2.34.1




[XEN PATCH] xen/arm: ffa: return fpi size from FFA_PARTITION_INFO_GET

2023-12-13 Thread Jens Wiklander
Until now has FFA_PARTITION_INFO_GET always returned zero in w3, but
FF-A v1.1 requires FFA_PARTITION_INFO_GET to return the size of each
partition information descriptor returned if
FFA_PARTITION_INFO_GET_COUNT_FLAG isn't set.

The SPMC queried with FFA_PARTITION_INFO_GET must also return the each
partition information descriptor returned so fix this by passing along
the same value.

Fixes: caf6491e95a9 ("xen/arm: ffa: support guest FFA_PARTITION_INFO_GET")
Signed-off-by: Jens Wiklander 
---
 xen/arch/arm/tee/ffa.c | 21 +
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 183528d13388..1d4e0a083006 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -514,7 +514,7 @@ static int32_t ffa_rxtx_map(paddr_t tx_addr, paddr_t 
rx_addr,
 
 static int32_t ffa_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3,
   uint32_t w4, uint32_t w5,
-  uint32_t *count)
+  uint32_t *count, uint32_t *fpi_size)
 {
 const struct arm_smccc_1_2_regs arg = {
 .a0 = FFA_PARTITION_INFO_GET,
@@ -531,7 +531,10 @@ static int32_t ffa_partition_info_get(uint32_t w1, 
uint32_t w2, uint32_t w3,
 
 ret = get_ffa_ret_code();
 if ( !ret )
+{
 *count = resp.a2;
+*fpi_size = resp.a3;
+}
 
 return ret;
 }
@@ -784,7 +787,7 @@ static uint32_t handle_rxtx_unmap(void)
 
 static int32_t handle_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3,
  uint32_t w4, uint32_t w5,
- uint32_t *count)
+ uint32_t *count, uint32_t *fpi_size)
 {
 int32_t ret = FFA_RET_DENIED;
 struct domain *d = current->domain;
@@ -799,7 +802,7 @@ static int32_t handle_partition_info_get(uint32_t w1, 
uint32_t w2, uint32_t w3,
  */
 if ( w5 == FFA_PARTITION_INFO_GET_COUNT_FLAG &&
  ctx->guest_vers == FFA_VERSION_1_1 )
-return ffa_partition_info_get(w1, w2, w3, w4, w5, count);
+return ffa_partition_info_get(w1, w2, w3, w4, w5, count, fpi_size);
 if ( w5 )
 return FFA_RET_INVALID_PARAMETERS;
 
@@ -812,7 +815,7 @@ static int32_t handle_partition_info_get(uint32_t w1, 
uint32_t w2, uint32_t w3,
 if ( !ctx->page_count || !ctx->rx_is_free )
 goto out;
 spin_lock(_rx_buffer_lock);
-ret = ffa_partition_info_get(w1, w2, w3, w4, w5, count);
+ret = ffa_partition_info_get(w1, w2, w3, w4, w5, count, fpi_size);
 if ( ret )
 goto out_rx_buf_unlock;
 /*
@@ -842,7 +845,7 @@ static int32_t handle_partition_info_get(uint32_t w1, 
uint32_t w2, uint32_t w3,
 }
 else
 {
-size_t sz = *count * sizeof(struct ffa_partition_info_1_1);
+size_t sz = *count * *fpi_size;
 
 if ( ctx->page_count * FFA_PAGE_SIZE < sz )
 {
@@ -1409,6 +1412,7 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 uint32_t fid = get_user_reg(regs, 0);
 struct domain *d = current->domain;
 struct ffa_ctx *ctx = d->arch.tee;
+uint32_t fpi_size;
 uint32_t count;
 int e;
 
@@ -1444,11 +1448,11 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
   get_user_reg(regs, 2),
   get_user_reg(regs, 3),
   get_user_reg(regs, 4),
-  get_user_reg(regs, 5), );
+  get_user_reg(regs, 5), , 
_size);
 if ( e )
 set_regs_error(regs, e);
 else
-set_regs_success(regs, count, 0);
+set_regs_success(regs, count, fpi_size);
 return true;
 case FFA_RX_RELEASE:
 e = handle_rx_release();
@@ -1629,10 +1633,11 @@ static bool init_subscribers(struct 
ffa_partition_info_1_1 *fpi, uint16_t count)
 static bool init_sps(void)
 {
 bool ret = false;
+uint32_t fpi_size;
 uint32_t count;
 int e;
 
-e = ffa_partition_info_get(0, 0, 0, 0, 0, );
+e = ffa_partition_info_get(0, 0, 0, 0, 0, , _size);
 if ( e )
 {
 printk(XENLOG_ERR "ffa: Failed to get list of SPs: %d\n", e);
-- 
2.34.1




Re: [RFC XEN PATCH] xen/arm: ffa: reclaim shared memory on guest destroy

2023-12-05 Thread Jens Wiklander
Hi Andrew,

On Tue, Dec 5, 2023 at 11:53 AM Andrew Cooper  wrote:
>
> On 05/12/2023 8:14 am, Bertrand Marquis wrote:
> > Hi Julien,
> >
> > Thanks a lot for your review and comment, this is very helpful.
> >
> >> On 4 Dec 2023, at 20:24, Julien Grall  wrote:
> >>
> >> Hi Jens,
> >>
> >> On 04/12/2023 07:55, Jens Wiklander wrote:
> >>>if ( ctx->rx )
> >>>  rxtx_unmap(ctx);
> >>>  +
> >>> +list_for_each_entry_safe(shm, tmp, >shm_list, list)
> >>> +{
> >>> +register_t handle_hi;
> >>> +register_t handle_lo;
> >>> +
> >>> +uint64_to_regpair(_hi, _lo, shm->handle);
> >>> +res = ffa_mem_reclaim(handle_lo, handle_hi, 0);
> >> Is this call expensive? If so, we may need to handle continuation here.
> > This call should not be expensive in the normal case as memory is 
> > reclaimable
> > so there is no processing required in the SP and all is done in the SPMC 
> > which
> > should basically just return a yes or no depending on a state for the 
> > handle.
> >
> > So I think this is the best trade.
> >
> > @Jens: One thing to consider is that a Destroy might get a retry or busy 
> > answer and we
> > will have to issue it again and this is not considered in the current 
> > implementation.
> >
> > After discussing the subject internally we could in fact consider that if 
> > an SP cannot release
> > some memory shared with the VM destroyed, it should tell it by returning 
> > "retry" to the message.
> > Here that could simplify things by doing a strategy where:
> > - we retry on the VM_DESTROY message if required
> > - if some memory is not reclaimable we check if we could park it and make 
> > the VM a zombie.
> > What do you think ?
>
> This is the cleanup issue discussed at XenSummit, isn't it?
>
> You cannot feasibly implement this cleanup by having
> ffa_domain_teardown() return -ERESTART.
>
> Yes, it will probably function - but now you're now bouncing in/out of
> Xen as fast as the CPU will allow, rechecking a condition which will
> take an unbounded quantity of time.  Meanwhile, you've tied up a
> userspace thread (the invocation of `xl destroy`) to do so, and one of
> dom0's vCPU for however long the scheduler is willing to schedule the
> destroy invocation, which will be 100% of the time as it's always busy
> in the hypervisor.
>
> The teardown/kill infrastructure is intended and expected to always make
> forward progress.
>

OK

>
> The closest thing to this patch which will work sanely is this:
>
> Hold a single domain reference for any non-zero amount of magic memory
> held.  See domain_adjust_tot_pages() and how it interacts with
> {get,put}_domain(), and copy it.  Importantly, this prevents the domain
> being freed until the final piece of magic memory has been released.
>
> Have some way (can be early on the teardown/kill path, or a separate
> hypercall - assuming the VM can't ever be scheduled again) to kick Xen
> into being responsible for trying to reclaim the memory.  (Start a
> timer, or reclaim in the idle loop, whatever.)
>
> This way, you can `xl destroy` a VM in an arbitrary state, *and* the
> invocation will terminate when Xen has nothing deterministic left to do,
> *and* in the case that the secure world or Xen has an issue, the VM will
> stay around as a zombie holding minimal resources.

Thanks for the pointers, very helpful, and now I at least know where
to start looking.

Cheers,
Jens

>
> ~Andrew



Re: [RFC XEN PATCH] xen/arm: ffa: reclaim shared memory on guest destroy

2023-12-05 Thread Jens Wiklander
Hi,

On Tue, Dec 5, 2023 at 9:14 AM Bertrand Marquis
 wrote:
>
> Hi Julien,
>
> Thanks a lot for your review and comment, this is very helpful.
>
> > On 4 Dec 2023, at 20:24, Julien Grall  wrote:
> >
> > Hi Jens,
> >
> > On 04/12/2023 07:55, Jens Wiklander wrote:
> >> When an FF-A enabled guest is destroyed it may leave behind memory
> >> shared with SPs. This memory must be reclaimed before it's reused or an
> >> SP may make changes to memory used by a new unrelated guest. So when the
> >> domain is teared down add FF-A requests to reclaim all remaining shared
> >> memory.
> >> SPs in the secure world are notified using VM_DESTROYED that a guest has
> >> been destroyed. An SP is supposed to relinquish all shared memory to allow
> >> reclaiming the memory. The relinquish operation may need to be delayed if
> >> the shared memory is for instance part of a DMA operation.
> >> If the FF-A memory reclaim request fails, return -ERESTART to retry
> >> again. This will effectively block the destruction of the guest until
> >> all memory has been reclaimed.
> >> Signed-off-by: Jens Wiklander 
> >> ---
> >> Hi,
> >> This patch is a bit crude, but gets the job done. In a well designed
> >> system this might even be good enough since the SP or the secure world
> >> will let the memory be reclaimed and we can move on. But, if for some
> >> reason reclaiming the memory is refused it must not be possible to reuse
> >> the memory.
> >
> > IIUC, we are trying to harden against a buggy SP. Is that correct?
>
> This is not hardening as this is a possible scenario with a correctly 
> implemented SP.
> This is valid for the SP to not be able to relinquish the memory directly so 
> we have
> to take this possibility into account and retry.
>
> What is not expected if for the SP to never release the memory hence the 
> possible
> "todo" at the end of the code where i think we might have to implement a 
> counter
> to bound the possible number of loops but as always the question is how 
> many...
>
> In this case the only solution would be to park the memory as suggested after
> but we are not completely sure where hence the RFC.
>
> >
> >> These shared memory ranges are typically quite small compared to the
> >> total memory usage of a guest so it would be an improvement if only
> >> refused shared memory ranges where set aside from future reuse while the
> >> guest was destroyed and other resources made available for reuse. This
> >> could be done by for instance assign the refused shared memory ranges
> >> to a dummy VM like DOMID_IO.
> >
> > I like the idea to use a dummy VM, but I don't think DOMID_IO is right. 
> > Once teardown has completed, the domain will stay around until the last 
> > reference on all pages are dropped. At this point, the amount of memory 
> > left-over is minimum (this is mostly bookeeping in Xen).
> >
> > From the userland PoV, the domain will still show-up in the list but tools 
> > like "xl list" will show "(null)". They are called zombie domains.
> >
> > So I would consider to keep the same domain around. The advantage is you 
> > can call "xl destroy" again to retry the operation.
>
> In this scenario the "restart" implementation here is right but how could we 
> park the VM as "zombie" instead of busy looping in
> the "kill" loop of userland ?
>
> Also we need to release all the memory of the VM but the one shared with the 
> SP.
>
> I will let Jens answer the more implementation questions here after and try 
> to help on the more "system" ones.
>
> >
> >> Thanks,
> >> Jens
> >> ---
> >>  xen/arch/arm/tee/ffa.c | 36 
> >>  1 file changed, 36 insertions(+)
> >> diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
> >> index 183528d13388..9c596462a8a2 100644
> >> --- a/xen/arch/arm/tee/ffa.c
> >> +++ b/xen/arch/arm/tee/ffa.c
> >> @@ -1539,6 +1539,7 @@ static bool is_in_subscr_list(const uint16_t 
> >> *subscr, uint16_t start,
> >>  static int ffa_domain_teardown(struct domain *d)
> >>  {
> >>  struct ffa_ctx *ctx = d->arch.tee;
> >> +struct ffa_shm_mem *shm, *tmp;
> >>  unsigned int n;
> >>  int32_t res;
> >>  @@ -1564,10 +1565,45 @@ static int ffa_domain_teardown(struct domain *d)
> >>  printk(XENLOG_ERR &quo

Re: [RFC XEN PATCH] xen/arm: ffa: reclaim shared memory on guest destroy

2023-12-05 Thread Jens Wiklander
Hi Julien,

Thanks for the feedback. I'm answering the straightforward issues here
and saving the rest for the emerging thread.

On Mon, Dec 4, 2023 at 8:24 PM Julien Grall  wrote:
>
> Hi Jens,
>
> On 04/12/2023 07:55, Jens Wiklander wrote:
> > When an FF-A enabled guest is destroyed it may leave behind memory
> > shared with SPs. This memory must be reclaimed before it's reused or an
> > SP may make changes to memory used by a new unrelated guest. So when the
> > domain is teared down add FF-A requests to reclaim all remaining shared
> > memory.
> >
> > SPs in the secure world are notified using VM_DESTROYED that a guest has
> > been destroyed. An SP is supposed to relinquish all shared memory to allow
> > reclaiming the memory. The relinquish operation may need to be delayed if
> > the shared memory is for instance part of a DMA operation.
> >
> > If the FF-A memory reclaim request fails, return -ERESTART to retry
> > again. This will effectively block the destruction of the guest until
> > all memory has been reclaimed.
> >
> > Signed-off-by: Jens Wiklander 
> > ---
> > Hi,
> >
> > This patch is a bit crude, but gets the job done. In a well designed
> > system this might even be good enough since the SP or the secure world
> > will let the memory be reclaimed and we can move on. But, if for some
> > reason reclaiming the memory is refused it must not be possible to reuse
> > the memory.
>
> IIUC, we are trying to harden against a buggy SP. Is that correct?
>
> >
> > These shared memory ranges are typically quite small compared to the
> > total memory usage of a guest so it would be an improvement if only
> > refused shared memory ranges where set aside from future reuse while the
> > guest was destroyed and other resources made available for reuse. This
> > could be done by for instance assign the refused shared memory ranges
> > to a dummy VM like DOMID_IO.
>
> I like the idea to use a dummy VM, but I don't think DOMID_IO is right.
> Once teardown has completed, the domain will stay around until the last
> reference on all pages are dropped. At this point, the amount of memory
> left-over is minimum (this is mostly bookeeping in Xen).
>
>  From the userland PoV, the domain will still show-up in the list but
> tools like "xl list" will show "(null)". They are called zombie domains.
>
> So I would consider to keep the same domain around. The advantage is you
> can call "xl destroy" again to retry the operation.
>
> >
> > Thanks,
> > Jens
> > ---
> >   xen/arch/arm/tee/ffa.c | 36 
> >   1 file changed, 36 insertions(+)
> >
> > diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
> > index 183528d13388..9c596462a8a2 100644
> > --- a/xen/arch/arm/tee/ffa.c
> > +++ b/xen/arch/arm/tee/ffa.c
> > @@ -1539,6 +1539,7 @@ static bool is_in_subscr_list(const uint16_t *subscr, 
> > uint16_t start,
> >   static int ffa_domain_teardown(struct domain *d)
> >   {
> >   struct ffa_ctx *ctx = d->arch.tee;
> > +struct ffa_shm_mem *shm, *tmp;
> >   unsigned int n;
> >   int32_t res;
> >
> > @@ -1564,10 +1565,45 @@ static int ffa_domain_teardown(struct domain *d)
> >   printk(XENLOG_ERR "ffa: Failed to report destruction of vm_id 
> > %u to  %u: res %d\n",
> >  get_vm_id(d), subscr_vm_destroyed[n], res);
> >   }
> > +/*
> > + * If this function is called again due to -ERESTART below, make sure
> > + * not to send the FFA_MSG_SEND_VM_DESTROYED's.
> > + */
> > +subscr_vm_destroyed_count = 0;
>
> AFAICT, this variable is global. So wouldn't you effectively break other
> domain if let say the unmapping error is temporary?

You're right! I'll have to change this part a bit.

>
> >
> >   if ( ctx->rx )
> >   rxtx_unmap(ctx);
> >
> > +
> > +list_for_each_entry_safe(shm, tmp, >shm_list, list)
> > +{
> > +register_t handle_hi;
> > +register_t handle_lo;
> > +
> > +uint64_to_regpair(_hi, _lo, shm->handle);
> > +res = ffa_mem_reclaim(handle_lo, handle_hi, 0);
>
> Is this call expensive? If so, we may need to handle continuation here.
>
> > +if ( res )
> > +{
> > +printk(XENLOG_INFO, "ffa: Failed to reclaim handle %#lx : 
> > %d\n",
> > +   shm->handle, res);
>
> I think you want to use XENLOG_G_INFO to use the guest

[RFC XEN PATCH] xen/arm: ffa: reclaim shared memory on guest destroy

2023-12-03 Thread Jens Wiklander
When an FF-A enabled guest is destroyed it may leave behind memory
shared with SPs. This memory must be reclaimed before it's reused or an
SP may make changes to memory used by a new unrelated guest. So when the
domain is teared down add FF-A requests to reclaim all remaining shared
memory.

SPs in the secure world are notified using VM_DESTROYED that a guest has
been destroyed. An SP is supposed to relinquish all shared memory to allow
reclaiming the memory. The relinquish operation may need to be delayed if
the shared memory is for instance part of a DMA operation.

If the FF-A memory reclaim request fails, return -ERESTART to retry
again. This will effectively block the destruction of the guest until
all memory has been reclaimed.

Signed-off-by: Jens Wiklander 
---
Hi,

This patch is a bit crude, but gets the job done. In a well designed
system this might even be good enough since the SP or the secure world
will let the memory be reclaimed and we can move on. But, if for some
reason reclaiming the memory is refused it must not be possible to reuse
the memory.

These shared memory ranges are typically quite small compared to the
total memory usage of a guest so it would be an improvement if only
refused shared memory ranges where set aside from future reuse while the
guest was destroyed and other resources made available for reuse. This
could be done by for instance assign the refused shared memory ranges
to a dummy VM like DOMID_IO.

Thanks,
Jens
---
 xen/arch/arm/tee/ffa.c | 36 
 1 file changed, 36 insertions(+)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 183528d13388..9c596462a8a2 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -1539,6 +1539,7 @@ static bool is_in_subscr_list(const uint16_t *subscr, 
uint16_t start,
 static int ffa_domain_teardown(struct domain *d)
 {
 struct ffa_ctx *ctx = d->arch.tee;
+struct ffa_shm_mem *shm, *tmp;
 unsigned int n;
 int32_t res;
 
@@ -1564,10 +1565,45 @@ static int ffa_domain_teardown(struct domain *d)
 printk(XENLOG_ERR "ffa: Failed to report destruction of vm_id %u 
to  %u: res %d\n",
get_vm_id(d), subscr_vm_destroyed[n], res);
 }
+/*
+ * If this function is called again due to -ERESTART below, make sure
+ * not to send the FFA_MSG_SEND_VM_DESTROYED's.
+ */
+subscr_vm_destroyed_count = 0;
 
 if ( ctx->rx )
 rxtx_unmap(ctx);
 
+
+list_for_each_entry_safe(shm, tmp, >shm_list, list)
+{
+register_t handle_hi;
+register_t handle_lo;
+
+uint64_to_regpair(_hi, _lo, shm->handle);
+res = ffa_mem_reclaim(handle_lo, handle_hi, 0);
+if ( res )
+{
+printk(XENLOG_INFO, "ffa: Failed to reclaim handle %#lx : %d\n",
+   shm->handle, res);
+}
+else
+{
+printk(XENLOG_DEBUG, "ffa: Reclaimed handle %#lx\n", shm->handle);
+ctx->shm_count--;
+list_del(>list);
+}
+}
+if ( !list_empty(>shm_list) )
+{
+printk(XENLOG_INFO, "ffa: Remaining unclaimed handles, retrying\n");
+/*
+ * TODO: add a timeout where we either panic or let the guest be
+ * fully destroyed.
+ */
+return -ERESTART;
+}
+
 XFREE(d->arch.tee);
 
 return 0;
-- 
2.34.1




[PATCH] xen/arm: ffa: fix guest map RX/TX error code

2023-09-04 Thread Jens Wiklander
FFA_RXTX_MAP is currently limited to mapping only one 4k page for each
RX and TX buffer. If a guest tries to map more than one page, an error
is returned. Until this patch, we have been using FFA_RET_NOT_SUPPORTED.
However, that error code is reserved in the FF-A specification to report
that the function is not implemented. Of all the other defined error
codes, the least bad is FFA_RET_INVALID_PARAMETERS, so use that instead.

Fixes: 38d81e7ccb11 ("xen/arm: ffa: support mapping guest RX/TX buffers")
Signed-off-by: Jens Wiklander 
---
 xen/arch/arm/tee/ffa.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 802b2dbb1d36..183528d13388 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -706,7 +706,7 @@ static uint32_t handle_rxtx_map(uint32_t fid, register_t 
tx_addr,
 {
 printk(XENLOG_ERR "ffa: RXTX_MAP: error: %u pages requested (limit 
%u)\n",
page_count, FFA_MAX_RXTX_PAGE_COUNT);
-return FFA_RET_NOT_SUPPORTED;
+return FFA_RET_INVALID_PARAMETERS;
 }
 
 /* Already mapped */
-- 
2.34.1




Re: [XEN PATCH v11 00/14] Xen FF-A mediator

2023-08-21 Thread Jens Wiklander
Hi Julien,

On Fri, Aug 18, 2023 at 10:32 AM Julien Grall  wrote:
>
> Hi Jens,
>
> On 31/07/2023 13:15, Jens Wiklander wrote:
> > Jens Wiklander (14):
> >xen/arm: ffa: add direct request support
> >xen/arm: ffa: map SPMC rx/tx buffers
> >xen/arm: ffa: send guest events to Secure Partitions
> >xen/arm: ffa: support mapping guest RX/TX buffers
> >xen/arm: ffa: support guest FFA_PARTITION_INFO_GET
> >xen/arm: move regpair_to_uint64() and uint64_to_regpair() to regs.h
> >xen/arm: ffa: add defines for sharing memory
> >xen/arm: ffa: add ABI structs for sharing memory
> >xen/arm: ffa: support sharing memory
> >xen/arm: ffa: add support to reclaim shared memory
> >xen/arm: ffa: improve lock granularity
> >xen/arm: ffa: list current limitations
> >tools: add Arm FF-A mediator
> >docs: add Arm FF-A mediator
>
> The series is now committed. Note, I had to resolve a context conflict
> in the CHANGELOG.md.

Thanks for the update, and a big thank you to all of you who have
helped me to get this into a committable state.

Cheers,
Jens

>
> Cheers,
>
> --
> Julien Grall



[XEN PATCH v11 13/14] tools: add Arm FF-A mediator

2023-07-31 Thread Jens Wiklander
Adds a new "ffa" value to the Enumeration "tee_type" to indicate if a
guest is trusted to use FF-A.

Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
Reviewed-by: Henry Wang 
---
v10->v11
- No changes
---
 tools/include/libxl.h| 5 +
 tools/libs/light/libxl_arm.c | 3 +++
 tools/libs/light/libxl_types.idl | 3 ++-
 3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/tools/include/libxl.h b/tools/include/libxl.h
index f3975ecc021f..bcf290de2446 100644
--- a/tools/include/libxl.h
+++ b/tools/include/libxl.h
@@ -283,6 +283,11 @@
  */
 #define LIBXL_HAVE_BUILDINFO_ARCH_ARM_TEE 1
 
+/*
+ * arch_arm.tee field in libxl_domain_build_info has ffa value.
+ */
+#define LIBXL_HAVE_BUILDINFO_ARCH_ARM_TEE_FFA 1
+
 /*
  * libxl_domain_build_info has the arch_arm.sve_vl field.
  */
diff --git a/tools/libs/light/libxl_arm.c b/tools/libs/light/libxl_arm.c
index f98e1affa294..15391917748c 100644
--- a/tools/libs/light/libxl_arm.c
+++ b/tools/libs/light/libxl_arm.c
@@ -207,6 +207,9 @@ int libxl__arch_domain_prepare_config(libxl__gc *gc,
 case LIBXL_TEE_TYPE_OPTEE:
 config->arch.tee_type = XEN_DOMCTL_CONFIG_TEE_OPTEE;
 break;
+case LIBXL_TEE_TYPE_FFA:
+config->arch.tee_type = XEN_DOMCTL_CONFIG_TEE_FFA;
+break;
 default:
 LOG(ERROR, "Unknown TEE type %d",
 d_config->b_info.tee);
diff --git a/tools/libs/light/libxl_types.idl b/tools/libs/light/libxl_types.idl
index b524d1578bd1..3bd66291afd4 100644
--- a/tools/libs/light/libxl_types.idl
+++ b/tools/libs/light/libxl_types.idl
@@ -520,7 +520,8 @@ libxl_gic_version = Enumeration("gic_version", [
 
 libxl_tee_type = Enumeration("tee_type", [
 (0, "none"),
-(1, "optee")
+(1, "optee"),
+(2, "ffa"),
 ], init_val = "LIBXL_TEE_TYPE_NONE")
 
 libxl_sve_type = Enumeration("sve_type", [
-- 
2.34.1




[XEN PATCH v11 14/14] docs: add Arm FF-A mediator

2023-07-31 Thread Jens Wiklander
Describes a FF-A version 1.1 [1] mediator to communicate with a Secure
Partition in secure world.

[1] https://developer.arm.com/documentation/den0077/latest
Signed-off-by: Jens Wiklander 
Reviewed-by: Henry Wang 
---
v10->v11
- Add a CHANGELOG.md entry as requested
---
 CHANGELOG.md |  3 ++-
 SUPPORT.md   |  9 +
 docs/man/xl.cfg.5.pod.in | 15 +++
 3 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7d7e0590f8c6..f24c8c4b8011 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -24,7 +24,8 @@ The format is based on [Keep a 
Changelog](https://keepachangelog.com/en/1.0.0/)
  - xl/libxl can customize SMBIOS strings for HVM guests.
  - Add support for AVX512-FP16 on x86.
  - On Arm, Xen supports guests running SVE/SVE2 instructions. (Tech Preview)
-
+ - On Arm, add suport for Firmware Framework for Arm A-profile (FF-A) Mediator
+   (Tech Preview)
 
 ## 
[4.17.0](https://xenbits.xen.org/gitweb/?p=xen.git;a=shortlog;h=RELEASE-4.17.0) 
- 2022-12-12
 
diff --git a/SUPPORT.md b/SUPPORT.md
index 35a6249e03b2..fe512762cee7 100644
--- a/SUPPORT.md
+++ b/SUPPORT.md
@@ -840,6 +840,15 @@ that covers the DMA of the device to be passed through.
 
 No support for QEMU backends in a 16K or 64K domain.
 
+### ARM: Firmware Framework for Arm A-profile (FF-A) Mediator
+
+Status, Arm64: Tech Preview
+
+There are still some code paths where a vCPU may hog a pCPU longer than
+necessary. The FF-A mediator is not yet implemented for Arm32. Part of the
+FF-A specification is not supported, see the top comment in
+xen/arch/arm/tee/ffa.c for limitations.
+
 ### ARM: Guest Device Tree support
 
 Status: Supported
diff --git a/docs/man/xl.cfg.5.pod.in b/docs/man/xl.cfg.5.pod.in
index a2bccd5b48a1..ec4864958e0e 100644
--- a/docs/man/xl.cfg.5.pod.in
+++ b/docs/man/xl.cfg.5.pod.in
@@ -1656,6 +1656,21 @@ in OP-TEE.
 
 This feature is a B.
 
+=item B
+
+B Allow a guest to communicate via FF-A with Secure Partitions
+(SP), default false.
+
+Currently only a small subset of the FF-A specification is supported. Just
+enough to communicate with OP-TEE. In general only direct messaging and
+sharing memory with one SP. More advanced use cases where memory might be
+shared or donated to multiple SPs are not supported.
+
+See L<https://developer.arm.com/documentation/den0077/latest> for more
+information about FF-A.
+
+This feature is a B.
+
 =back
 
 =back
-- 
2.34.1




[XEN PATCH v11 10/14] xen/arm: ffa: add support to reclaim shared memory

2023-07-31 Thread Jens Wiklander
Adds support to reclaim memory previously shared with FFA_MEM_SHARE.

A memory region that doesn't need to be shared any longer can be
reclaimed with FFA_MEM_RECLAIM once the SP doesn't use it any longer.
This is checked by the SPMC and not in control of the mediator.

Adds a check that the SP supports the needed FF-A feature
FFA_MEM_RECLAIM.

Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
---
v10->v11
- No changes
---
 xen/arch/arm/tee/ffa.c | 53 ++
 1 file changed, 53 insertions(+)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 74e3ef50091e..75700938c444 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -538,6 +538,12 @@ static int32_t ffa_mem_share(uint32_t tot_len, uint32_t 
frag_len,
 }
 }
 
+static int32_t ffa_mem_reclaim(uint32_t handle_lo, uint32_t handle_hi,
+   uint32_t flags)
+{
+return ffa_simple_call(FFA_MEM_RECLAIM, handle_lo, handle_hi, flags, 0);
+}
+
 static int32_t ffa_direct_req_send_vm(uint16_t sp_id, uint16_t vm_id,
   uint8_t msg)
 {
@@ -1283,6 +1289,43 @@ out_set_ret:
 set_regs_error(regs, ret);
 }
 
+static int handle_mem_reclaim(uint64_t handle, uint32_t flags)
+{
+struct domain *d = current->domain;
+struct ffa_ctx *ctx = d->arch.tee;
+struct ffa_shm_mem *shm;
+register_t handle_hi;
+register_t handle_lo;
+int ret;
+
+spin_lock(>lock);
+list_for_each_entry(shm, >shm_list, list)
+{
+if ( shm->handle == handle )
+goto found_it;
+}
+shm = NULL;
+ret = FFA_RET_INVALID_PARAMETERS;
+goto out;
+found_it:
+
+uint64_to_regpair(_hi, _lo, handle);
+ret = ffa_mem_reclaim(handle_lo, handle_hi, flags);
+if ( ret )
+{
+shm = NULL;
+goto out;
+}
+
+list_del(>list);
+
+out:
+free_ffa_shm_mem(ctx, shm);
+spin_unlock(>lock);
+
+return ret;
+}
+
 static bool ffa_handle_call(struct cpu_user_regs *regs)
 {
 uint32_t fid = get_user_reg(regs, 0);
@@ -1344,6 +1387,15 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 case FFA_MEM_SHARE_64:
 handle_mem_share(regs);
 return true;
+case FFA_MEM_RECLAIM:
+e = handle_mem_reclaim(regpair_to_uint64(get_user_reg(regs, 2),
+ get_user_reg(regs, 1)),
+   get_user_reg(regs, 3));
+if ( e )
+set_regs_error(regs, e);
+else
+set_regs_success(regs, 0, 0);
+return true;
 
 default:
 gprintk(XENLOG_ERR, "ffa: unhandled fid 0x%x\n", fid);
@@ -1581,6 +1633,7 @@ static bool ffa_probe(void)
  !check_mandatory_feature(FFA_MEM_SHARE_64) ||
  !check_mandatory_feature(FFA_RXTX_UNMAP) ||
  !check_mandatory_feature(FFA_MEM_SHARE_32) ||
+ !check_mandatory_feature(FFA_MEM_RECLAIM) ||
  !check_mandatory_feature(FFA_MSG_SEND_DIRECT_REQ_32) )
 return false;
 
-- 
2.34.1




[XEN PATCH v11 12/14] xen/arm: ffa: list current limitations

2023-07-31 Thread Jens Wiklander
Adds comments with a list of unsupported FF-A interfaces and limitations
in the implemented FF-A interfaces.

Signed-off-by: Jens Wiklander 
Reviewed-by: Henry Wang 
---
v10->v11
- No changes
---
 xen/arch/arm/tee/ffa.c | 31 +++
 1 file changed, 31 insertions(+)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index eb4a58fec470..cfbabec81dd2 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -13,6 +13,37 @@
  *https://developer.arm.com/documentation/den0077/e
  * TEEC-1.0C: TEE Client API Specification version 1.0c available at
  *
https://globalplatform.org/specs-library/tee-client-api-specification/
+ *
+ * Notes on the the current implementation.
+ *
+ * Unsupported FF-A interfaces:
+ * o FFA_MSG_POLL and FFA_MSG_SEND - deprecated in FF-A-1.1-REL0
+ * o FFA_MEM_RETRIEVE_* - Used when sharing memory from an SP to a VM
+ * o FFA_MEM_DONATE_* and FFA_MEM_LEND_* - Used when tranferring ownership
+ *   or access of a memory region
+ * o FFA_MSG_SEND2 and FFA_MSG_WAIT - Used for indirect messaging
+ * o FFA_MSG_YIELD
+ * o FFA_INTERRUPT - Used to report preemption
+ * o FFA_RUN
+ *
+ * Limitations in the implemented FF-A interfaces:
+ * o FFA_RXTX_MAP_*:
+ *   - Maps only one 4k page as RX and TX buffers
+ *   - Doesn't support forwarding this call on behalf of an endpoint
+ * o FFA_MEM_SHARE_*: only supports sharing
+ *   - from a VM to an SP
+ *   - with one borrower
+ *   - with the memory transaction descriptor in the RX/TX buffer
+ *   - normal memory
+ *   - at most 512 kB large memory regions
+ *   - at most 32 shared memory regions per guest
+ * o FFA_MSG_SEND_DIRECT_REQ:
+ *   - only supported from a VM to an SP
+ *
+ * There are some large locked sections with ffa_tx_buffer_lock and
+ * ffa_rx_buffer_lock. Especially the ffa_tx_buffer_lock spinlock used
+ * around share_shm() is a very large locked section which can let one VM
+ * affect another VM.
  */
 
 #include 
-- 
2.34.1




[XEN PATCH v11 11/14] xen/arm: ffa: improve lock granularity

2023-07-31 Thread Jens Wiklander
The single lock in struct ffa_ctx is complemented with rx_lock and tx_lock.

The old lock is used for small critical sections, like increasing
shm_count or adding another shm to shm_list.

rx_lock and tx_lock are only acquired using spin_trylock() which for
well-behaving guests should always succeed. Guests using the RX and TX
buffers are expected to serialize accesses before doing the FF-A
request.

Signed-off-by: Jens Wiklander 
---
v10->v11
- No changes except resolving conflicts since "xen/arm: ffa: support
  sharing large memory ranges" was dropped.
---
 xen/arch/arm/tee/ffa.c | 107 +
 1 file changed, 77 insertions(+), 30 deletions(-)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 75700938c444..eb4a58fec470 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -363,6 +363,13 @@ struct ffa_ctx {
 struct list_head shm_list;
 /* Number of allocated shared memory object */
 unsigned int shm_count;
+/*
+ * tx_lock is used to serialize access to tx
+ * rx_lock is used to serialize access to rx
+ * lock is used for the rest in this struct
+ */
+spinlock_t tx_lock;
+spinlock_t rx_lock;
 spinlock_t lock;
 };
 
@@ -768,7 +775,9 @@ static int32_t handle_partition_info_get(uint32_t w1, 
uint32_t w2, uint32_t w3,
 if ( !ffa_rx )
 return FFA_RET_DENIED;
 
-spin_lock(>lock);
+if ( !spin_trylock(>rx_lock) )
+return FFA_RET_BUSY;
+
 if ( !ctx->page_count || !ctx->rx_is_free )
 goto out;
 spin_lock(_rx_buffer_lock);
@@ -819,7 +828,7 @@ out_rx_release:
 out_rx_buf_unlock:
 spin_unlock(_rx_buffer_lock);
 out:
-spin_unlock(>lock);
+spin_unlock(>rx_lock);
 
 return ret;
 }
@@ -830,13 +839,15 @@ static int32_t handle_rx_release(void)
 struct domain *d = current->domain;
 struct ffa_ctx *ctx = d->arch.tee;
 
-spin_lock(>lock);
+if ( !spin_trylock(>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(>lock);
+spin_unlock(>rx_lock);
 
 return ret;
 }
@@ -947,21 +958,43 @@ static void put_shm_pages(struct ffa_shm_mem *shm)
 }
 }
 
+static bool inc_ctx_shm_count(struct ffa_ctx *ctx)
+{
+bool ret = true;
+
+spin_lock(>lock);
+if (ctx->shm_count >= FFA_MAX_SHM_COUNT)
+ret = false;
+else
+ctx->shm_count++;
+spin_unlock(>lock);
+
+return ret;
+}
+
+static void dec_ctx_shm_count(struct ffa_ctx *ctx)
+{
+spin_lock(>lock);
+ASSERT(ctx->shm_count > 0);
+ctx->shm_count--;
+spin_unlock(>lock);
+}
+
 static struct ffa_shm_mem *alloc_ffa_shm_mem(struct ffa_ctx *ctx,
  unsigned int page_count)
 {
 struct ffa_shm_mem *shm;
 
-if ( page_count >= FFA_MAX_SHM_PAGE_COUNT ||
- ctx->shm_count >= FFA_MAX_SHM_COUNT )
+if ( page_count >= FFA_MAX_SHM_PAGE_COUNT )
+return NULL;
+if ( !inc_ctx_shm_count(ctx) )
 return NULL;
 
 shm = xzalloc_flex_struct(struct ffa_shm_mem, pages, page_count);
 if ( shm )
-{
-ctx->shm_count++;
 shm->page_count = page_count;
-}
+else
+dec_ctx_shm_count(ctx);
 
 return shm;
 }
@@ -971,8 +1004,7 @@ static void free_ffa_shm_mem(struct ffa_ctx *ctx, struct 
ffa_shm_mem *shm)
 if ( !shm )
 return;
 
-ASSERT(ctx->shm_count > 0);
-ctx->shm_count--;
+dec_ctx_shm_count(ctx);
 put_shm_pages(shm);
 xfree(shm);
 }
@@ -1180,7 +1212,11 @@ static void handle_mem_share(struct cpu_user_regs *regs)
 goto out_set_ret;
 }
 
-spin_lock(>lock);
+if ( !spin_trylock(>tx_lock) )
+{
+ret = FFA_RET_BUSY;
+goto out_set_ret;
+}
 
 if ( frag_len > ctx->page_count * FFA_PAGE_SIZE )
 goto out_unlock;
@@ -1272,7 +1308,9 @@ static void handle_mem_share(struct cpu_user_regs *regs)
 if ( ret )
 goto out;
 
+spin_lock(>lock);
 list_add_tail(>list, >shm_list);
+spin_unlock(>lock);
 
 uint64_to_regpair(_hi, _lo, shm->handle);
 
@@ -1280,7 +1318,7 @@ out:
 if ( ret )
 free_ffa_shm_mem(ctx, shm);
 out_unlock:
-spin_unlock(>lock);
+spin_unlock(>tx_lock);
 
 out_set_ret:
 if ( ret == 0)
@@ -1289,6 +1327,18 @@ out_set_ret:
 set_regs_error(regs, ret);
 }
 
+/* Must only be called with ctx->lock held */
+static struct ffa_shm_mem *find_shm_mem(struct ffa_ctx *ctx, uint64_t handle)
+{
+struct ffa_shm_mem *shm;
+
+list_for_each_entry(shm, >shm_list, list)
+if ( shm->handle == handle )
+return shm;
+
+return NULL;
+}
+
 static int handle_mem_reclaim(uint64_t handle, uint32_t flags)
 {
 struct domain *d = current->

[XEN PATCH v11 09/14] xen/arm: ffa: support sharing memory

2023-07-31 Thread Jens Wiklander
Adds support for a guest to share memory with an SP using FFA_MEM_SHARE.
Only memory regions small enough to be shared with a single call to
FFA_MEM_SHARE are supported.

With this commit we have a FF-A version 1.1 [1] mediator able to
communicate with a Secure Partition in secure world using shared memory.
The secure world must use FF-A version 1.1, but the guest is free to use
version 1.0 or version 1.1.

Adds a check that the SP supports the needed FF-A features
FFA_MEM_SHARE_64 or FFA_MEM_SHARE_32.

[1] https://developer.arm.com/documentation/den0077/latest
Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
---
v10->v11
- Adding Reviewed-by: Bertrand Marquis 
---
 xen/arch/arm/tee/ffa.c | 486 +
 1 file changed, 486 insertions(+)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 9927fdf78af5..74e3ef50091e 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -297,6 +297,38 @@ struct ffa_mem_transaction_1_1 {
 uint8_t reserved[12];
 };
 
+/* Calculate offset of struct ffa_mem_access from start of buffer */
+#define MEM_ACCESS_OFFSET(access_idx) \
+( sizeof(struct ffa_mem_transaction_1_1) + \
+  ( access_idx ) * sizeof(struct ffa_mem_access) )
+
+/* Calculate offset of struct ffa_mem_region from start of buffer */
+#define REGION_OFFSET(access_count, region_idx) \
+( MEM_ACCESS_OFFSET(access_count) + \
+  ( region_idx ) * sizeof(struct ffa_mem_region) )
+
+/* Calculate offset of struct ffa_address_range from start of buffer */
+#define ADDR_RANGE_OFFSET(access_count, region_count, range_idx) \
+( REGION_OFFSET(access_count, region_count) + \
+  ( range_idx ) * sizeof(struct ffa_address_range) )
+
+/*
+ * The parts needed from struct ffa_mem_transaction_1_0 or struct
+ * ffa_mem_transaction_1_1, used to provide an abstraction of difference in
+ * data structures between version 1.0 and 1.1. This is just an internal
+ * interface and can be changed without changing any ABI.
+ */
+struct ffa_mem_transaction_int {
+uint16_t sender_id;
+uint8_t mem_reg_attr;
+uint8_t flags;
+uint8_t mem_access_size;
+uint8_t mem_access_count;
+uint16_t mem_access_offs;
+uint64_t handle;
+uint64_t tag;
+};
+
 /* Endpoint RX/TX descriptor */
 struct ffa_endpoint_rxtx_descriptor_1_0 {
 uint16_t sender_id;
@@ -327,9 +359,22 @@ struct ffa_ctx {
  */
 uint16_t create_signal_count;
 bool rx_is_free;
+/* Used shared memory objects, struct ffa_shm_mem */
+struct list_head shm_list;
+/* Number of allocated shared memory object */
+unsigned int shm_count;
 spinlock_t lock;
 };
 
+struct ffa_shm_mem {
+struct list_head list;
+uint16_t sender_id;
+uint16_t ep_id; /* endpoint, the one lending */
+uint64_t handle;/* FFA_HANDLE_INVALID if not set yet */
+unsigned int page_count;
+struct page_info *pages[];
+};
+
 /* Negotiated FF-A version to use with the SPMC */
 static uint32_t __ro_after_init ffa_version;
 
@@ -351,6 +396,7 @@ static uint16_t subscr_vm_destroyed_count __read_mostly;
 static void *ffa_rx __read_mostly;
 static void *ffa_tx __read_mostly;
 static DEFINE_SPINLOCK(ffa_rx_buffer_lock);
+static DEFINE_SPINLOCK(ffa_tx_buffer_lock);
 
 static bool ffa_get_version(uint32_t *vers)
 {
@@ -457,6 +503,41 @@ static int32_t ffa_rx_release(void)
 return ffa_simple_call(FFA_RX_RELEASE, 0, 0, 0, 0);
 }
 
+static int32_t ffa_mem_share(uint32_t tot_len, uint32_t frag_len,
+ register_t addr, uint32_t pg_count,
+ uint64_t *handle)
+{
+struct arm_smccc_1_2_regs arg = {
+.a0 = FFA_MEM_SHARE_64,
+.a1 = tot_len,
+.a2 = frag_len,
+.a3 = addr,
+.a4 = pg_count,
+};
+struct arm_smccc_1_2_regs resp;
+
+arm_smccc_1_2_smc(, );
+
+switch ( resp.a0 )
+{
+case FFA_ERROR:
+if ( resp.a2 )
+return resp.a2;
+else
+return FFA_RET_NOT_SUPPORTED;
+case FFA_SUCCESS_32:
+*handle = regpair_to_uint64(resp.a3, resp.a2);
+return FFA_RET_OK;
+case FFA_MEM_FRAG_RX:
+*handle = regpair_to_uint64(resp.a2, resp.a1);
+if ( resp.a3 > INT32_MAX ) /* Impossible value */
+return FFA_RET_ABORTED;
+return resp.a3 & INT32_MAX;
+default:
+return FFA_RET_NOT_SUPPORTED;
+}
+}
+
 static int32_t ffa_direct_req_send_vm(uint16_t sp_id, uint16_t vm_id,
   uint8_t msg)
 {
@@ -805,6 +886,403 @@ out:
  resp.a4 & mask, resp.a5 & mask, resp.a6 & mask, resp.a7 & mask);
 }
 
+/*
+ * Gets all page and assigns them to the supplied shared memory object. If
+ * this function fails then the caller is still expected to call
+ * put_shm_pages() as a cleanup.
+ */
+static int get_shm_pages(struct domain *d, struct ffa_shm_mem *shm,
+ const struc

[XEN PATCH v11 06/14] xen/arm: move regpair_to_uint64() and uint64_to_regpair() to regs.h

2023-07-31 Thread Jens Wiklander
Moves the two helper functions regpair_to_uint64() and
uint64_to_regpair() from xen/arch/arm/tee/optee.c to the common arm
specific regs.h. This enables reuse of these functions in the FF-A
mediator in a subsequent patch.

Signed-off-by: Jens Wiklander 
Reviewed-by: Michal Orzel 
Reviewed-by: Bertrand Marquis 
Reviewed-by: Henry Wang 
---
v10->v11
- No changes
---
 xen/arch/arm/include/asm/regs.h | 12 
 xen/arch/arm/tee/optee.c| 11 ---
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/xen/arch/arm/include/asm/regs.h b/xen/arch/arm/include/asm/regs.h
index ef34b38aa171..8a0db9541507 100644
--- a/xen/arch/arm/include/asm/regs.h
+++ b/xen/arch/arm/include/asm/regs.h
@@ -60,6 +60,18 @@ static inline bool guest_mode(const struct cpu_user_regs *r)
 register_t get_user_reg(struct cpu_user_regs *regs, int reg);
 void set_user_reg(struct cpu_user_regs *regs, int reg, register_t value);
 
+static inline uint64_t regpair_to_uint64(register_t reg0, register_t reg1)
+{
+return ((uint64_t)reg0 << 32) | (uint32_t)reg1;
+}
+
+static inline void uint64_to_regpair(register_t *reg0, register_t *reg1,
+ uint64_t val)
+{
+*reg0 = val >> 32;
+*reg1 = (uint32_t)val;
+}
+
 #endif
 
 #endif /* __ARM_REGS_H__ */
diff --git a/xen/arch/arm/tee/optee.c b/xen/arch/arm/tee/optee.c
index c91bd7d5ac25..5151bd90ed02 100644
--- a/xen/arch/arm/tee/optee.c
+++ b/xen/arch/arm/tee/optee.c
@@ -273,17 +273,6 @@ static int optee_domain_teardown(struct domain *d)
 return 0;
 }
 
-static uint64_t regpair_to_uint64(register_t reg0, register_t reg1)
-{
-return ((uint64_t)reg0 << 32) | (uint32_t)reg1;
-}
-
-static void uint64_to_regpair(register_t *reg0, register_t *reg1, uint64_t val)
-{
-*reg0 = val >> 32;
-*reg1 = (uint32_t)val;
-}
-
 static struct page_info *get_domain_ram_page(gfn_t gfn)
 {
 struct page_info *page;
-- 
2.34.1




[XEN PATCH v11 08/14] xen/arm: ffa: add ABI structs for sharing memory

2023-07-31 Thread Jens Wiklander
Adds the ABI structs used by function FFA_MEM_SHARE and friends for
sharing memory.

Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
---
v10->v11
- No changes
---
 xen/arch/arm/tee/ffa.c | 69 ++
 1 file changed, 69 insertions(+)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index e0d1746f3bfd..9927fdf78af5 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -243,6 +243,75 @@ struct ffa_partition_info_1_1 {
 uint8_t uuid[16];
 };
 
+/* Constituent memory region descriptor */
+struct ffa_address_range {
+uint64_t address;
+uint32_t page_count;
+uint32_t reserved;
+};
+
+/* Composite memory region descriptor */
+struct ffa_mem_region {
+uint32_t total_page_count;
+uint32_t address_range_count;
+uint64_t reserved;
+struct ffa_address_range address_range_array[];
+};
+
+/* Memory access permissions descriptor */
+struct ffa_mem_access_perm {
+uint16_t endpoint_id;
+uint8_t perm;
+uint8_t flags;
+};
+
+/* Endpoint memory access descriptor */
+struct ffa_mem_access {
+struct ffa_mem_access_perm access_perm;
+uint32_t region_offs;
+uint64_t reserved;
+};
+
+/* Lend, donate or share memory transaction descriptor */
+struct ffa_mem_transaction_1_0 {
+uint16_t sender_id;
+uint8_t mem_reg_attr;
+uint8_t reserved0;
+uint32_t flags;
+uint64_t handle;
+uint64_t tag;
+uint32_t reserved1;
+uint32_t mem_access_count;
+struct ffa_mem_access mem_access_array[];
+};
+
+struct ffa_mem_transaction_1_1 {
+uint16_t sender_id;
+uint16_t mem_reg_attr;
+uint32_t flags;
+uint64_t handle;
+uint64_t tag;
+uint32_t mem_access_size;
+uint32_t mem_access_count;
+uint32_t mem_access_offs;
+uint8_t reserved[12];
+};
+
+/* 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;
+};
+
 struct ffa_ctx {
 void *rx;
 const void *tx;
-- 
2.34.1




[XEN PATCH v11 07/14] xen/arm: ffa: add defines for sharing memory

2023-07-31 Thread Jens Wiklander
According to DEN0077A version 1.1 REL0
- Section 10.9.2 Memory region handle, page 167
- Table 10.18 at page 175
- Table 10.15 at page 168
- Section 10.11.4 Flags usage, page 184-187
add defines needed for sharing using the function FFA_MEM_SHARE and
friends.

Also add limits for how many shared buffers that a guest can have at
once and how large a shared buffer can be at most.

Signed-off-by: Jens Wiklander 
Reviewed-by: Henry Wang 
Reviewed-by: Bertrand Marquis 
---
v10->v11
- Adding Reviewed-by: Bertrand Marquis 
---
 xen/arch/arm/tee/ffa.c | 58 ++
 1 file changed, 58 insertions(+)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 6c889bf97002..e0d1746f3bfd 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -5,6 +5,14 @@
  * Arm Firmware Framework for ARMv8-A (FF-A) mediator
  *
  * Copyright (C) 2023  Linaro Limited
+ *
+ * References:
+ * FF-A-1.0-REL: FF-A specification version 1.0 available at
+ *   https://developer.arm.com/documentation/den0077/a
+ * FF-A-1.1-REL0: FF-A specification version 1.1 available at
+ *https://developer.arm.com/documentation/den0077/e
+ * TEEC-1.0C: TEE Client API Specification version 1.0c available at
+ *
https://globalplatform.org/specs-library/tee-client-api-specification/
  */
 
 #include 
@@ -80,6 +88,56 @@
  */
 #define FFA_MAX_RXTX_PAGE_COUNT 1
 
+/*
+ * Limit for shared buffer size. Please note that this define limits
+ * number of pages.
+ *
+ * FF-A doesn't have any direct requirements on GlobalPlatform or vice
+ * versa, but an implementation can very well use FF-A in order to provide
+ * a GlobalPlatform interface on top.
+ *
+ * Global Platform specification for TEE requires that any TEE
+ * implementation should allow to share buffers with size of at least
+ * 512KB, defined in TEEC-1.0C page 24, Table 4-1,
+ * TEEC_CONFIG_SHAREDMEM_MAX_SIZE.
+ * Due to overhead which can be hard to predict exactly, double this number
+ * to give a safe margin.
+ */
+#define FFA_MAX_SHM_PAGE_COUNT  (2 * SZ_512K / FFA_PAGE_SIZE)
+
+/*
+ * Limits the number of shared buffers that guest can have at once. This
+ * is to prevent case, when guests trick XEN into exhausting its own
+ * memory by allocating many small buffers. This value has been chosen
+ * arbitrarily.
+ */
+#define FFA_MAX_SHM_COUNT   32
+
+/* FF-A-1.1-REL0 section 10.9.2 Memory region handle, page 167 */
+#define FFA_HANDLE_HYP_FLAG BIT(63, ULL)
+#define FFA_HANDLE_INVALID  0xULL
+
+/*
+ * Memory attributes: Normal memory, Write-Back cacheable, Inner shareable
+ * Defined in FF-A-1.1-REL0 Table 10.18 at page 175.
+ */
+#define FFA_NORMAL_MEM_REG_ATTR 0x2fU
+/*
+ * Memory access permissions: Read-write
+ * Defined in FF-A-1.1-REL0 Table 10.15 at page 168.
+ */
+#define FFA_MEM_ACC_RW  0x2U
+
+/* FF-A-1.1-REL0 section 10.11.4 Flags usage, page 184-187 */
+/* Clear memory before mapping in receiver */
+#define FFA_MEMORY_REGION_FLAG_CLEARBIT(0, U)
+/* Relayer may time slice this operation */
+#define FFA_MEMORY_REGION_FLAG_TIME_SLICE   BIT(1, U)
+/* Clear memory after receiver relinquishes it */
+#define FFA_MEMORY_REGION_FLAG_CLEAR_RELINQUISH BIT(2, U)
+/* Share memory transaction */
+#define FFA_MEMORY_REGION_TRANSACTION_TYPE_SHARE (1U << 3)
+
 /*
  * Flags and field values used for the MSG_SEND_DIRECT_REQ/RESP:
  * BIT(31): Framework or partition message
-- 
2.34.1




[XEN PATCH v11 02/14] xen/arm: ffa: map SPMC rx/tx buffers

2023-07-31 Thread Jens Wiklander
When initializing the FF-A mediator map the RX and TX buffers shared with
the SPMC.

These buffer are later used to to transmit data that cannot be passed in
registers only.

Adds a check that the SP supports the needed FF-A features
FFA_RXTX_MAP_64 and FFA_RXTX_UNMAP.

Signed-off-by: Jens Wiklander 
Reviewed-by: Bertrand Marquis 
---
v10->v11
- Adding Reviewed-by: Bertrand Marquis 
---
 xen/arch/arm/tee/ffa.c | 50 +-
 1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 961a8c052f59..072198a1326d 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -67,6 +68,12 @@
  */
 #define FFA_PAGE_SIZE   SZ_4K
 
+/*
+ * The number of pages used for each of the RX and TX buffers shared with
+ * the SPMC.
+ */
+#define FFA_RXTX_PAGE_COUNT 1
+
 /*
  * Flags and field values used for the MSG_SEND_DIRECT_REQ/RESP:
  * BIT(31): Framework or partition message
@@ -161,6 +168,13 @@ struct ffa_ctx {
 /* Negotiated FF-A version to use with the SPMC */
 static uint32_t __ro_after_init ffa_version;
 
+/*
+ * Our rx/tx buffers shared with the SPMC. FFA_RXTX_PAGE_COUNT is the
+ * number of pages used in each of these buffers.
+ */
+static void *ffa_rx __read_mostly;
+static void *ffa_tx __read_mostly;
+
 static bool ffa_get_version(uint32_t *vers)
 {
 const struct arm_smccc_1_2_regs arg = {
@@ -231,6 +245,12 @@ 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 uint16_t get_vm_id(const struct domain *d)
 {
 /* +1 since 0 is reserved for the hypervisor in FF-A */
@@ -394,6 +414,7 @@ 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;
 
@@ -441,12 +462,39 @@ static bool ffa_probe(void)
  * TODO: Rework the code to allow domain to use a subset of the
  * features supported.
  */
-if ( !check_mandatory_feature(FFA_MSG_SEND_DIRECT_REQ_32) )
+if (
+ !check_mandatory_feature(FFA_RXTX_MAP_64) ||
+ !check_mandatory_feature(FFA_RXTX_UNMAP) ||
+ !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 )
 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;
 
 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;
+ffa_version = 0;
+
+return false;
 }
 
 static const struct tee_mediator_ops ffa_ops =
-- 
2.34.1




[XEN PATCH v11 01/14] xen/arm: ffa: add direct request support

2023-07-31 Thread Jens Wiklander
Adds support for sending a FF-A direct request. Checks that the SP also
supports handling a 32-bit direct request. 64-bit direct requests are
not used by the mediator itself so there is not need to check for that.

Signed-off-by: Jens Wiklander 
Reviewed-by: Henry Wang 
---
v10->v11
- In handle_msg_send_direct_req(), replaced the "arg" with "resp" at the
  default: label in the switch statement.
---
 xen/arch/arm/tee/ffa.c | 113 +
 1 file changed, 113 insertions(+)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index e157ed20ad8b..961a8c052f59 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -181,6 +181,56 @@ static bool ffa_get_version(uint32_t *vers)
 return true;
 }
 
+static int32_t get_ffa_ret_code(const struct arm_smccc_1_2_regs *resp)
+{
+switch ( resp->a0 )
+{
+case FFA_ERROR:
+if ( resp->a2 )
+return resp->a2;
+else
+return FFA_RET_NOT_SUPPORTED;
+case FFA_SUCCESS_32:
+case FFA_SUCCESS_64:
+return FFA_RET_OK;
+default:
+return FFA_RET_NOT_SUPPORTED;
+}
+}
+
+static int32_t ffa_simple_call(uint32_t fid, register_t a1, register_t a2,
+   register_t a3, register_t a4)
+{
+const struct arm_smccc_1_2_regs arg = {
+.a0 = fid,
+.a1 = a1,
+.a2 = a2,
+.a3 = a3,
+.a4 = a4,
+};
+struct arm_smccc_1_2_regs resp;
+
+arm_smccc_1_2_smc(, );
+
+return get_ffa_ret_code();
+}
+
+static int32_t ffa_features(uint32_t id)
+{
+return ffa_simple_call(FFA_FEATURES, id, 0, 0, 0);
+}
+
+static bool check_mandatory_feature(uint32_t id)
+{
+int32_t ret = ffa_features(id);
+
+if ( ret )
+printk(XENLOG_ERR "ffa: mandatory feature id %#x missing: error %d\n",
+   id, ret);
+
+return !ret;
+}
+
 static uint16_t get_vm_id(const struct domain *d)
 {
 /* +1 since 0 is reserved for the hypervisor in FF-A */
@@ -222,6 +272,57 @@ static void handle_version(struct cpu_user_regs *regs)
 set_regs(regs, vers, 0, 0, 0, 0, 0, 0, 0);
 }
 
+static void handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t 
fid)
+{
+struct arm_smccc_1_2_regs arg = { .a0 = fid, };
+struct arm_smccc_1_2_regs resp = { };
+struct domain *d = current->domain;
+uint32_t src_dst;
+uint64_t mask;
+
+if ( smccc_is_conv_64(fid) )
+mask = GENMASK_ULL(63, 0);
+else
+mask = GENMASK_ULL(31, 0);
+
+src_dst = get_user_reg(regs, 1);
+if ( (src_dst >> 16) != get_vm_id(d) )
+{
+resp.a0 = FFA_ERROR;
+resp.a2 = FFA_RET_INVALID_PARAMETERS;
+goto out;
+}
+
+arg.a1 = src_dst;
+arg.a2 = get_user_reg(regs, 2) & mask;
+arg.a3 = get_user_reg(regs, 3) & mask;
+arg.a4 = get_user_reg(regs, 4) & mask;
+arg.a5 = get_user_reg(regs, 5) & mask;
+arg.a6 = get_user_reg(regs, 6) & mask;
+arg.a7 = get_user_reg(regs, 7) & mask;
+
+arm_smccc_1_2_smc(, );
+switch ( resp.a0 )
+{
+case FFA_ERROR:
+case FFA_SUCCESS_32:
+case FFA_SUCCESS_64:
+case FFA_MSG_SEND_DIRECT_RESP_32:
+case FFA_MSG_SEND_DIRECT_RESP_64:
+break;
+default:
+/* Bad fid, report back to the caller. */
+memset(, 0, sizeof(resp));
+resp.a0 = FFA_ERROR;
+resp.a1 = src_dst;
+resp.a2 = FFA_RET_ABORTED;
+}
+
+out:
+set_regs(regs, resp.a0, resp.a1 & mask, resp.a2 & mask, resp.a3 & mask,
+ resp.a4 & mask, resp.a5 & mask, resp.a6 & mask, resp.a7 & mask);
+}
+
 static bool ffa_handle_call(struct cpu_user_regs *regs)
 {
 uint32_t fid = get_user_reg(regs, 0);
@@ -239,6 +340,10 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 case FFA_ID_GET:
 set_regs_success(regs, get_vm_id(d), 0);
 return true;
+case FFA_MSG_SEND_DIRECT_REQ_32:
+case FFA_MSG_SEND_DIRECT_REQ_64:
+handle_msg_send_direct_req(regs, fid);
+return true;
 
 default:
 gprintk(XENLOG_ERR, "ffa: unhandled fid 0x%x\n", fid);
@@ -331,6 +436,14 @@ static bool ffa_probe(void)
 printk(XENLOG_INFO "ARM FF-A Firmware version %u.%u\n",
major_vers, minor_vers);
 
+/*
+ * At the moment domains must support the same features used by Xen.
+ * TODO: Rework the code to allow domain to use a subset of the
+ * features supported.
+ */
+if ( !check_mandatory_feature(FFA_MSG_SEND_DIRECT_REQ_32) )
+return false;
+
 ffa_version = vers;
 
 return true;
-- 
2.34.1




[XEN PATCH v11 05/14] xen/arm: ffa: support guest FFA_PARTITION_INFO_GET

2023-07-31 Thread Jens Wiklander
Adds support in the mediator to handle FFA_PARTITION_INFO_GET requests
from a guest. The requests are forwarded to the SPMC and the response is
translated according to the FF-A version in use by the guest.

Using FFA_PARTITION_INFO_GET changes the owner of the RX buffer to the
caller (the guest in this case), so once it is done with the buffer it
must be released using FFA_RX_RELEASE before another call can be made.

Signed-off-by: Jens Wiklander 
---
v10->v11
- Fixing a typo in a comment and adding another comment as requested
---
 xen/arch/arm/tee/ffa.c | 134 +
 1 file changed, 134 insertions(+)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 6c76c9885774..6c889bf97002 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -166,7 +166,18 @@
 #define FFA_MSG_SEND0x846EU
 #define FFA_MSG_POLL0x846AU
 
+/*
+ * 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.
+ */
+
 /* Partition information descriptor */
+struct ffa_partition_info_1_0 {
+uint16_t id;
+uint16_t execution_context;
+uint32_t partition_properties;
+};
+
 struct ffa_partition_info_1_1 {
 uint16_t id;
 uint16_t execution_context;
@@ -189,6 +200,7 @@ struct ffa_ctx {
  */
 uint16_t create_signal_count;
 bool rx_is_free;
+spinlock_t lock;
 };
 
 /* Negotiated FF-A version to use with the SPMC */
@@ -203,9 +215,15 @@ static uint16_t subscr_vm_destroyed_count __read_mostly;
 /*
  * Our rx/tx buffers shared with the SPMC. FFA_RXTX_PAGE_COUNT is the
  * number of pages used in each of these buffers.
+ *
+ * The RX buffer is protected from concurrent usage with ffa_rx_buffer_lock.
+ * Note that the SPMC is also tracking the ownership of our RX buffer so
+ * for calls which uses our RX buffer to deliver a result we must call
+ * ffa_rx_release() to let the SPMC know that we're done with the buffer.
  */
 static void *ffa_rx __read_mostly;
 static void *ffa_tx __read_mostly;
+static DEFINE_SPINLOCK(ffa_rx_buffer_lock);
 
 static bool ffa_get_version(uint32_t *vers)
 {
@@ -512,6 +530,103 @@ static uint32_t handle_rxtx_unmap(void)
 return FFA_RET_OK;
 }
 
+static int32_t handle_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3,
+ uint32_t w4, uint32_t w5,
+ uint32_t *count)
+{
+int32_t ret = FFA_RET_DENIED;
+struct domain *d = current->domain;
+struct ffa_ctx *ctx = d->arch.tee;
+
+/*
+ * FF-A v1.0 has w5 MBZ while v1.1 allows
+ * FFA_PARTITION_INFO_GET_COUNT_FLAG to be non-zero.
+ *
+ * FFA_PARTITION_INFO_GET_COUNT is only using registers and not the
+ * rxtx buffer so do the partition_info_get directly.
+ */
+if ( w5 == FFA_PARTITION_INFO_GET_COUNT_FLAG &&
+ ctx->guest_vers == FFA_VERSION_1_1 )
+return ffa_partition_info_get(w1, w2, w3, w4, w5, count);
+if ( w5 )
+return FFA_RET_INVALID_PARAMETERS;
+
+if ( !ffa_rx )
+return FFA_RET_DENIED;
+
+spin_lock(>lock);
+if ( !ctx->page_count || !ctx->rx_is_free )
+goto out;
+spin_lock(_rx_buffer_lock);
+ret = ffa_partition_info_get(w1, w2, w3, w4, w5, count);
+if ( ret )
+goto out_rx_buf_unlock;
+/*
+ * ffa_partition_info_get() succeeded so we now own the RX buffer we
+ * share with the SPMC. We must give it back using ffa_rx_release()
+ * once we've copied the content.
+ */
+
+if ( ctx->guest_vers == FFA_VERSION_1_0 )
+{
+size_t n;
+struct ffa_partition_info_1_1 *src = ffa_rx;
+struct ffa_partition_info_1_0 *dst = ctx->rx;
+
+if ( ctx->page_count * FFA_PAGE_SIZE < *count * sizeof(*dst) )
+{
+ret = FFA_RET_NO_MEMORY;
+goto out_rx_release;
+}
+
+for ( n = 0; n < *count; n++ )
+{
+dst[n].id = src[n].id;
+dst[n].execution_context = src[n].execution_context;
+dst[n].partition_properties = src[n].partition_properties;
+}
+}
+else
+{
+size_t sz = *count * sizeof(struct ffa_partition_info_1_1);
+
+if ( ctx->page_count * FFA_PAGE_SIZE < sz )
+{
+ret = FFA_RET_NO_MEMORY;
+goto out_rx_release;
+}
+
+
+memcpy(ctx->rx, ffa_rx, sz);
+}
+ctx->rx_is_free = false;
+out_rx_release:
+ffa_rx_release();
+out_rx_buf_unlock:
+spin_unlock(_rx_buffer_lock);
+out:
+spin_unlock(>lock);
+
+return ret;
+}
+
+static int32_t handle_rx_release(void)
+{
+int32_t ret = FFA_RET_DENIED;
+struct domain *d = current->domain;
+struct ffa_ctx *ctx = d->arch.tee;
+
+spin_lock(>lock);
+if ( !ctx->page_count || ctx->rx_is_free )
+goto out;
+ret = FFA_RET_OK;
+  

[XEN PATCH v11 03/14] xen/arm: ffa: send guest events to Secure Partitions

2023-07-31 Thread Jens Wiklander
The FF-A specification defines framework messages sent as direct
requests when certain events occurs. For instance when a VM (guest) is
created or destroyed. Only SPs which have subscribed to these events
will receive them. An SP can subscribe to these messages in its
partition properties.

Adds a check that the SP supports the needed FF-A features
FFA_PARTITION_INFO_GET and FFA_RX_RELEASE.

The partition properties of each SP is retrieved with
FFA_PARTITION_INFO_GET which returns the information in our RX buffer.
Using FFA_PARTITION_INFO_GET changes the owner of the RX buffer to the
caller (us), so once we're done with the buffer it must be released
using FFA_RX_RELEASE before another call can be made.

Signed-off-by: Jens Wiklander 
---
v10->v11:
- Addressing comments and fixing a few style issues
- Fixing how is_in_subscr_list() is used, it's supposed to take an
  sp_id, not a vm_id.
---
 xen/arch/arm/tee/ffa.c | 234 -
 1 file changed, 233 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 072198a1326d..5af3e5eedc88 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -160,14 +160,33 @@
 #define FFA_MSG_SEND0x846EU
 #define FFA_MSG_POLL0x846AU
 
+/* Partition information descriptor */
+struct ffa_partition_info_1_1 {
+uint16_t id;
+uint16_t execution_context;
+uint32_t partition_properties;
+uint8_t uuid[16];
+};
+
 struct ffa_ctx {
 /* FF-A version used by the guest */
 uint32_t guest_vers;
+/*
+ * Number of SPs that we have sent a VM created signal to, used in
+ * ffa_domain_teardown() to know which SPs need to be signalled.
+ */
+uint16_t create_signal_count;
 };
 
 /* Negotiated FF-A version to use with the SPMC */
 static uint32_t __ro_after_init ffa_version;
 
+/* SPs subscribing to VM_CREATE and VM_DESTROYED events */
+static uint16_t *subscr_vm_created __read_mostly;
+static uint16_t subscr_vm_created_count __read_mostly;
+static uint16_t *subscr_vm_destroyed __read_mostly;
+static uint16_t subscr_vm_destroyed_count __read_mostly;
+
 /*
  * Our rx/tx buffers shared with the SPMC. FFA_RXTX_PAGE_COUNT is the
  * number of pages used in each of these buffers.
@@ -251,6 +270,87 @@ static int32_t ffa_rxtx_map(paddr_t tx_addr, paddr_t 
rx_addr,
 return ffa_simple_call(FFA_RXTX_MAP_64, tx_addr, rx_addr, page_count, 0);
 }
 
+static int32_t ffa_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3,
+  uint32_t w4, uint32_t w5,
+  uint32_t *count)
+{
+const struct arm_smccc_1_2_regs arg = {
+.a0 = FFA_PARTITION_INFO_GET,
+.a1 = w1,
+.a2 = w2,
+.a3 = w3,
+.a4 = w4,
+.a5 = w5,
+};
+struct arm_smccc_1_2_regs resp;
+uint32_t ret;
+
+arm_smccc_1_2_smc(, );
+
+ret = get_ffa_ret_code();
+if ( !ret )
+*count = resp.a2;
+
+return ret;
+}
+
+static int32_t ffa_rx_release(void)
+{
+return ffa_simple_call(FFA_RX_RELEASE, 0, 0, 0, 0);
+}
+
+static int32_t ffa_direct_req_send_vm(uint16_t sp_id, uint16_t vm_id,
+  uint8_t msg)
+{
+uint32_t exp_resp = FFA_MSG_FLAG_FRAMEWORK;
+unsigned int retry_count = 0;
+int32_t res;
+
+if ( msg == FFA_MSG_SEND_VM_CREATED )
+exp_resp |= FFA_MSG_RESP_VM_CREATED;
+else if ( msg == FFA_MSG_SEND_VM_DESTROYED )
+exp_resp |= FFA_MSG_RESP_VM_DESTROYED;
+else
+return FFA_RET_INVALID_PARAMETERS;
+
+do {
+const struct arm_smccc_1_2_regs arg = {
+.a0 = FFA_MSG_SEND_DIRECT_REQ_32,
+.a1 = sp_id,
+.a2 = FFA_MSG_FLAG_FRAMEWORK | msg,
+.a5 = vm_id,
+};
+struct arm_smccc_1_2_regs resp;
+
+arm_smccc_1_2_smc(, );
+if ( resp.a0 != FFA_MSG_SEND_DIRECT_RESP_32 || resp.a2 != exp_resp )
+{
+/*
+ * This is an invalid response, likely due to some error in the
+ * implementation of the ABI.
+ */
+return FFA_RET_INVALID_PARAMETERS;
+}
+res = resp.a3;
+if ( ++retry_count > 10 )
+{
+/*
+ * TODO
+ * FFA_RET_INTERRUPTED means that the SPMC has a pending
+ * non-secure interrupt, we need a way of delivering that
+ * non-secure interrupt.
+ * FFA_RET_RETRY is the SP telling us that it's temporarily
+ * blocked from handling the direct request, we need a generic
+ * way to deal with this.
+ * For now in both cases, give up after a few retries.
+ */
+return res;
+}
+} while ( res == FFA_RET_INTERRUPTED || res == FFA_RET_RETRY );
+
+return res;
+}
+
 static uint16_t get_vm_id(const struct domain *d)
 {
 /* +1 since 0 is re

[XEN PATCH v11 00/14] Xen FF-A mediator

2023-07-31 Thread Jens Wiklander
ense in new files.
* Fixed comment style issues in
  "xen/arm: smccc: add support for SMCCCv1.2 extended input/output registers"
* Made FFA support UNSUPPORTED in "xen/arm: add a primitive FF-A mediator"
* Replaced ffa_get_call_count() with FFA_NR_FUNCS
* Update the FFA_MAX_SHM_PAGE_COUNT with a formula instead of a value.
* Replaced XEN_ARM_FLAGS_FFA with XEN_DOMCTL_CONFIG_TEE_FFA to minimize impact
  on struct xen_arch_domainconfig. This works because the FF-A mediator and
  the OP-TEE mediator will not be used at the same time in by a guest.
* Replaced "ffa" boolean in the guest config with a new "ffa" value to the
  enumeration "tee_type".
* Integrated the FF-A mediator in the TEE mediator framework instead of
  being its own.
* Rebased on staging as of 2023-02-16

v5->v6:
* Updated "xen/arm: move regpair_to_uint64() and uint64_to_regpair() to regs.h"
  commit message and moved the patch right before the patch which needs it.
  Applied Michal Orzel's R-B tag.
* Renamed the guest configuration option "ffa_enabled" to "ffa" and
  updated the description.
* More tools update in "xen/arm: add a primitive FF-A mediator" with the "ffa"
  option, including golang and ocaml.
* Update ffa_domain_init() to return an error if communication with
  the SPMC can't be established.
* Factored out a ffa_domain_destroy() from ffa_relinquish_resources().
* Added ffa_get_call_count() to give an accurate number of FF-A function,
  updated in each patch as new FF-A functions are added.
* Added a flags field in struct xen_arch_domainconfig that replaces the
  ffa_enabled field.
* Made check_mandatory_feature() __init
* Replaced a few printk() calls with gprintk() where needed.
* Rebased on staging as of 2022-09-14

V4->v5:
* Added "xen/arm: move regpair_to_uint64() and uint64_to_regpair() to regs.h"
* Added documentation for the "ffa_enabled" guest config flag
* Changed to GPL license for xen/arch/arm/ffa.c
* Added __read_mostly and const where applicable
* Added more describing comments in the code
* Moved list of shared memory object ("ffa_mem_list") into the guest context
  as they are guest specific
* Simplified a few of the simple wrapper functions for SMC to SPMC
* Added a BUILD_BUG_ON(PAGE_SIZE != FFA_PAGE_SIZE) since the mediator
  currently depends on the page size to be same as FFA_PAGE_SIZE (4k).
* Added max number of shared memory object per guest and max number of
  size of each shared memory object
* Added helper macros to calculate offsets of different FF-A data structures
  in the communication buffer instead of relying on pointer arithmetic
* Addressed style issues and other comments
* Broke the commit "xen/arm: add FF-A mediator" into multiple parts, trying
  to add a few features at a time as requested
* Added a missing call to rxtx_unmap() in ffa_relinquish_resources()
* Assignment of "ffa_enabled" is kept as is until I have something definitive
  on the type etc.
* Tested with CONFIG_DEBUG=y

v3->v4:
* Missed v3 and sent a v4 instead by mistake.

v2->v3:
* Generates offsets into struct arm_smccc_1_2_regs with asm-offsets.c in
  order to avoid hard coded offsets in the assembly function
  arm_smccc_1_2_smc()
* Adds an entry in SUPPORT.md on the FF-A status
* Adds a configuration variable "ffa_enabled" to tell if FF-A should be
  enabled for a particular domu guest
* Moves the ffa_frag_list for fragmented memory share requests into
  struct ffa_ctx instead to keep it per guest in order to avoid mixups
  and simplify locking
* Adds a spinlock to struct ffa_ctx for per guest locking
* Addressing style issues and suggestions
* Uses FFA_FEATURES to check that all the needed features are available
  before initializing the mediator
* Rebased on staging as of 2022-06-20

v1->v2:
* Rebased on staging to resolve some merge conflicts as requested

Jens Wiklander (14):
  xen/arm: ffa: add direct request support
  xen/arm: ffa: map SPMC rx/tx buffers
  xen/arm: ffa: send guest events to Secure Partitions
  xen/arm: ffa: support mapping guest RX/TX buffers
  xen/arm: ffa: support guest FFA_PARTITION_INFO_GET
  xen/arm: move regpair_to_uint64() and uint64_to_regpair() to regs.h
  xen/arm: ffa: add defines for sharing memory
  xen/arm: ffa: add ABI structs for sharing memory
  xen/arm: ffa: support sharing memory
  xen/arm: ffa: add support to reclaim shared memory
  xen/arm: ffa: improve lock granularity
  xen/arm: ffa: list current limitations
  tools: add Arm FF-A mediator
  docs: add Arm FF-A mediator

 CHANGELOG.md |3 +-
 SUPPORT.md   |9 +
 docs/man/xl.cfg.5.pod.in |   15 +
 tools/include/libxl.h|5 +
 tools/libs/light/libxl_arm.c |3 +
 tools/libs/light/libxl_types.idl |3 +-
 xen/arch/arm/include/asm/regs.h  |   12 +
 xen/arch/arm/tee/ffa.c   | 1411 ++
 xen/arch/arm/tee/optee.c |   11 -
 9 files changed, 1459 insertions(+), 13 deletions(-)

-- 
2.34.1




[XEN PATCH v11 04/14] xen/arm: ffa: support mapping guest RX/TX buffers

2023-07-31 Thread Jens Wiklander
Adds support in the mediator to map and unmap the RX and TX buffers
provided by the guest using the two FF-A functions FFA_RXTX_MAP and
FFA_RXTX_UNMAP.

These buffer are later used to transmit data that cannot be passed in
registers only.

Signed-off-by: Jens Wiklander 
---
v10->v11
- Fixing a typo in a comment and adding a couple of newlines as requested
---
 xen/arch/arm/tee/ffa.c | 140 +
 1 file changed, 140 insertions(+)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 5af3e5eedc88..6c76c9885774 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -74,6 +74,12 @@
  */
 #define FFA_RXTX_PAGE_COUNT 1
 
+/*
+ * Limit the number of pages RX/TX buffers guests can map.
+ * TODO support a larger number.
+ */
+#define FFA_MAX_RXTX_PAGE_COUNT 1
+
 /*
  * Flags and field values used for the MSG_SEND_DIRECT_REQ/RESP:
  * BIT(31): Framework or partition message
@@ -169,6 +175,12 @@ struct ffa_partition_info_1_1 {
 };
 
 struct ffa_ctx {
+void *rx;
+const void *tx;
+struct page_info *rx_pg;
+struct page_info *tx_pg;
+/* Number of 4kB pages in each of rx/rx_pg and tx/tx_pg */
+unsigned int page_count;
 /* FF-A version used by the guest */
 uint32_t guest_vers;
 /*
@@ -176,6 +188,7 @@ struct ffa_ctx {
  * ffa_domain_teardown() to know which SPs need to be signalled.
  */
 uint16_t create_signal_count;
+bool rx_is_free;
 };
 
 /* Negotiated FF-A version to use with the SPMC */
@@ -371,6 +384,11 @@ static void set_regs(struct cpu_user_regs *regs, 
register_t v0, register_t v1,
 set_user_reg(regs, 7, v7);
 }
 
+static void set_regs_error(struct cpu_user_regs *regs, uint32_t error_code)
+{
+set_regs(regs, FFA_ERROR, 0, error_code, 0, 0, 0, 0, 0);
+}
+
 static void set_regs_success(struct cpu_user_regs *regs, uint32_t w2,
  uint32_t w3)
 {
@@ -392,6 +410,108 @@ static void handle_version(struct cpu_user_regs *regs)
 set_regs(regs, vers, 0, 0, 0, 0, 0, 0, 0);
 }
 
+static uint32_t 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_NOT_SUPPORTED;
+}
+
+/* Already mapped */
+if ( ctx->rx )
+return FFA_RET_DENIED;
+
+tx_pg = get_page_from_gfn(d, gfn_x(gaddr_to_gfn(tx_addr)), , 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)), , 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 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 void handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t 
fid)
 {
 struct arm_smccc_1_2_regs arg = { .a0 = fid, };
@@ -448,6 +568,7 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
 uint32_t fid = get_user_reg(regs, 0);
 struct domain *d = current->domain;
 struc

Re: [XEN PATCH v10 20/24] xen/arm: ffa: support sharing large memory ranges

2023-07-19 Thread Jens Wiklander
Hi Bertrand,

On Wed, Jul 19, 2023 at 11:37 AM Bertrand Marquis
 wrote:
>
> Hi Jens,
>
> > On 17 Jul 2023, at 09:21, Jens Wiklander  wrote:
> >
> > Adds support for sharing large memory ranges transmitted in fragments
> > using FFA_MEM_FRAG_TX.
> >
> > The implementation is the bare minimum to be able to communicate with
> > OP-TEE running as an SPMC at S-EL1.
> >
> > Adds a check that the SP supports the needed FF-A feature
> > FFA_MEM_FRAG_TX.
> >
> > Signed-off-by: Jens Wiklander 
> > ---
> > xen/arch/arm/tee/ffa.c | 253 ++---
> > 1 file changed, 240 insertions(+), 13 deletions(-)
> >
> > diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
> > index c623c51168b9..ac23b9edc74c 100644
> > --- a/xen/arch/arm/tee/ffa.c
> > +++ b/xen/arch/arm/tee/ffa.c
> > @@ -359,6 +359,8 @@ struct ffa_ctx {
> >  */
> > uint16_t create_signal_count;
> > bool rx_is_free;
> > +/* Currently used fragment states, struct mem_frag_state */
> > +struct list_head frag_list;
> > /* Used shared memory objects, struct ffa_shm_mem */
> > struct list_head shm_list;
> > /* Number of allocated shared memory object */
> > @@ -375,6 +377,18 @@ struct ffa_shm_mem {
> > struct page_info *pages[];
> > };
> >
> > +struct mem_frag_state {
> > +struct list_head list;
> > +struct ffa_shm_mem *shm;
> > +uint32_t range_count;
> > +unsigned int current_page_idx;
> > +unsigned int frag_offset;
> > +unsigned int range_offset;
> > +const uint8_t *buf;
> > +unsigned int buf_size;
> > +struct ffa_address_range range;
> > +};
>
> Please add some comments inside this structure as
> from reading the code it is not quite clear what is done.

OK

>
> > +
> > /* Negotiated FF-A version to use with the SPMC */
> > static uint32_t __ro_after_init ffa_version;
> >
> > @@ -538,6 +552,36 @@ static int32_t ffa_mem_share(uint32_t tot_len, 
> > uint32_t frag_len,
> > }
> > }
> >
> > +static int32_t ffa_mem_frag_tx(uint64_t handle, uint32_t frag_len,
> > +   uint16_t sender_id)
> > +{
> > +struct arm_smccc_1_2_regs arg = {
> > +.a0 = FFA_MEM_FRAG_TX,
> > +.a1 = handle & UINT32_MAX,
> > +.a2 = handle >> 32,
> > +.a3 = frag_len,
> > +.a4 = (uint32_t)sender_id << 16,
> > +};
> > +struct arm_smccc_1_2_regs resp;
> > +
> > +arm_smccc_1_2_smc(, );
> > +
> > +switch ( resp.a0 )
> > +{
> > +case FFA_ERROR:
> > +if ( resp.a2 )
> > +return resp.a2;
> > +else
> > +return FFA_RET_NOT_SUPPORTED;
> > +case FFA_SUCCESS_32:
> > +return FFA_RET_OK;
> > +case FFA_MEM_FRAG_RX:
> > +return resp.a3;
> > +default:
> > +return FFA_RET_NOT_SUPPORTED;
> > +}
> > +}
> > +
> > static int32_t ffa_mem_reclaim(uint32_t handle_lo, uint32_t handle_hi,
> >uint32_t flags)
> > {
> > @@ -627,6 +671,14 @@ static void set_regs_success(struct cpu_user_regs 
> > *regs, uint32_t w2,
> > set_regs(regs, FFA_SUCCESS_32, 0, w2, w3, 0, 0, 0, 0);
> > }
> >
> > +static void set_regs_frag_rx(struct cpu_user_regs *regs, uint32_t 
> > handle_lo,
> > + uint32_t handle_hi, uint32_t frag_offset,
> > + uint16_t sender_id)
> > +{
> > +set_regs(regs, FFA_MEM_FRAG_RX, handle_lo, handle_hi, frag_offset,
> > + (uint32_t)sender_id << 16, 0, 0, 0);
> > +}
> > +
> > static void handle_version(struct cpu_user_regs *regs)
> > {
> > struct domain *d = current->domain;
> > @@ -999,6 +1051,8 @@ static int share_shm(struct ffa_shm_mem *shm)
> > paddr_t last_pa;
> > unsigned int n;
> > paddr_t pa;
> > +bool first;
> > +int ret;
> >
> > ASSERT(spin_is_locked(_tx_buffer_lock));
> > ASSERT(shm->page_count);
> > @@ -1034,13 +1088,23 @@ static int share_shm(struct ffa_shm_mem *shm)
> >
> > tot_len = ADDR_RANGE_OFFSET(descr->mem_access_count, region_count,
> > region_descr->address_range_count);
> > -if ( tot_len > max_frag_len )
> > -return FFA_RET_NOT_SUPPORTED;
> >
> > +/*
>

Re: [XEN PATCH v10 14/24] xen/arm: ffa: support guest FFA_PARTITION_INFO_GET

2023-07-19 Thread Jens Wiklander
On Tue, Jul 18, 2023 at 12:22 PM Bertrand Marquis
 wrote:
>
> Hi Jens,
>
> > On 17 Jul 2023, at 09:20, Jens Wiklander  wrote:
> >
> > Adds support in the mediator to handle FFA_PARTITION_INFO_GET requests
> > from a guest. The requests are forwarded to the SPMC and the response is
> > translated according to the FF-A version in use by the guest.
> >
> > Using FFA_PARTITION_INFO_GET changes the owner of the RX buffer to the
> > caller (the guest in this case), so once it is done with the buffer it
> > must be released using FFA_RX_RELEASE before another call can be made.
> >
> > Signed-off-by: Jens Wiklander 
> > ---
> > xen/arch/arm/tee/ffa.c | 131 +
> > 1 file changed, 131 insertions(+)
> >
> > diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
> > index ffabb5ed0a80..d5748b9ce88c 100644
> > --- a/xen/arch/arm/tee/ffa.c
> > +++ b/xen/arch/arm/tee/ffa.c
> > @@ -166,7 +166,18 @@
> > #define FFA_MSG_SEND0x846EU
> > #define FFA_MSG_POLL0x846AU
> >
> > +/*
> > + * Structs below ending with _1_0 are defined in FF-A-1.0-REL and
> > + * struct ending with _1_1 are defined in FF-A-1.1-REL0.
>
> Nit: For coherency, second line should be "Structs" instead of "struct"

OK

>
> > + */
> > +
> > /* Partition information descriptor */
> > +struct ffa_partition_info_1_0 {
> > +uint16_t id;
> > +uint16_t execution_context;
> > +uint32_t partition_properties;
> > +};
> > +
> > struct ffa_partition_info_1_1 {
> > uint16_t id;
> > uint16_t execution_context;
> > @@ -189,6 +200,7 @@ struct ffa_ctx {
> >  */
> > uint16_t create_signal_count;
> > bool rx_is_free;
> > +spinlock_t lock;
> > };
> >
> > /* Negotiated FF-A version to use with the SPMC */
> > @@ -203,9 +215,15 @@ static uint16_t subscr_vm_destroyed_count 
> > __read_mostly;
> > /*
> >  * Our rx/tx buffers shared with the SPMC. FFA_RXTX_PAGE_COUNT is the
> >  * number of pages used in each of these buffers.
> > + *
> > + * The RX buffer is protected from concurrent usage with 
> > ffa_rx_buffer_lock.
> > + * Note that the SPMC is also tracking the ownership of our RX buffer so
> > + * for calls which uses our RX buffer to deliver a result we must call
> > + * ffa_rx_release() to let the SPMC know that we're done with the buffer.
> >  */
> > static void *ffa_rx __read_mostly;
> > static void *ffa_tx __read_mostly;
> > +static DEFINE_SPINLOCK(ffa_rx_buffer_lock);
> >
> > static bool ffa_get_version(uint32_t *vers)
> > {
> > @@ -510,6 +528,100 @@ static uint32_t handle_rxtx_unmap(void)
> > return FFA_RET_OK;
> > }
> >
> > +static int32_t handle_partition_info_get(uint32_t w1, uint32_t w2, 
> > uint32_t w3,
> > + uint32_t w4, uint32_t w5,
> > + uint32_t *count)
> > +{
> > +int32_t ret = FFA_RET_DENIED;
> > +struct domain *d = current->domain;
> > +struct ffa_ctx *ctx = d->arch.tee;
> > +
> > +/*
> > + * FF-A v1.0 has w5 MBZ while v1.1 allows
> > + * FFA_PARTITION_INFO_GET_COUNT_FLAG to be non-zero.
> > + */
>
> You should add something to say that the INFO_GET_COUNT does
> not use the rxtx buffer to explain why you do the call directly in this case.
>
> Reading the code as is, on might wonder why this case is different.
>
> How about:
> FFA_PARTITION_INFO_GET_COUNT is only using registers and not
> the rxtx buffer so do the partition_info_get directly.

OK, I'll add it.

Thanks,
Jens

>
> > +if ( w5 == FFA_PARTITION_INFO_GET_COUNT_FLAG &&
> > + ctx->guest_vers == FFA_VERSION_1_1 )
> > +return ffa_partition_info_get(w1, w2, w3, w4, w5, count);
> > +if ( w5 )
> > +return FFA_RET_INVALID_PARAMETERS;
> > +
> > +if ( !ffa_rx )
> > +return FFA_RET_DENIED;
> > +
> > +spin_lock(>lock);
> > +if ( !ctx->page_count || !ctx->rx_is_free )
> > +goto out;
> > +spin_lock(_rx_buffer_lock);
> > +ret = ffa_partition_info_get(w1, w2, w3, w4, w5, count);
> > +if ( ret )
> > +goto out_rx_buf_unlock;
> > +/*
> > + * ffa_partition_info_get() succeeded so we now own the RX buffer we
> > + * share with the SPMC. We must give it back using ffa_rx_release()
> > +

Re: [XEN PATCH v10 13/24] xen/arm: ffa: support mapping guest RX/TX buffers

2023-07-19 Thread Jens Wiklander
Hi Bertrand,

On Tue, Jul 18, 2023 at 12:10 PM Bertrand Marquis
 wrote:
>
> Hi Jens,
>
> > On 17 Jul 2023, at 09:20, Jens Wiklander  wrote:
> >
> > Adds support in the mediator to map and unmap the RX and TX buffers
> > provided by the guest using the two FF-A functions FFA_RXTX_MAP and
> > FFA_RXTX_UNMAP.
> >
> > These buffer are later used to transmit data that cannot be passed in
> > registers only.
> >
> > Signed-off-by: Jens Wiklander 
> > ---
> > xen/arch/arm/tee/ffa.c | 138 +
> > 1 file changed, 138 insertions(+)
> >
> > diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
> > index d755363de686..ffabb5ed0a80 100644
> > --- a/xen/arch/arm/tee/ffa.c
> > +++ b/xen/arch/arm/tee/ffa.c
> > @@ -74,6 +74,12 @@
> >  */
> > #define FFA_RXTX_PAGE_COUNT 1
> >
> > +/*
> > + * Limits the number of pages RX/TX buffers guests can map.
>
> Typo: s/Limits/Limit/

OK

>
> > + * TODO support a larger number.
> > + */
> > +#define FFA_MAX_RXTX_PAGE_COUNT 1
> > +
> > /*
> >  * Flags and field values used for the MSG_SEND_DIRECT_REQ/RESP:
> >  * BIT(31): Framework or partition message
> > @@ -169,6 +175,12 @@ struct ffa_partition_info_1_1 {
> > };
> >
> > struct ffa_ctx {
> > +void *rx;
> > +const void *tx;
> > +struct page_info *rx_pg;
> > +struct page_info *tx_pg;
> > +/* Number of 4kB pages in each of rx/rx_pg and tx/tx_pg */
> > +unsigned int page_count;
> > /* FF-A version used by the guest */
> > uint32_t guest_vers;
> > /*
> > @@ -176,6 +188,7 @@ struct ffa_ctx {
> >  * ffa_domain_teardown() to know which SPs need to be signalled.
> >  */
> > uint16_t create_signal_count;
> > +bool rx_is_free;
> > };
> >
> > /* Negotiated FF-A version to use with the SPMC */
> > @@ -371,6 +384,11 @@ static void set_regs(struct cpu_user_regs *regs, 
> > register_t v0, register_t v1,
> > set_user_reg(regs, 7, v7);
> > }
> >
> > +static void set_regs_error(struct cpu_user_regs *regs, uint32_t error_code)
> > +{
> > +set_regs(regs, FFA_ERROR, 0, error_code, 0, 0, 0, 0, 0);
> > +}
> > +
> > static void set_regs_success(struct cpu_user_regs *regs, uint32_t w2,
> >  uint32_t w3)
> > {
> > @@ -392,6 +410,106 @@ static void handle_version(struct cpu_user_regs *regs)
> > set_regs(regs, vers, 0, 0, 0, 0, 0, 0, 0);
> > }
> >
> > +static uint32_t 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_NOT_SUPPORTED;
> > +}
> > +
> > +/* Already mapped */
> > +if ( ctx->rx )
> > +return FFA_RET_DENIED;
> > +
> > +tx_pg = get_page_from_gfn(d, gfn_x(gaddr_to_gfn(tx_addr)), , 
> > P2M_ALLOC);
> > +if ( !tx_pg )
> > +return FFA_RET_INVALID_PARAMETERS;
>
> Please add a newline here

OK

>
> > +/* 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)), , 
> > P2M_ALLOC);
> > +if ( !tx_pg )
> > +goto err_put_tx_pg;
>
> Please add a newline here

OK

Thanks,
Jens

>
> > +/* 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 )
> > +g

Re: [XEN PATCH v10 12/24] xen/arm: ffa: send guest events to Secure Partitions

2023-07-19 Thread Jens Wiklander
Hi,

On Wed, Jul 19, 2023 at 11:19 AM Bertrand Marquis
 wrote:
>
> Hi Jens,
>
> > On 19 Jul 2023, at 10:27, Jens Wiklander  wrote:
> >
> > Hi Bertrand,
> >
> > On Tue, Jul 18, 2023 at 12:05 PM Bertrand Marquis
> >  wrote:
> >>
> >> Hi Jens,
> >>
> >>> On 17 Jul 2023, at 09:20, Jens Wiklander  
> >>> wrote:
> >>>
> >>> The FF-A specification defines framework messages sent as direct
> >>> requests when certain events occurs. For instance when a VM (guest) is
> >>> created or destroyed. Only SPs which have subscribed to these events
> >>> will receive them. An SP can subscribe to these messages in its
> >>> partition properties.
> >>>
> >>> Adds a check that the SP supports the needed FF-A features
> >>> FFA_PARTITION_INFO_GET and FFA_RX_RELEASE.
> >>>
> >>> The partition properties of each SP is retrieved with
> >>> FFA_PARTITION_INFO_GET which returns the information in our RX buffer.
> >>> Using FFA_PARTITION_INFO_GET changes the owner of the RX buffer to the
> >>> caller (us), so once we're done with the buffer it must be released
> >>> using FFA_RX_RELEASE before another call can be made.
> >>>
> >>> Signed-off-by: Jens Wiklander 
> >>> ---
> >>> xen/arch/arm/tee/ffa.c | 233 -
> >>> 1 file changed, 231 insertions(+), 2 deletions(-)
> >>>
> >>> diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
> >>> index f8ccaabc568d..d755363de686 100644
> >>> --- a/xen/arch/arm/tee/ffa.c
> >>> +++ b/xen/arch/arm/tee/ffa.c
> >>> @@ -160,14 +160,33 @@
> >>> #define FFA_MSG_SEND0x846EU
> >>> #define FFA_MSG_POLL0x846AU
> >>>
> >>> +/* Partition information descriptor */
> >>> +struct ffa_partition_info_1_1 {
> >>> +uint16_t id;
> >>> +uint16_t execution_context;
> >>> +uint32_t partition_properties;
> >>> +uint8_t uuid[16];
> >>> +};
> >>> +
> >>> struct ffa_ctx {
> >>>/* FF-A version used by the guest */
> >>>uint32_t guest_vers;
> >>> +/*
> >>> + * Number of SPs that we have sent a VM created signal to, used in
> >>> + * ffa_domain_teardown() to know which SPs need to be signalled.
> >>> + */
> >>> +uint16_t create_signal_count;
> >>> };
> >>>
> >>> /* Negotiated FF-A version to use with the SPMC */
> >>> static uint32_t __ro_after_init ffa_version;
> >>>
> >>> +/* SPs subscribing to VM_CREATE and VM_DESTROYED events */
> >>> +static uint16_t *subscr_vm_created __read_mostly;
> >>> +static uint16_t subscr_vm_created_count __read_mostly;
> >>> +static uint16_t *subscr_vm_destroyed __read_mostly;
> >>> +static uint16_t subscr_vm_destroyed_count __read_mostly;
> >>> +
> >>> /*
> >>> * Our rx/tx buffers shared with the SPMC. FFA_RXTX_PAGE_COUNT is the
> >>> * number of pages used in each of these buffers.
> >>> @@ -251,6 +270,87 @@ static int32_t ffa_rxtx_map(paddr_t tx_addr, paddr_t 
> >>> rx_addr,
> >>>return ffa_simple_call(FFA_RXTX_MAP_64, tx_addr, rx_addr, page_count, 
> >>> 0);
> >>> }
> >>>
> >>> +static int32_t ffa_partition_info_get(uint32_t w1, uint32_t w2, uint32_t 
> >>> w3,
> >>> +  uint32_t w4, uint32_t w5,
> >>> +  uint32_t *count)
> >>> +{
> >>> +const struct arm_smccc_1_2_regs arg = {
> >>> +.a0 = FFA_PARTITION_INFO_GET,
> >>> +.a1 = w1,
> >>> +.a2 = w2,
> >>> +.a3 = w3,
> >>> +.a4 = w4,
> >>> +.a5 = w5,
> >>> +};
> >>> +struct arm_smccc_1_2_regs resp;
> >>> +uint32_t ret;
> >>> +
> >>> +arm_smccc_1_2_smc(, );
> >>> +
> >>> +ret = get_ffa_ret_code();
> >>> +if ( !ret )
> >>> +*count = resp.a2;
> >>> +
> >>> +return ret;
> >>> +}
> >>> +
> >>> +static int32_t ffa_rx_release(void)
> >>>

Re: [XEN PATCH v10 12/24] xen/arm: ffa: send guest events to Secure Partitions

2023-07-19 Thread Jens Wiklander
Hi Bertrand,

On Tue, Jul 18, 2023 at 12:05 PM Bertrand Marquis
 wrote:
>
> Hi Jens,
>
> > On 17 Jul 2023, at 09:20, Jens Wiklander  wrote:
> >
> > The FF-A specification defines framework messages sent as direct
> > requests when certain events occurs. For instance when a VM (guest) is
> > created or destroyed. Only SPs which have subscribed to these events
> > will receive them. An SP can subscribe to these messages in its
> > partition properties.
> >
> > Adds a check that the SP supports the needed FF-A features
> > FFA_PARTITION_INFO_GET and FFA_RX_RELEASE.
> >
> > The partition properties of each SP is retrieved with
> > FFA_PARTITION_INFO_GET which returns the information in our RX buffer.
> > Using FFA_PARTITION_INFO_GET changes the owner of the RX buffer to the
> > caller (us), so once we're done with the buffer it must be released
> > using FFA_RX_RELEASE before another call can be made.
> >
> > Signed-off-by: Jens Wiklander 
> > ---
> > xen/arch/arm/tee/ffa.c | 233 -
> > 1 file changed, 231 insertions(+), 2 deletions(-)
> >
> > diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
> > index f8ccaabc568d..d755363de686 100644
> > --- a/xen/arch/arm/tee/ffa.c
> > +++ b/xen/arch/arm/tee/ffa.c
> > @@ -160,14 +160,33 @@
> > #define FFA_MSG_SEND0x846EU
> > #define FFA_MSG_POLL0x846AU
> >
> > +/* Partition information descriptor */
> > +struct ffa_partition_info_1_1 {
> > +uint16_t id;
> > +uint16_t execution_context;
> > +uint32_t partition_properties;
> > +uint8_t uuid[16];
> > +};
> > +
> > struct ffa_ctx {
> > /* FF-A version used by the guest */
> > uint32_t guest_vers;
> > +/*
> > + * Number of SPs that we have sent a VM created signal to, used in
> > + * ffa_domain_teardown() to know which SPs need to be signalled.
> > + */
> > +uint16_t create_signal_count;
> > };
> >
> > /* Negotiated FF-A version to use with the SPMC */
> > static uint32_t __ro_after_init ffa_version;
> >
> > +/* SPs subscribing to VM_CREATE and VM_DESTROYED events */
> > +static uint16_t *subscr_vm_created __read_mostly;
> > +static uint16_t subscr_vm_created_count __read_mostly;
> > +static uint16_t *subscr_vm_destroyed __read_mostly;
> > +static uint16_t subscr_vm_destroyed_count __read_mostly;
> > +
> > /*
> >  * Our rx/tx buffers shared with the SPMC. FFA_RXTX_PAGE_COUNT is the
> >  * number of pages used in each of these buffers.
> > @@ -251,6 +270,87 @@ static int32_t ffa_rxtx_map(paddr_t tx_addr, paddr_t 
> > rx_addr,
> > return ffa_simple_call(FFA_RXTX_MAP_64, tx_addr, rx_addr, page_count, 
> > 0);
> > }
> >
> > +static int32_t ffa_partition_info_get(uint32_t w1, uint32_t w2, uint32_t 
> > w3,
> > +  uint32_t w4, uint32_t w5,
> > +  uint32_t *count)
> > +{
> > +const struct arm_smccc_1_2_regs arg = {
> > +.a0 = FFA_PARTITION_INFO_GET,
> > +.a1 = w1,
> > +.a2 = w2,
> > +.a3 = w3,
> > +.a4 = w4,
> > +.a5 = w5,
> > +};
> > +struct arm_smccc_1_2_regs resp;
> > +uint32_t ret;
> > +
> > +arm_smccc_1_2_smc(, );
> > +
> > +ret = get_ffa_ret_code();
> > +if ( !ret )
> > +*count = resp.a2;
> > +
> > +return ret;
> > +}
> > +
> > +static int32_t ffa_rx_release(void)
> > +{
> > +return ffa_simple_call(FFA_RX_RELEASE, 0, 0, 0, 0);
> > +}
> > +
> > +static int32_t ffa_direct_req_send_vm(uint16_t sp_id, uint16_t vm_id,
> > +  uint8_t msg)
> > +{
> > +uint32_t exp_resp = FFA_MSG_FLAG_FRAMEWORK;
> > +unsigned int retry_count = 0;
> > +int32_t res;
> > +
> > +if ( msg == FFA_MSG_SEND_VM_CREATED )
> > +exp_resp |= FFA_MSG_RESP_VM_CREATED;
> > +else if ( msg == FFA_MSG_SEND_VM_DESTROYED )
> > +exp_resp |= FFA_MSG_RESP_VM_DESTROYED;
> > +else
> > +return FFA_RET_INVALID_PARAMETERS;
> > +
> > +do {
> > +const struct arm_smccc_1_2_regs arg = {
> > +.a0 = FFA_MSG_SEND_DIRECT_REQ_32,
> > +.a1 = sp_id,
> > +.a2 = FFA_MSG_FLAG_FRAMEWORK | msg,
> > +.a5 = vm_id,
> > +};
> > +s

Re: [XEN PATCH v10 10/24] xen/arm: ffa: add direct request support

2023-07-19 Thread Jens Wiklander
Hi Bertrand,

On Tue, Jul 18, 2023 at 11:41 AM Bertrand Marquis
 wrote:
>
> Hi Jens,
>
> > On 17 Jul 2023, at 09:20, Jens Wiklander  wrote:
> >
> > Adds support for sending a FF-A direct request. Checks that the SP also
> > supports handling a 32-bit direct request. 64-bit direct requests are
> > not used by the mediator itself so there is not need to check for that.
> >
> > Signed-off-by: Jens Wiklander 
> > Reviewed-by: Henry Wang 
> > ---
> > xen/arch/arm/tee/ffa.c | 113 +
> > 1 file changed, 113 insertions(+)
> >
> > diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
> > index e157ed20ad8b..e05d58cf7755 100644
> > --- a/xen/arch/arm/tee/ffa.c
> > +++ b/xen/arch/arm/tee/ffa.c
> > @@ -181,6 +181,56 @@ static bool ffa_get_version(uint32_t *vers)
> > return true;
> > }
> >
> > +static int32_t get_ffa_ret_code(const struct arm_smccc_1_2_regs *resp)
> > +{
> > +switch ( resp->a0 )
> > +{
> > +case FFA_ERROR:
> > +if ( resp->a2 )
> > +return resp->a2;
> > +else
> > +return FFA_RET_NOT_SUPPORTED;
> > +case FFA_SUCCESS_32:
> > +case FFA_SUCCESS_64:
> > +return FFA_RET_OK;
> > +default:
> > +return FFA_RET_NOT_SUPPORTED;
> > +}
> > +}
> > +
> > +static int32_t ffa_simple_call(uint32_t fid, register_t a1, register_t a2,
> > +   register_t a3, register_t a4)
> > +{
> > +const struct arm_smccc_1_2_regs arg = {
> > +.a0 = fid,
> > +.a1 = a1,
> > +.a2 = a2,
> > +.a3 = a3,
> > +.a4 = a4,
> > +};
> > +struct arm_smccc_1_2_regs resp;
> > +
> > +arm_smccc_1_2_smc(, );
> > +
> > +return get_ffa_ret_code();
> > +}
> > +
> > +static int32_t ffa_features(uint32_t id)
> > +{
> > +return ffa_simple_call(FFA_FEATURES, id, 0, 0, 0);
> > +}
> > +
> > +static bool check_mandatory_feature(uint32_t id)
> > +{
> > +int32_t ret = ffa_features(id);
> > +
> > +if ( ret )
> > +printk(XENLOG_ERR "ffa: mandatory feature id %#x missing: error 
> > %d\n",
> > +   id, ret);
> > +
> > +return !ret;
> > +}
> > +
> > static uint16_t get_vm_id(const struct domain *d)
> > {
> > /* +1 since 0 is reserved for the hypervisor in FF-A */
> > @@ -222,6 +272,57 @@ static void handle_version(struct cpu_user_regs *regs)
> > set_regs(regs, vers, 0, 0, 0, 0, 0, 0, 0);
> > }
> >
> > +static void handle_msg_send_direct_req(struct cpu_user_regs *regs, 
> > uint32_t fid)
> > +{
> > +struct arm_smccc_1_2_regs arg = { .a0 = fid, };
> > +struct arm_smccc_1_2_regs resp = { };
> > +struct domain *d = current->domain;
> > +uint32_t src_dst;
> > +uint64_t mask;
> > +
> > +if ( smccc_is_conv_64(fid) )
> > +mask = GENMASK_ULL(63, 0);
> > +else
> > +mask = GENMASK_ULL(31, 0);
> > +
> > +src_dst = get_user_reg(regs, 1);
> > +if ( (src_dst >> 16) != get_vm_id(d) )
> > +{
> > +resp.a0 = FFA_ERROR;
> > +resp.a2 = FFA_RET_INVALID_PARAMETERS;
> > +goto out;
> > +}
> > +
> > +arg.a1 = src_dst;
> > +arg.a2 = get_user_reg(regs, 2) & mask;
> > +arg.a3 = get_user_reg(regs, 3) & mask;
> > +arg.a4 = get_user_reg(regs, 4) & mask;
> > +arg.a5 = get_user_reg(regs, 5) & mask;
> > +arg.a6 = get_user_reg(regs, 6) & mask;
> > +arg.a7 = get_user_reg(regs, 7) & mask;
> > +
> > +arm_smccc_1_2_smc(, );
> > +switch ( resp.a0 )
> > +{
> > +case FFA_ERROR:
> > +case FFA_SUCCESS_32:
> > +case FFA_SUCCESS_64:
> > +case FFA_MSG_SEND_DIRECT_RESP_32:
> > +case FFA_MSG_SEND_DIRECT_RESP_64:
> > +break;
> > +default:
> > +/* Bad fid, report back. */
> > +memset(, 0, sizeof(arg));
> > +arg.a0 = FFA_ERROR;
> > +arg.a1 = src_dst;
> > +arg.a2 = FFA_RET_ABORTED;
>
> Those instructions setting arg have no consequence as arg is not used
> after. This is probably a left over from the previous loop.
>
> You can either send this back using arm_smcc but I would rather return
> a proper error back to the caller by setting properly resp regs.
&g

[XEN PATCH v10 21/24] xen/arm: ffa: improve lock granularity

2023-07-17 Thread Jens Wiklander
The single lock in struct ffa_ctx is complemented with rx_lock and tx_lock.

The old lock is used for small critical sections, like increasing
shm_count or adding another shm to shm_list.

rx_lock and tx_lock are only acquired using spin_trylock() which for
well-behaving guests should always succeed. Guests using the RX and TX
buffers are expected to serialize accesses before doing the FF-A
request.

Signed-off-by: Jens Wiklander 
---
 xen/arch/arm/tee/ffa.c | 121 ++---
 1 file changed, 89 insertions(+), 32 deletions(-)

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index ac23b9edc74c..59832f73c2be 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -365,6 +365,13 @@ struct ffa_ctx {
 struct list_head shm_list;
 /* Number of allocated shared memory object */
 unsigned int shm_count;
+/*
+ * tx_lock is used to serialize access to tx
+ * rx_lock is used to serialize access to rx
+ * lock is used for the rest in this struct
+ */
+spinlock_t tx_lock;
+spinlock_t rx_lock;
 spinlock_t lock;
 };
 
@@ -815,7 +822,9 @@ static int32_t handle_partition_info_get(uint32_t w1, 
uint32_t w2, uint32_t w3,
 if ( !ffa_rx )
 return FFA_RET_DENIED;
 
-spin_lock(>lock);
+if ( !spin_trylock(>rx_lock) )
+return FFA_RET_BUSY;
+
 if ( !ctx->page_count || !ctx->rx_is_free )
 goto out;
 spin_lock(_rx_buffer_lock);
@@ -866,7 +875,7 @@ out_rx_release:
 out_rx_buf_unlock:
 spin_unlock(_rx_buffer_lock);
 out:
-spin_unlock(>lock);
+spin_unlock(>rx_lock);
 
 return ret;
 }
@@ -877,13 +886,15 @@ static int32_t handle_rx_release(void)
 struct domain *d = current->domain;
 struct ffa_ctx *ctx = d->arch.tee;
 
-spin_lock(>lock);
+if ( !spin_trylock(>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(>lock);
+spin_unlock(>rx_lock);
 
 return ret;
 }
@@ -994,21 +1005,43 @@ static void put_shm_pages(struct ffa_shm_mem *shm)
 }
 }
 
+static bool inc_ctx_shm_count(struct ffa_ctx *ctx)
+{
+bool ret = true;
+
+spin_lock(>lock);
+if (ctx->shm_count >= FFA_MAX_SHM_COUNT)
+ret = false;
+else
+ctx->shm_count++;
+spin_unlock(>lock);
+
+return ret;
+}
+
+static void dec_ctx_shm_count(struct ffa_ctx *ctx)
+{
+spin_lock(>lock);
+ASSERT(ctx->shm_count > 0);
+ctx->shm_count--;
+spin_unlock(>lock);
+}
+
 static struct ffa_shm_mem *alloc_ffa_shm_mem(struct ffa_ctx *ctx,
  unsigned int page_count)
 {
 struct ffa_shm_mem *shm;
 
-if ( page_count >= FFA_MAX_SHM_PAGE_COUNT ||
- ctx->shm_count >= FFA_MAX_SHM_COUNT )
+if ( page_count >= FFA_MAX_SHM_PAGE_COUNT )
+return NULL;
+if ( !inc_ctx_shm_count(ctx) )
 return NULL;
 
 shm = xzalloc_flex_struct(struct ffa_shm_mem, pages, page_count);
 if ( shm )
-{
-ctx->shm_count++;
 shm->page_count = page_count;
-}
+else
+dec_ctx_shm_count(ctx);
 
 return shm;
 }
@@ -1018,8 +1051,7 @@ static void free_ffa_shm_mem(struct ffa_ctx *ctx, struct 
ffa_shm_mem *shm)
 if ( !shm )
 return;
 
-ASSERT(ctx->shm_count > 0);
-ctx->shm_count--;
+dec_ctx_shm_count(ctx);
 put_shm_pages(shm);
 xfree(shm);
 }
@@ -1299,7 +1331,11 @@ static void handle_mem_share(struct cpu_user_regs *regs)
 goto out_set_ret;
 }
 
-spin_lock(>lock);
+if ( !spin_trylock(>tx_lock) )
+{
+ret = FFA_RET_BUSY;
+goto out_set_ret;
+}
 
 if ( frag_len > ctx->page_count * FFA_PAGE_SIZE )
 goto out_unlock;
@@ -1421,7 +1457,9 @@ static void handle_mem_share(struct cpu_user_regs *regs)
 if ( ret )
 goto out;
 
+spin_lock(>lock);
 list_add_tail(>list, >shm_list);
+spin_unlock(>lock);
 
 uint64_to_regpair(_hi, _lo, shm->handle);
 
@@ -1429,7 +1467,7 @@ out:
 if ( ret )
 free_ffa_shm_mem(ctx, shm);
 out_unlock:
-spin_unlock(>lock);
+spin_unlock(>tx_lock);
 
 out_set_ret:
 if ( ret > 0 )
@@ -1464,7 +1502,12 @@ static void handle_mem_frag_tx(struct cpu_user_regs 
*regs)
 uint16_t sender_id = 0;
 int ret;
 
-spin_lock(>lock);
+if ( !spin_trylock(>tx_lock) )
+{
+ret = FFA_RET_BUSY;
+goto out_set_ret;
+}
+
 s = find_frag_state(ctx, handle);
 if ( !s )
 {
@@ -1489,15 +1532,20 @@ static void handle_mem_frag_tx(struct cpu_user_regs 
*regs)
 spin_unlock(_tx_buffer_lock);
 if ( ret < 0 )
 goto out_free_s;
+
+spin_lock(>lock);
 list_add_tail(>shm->list, >shm_list);
+spin_unlock(>lock);
+
 out

  1   2   3   >