From mboxrd@z Thu Jan 1 00:00:00 1970 From: achandran@mvista.com (Arun Chandran) Date: Tue, 12 Aug 2014 18:12:45 +0530 Subject: [PATCH] Arm64: convert soft_restart() to assembly code Message-ID: <1407847365-10873-1-git-send-email-achandran@mvista.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org 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 --- 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@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