kexec fixes and soft restart code
v6 cover kexec fixes and soft restart code
Hello,
This is version 6 of the patches originally posted here:
v1: http://lists.infradead.org/pipermail/linux-arm-kernel/2011-June/052157.html
v2: http://lists.infradead.org/pipermail/linux-arm-kernel/2011-June/052559.html
v3: http://lists.infradead.org/pipermail/linux-arm-kernel/2011-June/053252.html
v4: http://lists.infradead.org/pipermail/linux-arm-kernel/2011-August/062305.html
v5: http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/071909.html
This patch series is slightly smaller than the last post because it now depends on the idmap work I have posted separately here:
http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/073033.html
As before, this is also dependent on Russell's reset work (available in his reset branch).
Thanks,
Will
Will Deacon (5):
ARM: lib: add call_with_stack function for safely changing stack
ARM: reset: implement soft_restart for jumping to a physical address
ARM: soft_restart: disable the outer L2 when the last CPU is going
down
ARM: stop: execute platform callback from cpu_stop code
ARM: kexec: use soft_restart for branching to the reboot buffer
arch/arm/Kconfig | 2 +- arch/arm/kernel/machine_kexec.c | 15 ++-------- arch/arm/kernel/process.c | 55 ++++++++++++++++++++++++++++++-------- arch/arm/kernel/smp.c | 4 +++ arch/arm/lib/Makefile | 3 +- arch/arm/lib/call_with_stack.S | 44 +++++++++++++++++++++++++++++++ 6 files changed, 97 insertions(+), 26 deletions(-) create mode 100644 arch/arm/lib/call_with_stack.S
Signature · 1 line
1.7.4.1
PATCH v6 1/5 ARM: lib: add call_with_stack function for safely changing stack
When disabling the MMU, it is necessary to take out a 1:1 identity map of the reset code so that it can safely be executed with and without the MMU active. To avoid the situation where the physical address of the reset code aliases with the virtual address of the active stack (which cannot be included in the 1:1 mapping), it is desirable to change to a new stack at a location which is less likely to alias.
This code adds a new lib function, call_with_stack:
void call_with_stack(void (*fn)(void *), void *arg, void *sp);
which changes the stack to point at the sp parameter, before invoking fn(arg) with the new stack selected.
--- arch/arm/lib/Makefile | 3 +- arch/arm/lib/call_with_stack.S | 44 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletions(-) create mode 100644 arch/arm/lib/call_with_stack.S
arch/arm/lib/Makefile +2 -1
@@ -13,7 +13,8 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ testchangebit.o testclearbit.o testsetbit.o \ ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ ucmpdi2.o lib1funcs.o div64.o \ - io-readsb.o io-writesb.o io-readsl.o io-writesl.o + io-readsb.o io-writesb.o io-readsl.o io-writesl.o \ + call_with_stack.o mmu-y := clear_user.o copy_page.o getuser.o putuser.o
arch/arm/lib/call_with_stack.S new file +44 -0
44 lines not on this page · raw message
Signature · 1 line
1.7.4.1
PATCH v6 1/5 ARM: lib: add call_with_stack function for safely changing stack
Quoted 9 lines · Will Deacon
When disabling the MMU, it is necessary to take out a 1:1 identity map of the reset code so that it can safely be executed with and without the MMU active. To avoid the situation where the physical address of the reset code aliases with the virtual address of the active stack (which cannot be included in the 1:1 mapping), it is desirable to change to a new stack at a location which is less likely to alias.
This code adds a new lib function,
call_with_stack:
Quoted 8 lines
? ? ? ?void
call_with_stack(void (*fn)(void *), void *arg, void *sp);which changes the stack to point at the sp parameter, before invoking fn(arg) with the new stack selected.
Reviewed-by Nicolas Pitre <[email protected]>Signed-off-by Dave Martin <[email protected]>Signed-off-by Will Deacon <[email protected]>
PATCH v6 2/5 ARM: reset: implement soft_restart for jumping to a physical address
In reply to Will DeaconTools such as kexec and CPU hotplug require a way to reset the processor and branch to some code in physical space. This requires various bits of jiggery pokery with the caches and MMU which, when it goes wrong, tends to lock up the system.
This patch fleshes out the soft_restart implementation so that it branches to the reset code using the identity mapping. This requires us to change to a temporary stack, held within the kernel image as a static array, to avoid conflicting with the new view of memory.
--- arch/arm/kernel/process.c | 51 ++++++++++++++++++++++++++++++++++---------- 1 files changed, 39 insertions(+), 12 deletions(-)
arch/arm/kernel/process.c +39 -12
@@ -92,29 +92,56 @@ static int __init hlt_setup(char *__unused)__setup ("nohlt" , nohlt_setup);__setup ("hlt" , hlt_setup); -void soft_restart (unsigned long addr) +extern void call_with_stack (void (*fn)(void *),void *arg,void *sp); +typedef void (*phys_reset_t )(unsigned long ); + +/* +* A temporary stack to use for CPU reset. This is static so that we +* don't clobber it with the identity mapping. When running with this +* stack, any references to the current task *will not work* so you +* should really do as little as possible before jumping to your reset +* code. +*/ +#define SOFT_RESTART_STACK_WORDS 32 +static u32 soft_restart_stack[SOFT_RESTART_STACK_WORDS ]; + +static void __soft_restart (void *addr) { -/* Disable interrupts first */ -local_irq_disable (); -local_fiq_disable (); +phys_reset_t phys_reset; -/* -* Tell the mm system that we are going to reboot - -* we may need it to insert some 1:1 mappings so that -* soft boot works. -*/ +/* Take out a flat memory mapping. */ setup_mm_for_reboot (); -/* Clean and invalidate caches */ +/* Clean and invalidate caches. */ flush_cache_all (); -/* Turn off caching */ +/* Turn off caching. */ cpu_proc_fin ();/* Push out any further dirty data, and ensure cache is empty */ flush_cache_all (); -cpu_reset (addr); +/* Switch to the identity mapping. */ + phys_reset = (phys_reset_t )(unsigned long )virt_to_phys (cpu_reset); +phys_reset ((unsigned long )addr); + +/* Should never get here. */ +BUG (); +} + +void soft_restart (unsigned long addr) +{ +u32 *stack = soft_restart_stack +SOFT_RESTART_STACK_WORDS ; + +/* Disable interrupts first */ +local_irq_disable (); +local_fiq_disable (); + +/* Change to the new stack and continue with the reset. */ +call_with_stack (__soft_restart, (void *)addr, (void *)stack); + +/* Should never get here. */ +BUG (); }static void null_restart (char mode,const char *cmd)
Signature · 1 line
1.7.4.1
PATCH v6 2/5 ARM: reset: implement soft_restart for jumping to a physical address
Quoted 26 lines · Will Deacon
Tools such as kexec and CPU hotplug require a way to reset the processor and branch to some code in physical space. This requires various bits of jiggery pokery with the caches and MMU which, when it goes wrong, tends to lock up the system.
This patch fleshes out the
soft_restartimplementation so that it branches to the reset code using the identity mapping. This requires us to change to a temporary stack, held within the kernel image as a static array, to avoid conflicting with the new view of memory.Signed-off-by Will Deacon <[email protected]>---
?arch/arm/kernel/process.c | ? 51 ++++++++++++++++++++++++++++++++++---------- ?1 files changed, 39 insertions(+), 12 deletions(-)arch/arm/kernel/process.c +2
-1@@ -92,29 +92,56 @@ static int __init hlt_setup(char *__unused) ?__setup("nohlt", nohlt_setup); ?__setup("hlt", hlt_setup); -void soft_restart (unsigned long addr) +extern void call_with_stack (void (*fn)(void *),void *arg,void *sp); +typedef void (*phys_reset_t )(unsigned long );
arch/arm/kernel/process.c static int __init hlt_setup(char *__unused) · line 106
Quoted 10 lines
arch/arm/kernel/process.c +10
-0+ +/* +* A temporary stack to use for CPU reset. This is static so that we +* don't clobber it with the identity mapping. When running with this +* stack, any references to the current task *will not work* so you +* should really do as little as possible before jumping to your reset +* code. +*/ +#define SOFT_RESTART_STACK_WORDS ? ? ? 32 +static u32 soft_restart_stack[SOFT_RESTART_STACK_WORDS ];
Just for ABI stack alignment requirements, do we get the right alignment of this array in memory?
Quoted 12 lines
arch/arm/kernel/process.c +2
-8+static void __soft_restart (void *addr) ?{ - ? ? ? /* Disable interrupts first */ - ? ? ? local_irq_disable(); - ? ? ? local_fiq_disable(); + ? ? ? phys_reset_t phys_reset; - ? ? ? /* -? ? ? ?* Tell the mm system that we are going to reboot - -? ? ? ?* we may need it to insert some 1:1 mappings so that -? ? ? ?* soft boot works. -? ? ? ?*/
arch/arm/kernel/process.c static int __init hlt_setup(char *__unused) · line 118
Quoted 10 lines
arch/arm/kernel/process.c +3
-2+ ? ? ? /* Take out a flat memory mapping. */ ? ? ? ?setup_mm_for_reboot(); - ? ? ? /* Clean and invalidate caches */ + ? ? ? /* Clean and invalidate caches. */ ? ? ? ?flush_cache_all(); - ? ? ? /* Turn off caching */ + ? ? ? /* Turn off caching. */ ? ? ? ?cpu_proc_fin();
A few unnecessary comment changes :) (it's not clear in the Linux coding style but many single-line comments don't have a full-stop.
Quoted 7 lines
? ? ? ?/* Push out any further dirty data, and ensure cache is empty */ ? ? ? ?flush_cache_all();
- ? ? ?
cpu_reset(addr);
+ ? ? ? /* Switch to the identity mapping. */
+ ? ? ?phys_reset= (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
+ ? ? ?phys_reset((unsigned long)addr);
arch/arm/kernel/process.c static int __init hlt_setup(char *__unused)
Quoted 8 lines
arch/arm/kernel/process.c +8
-0+ + ? ? ? /* Should never get here. */ + ? ? ? BUG(); +} + +void soft_restart (unsigned long addr) +{ + ? ? ? u32 *stack = soft_restart_stack + SOFT_RESTART_STACK_WORDS;
We could use ARRAY_SIZE() here and just avoid defining SOFT_RESTART_STACK_WORDS.
Signature · 1 line
Catalin
PATCH v6 2/5 ARM: reset: implement soft_restart for jumping to a physical address
Quoted 24 lines · Catalin Marinas
Quoted 23 lines · Will Deacon
Tools such as kexec and CPU hotplug require a way to reset the processor and branch to some code in physical space. This requires various bits of jiggery pokery with the caches and MMU which, when it goes wrong, tends to lock up the system.
This patch fleshes out the
soft_restartimplementation so that it branches to the reset code using the identity mapping. This requires us to change to a temporary stack, held within the kernel image as a static array, to avoid conflicting with the new view of memory.Signed-off-by Will Deacon <[email protected]>---
?arch/arm/kernel/process.c | ? 51 ++++++++++++++++++++++++++++++++++---------- ?1 files changed, 39 insertions(+), 12 deletions(-)arch/arm/kernel/process.c +0
-0@@ -92,29 +92,56 @@ static int __init hlt_setup(char *__unused) ?__setup("nohlt", nohlt_setup); ?__setup("hlt", hlt_setup);
Quoted 16 lines
arch/arm/kernel/process.c static int __init hlt_setup(char *__unused) · line 106
Quoted 13 lines
arch/arm/kernel/process.c +12
-1-void soft_restart (unsigned long addr) +extern void call_with_stack (void (*fn)(void *),void *arg,void *sp); +typedef void (*phys_reset_t )(unsigned long ); + +/* +* A temporary stack to use for CPU reset. This is static so that we +* don't clobber it with the identity mapping. When running with this +* stack, any references to the current task *will not work* so you +* should really do as little as possible before jumping to your reset +* code. +*/ +#define SOFT_RESTART_STACK_WORDS ? ? ? 32 +static u32 soft_restart_stack[SOFT_RESTART_STACK_WORDS ];Just for ABI stack alignment requirements, do we get the right alignment of this array in memory?
Could we fix that by making it a u64 array?
In architecture versions where it matters, the compiler should also 64- bit align such an array.
Of we're paranoid, we could align the initial stack pointer explicitly.
Cheers
---Dave
PATCH v6 2/5 ARM: reset: implement soft_restart for jumping to a physical address
In reply to Catalin MarinasQuoted 9 lines · Catalin Marinas
Quoted 8 lines · Will Deacon
arch/arm/kernel/process.c +0
-0@@ -92,29 +92,56 @@ static int __init hlt_setup(char *__unused) ?__setup("nohlt", nohlt_setup); ?__setup("hlt", hlt_setup);
Quoted 16 lines
arch/arm/kernel/process.c static int __init hlt_setup(char *__unused) · line 106
Quoted 13 lines
arch/arm/kernel/process.c +12
-1-void soft_restart (unsigned long addr) +extern void call_with_stack (void (*fn)(void *),void *arg,void *sp); +typedef void (*phys_reset_t )(unsigned long ); + +/* +* A temporary stack to use for CPU reset. This is static so that we +* don't clobber it with the identity mapping. When running with this +* stack, any references to the current task *will not work* so you +* should really do as little as possible before jumping to your reset +* code. +*/ +#define SOFT_RESTART_STACK_WORDS ? ? ? 32 +static u32 soft_restart_stack[SOFT_RESTART_STACK_WORDS ];Just for ABI stack alignment requirements, do we get the right alignment of this array in memory?
I'll make it u64[16] instead then (as per Dave's suggestion).
Quoted 19 lines
Quoted 19 lines
arch/arm/kernel/process.c +4
-9+static void __soft_restart (void *addr) ?{ - ? ? ? /* Disable interrupts first */ - ? ? ? local_irq_disable(); - ? ? ? local_fiq_disable(); + ? ? ? phys_reset_t phys_reset; - ? ? ? /* - ? ? ? ?* Tell the mm system that we are going to reboot - - ? ? ? ?* we may need it to insert some 1:1 mappings so that - ? ? ? ?* soft boot works. - ? ? ? ?*/ + ? ? ? /* Take out a flat memory mapping. */ ? ? ? ?setup_mm_for_reboot(); - ? ? ? /* Clean and invalidate caches */ + ? ? ? /* Clean and invalidate caches. */ ? ? ? ?flush_cache_all();
Quoted 6 lines
arch/arm/kernel/process.c static int __init hlt_setup(char *__unused) · line 118
Quoted 3 lines
arch/arm/kernel/process.c +1
-1- ? ? ? /* Turn off caching */ + ? ? ? /* Turn off caching. */ ? ? ? ?cpu_proc_fin();A few unnecessary comment changes :) (it's not clear in the Linux coding style but many single-line comments don't have a full-stop.
I think the change to the setup_mm_for_reboot comment is valid, but I'll leave the other guys without full stops, even if it annoys me unjustifiably :)
Quoted 5 lines
arch/arm/kernel/process.c static int __init hlt_setup(char *__unused)
Quoted 3 lines
arch/arm/kernel/process.c +3
-0+void soft_restart (unsigned long addr) +{ + ? ? ? u32 *stack = soft_restart_stack + SOFT_RESTART_STACK_WORDS;We could use
ARRAY_SIZE()here and just avoid definingSOFT_RESTART_STACK_WORDS.
Sure.
Thanks for the review, I'll post a v2 of this after Russell has stablised the reset patches.
Will
PATCH v6 3/5 ARM: soft_restart: disable the outer L2 when the last CPU is going down
In reply to Will DeaconSoft-restarting a system with an outer, shared L2 requires us to disable it when no other CPUs are running.
This patch adds an outer_disable call to soft_restart so that the last CPU going down will disable the L2 cache.
--- arch/arm/kernel/process.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-)
arch/arm/kernel/process.c +4 -0
@@ -137,6 +137,10 @@ void soft_restart(unsigned long addr)local_irq_disable ();local_fiq_disable (); +/* Disable the L2 if we're the last man standing. */ +if (num_online_cpus () ==1 ) +outer_disable (); +/* Change to the new stack and continue with the reset. */ call_with_stack (__soft_restart, (void *)addr, (void *)stack);
Signature · 1 line
1.7.4.1
PATCH v6 3/5 ARM: soft_restart: disable the outer L2 when the last CPU is going down
arch/arm/kernel/process.c void soft_restart(unsigned long addr) · line 143
Quoted 12 lines · Will Deacon
arch/arm/kernel/process.c +4
-0@@ -137,6 +137,10 @@ void soft_restart(unsigned long addr)local_irq_disable ();local_fiq_disable (); +/* Disable the L2 if we're the last man standing. */ +if (num_online_cpus () ==1 ) +outer_disable (); +
When does this code execute on another cpu? My understanding is that soft_restart() is only called on one CPU so I would think checking the number of online cpus isn't necessary.
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH v6 3/5 ARM: soft_restart: disable the outer L2 when the last CPU is going down
Hi Stephen,
Quoted 9 lines · Stephen Boyd
Quoted 8 lines · Will Deacon
arch/arm/kernel/process.c +0
-0@@ -137,6 +137,10 @@ void soft_restart(unsigned long addr)local_irq_disable ();local_fiq_disable ();
Quoted 8 lines
arch/arm/kernel/process.c void soft_restart(unsigned long addr) · line 143
Quoted 4 lines
arch/arm/kernel/process.c +4
-0+/* Disable the L2 if we're the last man standing. */ +if (num_online_cpus () ==1 ) +outer_disable (); +When does this code execute on another cpu? My understanding is that
soft_restart()is only called on one CPU so I would think checking the number of online cpus isn't necessary.
Currently, yes, this only executes on one CPU. The code is there in case we want to implement a SMP kexec solution that doesn't require CPU hotplug at some point.
I suppose you could end up in a situation where the reset path leads to a soft reboot and you haven't dealt with the secondaries at this point, but then you have bigger problems to worry about (namely that whatever you jump to after turning the MMU off needs to deal with the secondaries somehow).
Are you seeing problems with this?
Cheers,
Will
PATCH v6 3/5 ARM: soft_restart: disable the outer L2 when the last CPU is going down
Quoted 6 lines · Will Deacon
Hi Stephen,
Quoted 3 lines · Stephen Boyd
When does this code execute on another cpu? My understanding is that
soft_restart()is only called on one CPU so I would think checking the number of online cpus isn't necessary.
Quoted 8 lines
Currently, yes, this only executes on one CPU. The code is there in case we want to implement a SMP kexec solution that doesn't require CPU hotplug at some point.
I suppose you could end up in a situation where the reset path leads to a soft reboot and you haven't dealt with the secondaries at this point, but then you have bigger problems to worry about (namely that whatever you jump to after turning the MMU off needs to deal with the secondaries somehow).
Fair enough. I was just curious.
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH v6 4/5 ARM: stop: execute platform callback from cpu_stop code
In reply to Will DeaconSending IPI_CPU_STOP to a CPU causes it to execute a busy cpu_relax loop forever. This makes it impossible to kexec successfully on an SMP system since the secondary CPUs do not reset.
This patch adds a callback to platform_cpu_kill, defined when CONFIG_HOTPLUG_CPU=y, from the ipi_cpu_stop handling code. This function currently just returns 1 on all platforms that define it but allows them to do something more sophisticated in the future.
--- arch/arm/Kconfig | 2 +- arch/arm/kernel/smp.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletions(-)
arch/arm/Kconfig +1 -1
@@ -1989,7 +1989,7 @@ config XIP_PHYS_ADDR config KEXEC bool "Kexec system call (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on EXPERIMENTAL && (!SMP || HOTPLUG_CPU) help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot
arch/arm/kernel/smp.c +4 -0
@@ -550,6 +550,10 @@ static void ipi_cpu_stop(unsigned int cpu)local_fiq_disable ();local_irq_disable (); +#ifdef CONFIG_HOTPLUG_CPU +platform_cpu_kill (cpu); +#endif +while (1 )cpu_relax (); }
Signature · 1 line
1.7.4.1
PATCH v6 5/5 ARM: kexec: use soft_restart for branching to the reboot buffer
In reply to Will DeaconNow that there is a common way to reset the machine, let's use it instead of reinventing the wheel in the kexec backend.
--- arch/arm/kernel/machine_kexec.c | 15 +++------------ 1 files changed, 3 insertions(+), 12 deletions(-)
arch/arm/kernel/machine_kexec.c +3 -12
@@ -12,12 +12,11 @@#include <asm/mmu_context.h> #include <asm/cacheflush.h> #include <asm/mach-types.h> +#include <asm/system.h> extern const unsigned char relocate_new_kernel[];extern const unsigned int relocate_new_kernel_size; -extern void setup_mm_for_reboot (void ); -extern unsigned long kexec_start_address;extern unsigned long kexec_indirection_page;extern unsigned long kexec_mach_type;
@@ -111,14 +110,6 @@ void machine_kexec(struct kimage *image)if (kexec_reinit)kexec_reinit (); -local_irq_disable (); -local_fiq_disable (); -setup_mm_for_reboot (); -flush_cache_all (); -outer_flush_all (); -outer_disable (); -cpu_proc_fin (); -outer_inv_all (); -flush_cache_all (); -cpu_reset (reboot_code_buffer_phys); + +soft_restart (reboot_code_buffer_phys); }
Signature · 1 line
1.7.4.1