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