1/* 2 * relocate_kernel.S for kexec 3 * Created by <nschichan@corp.free.fr> on Thu Oct 12 17:49:57 2006 4 * 5 * This source code is licensed under the GNU General Public License, 6 * Version 2. See the file COPYING for more details. 7 */ 8 9#include <asm/asm.h> 10#include <asm/asmmacro.h> 11#include <asm/regdef.h> 12#include <asm/page.h> 13#include <asm/mipsregs.h> 14#include <asm/stackframe.h> 15#include <asm/addrspace.h> 16 17LEAF(relocate_new_kernel) 18 PTR_L a0, arg0 19 PTR_L a1, arg1 20 PTR_L a2, arg2 21 PTR_L a3, arg3 22 23 PTR_L s0, kexec_indirection_page 24 PTR_L s1, kexec_start_address 25 26process_entry: 27 PTR_L s2, (s0) 28 PTR_ADD s0, s0, SZREG 29 30 /* destination page */ 31 and s3, s2, 0x1 32 beq s3, zero, 1f 33 and s4, s2, ~0x1 /* store destination addr in s4 */ 34 b process_entry 35 361: 37 /* indirection page, update s0 */ 38 and s3, s2, 0x2 39 beq s3, zero, 1f 40 and s0, s2, ~0x2 41 b process_entry 42 431: 44 /* done page */ 45 and s3, s2, 0x4 46 beq s3, zero, 1f 47 b done 481: 49 /* source page */ 50 and s3, s2, 0x8 51 beq s3, zero, process_entry 52 and s2, s2, ~0x8 53 li s6, (1 << PAGE_SHIFT) / SZREG 54 55copy_word: 56 /* copy page word by word */ 57 REG_L s5, (s2) 58 REG_S s5, (s4) 59 PTR_ADD s4, s4, SZREG 60 PTR_ADD s2, s2, SZREG 61 LONG_SUB s6, s6, 1 62 beq s6, zero, process_entry 63 b copy_word 64 b process_entry 65 66done: 67#ifdef CONFIG_SMP 68 /* kexec_flag reset is signal to other CPUs what kernel 69 was moved to it's location. Note - we need relocated address 70 of kexec_flag. */ 71 72 bal 1f 73 1: move t1,ra; 74 PTR_LA t2,1b 75 PTR_LA t0,kexec_flag 76 PTR_SUB t0,t0,t2; 77 PTR_ADD t0,t1,t0; 78 LONG_S zero,(t0) 79#endif 80 81#ifdef CONFIG_CPU_CAVIUM_OCTEON 82 /* We need to flush I-cache before jumping to new kernel. 83 * Unfortunatelly, this code is cpu-specific. 84 */ 85 .set push 86 .set noreorder 87 syncw 88 syncw 89 synci 0($0) 90 .set pop 91#else 92 sync 93#endif 94 /* jump to kexec_start_address */ 95 j s1 96 END(relocate_new_kernel) 97 98#ifdef CONFIG_SMP 99/* 100 * Other CPUs should wait until code is relocated and 101 * then start at entry (?) point. 102 */ 103LEAF(kexec_smp_wait) 104 PTR_L a0, s_arg0 105 PTR_L a1, s_arg1 106 PTR_L a2, s_arg2 107 PTR_L a3, s_arg3 108 PTR_L s1, kexec_start_address 109 110 /* Non-relocated address works for args and kexec_start_address ( old 111 * kernel is not overwritten). But we need relocated address of 112 * kexec_flag. 113 */ 114 115 bal 1f 1161: move t1,ra; 117 PTR_LA t2,1b 118 PTR_LA t0,kexec_flag 119 PTR_SUB t0,t0,t2; 120 PTR_ADD t0,t1,t0; 121 1221: LONG_L s0, (t0) 123 bne s0, zero,1b 124 125#ifdef CONFIG_CPU_CAVIUM_OCTEON 126 .set push 127 .set noreorder 128 synci 0($0) 129 .set pop 130#else 131 sync 132#endif 133 j s1 134 END(kexec_smp_wait) 135#endif 136 137#ifdef __mips64 138 /* all PTR's must be aligned to 8 byte in 64-bit mode */ 139 .align 3 140#endif 141 142/* All parameters to new kernel are passed in registers a0-a3. 143 * kexec_args[0..3] are uses to prepare register values. 144 */ 145 146kexec_args: 147 EXPORT(kexec_args) 148arg0: PTR 0x0 149arg1: PTR 0x0 150arg2: PTR 0x0 151arg3: PTR 0x0 152 .size kexec_args,PTRSIZE*4 153 154#ifdef CONFIG_SMP 155/* 156 * Secondary CPUs may have different kernel parameters in 157 * their registers a0-a3. secondary_kexec_args[0..3] are used 158 * to prepare register values. 159 */ 160secondary_kexec_args: 161 EXPORT(secondary_kexec_args) 162s_arg0: PTR 0x0 163s_arg1: PTR 0x0 164s_arg2: PTR 0x0 165s_arg3: PTR 0x0 166 .size secondary_kexec_args,PTRSIZE*4 167kexec_flag: 168 LONG 0x1 169 170#endif 171 172kexec_start_address: 173 EXPORT(kexec_start_address) 174 PTR 0x0 175 .size kexec_start_address, PTRSIZE 176 177kexec_indirection_page: 178 EXPORT(kexec_indirection_page) 179 PTR 0 180 .size kexec_indirection_page, PTRSIZE 181 182relocate_new_kernel_end: 183 184relocate_new_kernel_size: 185 EXPORT(relocate_new_kernel_size) 186 PTR relocate_new_kernel_end - relocate_new_kernel 187 .size relocate_new_kernel_size, PTRSIZE 188