summaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/relocate_kernel.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/relocate_kernel.S')
-rw-r--r--arch/mips/kernel/relocate_kernel.S112
1 files changed, 108 insertions, 4 deletions
diff --git a/arch/mips/kernel/relocate_kernel.S b/arch/mips/kernel/relocate_kernel.S
index 87481f916a61..43d2d78d3287 100644
--- a/arch/mips/kernel/relocate_kernel.S
+++ b/arch/mips/kernel/relocate_kernel.S
@@ -9,12 +9,16 @@
#include <asm/asm.h>
#include <asm/asmmacro.h>
#include <asm/regdef.h>
-#include <asm/page.h>
#include <asm/mipsregs.h>
#include <asm/stackframe.h>
#include <asm/addrspace.h>
LEAF(relocate_new_kernel)
+ PTR_L a0, arg0
+ PTR_L a1, arg1
+ PTR_L a2, arg2
+ PTR_L a3, arg3
+
PTR_L s0, kexec_indirection_page
PTR_L s1, kexec_start_address
@@ -26,11 +30,10 @@ process_entry:
and s3, s2, 0x1
beq s3, zero, 1f
and s4, s2, ~0x1 /* store destination addr in s4 */
- move a0, s4
b process_entry
1:
- /* indirection page, update s0 */
+ /* indirection page, update s0 */
and s3, s2, 0x2
beq s3, zero, 1f
and s0, s2, ~0x2
@@ -46,7 +49,7 @@ process_entry:
and s3, s2, 0x8
beq s3, zero, process_entry
and s2, s2, ~0x8
- li s6, (1 << PAGE_SHIFT) / SZREG
+ li s6, (1 << _PAGE_SHIFT) / SZREG
copy_word:
/* copy page word by word */
@@ -60,10 +63,111 @@ copy_word:
b process_entry
done:
+#ifdef CONFIG_SMP
+ /* kexec_flag reset is signal to other CPUs what kernel
+ was moved to it's location. Note - we need relocated address
+ of kexec_flag. */
+
+ bal 1f
+ 1: move t1,ra;
+ PTR_LA t2,1b
+ PTR_LA t0,kexec_flag
+ PTR_SUB t0,t0,t2;
+ PTR_ADD t0,t1,t0;
+ LONG_S zero,(t0)
+#endif
+
+#ifdef CONFIG_CPU_CAVIUM_OCTEON
+ /* We need to flush I-cache before jumping to new kernel.
+ * Unfortunatelly, this code is cpu-specific.
+ */
+ .set push
+ .set noreorder
+ syncw
+ syncw
+ synci 0($0)
+ .set pop
+#else
+ sync
+#endif
/* jump to kexec_start_address */
j s1
END(relocate_new_kernel)
+#ifdef CONFIG_SMP
+/*
+ * Other CPUs should wait until code is relocated and
+ * then start at entry (?) point.
+ */
+LEAF(kexec_smp_wait)
+ PTR_L a0, s_arg0
+ PTR_L a1, s_arg1
+ PTR_L a2, s_arg2
+ PTR_L a3, s_arg3
+ PTR_L s1, kexec_start_address
+
+ /* Non-relocated address works for args and kexec_start_address ( old
+ * kernel is not overwritten). But we need relocated address of
+ * kexec_flag.
+ */
+
+ bal 1f
+1: move t1,ra;
+ PTR_LA t2,1b
+ PTR_LA t0,kexec_flag
+ PTR_SUB t0,t0,t2;
+ PTR_ADD t0,t1,t0;
+
+1: LONG_L s0, (t0)
+ bne s0, zero,1b
+
+#ifdef CONFIG_CPU_CAVIUM_OCTEON
+ .set push
+ .set noreorder
+ synci 0($0)
+ .set pop
+#else
+ sync
+#endif
+ j s1
+ END(kexec_smp_wait)
+#endif
+
+#ifdef __mips64
+ /* all PTR's must be aligned to 8 byte in 64-bit mode */
+ .align 3
+#endif
+
+/* All parameters to new kernel are passed in registers a0-a3.
+ * kexec_args[0..3] are uses to prepare register values.
+ */
+
+kexec_args:
+ EXPORT(kexec_args)
+arg0: PTR 0x0
+arg1: PTR 0x0
+arg2: PTR 0x0
+arg3: PTR 0x0
+ .size kexec_args,PTRSIZE*4
+
+#ifdef CONFIG_SMP
+/*
+ * Secondary CPUs may have different kernel parameters in
+ * their registers a0-a3. secondary_kexec_args[0..3] are used
+ * to prepare register values.
+ */
+secondary_kexec_args:
+ EXPORT(secondary_kexec_args)
+s_arg0: PTR 0x0
+s_arg1: PTR 0x0
+s_arg2: PTR 0x0
+s_arg3: PTR 0x0
+ .size secondary_kexec_args,PTRSIZE*4
+kexec_flag:
+ LONG 0x1
+
+#endif
+
kexec_start_address:
EXPORT(kexec_start_address)
PTR 0x0