1 /* SPDX-License-Identifier: GPL-2.0 */ !! 1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 2 /* 3 * Copyright IBM Corp. 2005 !! 3 * relocate_kernel.S for kexec 4 * !! 4 * Created by <nschichan@corp.free.fr> on Thu Oct 12 17:49:57 2006 5 * Author(s): Rolf Adelsberger << 6 * << 7 */ 5 */ 8 6 9 #include <linux/linkage.h> !! 7 #include <asm/asm.h> 10 #include <asm/page.h> !! 8 #include <asm/asmmacro.h> 11 #include <asm/sigp.h> !! 9 #include <asm/regdef.h> >> 10 #include <asm/mipsregs.h> >> 11 #include <asm/stackframe.h> >> 12 #include <asm/addrspace.h> 12 13 >> 14 #include <kernel-entry-init.h> >> 15 >> 16 LEAF(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 >> 25 process_entry: >> 26 PTR_L s2, (s0) >> 27 PTR_ADDIU s0, s0, SZREG >> 28 >> 29 /* >> 30 * In case of a kdump/crash kernel, the indirection page is not >> 31 * populated as the kernel is directly copied to a reserved location >> 32 */ >> 33 beqz s2, done >> 34 >> 35 /* destination page */ >> 36 and s3, s2, 0x1 >> 37 beq s3, zero, 1f >> 38 and s4, s2, ~0x1 /* store destination addr in s4 */ >> 39 b process_entry >> 40 >> 41 1: >> 42 /* indirection page, update s0 */ >> 43 and s3, s2, 0x2 >> 44 beq s3, zero, 1f >> 45 and s0, s2, ~0x2 >> 46 b process_entry >> 47 >> 48 1: >> 49 /* done page */ >> 50 and s3, s2, 0x4 >> 51 beq s3, zero, 1f >> 52 b done >> 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) >> 101 >> 102 #ifdef CONFIG_SMP 13 /* 103 /* 14 * moves the new kernel to its destination... !! 104 * Other CPUs should wait until code is relocated and 15 * %r2 = pointer to first kimage_entry_t !! 105 * then start at entry (?) point. 16 * %r3 = start address - where to jump to afte << 17 * %r4 = subcode << 18 * << 19 * %r5 will be used as temp. storage << 20 * %r6 holds the destination address << 21 * %r7 = PAGE_SIZE << 22 * %r8 holds the source address << 23 * %r9 = PAGE_SIZE << 24 * << 25 * 0xf000 is a page_mask << 26 */ 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 */ >> 118 >> 119 bal 1f >> 120 1: move t1,ra; >> 121 PTR_LA t2,1b >> 122 PTR_LA t0,kexec_flag >> 123 PTR_SUB t0,t0,t2; >> 124 PTR_ADD t0,t1,t0; >> 125 >> 126 1: LONG_L s0, (t0) >> 127 bne s0, zero,1b >> 128 >> 129 #ifdef USE_KEXEC_SMP_WAIT_FINAL >> 130 kexec_smp_wait_final >> 131 #else >> 132 sync >> 133 #endif >> 134 j s1 >> 135 END(kexec_smp_wait) >> 136 #endif >> 137 >> 138 #ifdef __mips64 >> 139 /* all PTR's must be aligned to 8 byte in 64-bit mode */ >> 140 .align 3 >> 141 #endif >> 142 >> 143 /* All parameters to new kernel are passed in registers a0-a3. >> 144 * kexec_args[0..3] are used to prepare register values. >> 145 */ >> 146 >> 147 EXPORT(kexec_args) >> 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 >> 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 */ >> 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 >> 178 >> 179 relocate_new_kernel_end: 27 180 28 .text !! 181 EXPORT(relocate_new_kernel_size) 29 SYM_CODE_START(relocate_kernel) !! 182 PTR_WD relocate_new_kernel_end - relocate_new_kernel 30 basr %r13,0 # base address !! 183 .size relocate_new_kernel_size, PTRSIZE 31 .base: << 32 lghi %r7,PAGE_SIZE # load PAGE_SI << 33 lghi %r9,PAGE_SIZE # load PAGE_SI << 34 lg %r5,0(%r2) # read another << 35 aghi %r2,8 # increment po << 36 tml %r5,0x1 # is it a dest << 37 je .indir_check # NO, goto "in << 38 lgr %r6,%r5 # r6 = r5 << 39 nill %r6,0xf000 # mask it out << 40 j .base # ...next iter << 41 .indir_check: << 42 tml %r5,0x2 # is it a indi << 43 je .done_test # NO, goto "do << 44 nill %r5,0xf000 # YES, mask ou << 45 lgr %r2,%r5 # move it into << 46 j .base # and read nex << 47 .done_test: << 48 tml %r5,0x4 # is it the do << 49 je .source_test # NO! Well, th << 50 j .done # ok, lets fin << 51 .source_test: << 52 tml %r5,0x8 # it should be << 53 je .base # NO, ignore i << 54 lgr %r8,%r5 # r8 = r5 << 55 nill %r8,0xf000 # masking << 56 0: mvcle %r6,%r8,0x0 # copy PAGE_SI << 57 jo 0b << 58 j .base << 59 .done: << 60 lgr %r0,%r4 # subcode << 61 cghi %r3,0 << 62 je .diag << 63 la %r4,load_psw-.base(%r13) << 64 o %r3,4(%r4) # or load addr << 65 st %r3,4(%r4) << 66 mvc 0(8,%r0),0(%r4) # copy psw to << 67 .diag: << 68 diag %r0,%r0,0x308 << 69 SYM_CODE_END(relocate_kernel) << 70 << 71 .balign 8 << 72 SYM_DATA_START_LOCAL(load_psw) << 73 .long 0x00080000,0x80000000 << 74 SYM_DATA_END_LABEL(load_psw, SYM_L_LOCAL, relo << 75 .balign 8 << 76 SYM_DATA(relocate_kernel_len, .quad relocate_k <<
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.