Skip to contentSkip to conversation

kexec fixes and soft restart code

PATCH Superseded Will Deacon 1 participant 5 messages Dec 8, 2011 Arm (32-bit)

lore
Share & tools
lore
#0 lore raw

v8 cover kexec fixes and soft restart code

Hello,

This is version 8 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
v6: http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/073054.html
v7: http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/074338.html

There are a few small changes since v7:

- Fixed a warning in the stack declaration from an implicit u64* -> u32* cast
- Rebased onto rmk/devel-stable, which now includes my idmap patches
- Merged in the outer_disable patch with the soft_restart patch as it didn't warrant a separate commit.

I'm pretty happy with these patches, but I appreciate there is already a lot queued for 3.3. Russell - would you rather I held fire on these for the time being (the downside being that soft reboot is broken for a bit longer)?

Cheers,

Will

Will Deacon (4):
ARM: lib: add call_with_stack function for safely changing stack
ARM: reset: implement soft_restart for jumping to a physical address
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       |   50 +++++++++++++++++++++++++++++++-------
 arch/arm/kernel/smp.c           |    4 +++
 arch/arm/lib/Makefile           |    3 +-
 arch/arm/lib/call_with_stack.S  |   44 ++++++++++++++++++++++++++++++++++
 6 files changed, 94 insertions(+), 24 deletions(-)
 create mode 100644 arch/arm/lib/call_with_stack.S
Signature · 1 line
1.7.4.1
#1 lore raw

PATCH v8 1/4 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
index cf73a7f..0ade0ac 100644
@@ -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
#2 lore raw

PATCH v8 2/4 ARM: reset: implement soft_restart for jumping to a physical address

In reply to 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_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 |   50 ++++++++++++++++++++++++++++++++++++---------
 1 files changed, 40 insertions(+), 10 deletions(-)
arch/arm/kernel/process.c +40 -10
index eeb3e16..423bb20 100644
@@ -92,17 +92,23 @@ 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.
+ */
+static u64 soft_restart_stack[16];
+
+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 */
@@ -114,7 +120,31 @@ void soft_restart(unsigned long addr)
 	/* 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)
+{
+	u64 *stack = soft_restart_stack + ARRAY_SIZE(soft_restart_stack);
+
+	/* Disable interrupts first */
+	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);
+
+	/* Should never get here. */
+	BUG();
 }
 
 void arm_machine_restart(char mode, const char *cmd)
Signature · 1 line
1.7.4.1
#3 lore raw

PATCH v8 3/4 ARM: stop: execute platform callback from cpu_stop code

In reply to Will Deacon

Sending 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
index 4b01d71..abba5b8 100644
@@ -2001,7 +2001,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
index 76ff28d..57db122 100644
@@ -522,6 +522,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
#4 lore raw

PATCH v8 4/4 ARM: kexec: use soft_restart for branching to the reboot buffer

In reply to Will Deacon

Now 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
index 29620b6..764bd45 100644
@@ -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