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

Re: [PATCH 14/16] xen/arm: Resume memory management on Xen resume



Hi, @Julien Grall

On Wed, Mar 12, 2025 at 1:04 AM Julien Grall <julien@xxxxxxx> wrote:
>
> Hi,
>
> On 05/03/2025 09:11, Mykola Kvach wrote:
> > From: Mirela Simonovic <mirela.simonovic@xxxxxxxxxx>
> >
> > The MMU needs to be enabled in the resume flow before the context
> > can be restored (we need to be able to access the context data by
> > virtual address in order to restore it). The configuration of system
> > registers prior to branching to the routine that sets up the page
> > tables is copied from xen/arch/arm/arm64/head.S.
> > After the MMU is enabled, the content of TTBR0_EL2 is changed to
> > point to init_ttbr (page tables used at runtime).
> >
> > At boot the init_ttbr variable is updated when a secondary CPU is
> > hotplugged. In the scenario where there is only one physical CPU in
> > the system, the init_ttbr would not be initialized for the use in
> > resume flow. To get the variable initialized in all scenarios in this
> > patch we add that the boot CPU updates init_ttbr after it sets the
> > page tables for runtime.
> >
> > 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 V3:
> > - updated commit message
> > - instead of using create_page_tables, enable_mmu, and 
> > mmu_init_secondary_cpu,
> >    the existing function enable_secondary_cpu_mm is now used
> > - prepare_secondary_mm (previously init_secondary_pagetables in the previous
> >    patch series) is now called at the end of start_xen instead of
> >    setup_pagetables. Calling it in the previous location caused a crash
> > - add early printk init during resume
> >
> > Changes in V2:
> > - moved hyp_resume to head.S to place it near the rest of the start code
> > - simplified the code in hyp_resume by using existing functions such as
> >    check_cpu_mode, cpu_init, create_page_tables, and enable_mmu
> > ---
> >   xen/arch/arm/arm64/head.S | 23 +++++++++++++++++++++++
> >   xen/arch/arm/setup.c      |  8 ++++++++
> >   2 files changed, 31 insertions(+)
> >
> > diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
> > index 3522c497c5..fab2812e54 100644
> > --- a/xen/arch/arm/arm64/head.S
> > +++ b/xen/arch/arm/arm64/head.S
> > @@ -564,6 +564,29 @@ END(efi_xen_start)
> >   #ifdef CONFIG_SYSTEM_SUSPEND
> >
> >   FUNC(hyp_resume)
> > +        msr   DAIFSet, 0xf           /* Disable all interrupts */
>
> Surely we should be here with interrupts disabled. No?

You are right, I overlooked this and left the code unchanged from a
previous patch series.
According to the Power State Coordination Interface (DEN0022F.b 1.3):
```
6.4.3.3 Exceptions
The appropriate asynchronous exception masks must be set when starting
up the core at the Exception
level from which the call was made, or at ELns. Typically, this means
that for the Exception level where
execution is restarting:

If starting in AArch64 state, the SPSR_ELx.{D,A,I,F} bits must be set
to {1, 1, 1, 1}. ELx is the
Exception level being returned from.
```

The ARM Trusted Firmware code enforces this correctly here:
https://elixir.bootlin.com/arm-trusted-firmware/v2.13.0/source/lib/psci/psci_common.c#L869

So, the code should indeed expect DAIF bits to be set on resume. I
will update the patch accordingly.

>
> > +
> > +        tlbi  alle2
> > +        dsb   sy                     /* Ensure completion of TLB flush */
>
> This doesn't exist when booting Xen and I am not sure why we would need
> it for resume as we already nuke the TLbs in enable_mmu. Can you clarify?

You're absolutely right — that line is a leftover from earlier changes
when the memory handling logic was being reorganized.
It's no longer necessary because enable_mmu already handles TLB
invalidation, including the TLBI and DSB instructions.
I'll remove it in the next version. Thanks for catching this!

>
> > +        isb
> > +
> > +        ldr   x0, =start
> > +        adr   x19, start             /* x19 := paddr (start) */
> > +        sub   x20, x19, x0           /* x20 := phys-offset */
>
> Looking at the code, I wonder if it is still necessary to set x19 and
> x20 for booting secondary CPUs and resume. There doesn't seem to be any
> use of the registers.

x20 is still required during resume. It's used inside
enable_secondary_cpu_mm via the load_paddr macro.
So although x19 may no longer be necessary in this context, x20 is
still used and needs to be set beforehand.

>
> > +
> > +        /* 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   lr, =mmu_resumed
> > +        b     enable_secondary_cpu_mm
> > +
> > +mmu_resumed:
> >           b .
> >   END(hyp_resume)
> >
> > diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
> > index ffcae900d7..3a89ac436b 100644
> > --- a/xen/arch/arm/setup.c
> > +++ b/xen/arch/arm/setup.c
> > @@ -508,6 +508,14 @@ void asmlinkage __init start_xen(unsigned long 
> > fdt_paddr)
> >       for_each_domain( d )
> >           domain_unpause_by_systemcontroller(d);
> >
> > +#ifdef CONFIG_SYSTEM_SUSPEND
> > +    /*
> > +     * It is called to initialize init_ttbr.
> > +     * Without this call, Xen gets stuck after resuming.
>
> This is not a very descriptive comment. But, you seem to make the
> assumption that prepare_secondary_mm() can be called on the boot CPU.
> This is not always the case. For instance on arm32, it will allocate
> memory and overwrite the per-cpu page-tables pointer (not great). This
> will also soon be the case for arm64.
>
> Furthermore, this call reminded me that the secondary CPU page-tables
> are not freed when turning off a CPU. So they will leak. Not yet a
> problem for arm64 though.
>
> So overall, I think we need a separate function that will be prepare
> init_ttbr for a given CPU (not allocate any memory). This will then need
> to be called from the suspend helper.

Thank you for the detailed explanation.

I will rework this part to avoid calling prepare_secondary_mm() on
the boot CPU. As suggested, I plan to introduce a dedicated helper
function that will only initialize init_ttbr without allocating
memory and call it  from the suspend helper.

>
> > +     */
>  > +    prepare_secondary_mm(0);> +#endif
> > +
> >       /* Switch on to the dynamically allocated stack for the idle vcpu
> >        * since the static one we're running on is about to be freed. */
> >       memcpy(idle_vcpu[0]->arch.cpu_info, get_cpu_info(),
>
> Cheers,
>
> --
> Julien Grall
>

Thank you for reviewing this patch series.

Best regards,
Mykola



 


Rackspace

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