1 /* SPDX-License-Identifier: GPL-2.0 */ !! 1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 2 /* 3 * relocate_kernel.S - put the kernel image in !! 3 * relocate_kernel.S for kexec >> 4 * Created by <nschichan@corp.free.fr> on Thu Oct 12 17:49:57 2006 4 */ 5 */ 5 6 6 #include <linux/linkage.h> !! 7 #include <asm/asm.h> 7 #include <asm/assembler.h> !! 8 #include <asm/asmmacro.h> 8 #include <asm/asm-offsets.h> !! 9 #include <asm/regdef.h> 9 #include <asm/kexec.h> !! 10 #include <asm/mipsregs.h> 10 !! 11 #include <asm/stackframe.h> 11 .align 3 /* not needed for this !! 12 #include <asm/addrspace.h> 12 !! 13 13 ENTRY(relocate_new_kernel) !! 14 #include <kernel-entry-init.h> 14 !! 15 15 adr r7, relocate_new_kernel_end !! 16 LEAF(relocate_new_kernel) 16 ldr r0, [r7, #KEXEC_INDIR_PAGE] !! 17 PTR_L a0, arg0 17 ldr r1, [r7, #KEXEC_START_ADDR] !! 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 >> 25 process_entry: >> 26 PTR_L s2, (s0) >> 27 PTR_ADDIU s0, s0, SZREG 18 28 19 /* 29 /* 20 * If there is no indirection page (we !! 30 * In case of a kdump/crash kernel, the indirection page is not 21 * skip any relocation. !! 31 * populated as the kernel is directly copied to a reserved location 22 */ 32 */ 23 cmp r0, #0 !! 33 beqz s2, done 24 beq 2f << 25 34 26 0: /* top, read another word for the indi !! 35 /* destination page */ 27 ldr r3, [r0],#4 !! 36 and s3, s2, 0x1 >> 37 beq s3, zero, 1f >> 38 and s4, s2, ~0x1 /* store destination addr in s4 */ >> 39 b process_entry 28 40 29 /* Is it a destination page. Put desti << 30 tst r3,#1 << 31 beq 1f << 32 bic r4,r3,#1 << 33 b 0b << 34 1: 41 1: 35 /* Is it an indirection page */ !! 42 /* indirection page, update s0 */ 36 tst r3,#2 !! 43 and s3, s2, 0x2 37 beq 1f !! 44 beq s3, zero, 1f 38 bic r0,r3,#2 !! 45 and s0, s2, ~0x2 39 b 0b !! 46 b process_entry >> 47 >> 48 1: >> 49 /* done page */ >> 50 and s3, s2, 0x4 >> 51 beq s3, zero, 1f >> 52 b done 40 1: 53 1: >> 54 /* source page */ >> 55 and s3, s2, 0x8 >> 56 beq s3, zero, process_entry >> 57 and s2, s2, ~0x8 >> 58 li s6, (1 << _PAGE_SHIFT) / SZREG >> 59 >> 60 copy_word: >> 61 /* copy page word by word */ >> 62 REG_L s5, (s2) >> 63 REG_S s5, (s4) >> 64 PTR_ADDIU s4, s4, SZREG >> 65 PTR_ADDIU s2, s2, SZREG >> 66 LONG_ADDIU s6, s6, -1 >> 67 beq s6, zero, process_entry >> 68 b copy_word >> 69 >> 70 done: >> 71 #ifdef CONFIG_SMP >> 72 /* kexec_flag reset is signal to other CPUs what kernel >> 73 was moved to its location. Note - we need relocated address >> 74 of kexec_flag. */ >> 75 >> 76 bal 1f >> 77 1: move t1,ra; >> 78 PTR_LA t2,1b >> 79 PTR_LA t0,kexec_flag >> 80 PTR_SUB t0,t0,t2; >> 81 PTR_ADD t0,t1,t0; >> 82 LONG_S zero,(t0) >> 83 #endif >> 84 >> 85 #ifdef CONFIG_CPU_CAVIUM_OCTEON >> 86 /* We need to flush I-cache before jumping to new kernel. >> 87 * Unfortunately, this code is cpu-specific. >> 88 */ >> 89 .set push >> 90 .set noreorder >> 91 syncw >> 92 syncw >> 93 synci 0($0) >> 94 .set pop >> 95 #else >> 96 sync >> 97 #endif >> 98 /* jump to kexec_start_address */ >> 99 j s1 >> 100 END(relocate_new_kernel) 41 101 42 /* are we done ? */ !! 102 #ifdef CONFIG_SMP 43 tst r3,#4 !! 103 /* 44 beq 1f !! 104 * Other CPUs should wait until code is relocated and 45 b 2f !! 105 * then start at entry (?) point. >> 106 */ >> 107 LEAF(kexec_smp_wait) >> 108 PTR_L a0, s_arg0 >> 109 PTR_L a1, s_arg1 >> 110 PTR_L a2, s_arg2 >> 111 PTR_L a3, s_arg3 >> 112 PTR_L s1, kexec_start_address >> 113 >> 114 /* Non-relocated address works for args and kexec_start_address ( old >> 115 * kernel is not overwritten). But we need relocated address of >> 116 * kexec_flag. >> 117 */ 46 118 47 1: !! 119 bal 1f 48 /* is it source ? */ !! 120 1: move t1,ra; 49 tst r3,#8 !! 121 PTR_LA t2,1b 50 beq 0b !! 122 PTR_LA t0,kexec_flag 51 bic r3,r3,#8 !! 123 PTR_SUB t0,t0,t2; 52 mov r6,#1024 !! 124 PTR_ADD t0,t1,t0; 53 9: !! 125 54 ldr r5,[r3],#4 !! 126 1: LONG_L s0, (t0) 55 str r5,[r4],#4 !! 127 bne s0, zero,1b 56 subs r6,r6,#1 !! 128 57 bne 9b !! 129 #ifdef USE_KEXEC_SMP_WAIT_FINAL 58 b 0b !! 130 kexec_smp_wait_final 59 !! 131 #else 60 2: !! 132 sync 61 /* Jump to relocated kernel */ !! 133 #endif 62 mov lr, r1 !! 134 j s1 63 mov r0, #0 !! 135 END(kexec_smp_wait) 64 ldr r1, [r7, #KEXEC_MACH_TYPE] !! 136 #endif 65 ldr r2, [r7, #KEXEC_R2] !! 137 66 ARM( ret lr ) !! 138 #ifdef __mips64 67 THUMB( bx lr ) !! 139 /* all PTR's must be aligned to 8 byte in 64-bit mode */ >> 140 .align 3 >> 141 #endif 68 142 69 ENDPROC(relocate_new_kernel) !! 143 /* All parameters to new kernel are passed in registers a0-a3. >> 144 * kexec_args[0..3] are used to prepare register values. >> 145 */ 70 146 71 .align 3 !! 147 EXPORT(kexec_args) 72 relocate_new_kernel_end: !! 148 arg0: PTR_WD 0x0 >> 149 arg1: PTR_WD 0x0 >> 150 arg2: PTR_WD 0x0 >> 151 arg3: PTR_WD 0x0 >> 152 .size kexec_args,PTRSIZE*4 73 153 74 .globl relocate_new_kernel_size !! 154 #ifdef CONFIG_SMP 75 relocate_new_kernel_size: !! 155 /* 76 .long relocate_new_kernel_end - reloca !! 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 */ >> 160 EXPORT(secondary_kexec_args) >> 161 s_arg0: PTR_WD 0x0 >> 162 s_arg1: PTR_WD 0x0 >> 163 s_arg2: PTR_WD 0x0 >> 164 s_arg3: PTR_WD 0x0 >> 165 .size secondary_kexec_args,PTRSIZE*4 >> 166 kexec_flag: >> 167 LONG 0x1 >> 168 >> 169 #endif >> 170 >> 171 EXPORT(kexec_start_address) >> 172 PTR_WD 0x0 >> 173 .size kexec_start_address, PTRSIZE >> 174 >> 175 EXPORT(kexec_indirection_page) >> 176 PTR_WD 0 >> 177 .size kexec_indirection_page, PTRSIZE 77 178 >> 179 relocate_new_kernel_end: 78 180 >> 181 EXPORT(relocate_new_kernel_size) >> 182 PTR_WD relocate_new_kernel_end - relocate_new_kernel >> 183 .size relocate_new_kernel_size, PTRSIZE
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.