arm64: kernel: Add support for hibernate/suspend-to-disk
Subsystems (5)
v2 cover arm64: kernel: Add support for hibernate/suspend-to-disk
Hi all,
This version of the series follows Lorenzo's option one, described at [0], when cleaning executable code that may be held in data caches after hibernate/resume. Patch ten adds the necessary hook to kernel/power/snapshot.c.
This allows the architecture's hibernate assembly code to clean all the pages that it copies, meaning the for_each_process(); for_each_vma(); version of this can be removed.
The other changes were fixes so that this code works both before and after Ard Biesheuvel's 'relax Image placement rules' series [1] that moves the kernel text out of the linear map.
Finally the series has picked up Lorenzo's t0sz fix [2], as it refactors all of those changes out, and the first four patches of kexec v10, [3].
(Version one here: [4])
James
[0] http://lists.infradead.org/pipermail/linux-arm-kernel/2015-October/380153.html
[1] http://www.spinics.net/lists/arm-kernel/msg446929.html
[2] http://www.spinics.net/lists/arm-kernel/msg454862.html
[3] http://lists.infradead.org/pipermail/linux-arm-kernel/2015-October/379268.html
[4] http://lists.infradead.org/pipermail/linux-arm-kernel/2015-October/376450.html
AKASHI Takahiro (1):
arm64: kvm: allows kvm cpu hotplug
Geoff Levand (3):
arm64: Fold proc-macros.S into assembler.h
arm64: Convert hcalls to use HVC immediate value
arm64: Add new hcall HVC_CALL_FUNC
James Morse (6):
arm64: kernel: Rework finisher callback out of __cpu_suspend_enter().
arm64: Change cpu_resume() to enable mmu early then access sleep_sp by
va
arm64: kernel: Include _AC definition in page.h
arm64: Promote KERNEL_START/KERNEL_END definitions to a header file PM / Hibernate: clean cached pages on architectures that require it
arm64: kernel: Add support for hibernate/suspend-to-disk.
Lorenzo Pieralisi (1):
arm64: kernel: fix tcr_el1.t0sz restore on systems with extended idmap
arch/arm/include/asm/kvm_host.h | 10 +- arch/arm/include/asm/kvm_mmu.h | 1 + arch/arm/kvm/arm.c | 79 ++++---- arch/arm/kvm/mmu.c | 5 + arch/arm64/Kconfig | 3 + arch/arm64/include/asm/assembler.h | 48 ++++- arch/arm64/include/asm/kvm_host.h | 16 +- arch/arm64/include/asm/kvm_mmu.h | 1 + arch/arm64/include/asm/memory.h | 3 + arch/arm64/include/asm/page.h | 2 + arch/arm64/include/asm/suspend.h | 31 +++- arch/arm64/include/asm/virt.h | 49 +++++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/asm-offsets.c | 9 +- arch/arm64/kernel/head.S | 6 +- arch/arm64/kernel/hibernate-asm.S | 118 ++++++++++++ arch/arm64/kernel/hibernate.c | 359 +++++++++++++++++++++++++++++++++++++ arch/arm64/kernel/hyp-stub.S | 43 +++-- arch/arm64/kernel/setup.c | 1 - arch/arm64/kernel/sleep.S | 148 ++++++--------- arch/arm64/kernel/suspend.c | 99 ++++------ arch/arm64/kernel/vmlinux.lds.S | 15 ++ arch/arm64/kvm/hyp-init.S | 34 +++- arch/arm64/kvm/hyp.S | 44 ++++- arch/arm64/mm/cache.S | 2 - arch/arm64/mm/proc-macros.S | 64 ------- arch/arm64/mm/proc.S | 30 +--- kernel/power/snapshot.c | 4 + 28 files changed, 900 insertions(+), 325 deletions(-) create mode 100644 arch/arm64/kernel/hibernate-asm.S create mode 100644 arch/arm64/kernel/hibernate.c delete mode 100644 arch/arm64/mm/proc-macros.S
Signature · 1 line
2.1.4
PATCH v2 1/11 arm64: kernel: fix tcr_el1.t0sz restore on systems with extended idmap
From: Lorenzo Pieralisi <[email protected]>
Commit dd006da21646 ("arm64: mm: increase VA range of identity map") introduced a mechanism to extend the virtual memory map range to support arm64 systems with system RAM located at very high offset, where the identity mapping used to enable/disable the MMU requires additional translation levels to map the physical memory at an equal virtual offset.
The kernel detects at boot time the tcr_el1.t0sz value required by the identity mapping and sets-up the tcr_el1.t0sz register field accordingly, any time the identity map is required in the kernel (ie when enabling the MMU).
After enabling the MMU, in the cold boot path the kernel resets the tcr_el1.t0sz to its default value (ie the actual configuration value for the system virtual address space) so that after enabling the MMU the memory space translated by ttbr0_el1 is restored as expected.
Commit dd006da21646 ("arm64: mm: increase VA range of identity map") also added code to set-up the tcr_el1.t0sz value when the kernel resumes from low-power states with the MMU off through cpu_resume() in order to effectively use the identity mapping to enable the MMU but failed to add the code required to restore the tcr_el1.t0sz to its default value, when the core returns to the kernel with the MMU enabled, so that the kernel might end up running with tcr_el1.t0sz value set-up for the identity mapping which can be lower than the value required by the actual virtual address space, resulting in an erroneous set-up.
This patchs adds code in the resume path that restores the tcr_el1.t0sz default value upon core resume, mirroring this way the cold boot path behaviour therefore fixing the issue.
--- arch/arm64/kernel/suspend.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-)
arch/arm64/kernel/suspend.c +13 -9
@@ -80,17 +80,21 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))if (ret ==0 ) {/* * We are resuming from reset with TTBR0_EL1 set to the -* idmap to enable the MMU; restore the active_mm mappings in -* TTBR0_EL1 unless the active_mm == &init_mm, in which case -* the thread entered cpu_suspend with TTBR0_EL1 set to -* reserved TTBR0 page tables and should be restored as such. +* idmap to enable the MMU; set the TTBR0 to the reserved +* page tables to prevent speculative TLB allocations, flush +* the local tlb and set the default tcr_el1.t0sz so that +* the TTBR0 address space set-up is properly restored. +* If the current active_mm != &init_mm we entered cpu_suspend +* with mappings in TTBR0 that must be restored, so we switch +* them back to complete the address space configuration +* restoration before returning. */ -if (mm == &init_mm) -cpu_set_reserved_ttbr0 (); -else -cpu_switch_mm (mm->pgd, mm); - +cpu_set_reserved_ttbr0 ();flush_tlb_all (); +cpu_set_default_tcr_t0sz (); + +if (mm != &init_mm) +cpu_switch_mm (mm->pgd, mm);/* * Restore per-cpu offset before any kernel
Signature · 1 line
2.1.4
PATCH v2 2/11 arm64: Fold proc-macros.S into assembler.h
In reply to James MorseFrom: Geoff Levand <[email protected]>
To allow the assembler macros defined in arch/arm64/mm/proc-macros.S to be used outside the mm code move the contents of proc-macros.S to asm/assembler.h. Also, delete proc-macros.S, and fix up all references to proc-macros.S.
--- arch/arm64/include/asm/assembler.h | 48 +++++++++++++++++++++++++++- arch/arm64/kernel/head.S | 1 - arch/arm64/kvm/hyp-init.S | 1 - arch/arm64/mm/cache.S | 2 -- arch/arm64/mm/proc-macros.S | 64 -------------------------------------- arch/arm64/mm/proc.S | 3 -- 6 files changed, 47 insertions(+), 72 deletions(-) delete mode 100644 arch/arm64/mm/proc-macros.S
arch/arm64/include/asm/assembler.h +47 -1
@@ -1,5 +1,5 @@/* -* Based on arch/arm/include/asm/assembler.h +* * Based on arch/arm/include/asm/assembler.h, arch/arm/mm/proc-macros.S * * Copyright (C) 1996-2000 Russell King * Copyright (C) 2012 ARM Ltd.
@@ -23,6 +23,8 @@#ifndef __ASM_ASSEMBLER_H#define __ASM_ASSEMBLER_H +#include <asm/asm-offsets.h> +#include <asm/pgtable-hwdef.h> #include <asm/ptrace.h> #include <asm/thread_info.h>
@@ -193,4 +195,48 @@ lr .req x30 // link register str \src, [\tmp, :lo12:\sym] .endm +/* + * vma_vm_mm - get mm pointer from vma pointer (vma->vm_mm) + */ + .macro vma_vm_mm, rd, rn + ldr \rd, [\rn, #VMA_VM_MM] + .endm + +/* + * mmid - get context id from mm pointer (mm->context.id) + */ + .macro mmid, rd, rn + ldr \rd, [\rn, #MM_CONTEXT_ID] + .endm + +/* + * dcache_line_size - get the minimum D-cache line size from the CTR register. + */ + .macro dcache_line_size, reg, tmp + mrs \tmp, ctr_el0 // read CTR + ubfm \tmp, \tmp, #16, #19 // cache line size encoding + mov \reg, #4 // bytes per word + lsl \reg, \reg, \tmp // actual cache line size + .endm + +/* + * icache_line_size - get the minimum I-cache line size from the CTR register. + */ + .macro icache_line_size, reg, tmp + mrs \tmp, ctr_el0 // read CTR + and \tmp, \tmp, #0xf // cache line size encoding + mov \reg, #4 // bytes per word + lsl \reg, \reg, \tmp // actual cache line size + .endm + +/* + * tcr_set_idmap_t0sz - update TCR.T0SZ so that we can load the ID map + */ + .macro tcr_set_idmap_t0sz, valreg, tmpreg +#ifndef CONFIG_ARM64_VA_BITS_48 + ldr_l \tmpreg, idmap_t0sz + bfi \valreg, \tmpreg, #TCR_T0SZ_OFFSET, #TCR_TxSZ_WIDTH +#endif + .endm + #endif /* __ASM_ASSEMBLER_H */
arch/arm64/kernel/head.S +0 -1
@@ -31,7 +31,6 @@ #include <asm/cputype.h> #include <asm/memory.h> #include <asm/thread_info.h> -#include <asm/pgtable-hwdef.h> #include <asm/pgtable.h> #include <asm/page.h> #include <asm/virt.h>
arch/arm64/kvm/hyp-init.S +0 -1
@@ -20,7 +20,6 @@ #include <asm/assembler.h> #include <asm/kvm_arm.h> #include <asm/kvm_mmu.h> -#include <asm/pgtable-hwdef.h> .text .pushsection .hyp.idmap.text, "ax"
arch/arm64/mm/cache.S +0 -2
@@ -24,8 +24,6 @@ #include <asm/cpufeature.h> #include <asm/alternative.h> -#include "proc-macros.S" - /* * flush_icache_range(start,end) *
arch/arm64/mm/proc-macros.S deleted +0 -64
64 lines not on this page · raw message
arch/arm64/mm/proc.S +0 -3
@@ -23,11 +23,8 @@ #include <asm/assembler.h> #include <asm/asm-offsets.h> #include <asm/hwcap.h> -#include <asm/pgtable-hwdef.h> #include <asm/pgtable.h> -#include "proc-macros.S" - #ifdef CONFIG_ARM64_64K_PAGES #define TCR_TG_FLAGS TCR_TG0_64K | TCR_TG1_64K #else
Signature · 1 line
2.1.4
PATCH v2 2/11 arm64: Fold proc-macros.S into assembler.h
Quoted 24 lines · James Morse
From: Geoff Levand <[email protected]>
To allow the assembler macros defined in
arch/arm64/mm/proc-macros.Sto be used outside the mm code move the contents ofproc-macros.Stoasm/assembler.h. Also, deleteproc-macros.S, and fix up all references toproc-macros.S.Signed-off-by Geoff Levand <[email protected]>Signed-off-by James Morse <[email protected]>--- arch/arm64/include/asm/assembler.h | 48 +++++++++++++++++++++++++++- arch/arm64/kernel/head.S | 1 - arch/arm64/kvm/hyp-init.S | 1 - arch/arm64/mm/cache.S | 2 -- arch/arm64/mm/proc-macros.S | 64 -------------------------------------- arch/arm64/mm/proc.S | 3 -- 6 files changed, 47 insertions(+), 72 deletions(-) delete mode 100644 arch/arm64/mm/proc-macros.Sarch/arm64/include/asm/assembler.h +0
-0
arch/arm64/include/asm/assembler.h line 2
Quoted 3 lines
arch/arm64/include/asm/assembler.h +1
-1@@ -1,5 +1,5 @@/* -* Based on arch/arm/include/asm/assembler.h +* * Based on arch/arm/include/asm/assembler.h, arch/arm/mm/proc-macros.S
Why the two stars?
Otherwise looks ok.
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
PATCH v2 2/11 arm64: Fold proc-macros.S into assembler.h
Hi,
Quoted 4 lines · Pavel Machek
Quoted 1 line · James Morse
From: Geoff Levand <[email protected]>
Why the two stars?
I have a newer version that fixed that typo in
my kexec-v11 branch:
-Geoff
PATCH v2 3/11 arm64: Convert hcalls to use HVC immediate value
In reply to James MorseFrom: Geoff Levand <[email protected]>
The existing arm64 hcall implementations are limited in that they only allow for two distinct hcalls; with the x0 register either zero or not zero. Also, the API of the hyp-stub exception vector routines and the KVM exception vector routines differ; hyp-stub uses a non-zero value in x0 to implement __hyp_set_vectors, whereas KVM uses it to implement kvm_call_hyp.
To allow for additional hcalls to be defined and to make the arm64 hcall API more consistent across exception vector routines, change the hcall implementations to use the 16 bit immediate value of the HVC instruction to specify the hcall type.
Define three new preprocessor macros HVC_CALL_HYP, HVC_GET_VECTORS, and HVC_SET_VECTORS to be used as hcall type specifiers and convert the existing __hyp_get_vectors(), __hyp_set_vectors() and kvm_call_hyp() routines to use these new macros when executing an HVC call. Also, change the corresponding hyp-stub and KVM el1_sync exception vector routines to use these new macros.
--- arch/arm64/include/asm/virt.h | 27 +++++++++++++++++++++++++++ arch/arm64/kernel/hyp-stub.S | 32 +++++++++++++++++++++----------- arch/arm64/kvm/hyp.S | 16 +++++++++------- 3 files changed, 57 insertions(+), 18 deletions(-)
arch/arm64/include/asm/virt.h +27 -0
@@ -18,6 +18,33 @@#ifndef __ASM__VIRT_H#define __ASM__VIRT_H +/* +* The arm64 hcall implementation uses the ISS field of the ESR_EL2 register to +* specify the hcall type. The exception handlers are allowed to use registers +* x17 and x18 in their implementation. Any routine issuing an hcall must not +* expect these registers to be preserved. +*/ + +/* +* HVC_CALL_HYP - Execute a hyp routine. +*/ + +#define HVC_CALL_HYP 0 + +/* +* HVC_GET_VECTORS - Return the value of the vbar_el2 register. +*/ + +#define HVC_GET_VECTORS 1 + +/* +* HVC_SET_VECTORS - Set the value of the vbar_el2 register. +* +* @x0: Physical address of the new vector table. +*/ + +#define HVC_SET_VECTORS 2 +#define BOOT_CPU_MODE_EL1 (0xe11)#define BOOT_CPU_MODE_EL2 (0xe12)
arch/arm64/kernel/hyp-stub.S +21 -11
@@ -22,6 +22,7 @@ #include <linux/irqchip/arm-gic-v3.h> #include <asm/assembler.h> +#include <asm/kvm_arm.h> #include <asm/ptrace.h> #include <asm/virt.h>
@@ -53,14 +54,22 @@ ENDPROC(__hyp_stub_vectors) .align 11 el1_sync: - mrs x1, esr_el2 - lsr x1, x1, #26 - cmp x1, #0x16 + mrs x18, esr_el2 + lsr x17, x18, #ESR_ELx_EC_SHIFT + and x18, x18, #ESR_ELx_ISS_MASK + + cmp x17, #ESR_ELx_EC_HVC64 b.ne 2f // Not an HVC trap - cbz x0, 1f - msr vbar_el2, x0 // Set vbar_el2 + + cmp x18, #HVC_GET_VECTORS + b.ne 1f + mrs x0, vbar_el2 b 2f -1: mrs x0, vbar_el2 // Return vbar_el2 + +1: cmp x18, #HVC_SET_VECTORS + b.ne 2f + msr vbar_el2, x0 + 2: eret ENDPROC(el1_sync)
@@ -100,11 +109,12 @@ ENDPROC(\label) * initialisation entry point. */ -ENTRY(__hyp_get_vectors) - mov x0, xzr - // fall through ENTRY(__hyp_set_vectors) - hvc #0 + hvc #HVC_SET_VECTORS ret -ENDPROC(__hyp_get_vectors) ENDPROC(__hyp_set_vectors) + +ENTRY(__hyp_get_vectors) + hvc #HVC_GET_VECTORS + ret +ENDPROC(__hyp_get_vectors)
arch/arm64/kvm/hyp.S +9 -7
@@ -29,6 +29,7 @@ #include <asm/kvm_asm.h> #include <asm/kvm_mmu.h> #include <asm/memory.h> +#include <asm/virt.h> #define CPU_GP_REG_OFFSET(x) (CPU_GP_REGS + x) #define CPU_XREG_OFFSET(x) CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x)
@@ -924,12 +925,9 @@ __hyp_panic_str: * in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c). Return values are * passed in r0 and r1. * - * A function pointer with a value of 0 has a special meaning, and is - * used to implement __hyp_get_vectors in the same way as in - * arch/arm64/kernel/hyp_stub.S. */ ENTRY(kvm_call_hyp) - hvc #0 + hvc #HVC_CALL_HYP ret ENDPROC(kvm_call_hyp)
@@ -960,6 +958,7 @@ el1_sync: // Guest trapped into EL2 mrs x1, esr_el2 lsr x2, x1, #ESR_ELx_EC_SHIFT + and x0, x1, #ESR_ELx_ISS_MASK cmp x2, #ESR_ELx_EC_HVC64 b.ne el1_trap
@@ -968,15 +967,18 @@ el1_sync: // Guest trapped into EL2 cbnz x3, el1_trap // called HVC /* Here, we're pretty sure the host called HVC. */ + mov x18, x0 pop x2, x3 pop x0, x1 - /* Check for __hyp_get_vectors */ - cbnz x0, 1f + cmp x18, #HVC_GET_VECTORS + b.ne 1f mrs x0, vbar_el2 b 2f -1: push lr, xzr +1: /* Default to HVC_CALL_HYP. */ + + push lr, xzr /* * Compute the function address in EL2, and shuffle the parameters.
Signature · 1 line
2.1.4
PATCH v2 4/11 arm64: Add new hcall HVC_CALL_FUNC
In reply to James MorseFrom: Geoff Levand <[email protected]>
Add the new hcall HVC_CALL_FUNC that allows execution of a function at EL2. During CPU reset the CPU must be brought to the exception level it had on entry to the kernel. The HVC_CALL_FUNC hcall will provide the mechanism needed for this exception level switch.
To allow the HVC_CALL_FUNC exception vector to work without a stack, which is needed to support an hcall at CPU reset, this implementation uses register x18 to store the link register across the caller provided function. This dictates that the caller provided function must preserve the contents of register x18.
--- arch/arm64/include/asm/virt.h | 13 +++++++++++++ arch/arm64/kernel/hyp-stub.S | 13 ++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-)
arch/arm64/include/asm/virt.h +13 -0
@@ -45,6 +45,19 @@#define HVC_SET_VECTORS 2 +/* +* HVC_CALL_FUNC - Execute a function at EL2. +* +* @x0: Physical address of the function to be executed. +* @x1: Passed as the first argument to the function. +* @x2: Passed as the second argument to the function. +* @x3: Passed as the third argument to the function. +* +* The called function must preserve the contents of register x18. +*/ + +#define HVC_CALL_FUNC 3 +#define BOOT_CPU_MODE_EL1 (0xe11)#define BOOT_CPU_MODE_EL2 (0xe12)
arch/arm64/kernel/hyp-stub.S +12 -1
@@ -67,8 +67,19 @@ el1_sync: b 2f 1: cmp x18, #HVC_SET_VECTORS - b.ne 2f + b.ne 1f msr vbar_el2, x0 + b 2f + +1: cmp x18, #HVC_CALL_FUNC + b.ne 2f + mov x18, lr + mov lr, x0 + mov x0, x1 + mov x1, x2 + mov x2, x3 + blr lr + mov lr, x18 2: eret ENDPROC(el1_sync)
Signature · 1 line
2.1.4
PATCH v2 5/11 arm64: kvm: allows kvm cpu hotplug
In reply to James MorseFrom: AKASHI Takahiro <[email protected]>
The current kvm implementation on arm64 does cpu-specific initialization at system boot, and has no way to gracefully shutdown a core in terms of kvm. This prevents, especially, kexec from rebooting the system on a boot core in EL2.
This patch adds a cpu tear-down function and also puts an existing cpu-init code into a separate function, kvm_arch_hardware_disable() and kvm_arch_hardware_enable() respectively.
We don't need arm64-specific cpu hotplug hook any more.
Since this patch modifies common part of code between arm and arm64, one stub definition, __cpu_reset_hyp_mode(), is added on arm side to avoid compiling errors.
--- arch/arm/include/asm/kvm_host.h | 10 ++++- arch/arm/include/asm/kvm_mmu.h | 1 + arch/arm/kvm/arm.c | 79 ++++++++++++++++++--------------------- arch/arm/kvm/mmu.c | 5 +++ arch/arm64/include/asm/kvm_host.h | 16 +++++++- arch/arm64/include/asm/kvm_mmu.h | 1 + arch/arm64/include/asm/virt.h | 9 +++++ arch/arm64/kvm/hyp-init.S | 33 ++++++++++++++++ arch/arm64/kvm/hyp.S | 32 ++++++++++++++-- 9 files changed, 138 insertions(+), 48 deletions(-)
arch/arm/include/asm/kvm_host.h +9 -1
@@ -211,6 +211,15 @@ static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,kvm_call_hyp ((void *)hyp_stack_ptr, vector_ptr, pgd_ptr); } +static inline void __cpu_reset_hyp_mode (phys_addr_t boot_pgd_ptr, +phys_addr_t phys_idmap_start) +{ +/* +* TODO +* kvm_call_reset(boot_pgd_ptr, phys_idmap_start); +*/ +} +static inline int kvm_arch_dev_ioctl_check_extension (long ext) {return 0 ;
@@ -223,7 +232,6 @@ void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot);struct kvm_vcpu *kvm_mpidr_to_vcpu (struct kvm *kvm,unsigned long mpidr); -static inline void kvm_arch_hardware_disable (void ) {}static inline void kvm_arch_hardware_unsetup (void ) {}static inline void kvm_arch_sync_events (struct kvm *kvm) {}static inline void kvm_arch_vcpu_uninit (struct kvm_vcpu *vcpu) {}
arch/arm/include/asm/kvm_mmu.h +1 -0
@@ -66,6 +66,7 @@ void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu);phys_addr_t kvm_mmu_get_httbr (void );phys_addr_t kvm_mmu_get_boot_httbr (void );phys_addr_t kvm_get_idmap_vector (void ); +phys_addr_t kvm_get_idmap_start (void );int kvm_mmu_init (void );void kvm_clear_hyp_idmap (void );
arch/arm/kvm/arm.c +37 -42
149 lines not on this page · raw message
arch/arm/kvm/mmu.c +5 -0
@@ -1644,6 +1644,11 @@ phys_addr_t kvm_get_idmap_vector(void)return hyp_idmap_vector; } +phys_addr_t kvm_get_idmap_start (void ) +{ +return hyp_idmap_start; +} +int kvm_mmu_init (void ) {int err;
arch/arm64/include/asm/kvm_host.h +15 -1
@@ -220,6 +220,7 @@ struct kvm_vcpu *kvm_arm_get_running_vcpu(void);struct kvm_vcpu *__percpu *kvm_get_running_vcpus (void );u64 kvm_call_hyp (void *hypfn, ...); +void kvm_call_reset (phys_addr_t boot_pgd_ptr,phys_addr_t phys_idmap_start);void force_vm_exit (const cpumask_t *mask);void kvm_mmu_wp_memory_region (struct kvm *kvm,int slot);
@@ -244,7 +245,20 @@ static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr, hyp_stack_ptr, vector_ptr); } -static inline void kvm_arch_hardware_disable (void ) {} +static inline void __cpu_reset_hyp_mode (phys_addr_t boot_pgd_ptr, +phys_addr_t phys_idmap_start) +{ +/* +* Call reset code, and switch back to stub hyp vectors. +*/ +kvm_call_reset (boot_pgd_ptr, phys_idmap_start); +} + +struct vgic_sr_vectors { +void *save_vgic; +void *restore_vgic; +}; +static inline void kvm_arch_hardware_unsetup (void ) {}static inline void kvm_arch_sync_events (struct kvm *kvm) {}static inline void kvm_arch_vcpu_uninit (struct kvm_vcpu *vcpu) {}
arch/arm64/include/asm/kvm_mmu.h +1 -0
@@ -98,6 +98,7 @@ void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu);phys_addr_t kvm_mmu_get_httbr (void );phys_addr_t kvm_mmu_get_boot_httbr (void );phys_addr_t kvm_get_idmap_vector (void ); +phys_addr_t kvm_get_idmap_start (void );int kvm_mmu_init (void );void kvm_clear_hyp_idmap (void );
arch/arm64/include/asm/virt.h +9 -0
@@ -58,9 +58,18 @@#define HVC_CALL_FUNC 3 +/* +* HVC_RESET_CPU - Reset cpu in EL2 to initial state. +* +* @x0: entry address in trampoline code in va +* @x1: identical mapping page table in pa +*/ +#define BOOT_CPU_MODE_EL1 (0xe11)#define BOOT_CPU_MODE_EL2 (0xe12) +#define HVC_RESET_CPU 4 +#ifndef __ASSEMBLY__/*
arch/arm64/kvm/hyp-init.S +33 -0
@@ -139,6 +139,39 @@ merged: eret ENDPROC(__kvm_hyp_init) + /* + * x0: HYP boot pgd + * x1: HYP phys_idmap_start + */ +ENTRY(__kvm_hyp_reset) + /* We're in trampoline code in VA, switch back to boot page tables */ + msr ttbr0_el2, x0 + isb + + /* Invalidate the old TLBs */ + tlbi alle2 + dsb sy + + /* Branch into PA space */ + adr x0, 1f + bfi x1, x0, #0, #PAGE_SHIFT + br x1 + + /* We're now in idmap, disable MMU */ +1: mrs x0, sctlr_el2 + ldr x1, =SCTLR_EL2_FLAGS + bic x0, x0, x1 // Clear SCTL_M and etc + msr sctlr_el2, x0 + isb + + /* Install stub vectors */ + adrp x0, __hyp_stub_vectors + add x0, x0, #:lo12:__hyp_stub_vectors + msr vbar_el2, x0 + + eret +ENDPROC(__kvm_hyp_reset) + .ltorg .popsection
arch/arm64/kvm/hyp.S +28 -4
@@ -931,6 +931,11 @@ ENTRY(kvm_call_hyp) ret ENDPROC(kvm_call_hyp) +ENTRY(kvm_call_reset) + hvc #HVC_RESET_CPU + ret +ENDPROC(kvm_call_reset) + .macro invalid_vector label, target .align 2 \label:
@@ -974,10 +979,27 @@ el1_sync: // Guest trapped into EL2 cmp x18, #HVC_GET_VECTORS b.ne 1f mrs x0, vbar_el2 - b 2f - -1: /* Default to HVC_CALL_HYP. */ + b do_eret + /* jump into trampoline code */ +1: cmp x18, #HVC_RESET_CPU + b.ne 2f + /* + * Entry point is: + * TRAMPOLINE_VA + * + (__kvm_hyp_reset - (__hyp_idmap_text_start & PAGE_MASK)) + */ + adrp x2, __kvm_hyp_reset + add x2, x2, #:lo12:__kvm_hyp_reset + adrp x3, __hyp_idmap_text_start + add x3, x3, #:lo12:__hyp_idmap_text_start + and x3, x3, PAGE_MASK + sub x2, x2, x3 + ldr x3, =TRAMPOLINE_VA + add x2, x2, x3 + br x2 // no return + +2: /* Default to HVC_CALL_HYP. */ push lr, xzr /*
@@ -991,7 +1013,9 @@ el1_sync: // Guest trapped into EL2 blr lr pop lr, xzr -2: eret + +do_eret: + eret el1_trap: /*
Signature · 1 line
2.1.4
PATCH v2 6/11 arm64: kernel: Rework finisher callback out of __cpu_suspend_enter().
In reply to James MorseHibernate could make use of the cpu_suspend() code to save/restore cpu state, however it needs to be able to return '0' from the 'finisher'.
Rework cpu_suspend() so that the finisher is called from C code, independently from the save/restore of cpu state. Space to save the context in is allocated in the caller's stack frame, and passed into __cpu_suspend_enter().
Hibernate's use of this API will look like a copy of the cpu_suspend() function.
---
Changes since v1:
* Added/fixed two comments identified by Lorenzo
* Rebased onto Lorenzo's tcr_el1.t0sz fix.
arch/arm64/include/asm/suspend.h | 20 +++++++++ arch/arm64/kernel/asm-offsets.c | 2 + arch/arm64/kernel/sleep.S | 93 ++++++++++++++-------------------------- arch/arm64/kernel/suspend.c | 89 ++++++++++++++++++++++---------------- 4 files changed, 108 insertions(+), 96 deletions(-)
arch/arm64/include/asm/suspend.h +20 -0
@@ -2,6 +2,7 @@#define __ASM_SUSPEND_H#define NR_CTX_REGS 11 +#define NR_CALLEE_SAVED_REGS 12/* * struct cpu_suspend_ctx must be 16-byte aligned since it is allocated on
@@ -21,6 +22,25 @@ struct sleep_save_sp { phys_addr_t save_ptr_stash_phys; }; +/* +* Memory to save the cpu state is allocated on the stack by +* __cpu_suspend_enter()'s caller, and populated by __cpu_suspend_enter(). +* This data must survive until cpu_resume() is called. +* +* This struct desribes the size and the layout of the saved cpu state. +* The layout of the callee_saved_regs is defined by the implementation +* of __cpu_suspend_enter(), and cpu_resume(). This struct must be passed +* in by the caller as __cpu_suspend_enter()'s stack-frame is gone once it +* returns, and the data would be subsequently corrupted by the call to the +* finisher. +*/ +struct sleep_stack_data { +struct cpu_suspend_ctx system_regs; +unsigned long callee_saved_regs[NR_CALLEE_SAVED_REGS ]; +}; +extern int cpu_suspend (unsigned long arg,int (*fn)(unsigned long ));extern void cpu_resume (void ); +int __cpu_suspend_enter (struct sleep_stack_data *state); +void __cpu_suspend_exit (struct mm_struct *mm);#endif
arch/arm64/kernel/asm-offsets.c +2 -0
@@ -160,6 +160,8 @@ int main(void)DEFINE (SLEEP_SAVE_SP_SZ ,sizeof (struct sleep_save_sp ));DEFINE (SLEEP_SAVE_SP_PHYS , offsetof(struct sleep_save_sp , save_ptr_stash_phys));DEFINE (SLEEP_SAVE_SP_VIRT , offsetof(struct sleep_save_sp , save_ptr_stash)); +DEFINE (SLEEP_STACK_DATA_SYSTEM_REGS , offsetof(struct sleep_stack_data , system_regs)); +DEFINE (SLEEP_STACK_DATA_CALLEE_REGS , offsetof(struct sleep_stack_data , callee_saved_regs));#endif return 0 ; }
arch/arm64/kernel/sleep.S +33 -60
127 lines not on this page · raw message
arch/arm64/kernel/suspend.c +53 -36
129 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v2 7/11 arm64: Change cpu_resume() to enable mmu early then access sleep_sp by va
In reply to James MorseBy enabling the MMU early in cpu_resume(), the sleep_save_sp and stack can be accessed by VA, which avoids the need to convert-addresses and clean to PoC on the suspend path.
MMU setup is shared with the boot path, meaning the swapper_pg_dir is restored directly: ttbr1_el1 is no longer saved/restored.
struct sleep_save_sp is removed, replacing it with a single array of pointers.
cpu_do_{suspend,resume} could be further reduced to not restore: cpacr_el1, mdscr_el1, tcr_el1, vbar_el1 and sctlr_el1, all of which are set by __cpu_setup(). However these values all contain res0 bits that may be used to enable future features.
--- arch/arm64/include/asm/suspend.h | 7 +---- arch/arm64/kernel/asm-offsets.c | 3 --- arch/arm64/kernel/head.S | 2 +- arch/arm64/kernel/setup.c | 1 - arch/arm64/kernel/sleep.S | 57 ++++++++++++++-------------------------- arch/arm64/kernel/suspend.c | 52 +++--------------------------------- arch/arm64/mm/proc.S | 27 +++++-------------- 7 files changed, 33 insertions(+), 116 deletions(-)
arch/arm64/include/asm/suspend.h +1 -6
@@ -1,7 +1,7 @@#ifndef __ASM_SUSPEND_H#define __ASM_SUSPEND_H -#define NR_CTX_REGS 11 +#define NR_CTX_REGS 10#define NR_CALLEE_SAVED_REGS 12/*
@@ -17,11 +17,6 @@ struct cpu_suspend_ctx {u64 sp; }__aligned(16) ; -struct sleep_save_sp { -phys_addr_t *save_ptr_stash; -phys_addr_t save_ptr_stash_phys; -}; -/* * Memory to save the cpu state is allocated on the stack by * __cpu_suspend_enter()'s caller, and populated by __cpu_suspend_enter().
arch/arm64/kernel/asm-offsets.c +0 -3
@@ -157,9 +157,6 @@ int main(void)DEFINE (CPU_CTX_SP , offsetof(struct cpu_suspend_ctx , sp));DEFINE (MPIDR_HASH_MASK , offsetof(struct mpidr_hash , mask));DEFINE (MPIDR_HASH_SHIFTS , offsetof(struct mpidr_hash , shift_aff)); -DEFINE (SLEEP_SAVE_SP_SZ ,sizeof (struct sleep_save_sp )); -DEFINE (SLEEP_SAVE_SP_PHYS , offsetof(struct sleep_save_sp , save_ptr_stash_phys)); -DEFINE (SLEEP_SAVE_SP_VIRT , offsetof(struct sleep_save_sp , save_ptr_stash));DEFINE (SLEEP_STACK_DATA_SYSTEM_REGS , offsetof(struct sleep_stack_data , system_regs));DEFINE (SLEEP_STACK_DATA_CALLEE_REGS , offsetof(struct sleep_stack_data , callee_saved_regs));#endif
arch/arm64/kernel/head.S +1 -1
@@ -630,7 +630,7 @@ ENDPROC(__secondary_switched) * other registers depend on the function called upon completion */ .section ".idmap.text", "ax" -__enable_mmu: +ENTRY(__enable_mmu) ldr x5, =vectors msr vbar_el1, x5 msr ttbr0_el1, x25 // load TTBR0
arch/arm64/kernel/setup.c +0 -1
@@ -192,7 +192,6 @@ static void __init smp_build_mpidr_hash(void)*/ if (mpidr_hash_size () >4 *num_possible_cpus ())pr_warn ("Large number of MPIDR hash buckets detected\n" ); -__flush_dcache_area (&mpidr_hash,sizeof (struct mpidr_hash )); }static void __init setup_processor (void )
arch/arm64/kernel/sleep.S +20 -37
94 lines not on this page · raw message
arch/arm64/kernel/suspend.c +4 -48
77 lines not on this page · raw message
arch/arm64/mm/proc.S +7 -20
@@ -59,20 +59,17 @@ ENTRY(cpu_do_suspend) mrs x2, tpidr_el0 mrs x3, tpidrro_el0 mrs x4, contextidr_el1 - mrs x5, mair_el1 mrs x6, cpacr_el1 - mrs x7, ttbr1_el1 mrs x8, tcr_el1 mrs x9, vbar_el1 mrs x10, mdscr_el1 mrs x11, oslsr_el1 mrs x12, sctlr_el1 stp x2, x3, [x0] - stp x4, x5, [x0, #16] - stp x6, x7, [x0, #32] - stp x8, x9, [x0, #48] - stp x10, x11, [x0, #64] - str x12, [x0, #80] + stp x4, xzr, [x0, #16] + stp x6, x8, [x0, #32] + stp x9, x10, [x0, #48] + stp x11, x12, [x0, #64] ret ENDPROC(cpu_do_suspend)
@@ -80,29 +77,20 @@ ENDPROC(cpu_do_suspend) * cpu_do_resume - restore CPU register context * * x0: Physical address of context pointer - * x1: ttbr0_el1 to be restored * * Returns: * sctlr_el1 value in x0 */ ENTRY(cpu_do_resume) - /* - * Invalidate local tlb entries before turning on MMU - */ - tlbi vmalle1 ldp x2, x3, [x0] ldp x4, x5, [x0, #16] - ldp x6, x7, [x0, #32] - ldp x8, x9, [x0, #48] - ldp x10, x11, [x0, #64] - ldr x12, [x0, #80] + ldp x6, x8, [x0, #32] + ldp x9, x10, [x0, #48] + ldp x11, x12, [x0, #64] msr tpidr_el0, x2 msr tpidrro_el0, x3 msr contextidr_el1, x4 - msr mair_el1, x5 msr cpacr_el1, x6 - msr ttbr0_el1, x1 - msr ttbr1_el1, x7 tcr_set_idmap_t0sz x8, x7 msr tcr_el1, x8 msr vbar_el1, x9
@@ -113,7 +101,6 @@ ENTRY(cpu_do_resume) ubfx x11, x11, #1, #1 msr oslar_el1, x11 mov x0, x12 - dsb nsh // Make sure local tlb invalidation completed isb ret ENDPROC(cpu_do_resume)
Signature · 1 line
2.1.4
PATCH v2 8/11 arm64: kernel: Include _AC definition in page.h
In reply to James Morsepage.h uses '_AC' in the definition of PAGE_SIZE, but doesn't include linux/const.h where this is defined. This produces build warnings when only asm/page.h is included by asm code.
--- arch/arm64/include/asm/page.h | 2 ++ 1 file changed, 2 insertions(+)
arch/arm64/include/asm/page.h +2 -0
@@ -19,6 +19,8 @@#ifndef __ASM_PAGE_H#define __ASM_PAGE_H +#include <linux/const.h> +/* PAGE_SHIFT determines the page size */ #ifdef CONFIG_ARM64_64K_PAGES #define PAGE_SHIFT 16
Signature · 1 line
2.1.4
PATCH v2 9/11 arm64: Promote KERNEL_START/KERNEL_END definitions to a header file
In reply to James MorseKERNEL_START and KERNEL_END are useful outside head.S, move them to a header file.
--- arch/arm64/include/asm/memory.h | 3 +++ arch/arm64/kernel/head.S | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-)
arch/arm64/include/asm/memory.h +3 -0
@@ -72,6 +72,9 @@#error Top of 64-bit user space clashes with start of module space#endif +#define KERNEL_START _text +#define KERNEL_END _end +/* * Physical vs virtual RAM address space conversion. These are * private definitions which should NOT be used outside memory.h
arch/arm64/kernel/head.S +0 -3
@@ -55,9 +55,6 @@ #define TABLE_SHIFT PUD_SHIFT #endif -#define KERNEL_START _text -#define KERNEL_END _end - /* * Initial memory map attributes. */
Signature · 1 line
2.1.4
PATCH v2 10/11 PM / Hibernate: clean cached pages on architectures that require it
In reply to James MorseSome architectures require code written to memory as if it were data to be 'cleaned' from any data caches so that the processor can fetch them as new instructions.
During resume from hibernate, the snapshot code copies some pages directly, meaning these architectures do not get a chance to perform their cache maintenance. Add a call to flush_icache_range(), which is provided by architectures that require it, to perform the maintenance.
This mirrors the kernel's behaviour when loading kernel modules and when mapping executable pages to user space.
--- kernel/power/snapshot.c | 4 ++++ 1 file changed, 4 insertions(+)
kernel/power/snapshot.c +4 -0
@@ -31,6 +31,7 @@#include <linux/ktime.h> #include <asm/uaccess.h> +#include <asm/cacheflush.h> #include <asm/mmu_context.h> #include <asm/pgtable.h> #include <asm/tlbflush.h>
@@ -1196,9 +1197,12 @@ static unsigned int count_data_pages(void)static inline void do_copy_page (long *dst,long *src) {int n; +unsigned long __maybe_unused start = (unsigned long )dst;for (n =PAGE_SIZE /sizeof (long ); n; n--) *dst++ = *src++; + +flush_icache_range (start, start+PAGE_SIZE ); }
Signature · 1 line
2.1.4
PATCH v2 10/11 PM / Hibernate: clean cached pages on architectures that require it
Hi Pavel, Rafael,
Do you have any feedback on this patch ?
It is fundamental to this series and affects Hibernate core code so if you have any feedback that would be much appreciated.
Thanks a lot,
Lorenzo
Quoted 45 lines · James Morse
Some architectures require code written to memory as if it were data to be 'cleaned' from any data caches so that the processor can fetch them as new instructions.
During resume from hibernate, the snapshot code copies some pages directly, meaning these architectures do not get a chance to perform their cache maintenance. Add a call to
flush_icache_range(), which is provided by architectures that require it, to perform the maintenance.This mirrors the kernel's behaviour when loading kernel modules and when mapping executable pages to user space.
Signed-off-by James Morse <[email protected]>--- kernel/power/snapshot.c | 4 ++++ 1 file changed, 4 insertions(+)kernel/power/snapshot.c +4
-0@@ -31,6 +31,7 @@#include <linux/ktime.h> #include <asm/uaccess.h> +#include <asm/cacheflush.h> #include <asm/mmu_context.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> @@ -1196,9 +1197,12 @@ static unsigned int count_data_pages(void)static inline void do_copy_page (long *dst,long *src) {int n; +unsigned long __maybe_unused start = (unsigned long )dst;for (n =PAGE_SIZE /sizeof (long ); n; n--) *dst++ = *src++; + +flush_icache_range (start, start+PAGE_SIZE ); }Signature · 1 line
2.1.4
PATCH v2 10/11 PM / Hibernate: clean cached pages on architectures that require it
Quoted 6 lines · Lorenzo Pieralisi
Hi Pavel, Rafael,
Do you have any feedback on this patch ?
It is fundamental to this series and affects Hibernate core code so if you have any feedback that would be much appreciated.
I'm really not familiar with the flush_icache_range() interface.
What exactly does it do?
Rafael
Quoted 47 lines · James Morse
Quoted 32 lines
Some architectures require code written to memory as if it were data to be 'cleaned' from any data caches so that the processor can fetch them as new instructions.
During resume from hibernate, the snapshot code copies some pages directly, meaning these architectures do not get a chance to perform their cache maintenance. Add a call to
flush_icache_range(), which is provided by architectures that require it, to perform the maintenance.This mirrors the kernel's behaviour when loading kernel modules and when mapping executable pages to user space.
Signed-off-by James Morse <[email protected]>--- kernel/power/snapshot.c | 4 ++++ 1 file changed, 4 insertions(+)kernel/power/snapshot.c +1
-0@@ -31,6 +31,7 @@#include <linux/ktime.h> #include <asm/uaccess.h> +#include <asm/cacheflush.h> #include <asm/mmu_context.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> @@ -1196,9 +1197,12 @@ static unsigned int count_data_pages(void)static inline void do_copy_page (long *dst,long *src) {kernel/power/snapshot.c static unsigned int count_data_pages(void) · line 1208
Quoted 10 lines
kernel/power/snapshot.c +3
-0int n; +unsigned long __maybe_unused start = (unsigned long )dst;for (n =PAGE_SIZE /sizeof (long ); n; n--) *dst++ = *src++; + +flush_icache_range (start, start+PAGE_SIZE ); }--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center.
PATCH v2 10/11 PM / Hibernate: clean cached pages on architectures that require it
Quoted 11 lines · Rafael J. Wysocki
Quoted 6 lines · Lorenzo Pieralisi
Hi Pavel, Rafael,
Do you have any feedback on this patch ?
It is fundamental to this series and affects Hibernate core code so if you have any feedback that would be much appreciated.
I'm really not familiar with the
flush_icache_range()interface.What exactly does it do?
It is used to sync a memory range that is written into (eg loading modules, copying from snapshot is basically the same thing, reads from storage and restore pages that might well be executable code), in particular to sync the I-cache and the D-cache, eg on arm64 the page that the snapshot code is copying might be executable code that has to be cleaned from the D-cache so that it is made visible to the I-cache.
On x86 it is a NOP AFAIK.
Thanks,
Lorenzo
Quoted 56 lines
Rafael
Quoted 47 lines · James Morse
Quoted 32 lines
Some architectures require code written to memory as if it were data to be 'cleaned' from any data caches so that the processor can fetch them as new instructions.
During resume from hibernate, the snapshot code copies some pages directly, meaning these architectures do not get a chance to perform their cache maintenance. Add a call to
flush_icache_range(), which is provided by architectures that require it, to perform the maintenance.This mirrors the kernel's behaviour when loading kernel modules and when mapping executable pages to user space.
Signed-off-by James Morse <[email protected]>--- kernel/power/snapshot.c | 4 ++++ 1 file changed, 4 insertions(+)kernel/power/snapshot.c +1
-0@@ -31,6 +31,7 @@#include <linux/ktime.h> #include <asm/uaccess.h> +#include <asm/cacheflush.h> #include <asm/mmu_context.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> @@ -1196,9 +1197,12 @@ static unsigned int count_data_pages(void)static inline void do_copy_page (long *dst,long *src) {kernel/power/snapshot.c static unsigned int count_data_pages(void) · line 1208
Quoted 10 lines
kernel/power/snapshot.c +3
-0int n; +unsigned long __maybe_unused start = (unsigned long )dst;for (n =PAGE_SIZE /sizeof (long ); n; n--) *dst++ = *src++; + +flush_icache_range (start, start+PAGE_SIZE ); }--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.htmlSignature · 2 lines
I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center.
PATCH v2 10/11 PM / Hibernate: clean cached pages on architectures that require it
Quoted 13 lines · Lorenzo Pieralisi
Quoted 11 lines · Rafael J. Wysocki
Quoted 6 lines · Lorenzo Pieralisi
Hi Pavel, Rafael,
Do you have any feedback on this patch ?
It is fundamental to this series and affects Hibernate core code so if you have any feedback that would be much appreciated.
I'm really not familiar with the
flush_icache_range()interface.What exactly does it do?
Quoted 8 lines
It is used to sync a memory range that is written into (eg loading modules, copying from snapshot is basically the same thing, reads from storage and restore pages that might well be executable code), in particular to sync the I-cache and the D-cache, eg on arm64 the page that the snapshot code is copying might be executable code that has to be cleaned from the D-cache so that it is made visible to the I-cache.
On x86 it is a NOP AFAIK.
If that's the case, I have no problems with this change as long as the code works on architectures with non-trivial flush_icache_range().
Thanks,
Rafael
PATCH v2 10/11 PM / Hibernate: clean cached pages on architectures that require it
[Cc'ed maintainers of affected arches]
Quoted 21 lines · Rafael J. Wysocki
Quoted 20 lines · Lorenzo Pieralisi
Quoted 11 lines · Rafael J. Wysocki
Quoted 6 lines · Lorenzo Pieralisi
Hi Pavel, Rafael,
Do you have any feedback on this patch ?
It is fundamental to this series and affects Hibernate core code so if you have any feedback that would be much appreciated.
I'm really not familiar with the
flush_icache_range()interface.What exactly does it do?
It is used to sync a memory range that is written into (eg loading modules, copying from snapshot is basically the same thing, reads from storage and restore pages that might well be executable code), in particular to sync the I-cache and the D-cache, eg on arm64 the page that the snapshot code is copying might be executable code that has to be cleaned from the D-cache so that it is made visible to the I-cache.
Quoted 4 lines
Quoted 1 line
On x86 it is a NOP AFAIK.
If that's the case, I have no problems with this change as long as the code works on architectures with non-trivial
flush_icache_range().
I Cc'ed the respective arches maintainers, it should work (it may make resuming a bit slower, owing to the cache syncing), problem is that we have no way of testing it on platforms other than arm/arm64.
How do you want us to go on about this ? Should we add a config option to prevent calling flush_icache_range() on all platforms (where it is not a nop) ?
Thanks a lot !
Lorenzo
PATCH v2 10/11 PM / Hibernate: clean cached pages on architectures that require it
Quoted 24 lines · Lorenzo Pieralisi
[Cc'ed maintainers of affected arches]
Quoted 21 lines · Rafael J. Wysocki
Quoted 20 lines · Lorenzo Pieralisi
Quoted 11 lines · Rafael J. Wysocki
Quoted 6 lines · Lorenzo Pieralisi
Hi Pavel, Rafael,
Do you have any feedback on this patch ?
It is fundamental to this series and affects Hibernate core code so if you have any feedback that would be much appreciated.
I'm really not familiar with the
flush_icache_range()interface.What exactly does it do?
It is used to sync a memory range that is written into (eg loading modules, copying from snapshot is basically the same thing, reads from storage and restore pages that might well be executable code), in particular to sync the I-cache and the D-cache, eg on arm64 the page that the snapshot code is copying might be executable code that has to be cleaned from the D-cache so that it is made visible to the I-cache.
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
On x86 it is a NOP AFAIK.
If that's the case, I have no problems with this change as long as the code works on architectures with non-trivial
flush_icache_range().I Cc'ed the respective arches maintainers, it should work (it may make resuming a bit slower, owing to the cache syncing), problem is that we have no way of testing it on platforms other than arm/arm64.
Sure you can find x86 and x86-64 machine near you?
And as hibernation is only supported on x86 and arm, that should be ok.
Or just merge it to the next and let the world do testing for you...
Quoted 3 lines
How do you want us to go on about this ? Should we add a config option to prevent calling
flush_icache_range()on all platforms (where it is not a nop) ?
Config option is definitely not an option ;-).
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
PATCH v2 10/11 PM / Hibernate: clean cached pages on architectures that require it
Quoted 27 lines · Pavel Machek
Quoted 26 lines · Lorenzo Pieralisi
[Cc'ed maintainers of affected arches]
Quoted 23 lines · Rafael J. Wysocki
Quoted 21 lines · Lorenzo Pieralisi
Quoted 11 lines · Rafael J. Wysocki
Quoted 6 lines · Lorenzo Pieralisi
Hi Pavel, Rafael,
Do you have any feedback on this patch ?
It is fundamental to this series and affects Hibernate core code so if you have any feedback that would be much appreciated.
I'm really not familiar with the
flush_icache_range()interface.What exactly does it do?
It is used to sync a memory range that is written into (eg loading modules, copying from snapshot is basically the same thing, reads from storage and restore pages that might well be executable code), in particular to sync the I-cache and the D-cache, eg on arm64 the page that the snapshot code is copying might be executable code that has to be cleaned from the D-cache so that it is made visible to the I-cache.
On x86 it is a NOP AFAIK.
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
If that's the case, I have no problems with this change as long as the code works on architectures with non-trivial
flush_icache_range().I Cc'ed the respective arches maintainers, it should work (it may make resuming a bit slower, owing to the cache syncing), problem is that we have no way of testing it on platforms other than arm/arm64.
Sure you can find x86 and x86-64 machine near you?
Yes but on x86 this patch is a NOP so testing on it does not really add much.
Quoted 2 lines
And as hibernation is only supported on x86 and arm, that should be ok.
And what are the other arches swsusp_arch_{suspend/resume} there for then ?
I just had a look at arch code implementing swsusp_arch_{suspend/resume}, if it has to work only on x86 and arm we will give it a spin on arm (32-bit) platforms (I really doubt it is going to be even noticeable) and we are done.
Quoted 1 line
Or just merge it to the next and let the world do testing for you...
I wanted to ask before because I am not sure that's something people regularly test and I do not want to end up with regressions that might have been prevented by just enquiring, I am not sure that's something -next will help detect either.
Quoted 5 lines
Quoted 3 lines
How do you want us to go on about this ? Should we add a config option to prevent calling
flush_icache_range()on all platforms (where it is not a nop) ?Config option is definitely not an option ;-).
Ok, thanks.
Lorenzo
PATCH v2 10/11 PM / Hibernate: clean cached pages on architectures that require it
In reply to Lorenzo PieralisiHi,
Quoted 56 lines
-----Original Message-----
From: linux-pm-owner at vger.kernel.org [mailto:linux-pm-
owner at vger.kernel.org] On Behalf Of Lorenzo Pieralisi
Sent: Wednesday, November 11, 2015 7:41 PM
To: James Morse; Rafael J. Wysocki; Pavel Machek
Cc: linux-arm-kernel at lists.infradead.org; linux-pm at vger.kernel.org; Will Deacon; Sudeep Holla; Kevin Kang; Geoff Levand; Catalin Marinas; Mark Rutland; AKASHI Takahiro; wangfei; Marc Zyngier
Subject: Re: [PATCH v2 10/11] PM / Hibernate: clean cached pages on architectures that require itHi Pavel, Rafael,
Do you have any feedback on this patch ?
It is fundamental to this series and affects Hibernate core code so if you have any feedback that would be much appreciated.
Thanks a lot,
LorenzoQuoted 34 lines · James Morse
Some architectures require code written to memory as if it were data to be 'cleaned' from any data caches so that the processor can fetch them as new instructions.
During resume from hibernate, the snapshot code copies some pages directly, meaning these architectures do not get a chance to perform their cache maintenance. Add a call to
flush_icache_range(), which is provided by architectures that require it, to perform the maintenance.This mirrors the kernel's behaviour when loading kernel modules and when mapping executable pages to user space.
Signed-off-by James Morse <[email protected]>--- kernel/power/snapshot.c | 4 ++++ 1 file changed, 4 insertions(+)kernel/power/snapshot.c index renamed from kernel/power/snapshot.c +0
-0
5235dd4e1e2f..139fc449ad75100644kernel/power/snapshot.c +2
-0@@ -31,6 +31,7 @@#include <linux/ktime.h> #include <asm/uaccess.h> +#include <asm/cacheflush.h> #include <asm/mmu_context.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> @@ -1196,9 +1197,12 @@ static unsigned int count_data_pages(void)static inline void do_copy_page (long *dst,long *src) {int n; +unsigned long __maybe_unused start = (unsigned long )dst;
Quoted 5 lines
kernel/power/snapshot.c static unsigned int count_data_pages(void) · line 1206
Quoted 5 lines
kernel/power/snapshot.c +2
-0for (n =PAGE_SIZE /sizeof (long ); n; n--) *dst++ = *src++; + +flush_icache_range (start, start+PAGE_SIZE ); }
How about invalid all icache lines before doing do_copy_page, since do_copy_page might deal with both data pages and execute pages, that might be redundant to do it for every page?
Yu
PATCH v2 10/11 PM / Hibernate: clean cached pages on architectures that require it
On Thu, Nov 12, 2015 at 02:53:35AM +0000, Chen, Yu C wrote:
[...]
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
static inline void
do_copy_page(long *dst, long *src){kernel/power/snapshot.c +1
-0int n; +unsigned long __maybe_unused start = (unsigned long )dst;
Quoted 8 lines
Quoted 5 lines
kernel/power/snapshot.c static unsigned int count_data_pages(void) · line 1206
Quoted 5 lines
kernel/power/snapshot.c +2
-0for (n =PAGE_SIZE /sizeof (long ); n; n--) *dst++ = *src++; + +flush_icache_range (start, start+PAGE_SIZE ); }How about invalid all icache lines before doing
do_copy_page, sincedo_copy_pagemight deal with both data pages and execute pages, that might be redundant to do it for every page?
The point here is to make sure I-cache and D-cache are in sync, because the page we are copying can be executable code, so flush_icache_range is there to make sure that the code is cleaned from the D-cache to a cache level that is visible to the I-cache (yes, the I-cache range is invalidate too in the process).
I agree it is redundant for data pages, the point is, you do not really know what you are copying at this stage, we can extend the snapshot code to flag the pages accordingly, but it might well be overkill, so we posted this patch to get consensus before proceeding.
Thanks,
Lorenzo
PATCH v2 10/11 PM / Hibernate: clean cached pages on architectures that require it
In reply to James MorseQuoted 9 lines · James Morse
Some architectures require code written to memory as if it were data to be 'cleaned' from any data caches so that the processor can fetch them as new instructions.
During resume from hibernate, the snapshot code copies some pages directly, meaning these architectures do not get a chance to perform their cache maintenance. Add a call to
flush_icache_range(), which is provided by architectures that require it, to perform the maintenance.
Quoted 4 lines
This mirrors the kernel's behaviour when loading kernel modules and when mapping executable pages to user space.
Signed-off-by James Morse <[email protected]>
Looks reasonable.
kernel/power/snapshot.c static unsigned int count_data_pages(void) · line 1200
Quoted 13 lines
--- kernel/power/snapshot.c | 4 ++++ 1 file changed, 4 insertions(+)kernel/power/snapshot.c +1
-0@@ -1196,9 +1197,12 @@ static unsigned int count_data_pages(void)static inline void do_copy_page (long *dst,long *src) {int n; +unsigned long __maybe_unused start = (unsigned long )dst;
Why the "maybe unused"?
kernel/power/snapshot.c static unsigned int count_data_pages(void) · line 1206
Quoted 5 lines
kernel/power/snapshot.c +2
-0for (n =PAGE_SIZE /sizeof (long ); n; n--) *dst++ = *src++; + +flush_icache_range (start, start+PAGE_SIZE ); }
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
PATCH v2 10/11 PM / Hibernate: clean cached pages on architectures that require it
Quoted 10 lines · Pavel Machek
Quoted 9 lines · James Morse
Some architectures require code written to memory as if it were data to be 'cleaned' from any data caches so that the processor can fetch them as new instructions.
During resume from hibernate, the snapshot code copies some pages directly, meaning these architectures do not get a chance to perform their cache maintenance. Add a call to
flush_icache_range(), which is provided by architectures that require it, to perform the maintenance.
Quoted 8 lines
Quoted 4 lines
This mirrors the kernel's behaviour when loading kernel modules and when mapping executable pages to user space.
Signed-off-by James Morse <[email protected]>Looks reasonable.
Acked-by Pavel Machek <[email protected]>
Thanks!
Quoted 5 lines
Quoted 5 lines
--- kernel/power/snapshot.c | 4 ++++ 1 file changed, 4 insertions(+)
Quoted 11 lines
kernel/power/snapshot.c static unsigned int count_data_pages(void) · line 1200
Quoted 9 lines
kernel/power/snapshot.c +1
-0@@ -1196,9 +1197,12 @@ static unsigned int count_data_pages(void)static inline void do_copy_page (long *dst,long *src) {int n; +unsigned long __maybe_unused start = (unsigned long )dst;Why the "maybe unused"?
To avoid a build warning on x86_64, and any other architectures that don't use the arguments in their flush_icache_range() implementation.
Without __maybe_unused, gcc 4.9.2, building for x86_64:
Quoted 11 lines
../kernel/power/snapshot.c: In function ?do_copy_page?:../kernel/power/snapshot.c:1200:16: warning: unused variable ?start? [-Wunused-variable]
unsigned long start = (unsigned long)dst;kernel/power/snapshot.c static unsigned int count_data_pages(void) · line 1206
Quoted 5 lines
kernel/power/snapshot.c +2
-0for (n =PAGE_SIZE /sizeof (long ); n; n--) *dst++ = *src++; + +flush_icache_range (start, start+PAGE_SIZE ); }
Thanks,
James
PATCH v2 10/11 PM / Hibernate: clean cached pages on architectures that require it
Quoted 39 lines · James Morse
Quoted 10 lines · Pavel Machek
Quoted 9 lines · James Morse
Some architectures require code written to memory as if it were data to be 'cleaned' from any data caches so that the processor can fetch them as new instructions.
During resume from hibernate, the snapshot code copies some pages directly, meaning these architectures do not get a chance to perform their cache maintenance. Add a call to
flush_icache_range(), which is provided by architectures that require it, to perform the maintenance.Quoted 8 lines
Quoted 4 lines
This mirrors the kernel's behaviour when loading kernel modules and when mapping executable pages to user space.
Signed-off-by James Morse <[email protected]>Looks reasonable.
Acked-by Pavel Machek <[email protected]>Thanks!
Quoted 5 lines
Quoted 5 lines
--- kernel/power/snapshot.c | 4 ++++ 1 file changed, 4 insertions(+)Quoted 11 lines
kernel/power/snapshot.c static unsigned int count_data_pages(void) · line 1200
Quoted 9 lines
kernel/power/snapshot.c +1
-0@@ -1196,9 +1197,12 @@ static unsigned int count_data_pages(void)static inline void do_copy_page (long *dst,long *src) {int n; +unsigned long __maybe_unused start = (unsigned long )dst;Why the "maybe unused"?
Quoted 2 lines
To avoid a build warning on
x86_64, and any other architectures that don't use the arguments in theirflush_icache_range()implementation.
That's wrong fix, I believe.
flush_icache_range() should use their arguments. We should not have all the callers caring about this.
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
PATCH v2 10/11 PM / Hibernate: clean cached pages on architectures that require it
In reply to James MorseQuoted 11 lines · James Morse
Some architectures require code written to memory as if it were data to be 'cleaned' from any data caches so that the processor can fetch them as new instructions.
During resume from hibernate, the snapshot code copies some pages directly, meaning these architectures do not get a chance to perform their cache maintenance. Add a call to
flush_icache_range(), which is provided by architectures that require it, to perform the maintenance.This mirrors the kernel's behaviour when loading kernel modules and when mapping executable pages to user space.
While trying to benchmark the impact of this patch on 32bit ARM, I've discovered the fix is in the wrong place! do_copy_page() isn't used on the resume path for the pages restored 'in place'.
I will produce another version of the series - hopefully later today.
James
PATCH v2 11/11 arm64: kernel: Add support for hibernate/suspend-to-disk.
In reply to James MorseAdd support for hibernate/suspend-to-disk.
Suspend borrows code from cpu_suspend() to write cpu state onto the stack, before calling swsusp_save() to save the memory image.
Restore creates a set of temporary page tables, covering the kernel and the linear map, copies the restore code to a 'safe' page, then uses the copy to restore the memory image. It calls into cpu_resume(),
and then follows the normal cpu_suspend() path back into the suspend code.
The implementation assumes that exactly the same kernel is booted on the same hardware, and that the kernel is loaded at the same physical address.
--- arch/arm64/Kconfig | 3 + arch/arm64/include/asm/suspend.h | 8 + arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/asm-offsets.c | 4 + arch/arm64/kernel/hibernate-asm.S | 118 +++++++++++++ arch/arm64/kernel/hibernate.c | 359 ++++++++++++++++++++++++++++++++++++++ arch/arm64/kernel/vmlinux.lds.S | 15 ++ 7 files changed, 508 insertions(+) create mode 100644 arch/arm64/kernel/hibernate-asm.S create mode 100644 arch/arm64/kernel/hibernate.c
arch/arm64/Kconfig +3 -0
@@ -707,6 +707,9 @@ menu "Power management options" source "kernel/power/Kconfig" +config ARCH_HIBERNATION_POSSIBLE + def_bool y + config ARCH_SUSPEND_POSSIBLE def_bool y
arch/arm64/include/asm/suspend.h +8 -0
@@ -1,3 +1,5 @@ +#include <linux/suspend.h> +#ifndef __ASM_SUSPEND_H#define __ASM_SUSPEND_H
@@ -34,6 +36,12 @@ struct sleep_stack_data {unsigned long callee_saved_regs[NR_CALLEE_SAVED_REGS ]; }; +extern int swsusp_arch_suspend (void ); +extern int swsusp_arch_resume (void ); +int swsusp_arch_suspend_enter (struct cpu_suspend_ctx *ptr); +void __noreturn swsusp_arch_suspend_exit (phys_addr_t tmp_pg_dir, +phys_addr_t swapper_pg_dir, +void *kernel_start,void *kernel_end);extern int cpu_suspend (unsigned long arg,int (*fn)(unsigned long ));extern void cpu_resume (void );int __cpu_suspend_enter (struct sleep_stack_data *state);
arch/arm64/kernel/Makefile +1 -0
@@ -36,6 +36,7 @@ arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o arm64-obj-$(CONFIG_PCI) += pci.o arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o arm64-obj-$(CONFIG_ACPI) += acpi.o +arm64-obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o obj-y += $(arm64-obj-y) vdso/ obj-m += $(arm64-obj-m)
arch/arm64/kernel/asm-offsets.c +4 -0
@@ -22,6 +22,7 @@#include <linux/mm.h> #include <linux/dma-mapping.h> #include <linux/kvm_host.h> +#include <linux/suspend.h> #include <asm/thread_info.h> #include <asm/memory.h> #include <asm/smp_plat.h>
@@ -160,5 +161,8 @@ int main(void)DEFINE (SLEEP_STACK_DATA_SYSTEM_REGS , offsetof(struct sleep_stack_data , system_regs));DEFINE (SLEEP_STACK_DATA_CALLEE_REGS , offsetof(struct sleep_stack_data , callee_saved_regs));#endif +DEFINE (HIBERN_PBE_ORIG , offsetof(struct pbe , orig_address)); +DEFINE (HIBERN_PBE_ADDR , offsetof(struct pbe , address)); +DEFINE (HIBERN_PBE_NEXT , offsetof(struct pbe , next));return 0 ; }
arch/arm64/kernel/hibernate-asm.S new file +118 -0
118 lines not on this page · raw message
arch/arm64/kernel/hibernate.c new file +359 -0
359 lines not on this page · raw message
arch/arm64/kernel/vmlinux.lds.S +15 -0
@@ -44,6 +44,16 @@ jiffies = jiffies_64; *(.idmap.text) \ VMLINUX_SYMBOL(__idmap_text_end) = .; +#ifdef CONFIG_HIBERNATION +#define HIBERNATE_TEXT \ + . = ALIGN(SZ_4K); \ + VMLINUX_SYMBOL(__hibernate_exit_text_start) = .;\ + *(.hibernate_exit.text) \ + VMLINUX_SYMBOL(__hibernate_exit_text_end) = .; +#else +#define HIBERNATE_TEXT +#endif + /* * The size of the PE/COFF section that covers the kernel image, which * runs from stext to _edata, must be a round multiple of the PE/COFF
@@ -102,6 +112,7 @@ SECTIONS LOCK_TEXT HYPERVISOR_TEXT IDMAP_TEXT + HIBERNATE_TEXT *(.fixup) *(.gnu.warning) . = ALIGN(16);
@@ -181,6 +192,10 @@ ASSERT(__hyp_idmap_text_end - (__hyp_idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K, "HYP init code too big or misaligned") ASSERT(__idmap_text_end - (__idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K, "ID map text too big or misaligned") +#ifdef CONFIG_HIBERNATION +ASSERT(__hibernate_exit_text_end - (__hibernate_exit_text_start & ~(SZ_4K - 1)) + <= SZ_4K, "Hibernate exit text too big or misaligned") +#endif /* * If padding is applied before .head.text, virt<->phys conversions will fail.
Signature · 1 line
2.1.4
PATCH v2 11/11 arm64: kernel: Add support for hibernate/suspend-to-disk.
Hi!
Quoted 2 lines
The implementation assumes that exactly the same kernel is booted on the same hardware, and that the kernel is loaded at the same physical address.
BTW... on newer implementations (and I have patch for x86, too), we try to make it so that resume kernel does not have to be same as suspend one. It would be nice to move there with arm64, too.
Quoted 1 line
Signed-off-by James Morse <[email protected]>
Quoted 3 lines
+/*
+ * Corrupt memory.
+ *
Umm. Really?
Quoted 2 lines
+ * Because this code has to be copied to a
safe_page, it can't call out to
+ * other functions by pc-relative address. Also remember that it
PC-relative?
Quoted 5 lines
+ * mid-way through over-writing other functions. For this reason it contains
+ * a copy ofcopy_page()and code fromflush_icache_range().
+ *
+ * All of memory gets written to, including code. We need to clean the kernel
+ * text to the PoC before secondary cores can be booted. Because kernel modules,
"the kernel modules" and no ","?
Quoted 2 lines
+ * and executable pages mapped to user space are also written as data, we
+ * clean all pages we touch to the PoU.
What is PoC and PoU?
Thanks, Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
PATCH v2 11/11 arm64: kernel: Add support for hibernate/suspend-to-disk.
Hi!
Quoted 6 lines · Pavel Machek
Quoted 2 lines
The implementation assumes that exactly the same kernel is booted on the same hardware, and that the kernel is loaded at the same physical address.
BTW... on newer implementations (and I have patch for x86, too), we try to make it so that resume kernel does not have to be same as suspend one. It would be nice to move there with arm64, too.
Yes, that is a neat trick, can I leave it as future work?
Quoted 3 lines
Quoted 1 line
Signed-off-by James Morse <[email protected]>Acked-by Pavel Machek <[email protected]>
Thanks!
(I have a fixup for this patch to add a missing __pgprot() in the page
table copy code.)
Quoted 5 lines
Quoted 3 lines
+/*
+ * Corrupt memory.
+ *Umm. Really?
Effectively. Until it finishes copying, you have to assume all memory is corrupt, code, page-tables etc. It was more a tounge-in-cheek reminder to myself to be careful.
Quoted 4 lines
Quoted 2 lines
+ * Because this code has to be copied to a
safe_page, it can't call out to
+ * other functions by pc-relative address. Also remember that itPC-relative?
The linker may (often!) use program-counter relative addresses for loads and stores. This code gets copied, so the linker doesn't know where the code will be executed from, so any instructions using pc-relative addresses will get the wrong result, (if they reference something outside the function).
Quoted 7 lines
Quoted 5 lines
+ * mid-way through over-writing other functions. For this reason it contains
+ * a copy ofcopy_page()and code fromflush_icache_range().
+ *
+ * All of memory gets written to, including code. We need to clean the kernel
+ * text to the PoC before secondary cores can be booted. Because kernel modules,"the kernel modules" and no ","?
Sure.
Quoted 4 lines
Quoted 2 lines
+ * and executable pages mapped to user space are also written as data, we
+ * clean all pages we touch to the PoU.What is PoC and PoU?
They are points in the CPU's cache hierarchy:
ARM processors are of a 'modified Harvard' architecture, their paths to read instructions and data are different. The 'Point of Unification' is the first point in the cache hierarchy that is the same for both. On ARM, flush_icache_range() makes sure code written as data is pushed through any data caches to this point, and then evicts any stale copies in the instruction caches.
PoC is the 'Point of Coherency', it is the first point that is the same for all devices, (e.g. a cpu with caches turned on, and one with them off), it is normally main memory. The kernel text has to be pushed to this point, so that secondary cores, while running early-boot code with their MMU and caches turned off, don't get incorrect code/data from before resume.
I have resisted the urge to draw some ascii-art!
Thanks for your comments,
James
PATCH v2 11/11 arm64: kernel: Add support for hibernate/suspend-to-disk.
Hi!
Quoted 9 lines · Pavel Machek
Quoted 6 lines
Quoted 2 lines
The implementation assumes that exactly the same kernel is booted on the same hardware, and that the kernel is loaded at the same physical address.
BTW... on newer implementations (and I have patch for x86, too), we try to make it so that resume kernel does not have to be same as suspend one. It would be nice to move there with arm64, too.
Yes, that is a neat trick, can I leave it as future work?
Yes. But it is really not hard.
Quoted 10 lines
Quoted 4 lines
Quoted 2 lines
+ * Because this code has to be copied to a
safe_page, it can't call out to
+ * other functions by pc-relative address. Also remember that itPC-relative?
The linker may (often!) use program-counter relative addresses for loads and stores. This code gets copied, so the linker doesn't know where the code will be executed from, so any instructions using pc-relative addresses will get the wrong result, (if they reference something outside the function).
I was wondering if it should be spelled "PC-relative", not "pc-relative" :-).
Quoted 14 lines
Quoted 4 lines
Quoted 2 lines
+ * and executable pages mapped to user space are also written as data, we
+ * clean all pages we touch to the PoU.What is PoC and PoU?
They are points in the CPU's cache hierarchy:
ARM processors are of a 'modified Harvard' architecture, their paths to read instructions and data are different. The 'Point of Unification' is the first point in the cache hierarchy that is the same for both. On ARM,
flush_icache_range()makes sure code written as data is pushed through any data caches to this point, and then evicts any stale copies in the instruction caches.
Quoted 7 lines
PoC is the 'Point of Coherency', it is the first point that is the same for all devices, (e.g. a cpu with caches turned on, and one with them off), it is normally main memory. The kernel text has to be pushed to this point, so that secondary cores, while running early-boot code with their MMU and caches turned off, don't get incorrect code/data from before resume.
I have resisted the urge to draw some ascii-art!
That's ok, you just might want to replace PoI -> 'Point of Unification' and PoC -> 'Point of Coherency' in the comments. That should make googling easier for people not familiar with arm terminology.
Thanks,
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
PATCH v2 11/11 arm64: kernel: Add support for hibernate/suspend-to-disk.
Hi,
Quoted 11 lines · Pavel Machek
Quoted 9 lines · Pavel Machek
Quoted 6 lines
Quoted 2 lines
The implementation assumes that exactly the same kernel is booted on the same hardware, and that the kernel is loaded at the same physical address.
BTW... on newer implementations (and I have patch for x86, too), we try to make it so that resume kernel does not have to be same as suspend one. It would be nice to move there with arm64, too.
Yes, that is a neat trick, can I leave it as future work?
Yes. But it is really not hard.
I think its harder than it looks:
It means the MMU has to be turned off, as two different kernels may not have used the same configuration for the MMU - and I don't think its safe to change while the MMU is running. There are also going to be complications with resetting the hypervisor/el2 configuration, which I need to spend more time thinking about (and probably ask for advice!).
Quoted 5 lines
Quoted 5 lines
Quoted 4 lines
Quoted 2 lines
+ * Because this code has to be copied to a
safe_page, it can't call out to
+ * other functions by pc-relative address. Also remember that itPC-relative?
Quoted 8 lines
Quoted 5 lines
The linker may (often!) use program-counter relative addresses for loads and stores. This code gets copied, so the linker doesn't know where the code will be executed from, so any instructions using pc-relative addresses will get the wrong result, (if they reference something outside the function).
I was wondering if it should be spelled "PC-relative", not "pc-relative" :-).
Hah - sorry!
Fixed.
Quoted 20 lines
Quoted 20 lines
Quoted 4 lines
Quoted 2 lines
+ * and executable pages mapped to user space are also written as data, we
+ * clean all pages we touch to the PoU.What is PoC and PoU?
They are points in the CPU's cache hierarchy:
ARM processors are of a 'modified Harvard' architecture, their paths to read instructions and data are different. The 'Point of Unification' is the first point in the cache hierarchy that is the same for both. On ARM,
flush_icache_range()makes sure code written as data is pushed through any data caches to this point, and then evicts any stale copies in the instruction caches.PoC is the 'Point of Coherency', it is the first point that is the same for all devices, (e.g. a cpu with caches turned on, and one with them off), it is normally main memory. The kernel text has to be pushed to this point, so that secondary cores, while running early-boot code with their MMU and caches turned off, don't get incorrect code/data from before resume.
Quoted 6 lines
Quoted 1 line
I have resisted the urge to draw some ascii-art!
That's ok, you just might want to replace PoI -> 'Point of Unification' and PoC -> 'Point of Coherency' in the comments. That should make googling easier for people not familiar with arm terminology.
There aren't any other points under arch/arm64 that use the full expansion, but it can't hurt to include both.
Thanks,
James
Mark Rutland
reviewerPATCH v2 11/11 arm64: kernel: Add support for hibernate/suspend-to-disk.
Quoted 19 lines
Quoted 19 lines
Quoted 18 lines
Quoted 1 line
What is PoC and PoU?
They are points in the CPU's cache hierarchy:
ARM processors are of a 'modified Harvard' architecture, their paths to read instructions and data are different. The 'Point of Unification' is the first point in the cache hierarchy that is the same for both. On ARM,
flush_icache_range()makes sure code written as data is pushed through any data caches to this point, and then evicts any stale copies in the instruction caches.PoC is the 'Point of Coherency', it is the first point that is the same for all devices, (e.g. a cpu with caches turned on, and one with them off), it is normally main memory. The kernel text has to be pushed to this point, so that secondary cores, while running early-boot code with their MMU and caches turned off, don't get incorrect code/data from before resume.
I have resisted the urge to draw some ascii-art!
Quoted 7 lines
Quoted 4 lines
That's ok, you just might want to replace PoI -> 'Point of Unification' and PoC -> 'Point of Coherency' in the comments. That should make googling easier for people not familiar with arm terminology.
There aren't any other points under
arch/arm64that use the full expansion, but it can't hurt to include both.
I would prefer to keep PoC/PoU as they are for consistency.
The abbreviations are provided by the architecture, and much like register names that we do not expand, to reason about them you need to read the architecture documentation anyway. So the short forms alone are fine.
Mark.
PATCH v2 11/11 arm64: kernel: Add support for hibernate/suspend-to-disk.
In reply to James MorseQuoted 13 lines · James Morse
Hi,
Quoted 10 lines · Pavel Machek
Quoted 9 lines · Pavel Machek
Quoted 6 lines
Quoted 2 lines
The implementation assumes that exactly the same kernel is booted on the same hardware, and that the kernel is loaded at the same physical address.
BTW... on newer implementations (and I have patch for x86, too), we try to make it so that resume kernel does not have to be same as suspend one. It would be nice to move there with arm64, too.
Yes, that is a neat trick, can I leave it as future work?
Quoted 8 lines
Quoted 1 line
Yes. But it is really not hard.
I think its harder than it looks:
It means the MMU has to be turned off, as two different kernels may not have used the same configuration for the MMU - and I don't think its safe to change while the MMU is running. There are also going to be complications with resetting the hypervisor/el2 configuration, which I need to spend more time thinking about (and probably ask for advice!).
Well, you can simplify it here: If MMU configuration is stable between 4.3, 4.4 and 4.5 kernels, you just use suspend signature for 4.3-like kernels. If you need to change it in future, you change the signature.
(If it changes too often, this might not work).
Best regards,
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html