|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v5 10/12] xen/arm: Save/restore context on suspend/resume
Hi Volodymyr,
On Sat, Aug 23, 2025 at 8:34 PM Volodymyr Babchuk
<Volodymyr_Babchuk@xxxxxxxx> wrote:
>
>
> Hi Mykola,
>
> Mykola Kvach <xakep.amatop@xxxxxxxxx> writes:
>
> > From: Mirela Simonovic <mirela.simonovic@xxxxxxxxxx>
> >
> > The context of CPU general purpose and system control registers
> > has to be saved on suspend and restored on resume. This is
> > implemented in hyp_suspend and before the return from hyp_resume
> > function. The hyp_suspend is invoked just before the PSCI system
> > suspend call is issued to the ATF. The hyp_suspend has to return a
> > non-zero value so that the calling 'if' statement evaluates to true,
> > causing the system suspend to be invoked. Upon the resume, context
> > saved on suspend will be restored, including the link register.
> > Therefore, after restoring the context the control flow will
> > return to the address pointed by the saved link register, which
> > is the place from which the hyp_suspend was called. To ensure
> > that the calling 'if' statement doesn't again evaluate to true
> > and initiate system suspend, hyp_resume has to return a zero value
> > after restoring the context.
> >
> > Note that the order of saving register context into cpu_context
> > structure has to match the order of restoring.
> >
> > Support for ARM32 is not implemented. Instead, compilation fails with a
> > build-time error if suspend is enabled for ARM32.
> >
> > Signed-off-by: Mirela Simonovic <mirela.simonovic@xxxxxxxxxx>
> > Signed-off-by: Saeed Nowshadi <saeed.nowshadi@xxxxxxxxxx>
> > Signed-off-by: Mykyta Poturai <mykyta_poturai@xxxxxxxx>
> > Signed-off-by: Mykola Kvach <mykola_kvach@xxxxxxxx>
> > ---
> > Changes in v4:
> > - produce build-time error for ARM32 when CONFIG_SYSTEM_SUSPEND is enabled
> > - use register_t instead of uint64_t in cpu_context structure
> > ---
> > xen/arch/arm/arm64/head.S | 91 +++++++++++++++++++++++++++++-
> > xen/arch/arm/include/asm/suspend.h | 20 +++++++
> > xen/arch/arm/suspend.c | 23 +++++++-
> > 3 files changed, 130 insertions(+), 4 deletions(-)
> >
> > diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
> > index 596e960152..ad8b48de3a 100644
> > --- a/xen/arch/arm/arm64/head.S
> > +++ b/xen/arch/arm/arm64/head.S
> > @@ -562,6 +562,52 @@ END(efi_xen_start)
> > #endif /* CONFIG_ARM_EFI */
> >
> > #ifdef CONFIG_SYSTEM_SUSPEND
> > +/*
> > + * int hyp_suspend(struct cpu_context *ptr)
> > + *
> > + * x0 - pointer to the storage where callee's context will be saved
> > + *
> > + * CPU context saved here will be restored on resume in hyp_resume
> > function.
> > + * hyp_suspend shall return a non-zero value. Upon restoring context
> > + * hyp_resume shall return value zero instead. From C code that invokes
> > + * hyp_suspend, the return value is interpreted to determine whether the
> > context
> > + * is saved (hyp_suspend) or restored (hyp_resume).
> > + */
> > +FUNC(hyp_suspend)
>
> I don't think that hyp_suspend is the correct name, as this function in
> fact suspend_nothing. Maybe "prepare_resume_ctx" will be better?
Not a problem to rename it.
>
> > + /* Store callee-saved registers */
> > + stp x19, x20, [x0], #16
>
> If you have struct cpu_context defined, then you probably should use
> define provided by <asm-offsets.h> to access struct fields. Otherwise,
> it will be really easy to get desync between struct definition and this
> asm code.
>
> > + stp x21, x22, [x0], #16
> > + stp x23, x24, [x0], #16
> > + stp x25, x26, [x0], #16
> > + stp x27, x28, [x0], #16
> > + stp x29, lr, [x0], #16
> > +
> > + /* Store stack-pointer */
> > + mov x2, sp
> > + str x2, [x0], #8
> > +
> > + /* Store system control registers */
> > + mrs x2, VBAR_EL2
> > + str x2, [x0], #8
> > + mrs x2, VTCR_EL2
> > + str x2, [x0], #8
> > + mrs x2, VTTBR_EL2
> > + str x2, [x0], #8
> > + mrs x2, TPIDR_EL2
> > + str x2, [x0], #8
> > + mrs x2, MDCR_EL2
> > + str x2, [x0], #8
> > + mrs x2, HSTR_EL2
> > + str x2, [x0], #8
> > + mrs x2, CPTR_EL2
> > + str x2, [x0], #8
> > + mrs x2, HCR_EL2
> > + str x2, [x0], #8
> > +
> > + /* hyp_suspend must return a non-zero value */
> > + mov x0, #1
> > + ret
> > +END(hyp_suspend)
> >
> > FUNC(hyp_resume)
> > /* Initialize the UART if earlyprintk has been enabled. */
> > @@ -580,7 +626,50 @@ FUNC(hyp_resume)
> > b enable_secondary_cpu_mm
> >
> > mmu_resumed:
> > - b .
> > + /*
> > + * Now we can access the cpu_context, so restore the context here
> > + * TODO: can we reuse __context_switch and saved_context struct
> > here ?
> > + */
>
> This is a great idea and I like it very much, but sadly saved_context
> struct has no fields for system _EL2 registers.
>
> > + ldr x0, =cpu_context
> > +
> > + /* Restore callee-saved registers */
> > + ldp x19, x20, [x0], #16
> > + ldp x21, x22, [x0], #16
> > + ldp x23, x24, [x0], #16
> > + ldp x25, x26, [x0], #16
> > + ldp x27, x28, [x0], #16
> > + ldp x29, lr, [x0], #16
> > +
> > + /* Restore stack pointer */
> > + ldr x2, [x0], #8
> > + mov sp, x2
> > +
> > + /* Restore system control registers */
> > + ldr x2, [x0], #8
> > + msr VBAR_EL2, x2
> > + ldr x2, [x0], #8
> > + msr VTCR_EL2, x2
> > + ldr x2, [x0], #8
> > + msr VTTBR_EL2, x2
> > + ldr x2, [x0], #8
> > + msr TPIDR_EL2, x2
> > + ldr x2, [x0], #8
> > + msr MDCR_EL2, x2
> > + ldr x2, [x0], #8
> > + msr HSTR_EL2, x2
> > + ldr x2, [x0], #8
> > + msr CPTR_EL2, x2
> > + ldr x2, [x0], #8
> > + msr HCR_EL2, x2
> > + isb
> > +
> > + /* Since context is restored return from this function will appear
> > as
> > + * return from hyp_suspend. To distinguish a return from
> > hyp_suspend
> > + * which is called upon finalizing the suspend, as opposed to
> > return
> > + * from this function which executes on resume, we need to return
> > zero
> > + * value here. */
> > + mov x0, #0
> > + ret
> > END(hyp_resume)
> >
> > #endif /* CONFIG_SYSTEM_SUSPEND */
> > diff --git a/xen/arch/arm/include/asm/suspend.h
> > b/xen/arch/arm/include/asm/suspend.h
> > index 55041a5d06..ae71ccb87b 100644
> > --- a/xen/arch/arm/include/asm/suspend.h
> > +++ b/xen/arch/arm/include/asm/suspend.h
> > @@ -5,9 +5,29 @@
> >
> > #ifdef CONFIG_SYSTEM_SUSPEND
> >
> > +#ifdef CONFIG_ARM_64
> > +struct cpu_context {
> > + register_t callee_regs[12];
> > + register_t sp;
> > + register_t vbar_el2;
> > + register_t vtcr_el2;
> > + register_t vttbr_el2;
> > + register_t tpidr_el2;
> > + register_t mdcr_el2;
> > + register_t hstr_el2;
> > + register_t cptr_el2;
> > + register_t hcr_el2;
> > +} __aligned(16);
> > +#else
> > +#error "Define cpu_context structure for arm32"
> > +#endif
> > +
> > +extern struct cpu_context cpu_context;
> > +
> > int host_system_suspend(void);
> >
> > void hyp_resume(void);
> > +int hyp_suspend(struct cpu_context *ptr);
> >
> > #endif /* CONFIG_SYSTEM_SUSPEND */
> >
> > diff --git a/xen/arch/arm/suspend.c b/xen/arch/arm/suspend.c
> > index 08b6acaede..b5398e5ca6 100644
> > --- a/xen/arch/arm/suspend.c
> > +++ b/xen/arch/arm/suspend.c
> > @@ -1,6 +1,7 @@
> > /* SPDX-License-Identifier: GPL-2.0-only */
> >
> > #include <asm/psci.h>
> > +#include <asm/suspend.h>
> > #include <xen/console.h>
> > #include <xen/cpu.h>
> > #include <xen/llc-coloring.h>
> > @@ -17,6 +18,8 @@
> > * - Investigate feasibility and need for implementing system suspend on
> > ARM32
> > */
> >
> > +struct cpu_context cpu_context;
> > +
> > /* Xen suspend. Note: data is not used (suspend is the suspend to RAM) */
> > static long system_suspend(void *data)
> > {
> > @@ -73,9 +76,23 @@ static long system_suspend(void *data)
> > */
> > update_boot_mapping(true);
> >
> > - status = call_psci_system_suspend();
> > - if ( status )
> > - dprintk(XENLOG_WARNING, "PSCI system suspend failed, err=%d\n",
> > status);
> > + if ( hyp_suspend(&cpu_context) )
> > + {
> > + status = call_psci_system_suspend();
> > + /*
> > + * If suspend is finalized properly by above system suspend PSCI
> > call,
> > + * the code below in this 'if' branch will never execute. Execution
> > + * will continue from hyp_resume which is the hypervisor's resume
> > point.
> > + * In hyp_resume CPU context will be restored and since
> > link-register is
> > + * restored as well, it will appear to return from hyp_suspend. The
> > + * difference in returning from hyp_suspend on system suspend
> > versus
> > + * resume is in function's return value: on suspend, the return
> > value is
> > + * a non-zero value, on resume it is zero. That is why the control
> > flow
> > + * will not re-enter this 'if' branch on resume.
> > + */
>
> Looks like this comment is misplaced. It should be before "if (
> hyp_suspend() )", right?
Actually, the comment is correctly placed here and does not need to be moved.
>
> > + if ( status )
> > + dprintk(XENLOG_WARNING, "PSCI system suspend failed,
> > err=%d\n", status);
> > + }
> >
> > system_state = SYS_STATE_resume;
> > update_boot_mapping(false);
>
> --
> WBR, Volodymyr
Best regards,
Mykola
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |