[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v12 10/13] xen/arm64: Save/restore CPU context across SYSTEM_SUSPEND


  • To: Mykola Kvach <mykola_kvach@xxxxxxxx>
  • From: Bertrand Marquis <Bertrand.Marquis@xxxxxxx>
  • Date: Mon, 28 Sep 2026 16:17:59 +0000
  • Accept-language: en-GB, en-US
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 4.158.2.129) smtp.rcpttodomain=epam.com smtp.mailfrom=arm.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=arm.com; dkim=pass (signature was verified) header.d=arm.com; arc=none (0)
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=FHfQ6x0TuWYN9jzUa+00XdYZIgWlMVC7rUAENlKK84w=; b=spE7BWz3zMTiz8X2YlL9aSFEN75vITiFCZBnZ0CgUgr+81PLI1p8EEd566b9yRNo0b3OR+EvG/7mUOhpubpjMq/EJZyBRREpk3pVojezYnTLnqYs9uzzA0s1FYo/US2nulLGJ7kcCkQed7vOBoqjoqqpfkQFanJLq522KBXqIyYyiaEyVYSJiO6jDaDHjLYVquNPqwKMYVh5quuvRmPZh2qXjq0qSowy+grIaGxrFg+Zd5dHHk454+5d7SDxlmLgWg0pQ387/ADrZZ/O43gyWUX5oXe/CR+M4eVTfELWge1Wok0+2CC2x+WZmzA8vQ9iSIWx/SXm6X8Kdjopa9ihgw==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=fv3pyUWxwm5sfNEGJ4cWT5uGTVC+WQp+AnyTpFS7okYnEqVccbRRP+K0kPmeKajldPQnDu91Akt8fymuVgobWnQTP3v6485x0ZwdlfbXJJOQV8ppOvVDgq+Bb+m4xoBs5+9QuCeh0R672iYubzXXiFcbIclJQfTC8kkqJ2KtwgoAtpLetJWiE+loj11tMKHaM32MBrWXvqWUGvwrTxJepEbOXEtMjYGUbnyRJfAXjLuGhLMyjYxJ8noxUDZITUliHXZP+TpwUulhG8FD1v3RwT9+N1m41XARI3u6xrP9i8XM20NlWCwbssnRWsXAaQzCWhSZvR6WpW+PEdw6Yb7PlQ==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=arm.com header.i="@arm.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"; dkim=pass header.s=selector1 header.d=arm.com header.i="@arm.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"
  • Authentication-results-original: mx.microsoft.com 1; dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com;
  • Cc: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>, Oleksandr Tyshchenko <oleksandr_tyshchenko@xxxxxxxx>, Luca Fancellu <Luca.Fancellu@xxxxxxx>
  • Delivery-date: Mon, 28 Sep 2026 16:18:40 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Nodisclaimer: true
  • Thread-index: AQHdNjDrck5tdQi+nEWf4DlkNNzg5rbkXWsA
  • Thread-topic: [PATCH v12 10/13] xen/arm64: Save/restore CPU context across SYSTEM_SUSPEND

Hi Mykola,

> On 27 Aug 2026, at 16:31, Mykola Kvach <mykola_kvach@xxxxxxxx> wrote:
> 
> From: Mirela Simonovic <mirela.simonovic@xxxxxxxxxx>
> 
> On wakeup from PSCI SYSTEM_SUSPEND, Xen re-enters EL2 with the MMU and
> data cache disabled. The resume path must first switch back to Xen's
> runtime page tables before it can access the saved CPU context using
> virtual addresses.
> 
> Add an arm64 hyp_resume trampoline that reuses enable_secondary_cpu_mm()
> to enable the data cache and MMU, switch to init_ttbr, and resume in the
> runtime virtual mapping. The trampoline then restores the saved CPU
> general-purpose and system-control register context.
> 
> prepare_resume_ctx() must be invoked just before the PSCI system suspend
> call is issued to the platform firmware. It saves the current CPU context
> and returns a non-zero value so that the caller enters the physical
> SYSTEM_SUSPEND call.
> 
> On resume, hyp_resume restores the saved context, including the saved link
> register. Control therefore returns to the place where prepare_resume_ctx()
> was called. To avoid re-entering the suspend path, the restored path sees
> prepare_resume_ctx() return zero.
> 
> The assembly save/restore code uses offsets generated by asm-offsets.c
> from struct resume_cpu_context, keeping the assembly memory accesses in
> sync with the C structure layout.
> 
> 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>
> Reviewed-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@xxxxxxxx>
> Reviewed-by: Luca Fancellu <luca.fancellu@xxxxxxx>

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

