[PATCH] Arm64: convert soft_restart() to assembly code

Arun Chandran achandran at mvista.com
Tue Aug 12 05:42:45 PDT 2014


soft_restart() will fail on arm64 systems that does not
quarantee the flushing of cache to PoC with flush_cache_all().

soft_restart(addr)
{
	push_to_stack(addr);

	Do mm setup for restart;
	Flush&turnoff D-cache;

	pop_from_stack(addr); --> fails here as addr is not at PoC
	cpu_reset(addr) --> Jumps to invalid address
}

So convert the whole code to assembly to make sure that addr
is not pushed to stack.

Signed-off-by: Arun Chandran <achandran at mvista.com>
---
 arch/arm64/include/asm/proc-fns.h    |    1 +
 arch/arm64/include/asm/system_misc.h |    1 -
 arch/arm64/kernel/process.c          |   38 ++--------------------------------
 arch/arm64/mm/proc.S                 |   34 ++++++++++++++++++++++++++++++
 4 files changed, 37 insertions(+), 37 deletions(-)

diff --git a/arch/arm64/include/asm/proc-fns.h b/arch/arm64/include/asm/proc-fns.h
index 0c657bb..e18d5d0 100644
--- a/arch/arm64/include/asm/proc-fns.h
+++ b/arch/arm64/include/asm/proc-fns.h
@@ -32,6 +32,7 @@ extern void cpu_cache_off(void);
 extern void cpu_do_idle(void);
 extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
 extern void cpu_reset(unsigned long addr) __attribute__((noreturn));
+extern void cpu_soft_restart(unsigned long addr) __attribute__((noreturn));
 extern void cpu_do_suspend(struct cpu_suspend_ctx *ptr);
 extern u64 cpu_do_resume(phys_addr_t ptr, u64 idmap_ttbr);
 
diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h
index 7a18fab..659fbf5 100644
--- a/arch/arm64/include/asm/system_misc.h
+++ b/arch/arm64/include/asm/system_misc.h
@@ -41,7 +41,6 @@ struct mm_struct;
 extern void show_pte(struct mm_struct *mm, unsigned long addr);
 extern void __show_regs(struct pt_regs *);
 
-void soft_restart(unsigned long);
 extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
 
 #define UDBG_UNDEFINED	(1 << 0)
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 1309d64..3ca1ade 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -57,40 +57,6 @@ unsigned long __stack_chk_guard __read_mostly;
 EXPORT_SYMBOL(__stack_chk_guard);
 #endif
 
-static void setup_restart(void)
-{
-	/*
-	 * 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.
-	 */
-	setup_mm_for_reboot();
-
-	/* Clean and invalidate caches */
-	flush_cache_all();
-
-	/* Turn D-cache off */
-	cpu_cache_off();
-
-	/* Push out any further dirty data, and ensure cache is empty */
-	flush_cache_all();
-}
-
-void soft_restart(unsigned long addr)
-{
-	typedef void (*phys_reset_t)(unsigned long);
-	phys_reset_t phys_reset;
-
-	setup_restart();
-
-	/* Switch to the identity mapping */
-	phys_reset = (phys_reset_t)virt_to_phys(cpu_reset);
-	phys_reset(addr);
-
-	/* Should never get here */
-	BUG();
-}
-
 /*
  * Function pointers to optional machine specific functions
  */
@@ -162,8 +128,8 @@ void machine_power_off(void)
 
 /*
  * Restart requires that the secondary CPUs stop performing any activity
- * while the primary CPU resets the system. Systems with a single CPU can
- * use soft_restart() as their machine descriptor's .restart hook, since that
+ * while the primary CPU resets the system. Systems with a single CPU can use
+ * cpu_soft_restart() as their machine descriptor's .restart hook, since that
  * will cause the only available CPU to reset. Systems with multiple CPUs must
  * provide a HW restart implementation, to ensure that all CPUs reset at once.
  * This is required so that any code running after reset on the primary CPU
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index 7736779..a7c3fce 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -76,6 +76,40 @@ ENTRY(cpu_reset)
 	ret	x0
 ENDPROC(cpu_reset)
 
+	.align 3
+1:	.quad	memstart_addr
+
+ENTRY(cpu_soft_restart)
+	adr	x1, cpu_reset
+	adr	x2, 1b
+
+	/* virt_to_phys(cpu_reset) */
+	ldr	x3, [x2]
+	ldr	x3, [x3]
+	mov	x4, #1
+	lsl	x4, x4, #(VA_BITS - 1)
+	add	x1, x1, x4
+	add	x1, x1, x3
+
+	/* Save it; We can't use stack as it is going to run with caches OFF */
+	mov	x19, x0
+	mov	x20, x1
+
+	bl	setup_mm_for_reboot
+
+	bl	flush_cache_all
+	/* Turn D-cache off */
+	bl	cpu_cache_off
+	/* Push out any further dirty data, and ensure cache is empty */
+	bl	flush_cache_all
+
+	mov	x0, x19
+
+	br	x20
+	/* It should never come back */
+	bl	panic
+ENDPROC(cpu_soft_restart)
+
 /*
  *	cpu_do_idle()
  *
-- 
1.7.9.5




More information about the linux-arm-kernel mailing list