Cheers
Bertrand

> ---
> Changes in v10:
> - Save and restore CNTHCTL_EL2 across SYSTEM_SUSPEND
> 
> Changes in v9:
> - Drop the misleading prepare_resume_ctx() pointer argument and make both
>  save/restore paths use the global resume_cpu_context.
> - Squash the arm64 resume trampoline into the context save/restore patch.
> - Document in code that hyp_resume relies on PSCI initial-state rules.
> - Use generic platform firmware wording instead of ATF-specific wording.
> - Rename the saved context type/storage to resume_cpu_context and rely on
>  implicit zero-initialization for the file-scope object.
> - Use asm-offsets.c-generated RESUME_CTX_* offsets to keep the assembly
>  save/restore code in sync with struct resume_cpu_context.
> 
> Changes in v8:
> - Fix alignments in code.
> 
> Changes in v7:
> - No functional changes, just moved commit.
> ---
> xen/arch/arm/Makefile              |   1 +
> xen/arch/arm/arm64/asm-offsets.c   |  21 +++++
> xen/arch/arm/arm64/head.S          | 122 +++++++++++++++++++++++++++++
> xen/arch/arm/include/asm/suspend.h |  27 +++++++
> xen/arch/arm/suspend.c             |  14 ++++
> 5 files changed, 185 insertions(+)
> create mode 100644 xen/arch/arm/suspend.c
> 
> diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
> index b7afd3e58c..788db83ba9 100644
> --- a/xen/arch/arm/Makefile
> +++ b/xen/arch/arm/Makefile
> @@ -51,6 +51,7 @@ obj-y += setup.o
> obj-y += shutdown.o
> obj-y += smp.o
> obj-y += smpboot.o
> +obj-$(CONFIG_SYSTEM_SUSPEND) += suspend.o
> obj-$(CONFIG_SYSCTL) += sysctl.o
> obj-y += time.o
> obj-y += traps.o
> diff --git a/xen/arch/arm/arm64/asm-offsets.c 
> b/xen/arch/arm/arm64/asm-offsets.c
> index 38a3894a3b..5d60406e9c 100644
> --- a/xen/arch/arm/arm64/asm-offsets.c
> +++ b/xen/arch/arm/arm64/asm-offsets.c
> @@ -13,6 +13,7 @@
> #include <asm/mm.h>
> #include <asm/setup.h>
> #include <asm/smccc.h>
> +#include <asm/suspend.h>
> 
> #define DEFINE(_sym, _val)                                                 \
>     asm volatile ( "\n.ascii\"==>#define " #_sym " %0 /* " #_val " */<==\""\
> @@ -57,6 +58,26 @@ void __dummy__(void)
>    OFFSET(INITINFO_stack, struct init_info, stack);
>    BLANK();
> 
> +#ifdef CONFIG_SYSTEM_SUSPEND
> +   OFFSET(RESUME_CTX_X19, struct resume_cpu_context, callee_regs[0]);
> +   OFFSET(RESUME_CTX_X21, struct resume_cpu_context, callee_regs[2]);
> +   OFFSET(RESUME_CTX_X23, struct resume_cpu_context, callee_regs[4]);
> +   OFFSET(RESUME_CTX_X25, struct resume_cpu_context, callee_regs[6]);
> +   OFFSET(RESUME_CTX_X27, struct resume_cpu_context, callee_regs[8]);
> +   OFFSET(RESUME_CTX_X29, struct resume_cpu_context, callee_regs[10]);
> +   OFFSET(RESUME_CTX_SP, struct resume_cpu_context, sp);
> +   OFFSET(RESUME_CTX_VBAR_EL2, struct resume_cpu_context, vbar_el2);
> +   OFFSET(RESUME_CTX_VTCR_EL2, struct resume_cpu_context, vtcr_el2);
> +   OFFSET(RESUME_CTX_VTTBR_EL2, struct resume_cpu_context, vttbr_el2);
> +   OFFSET(RESUME_CTX_TPIDR_EL2, struct resume_cpu_context, tpidr_el2);
> +   OFFSET(RESUME_CTX_MDCR_EL2, struct resume_cpu_context, mdcr_el2);
> +   OFFSET(RESUME_CTX_HSTR_EL2, struct resume_cpu_context, hstr_el2);
> +   OFFSET(RESUME_CTX_CPTR_EL2, struct resume_cpu_context, cptr_el2);
> +   OFFSET(RESUME_CTX_HCR_EL2, struct resume_cpu_context, hcr_el2);
> +   OFFSET(RESUME_CTX_CNTHCTL_EL2, struct resume_cpu_context, cnthctl_el2);
> +   BLANK();
> +#endif
> +
>    OFFSET(SMCCC_RES_a0, struct arm_smccc_res, a0);
>    OFFSET(SMCCC_RES_a2, struct arm_smccc_res, a2);
>    OFFSET(ARM_SMCCC_1_2_REGS_X0_OFFS, struct arm_smccc_1_2_regs, a0);
> diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
> index 72c7b24498..962be716ae 100644
> --- a/xen/arch/arm/arm64/head.S
> +++ b/xen/arch/arm/arm64/head.S
> @@ -561,6 +561,128 @@ END(efi_xen_start)
> 
> #endif /* CONFIG_ARM_EFI */
> 
> +#ifdef CONFIG_SYSTEM_SUSPEND
> +/*
> + * int prepare_resume_ctx(void)
> + *
> + * CPU context saved here will be restored on resume in hyp_resume function.
> + * prepare_resume_ctx shall return a non-zero value. Upon restoring context
> + * hyp_resume shall return value zero instead. From C code that invokes
> + * prepare_resume_ctx, the return value is interpreted to determine whether
> + * the context is saved (prepare_resume_ctx) or restored (hyp_resume).
> + */
> +FUNC(prepare_resume_ctx)
> +        ldr   x0, =resume_cpu_context
> +
> +        /* Store callee-saved registers */
> +        stp   x19, x20, [x0, #RESUME_CTX_X19]
> +        stp   x21, x22, [x0, #RESUME_CTX_X21]
> +        stp   x23, x24, [x0, #RESUME_CTX_X23]
> +        stp   x25, x26, [x0, #RESUME_CTX_X25]
> +        stp   x27, x28, [x0, #RESUME_CTX_X27]
> +        stp   x29, lr, [x0, #RESUME_CTX_X29]
> +
> +        /* Store stack-pointer */
> +        mov   x2, sp
> +        str   x2, [x0, #RESUME_CTX_SP]
> +
> +        /* Store system control registers */
> +        mrs   x2, VBAR_EL2
> +        str   x2, [x0, #RESUME_CTX_VBAR_EL2]
> +        mrs   x2, VTCR_EL2
> +        str   x2, [x0, #RESUME_CTX_VTCR_EL2]
> +        mrs   x2, VTTBR_EL2
> +        str   x2, [x0, #RESUME_CTX_VTTBR_EL2]
> +        mrs   x2, TPIDR_EL2
> +        str   x2, [x0, #RESUME_CTX_TPIDR_EL2]
> +        mrs   x2, MDCR_EL2
> +        str   x2, [x0, #RESUME_CTX_MDCR_EL2]
> +        mrs   x2, HSTR_EL2
> +        str   x2, [x0, #RESUME_CTX_HSTR_EL2]
> +        mrs   x2, CPTR_EL2
> +        str   x2, [x0, #RESUME_CTX_CPTR_EL2]
> +        mrs   x2, HCR_EL2
> +        str   x2, [x0, #RESUME_CTX_HCR_EL2]
> +        mrs   x2, CNTHCTL_EL2
> +        str   x2, [x0, #RESUME_CTX_CNTHCTL_EL2]
> +
> +        /* prepare_resume_ctx must return a non-zero value */
> +        mov   x0, #1
> +        ret
> +END(prepare_resume_ctx)
> +
> +FUNC(hyp_resume)
> +        /*
> +         * PSCI states that SYSTEM_SUSPEND follows the CPU_SUSPEND initial
> +         * state rules, so PSCI-compliant firmware must enter the return
> +         * exception level with DAIF masked.
> +         */
> +
> +        /* Initialize the UART if earlyprintk has been enabled. */
> +#ifdef CONFIG_EARLY_PRINTK
> +        bl    init_uart
> +#endif
> +        PRINT_ID("- Xen resuming -\r\n")
> +
> +        bl    check_cpu_mode
> +        bl    cpu_init
> +
> +        ldr   x0, =start
> +        adr   x20, start             /* x20 := paddr (start) */
> +        sub   x20, x20, x0           /* x20 := phys-offset */
> +        ldr   lr, =mmu_resumed
> +        b     enable_secondary_cpu_mm
> +
> +mmu_resumed:
> +        /* Now we can access the saved context, so restore it here. */
> +        ldr   x0, =resume_cpu_context
> +
> +        /* Restore callee-saved registers */
> +        ldp   x19, x20, [x0, #RESUME_CTX_X19]
> +        ldp   x21, x22, [x0, #RESUME_CTX_X21]
> +        ldp   x23, x24, [x0, #RESUME_CTX_X23]
> +        ldp   x25, x26, [x0, #RESUME_CTX_X25]
> +        ldp   x27, x28, [x0, #RESUME_CTX_X27]
> +        ldp   x29, lr, [x0, #RESUME_CTX_X29]
> +
> +        /* Restore stack pointer */
> +        ldr   x2, [x0, #RESUME_CTX_SP]
> +        mov   sp, x2
> +
> +        /* Restore system control registers */
> +        ldr   x2, [x0, #RESUME_CTX_VBAR_EL2]
> +        msr   VBAR_EL2, x2
> +        ldr   x2, [x0, #RESUME_CTX_VTCR_EL2]
> +        msr   VTCR_EL2, x2
> +        ldr   x2, [x0, #RESUME_CTX_VTTBR_EL2]
> +        msr   VTTBR_EL2, x2
> +        ldr   x2, [x0, #RESUME_CTX_TPIDR_EL2]
> +        msr   TPIDR_EL2, x2
> +        ldr   x2, [x0, #RESUME_CTX_MDCR_EL2]
> +        msr   MDCR_EL2, x2
> +        ldr   x2, [x0, #RESUME_CTX_HSTR_EL2]
> +        msr   HSTR_EL2, x2
> +        ldr   x2, [x0, #RESUME_CTX_CPTR_EL2]
> +        msr   CPTR_EL2, x2
> +        ldr   x2, [x0, #RESUME_CTX_HCR_EL2]
> +        msr   HCR_EL2, x2
> +        ldr   x2, [x0, #RESUME_CTX_CNTHCTL_EL2]
> +        msr   CNTHCTL_EL2, x2
> +        isb
> +
> +        /*
> +         * Since context is restored return from this function will appear
> +         * as return from prepare_resume_ctx. To distinguish a return from
> +         * prepare_resume_ctx 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 */
> +
> /*
>  * Local variables:
>  * mode: ASM
> diff --git a/xen/arch/arm/include/asm/suspend.h 
> b/xen/arch/arm/include/asm/suspend.h
> index 31a98a1f1b..c848fc6340 100644
> --- a/xen/arch/arm/include/asm/suspend.h
> +++ b/xen/arch/arm/include/asm/suspend.h
> @@ -3,6 +3,8 @@
> #ifndef ARM_SUSPEND_H
> #define ARM_SUSPEND_H
> 
> +#include <xen/types.h>
> +
> struct domain;
> struct vcpu;
> struct vcpu_guest_context;
> @@ -14,6 +16,31 @@ struct resume_info {
> 
> void arch_domain_resume(struct domain *d);
> 
> +#ifdef CONFIG_SYSTEM_SUSPEND
> +#ifdef CONFIG_ARM_64
> +struct resume_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;
> +    register_t cnthctl_el2;
> +} __aligned(16);
> +#else
> +#error "Define resume_cpu_context structure for arm32"
> +#endif
> +
> +extern struct resume_cpu_context resume_cpu_context;
> +
> +int prepare_resume_ctx(void);
> +void hyp_resume(void);
> +#endif /* CONFIG_SYSTEM_SUSPEND */
> +
> #endif /* ARM_SUSPEND_H */
> 
> /*
> diff --git a/xen/arch/arm/suspend.c b/xen/arch/arm/suspend.c
> new file mode 100644
> index 0000000000..6ea4a0f9cc
> --- /dev/null
> +++ b/xen/arch/arm/suspend.c
> @@ -0,0 +1,14 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +#include <asm/suspend.h>
> +
> +struct resume_cpu_context resume_cpu_context;
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> -- 
> 2.43.0
> 




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.