1 /* SPDX-License-Identifier: GPL-2.0 */ !! 1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 #include <linux/linkage.h> !! 2 /* 3 #include <linux/kexec.h> !! 3 * relocate_kernel.S for kexec 4 !! 4 * Created by <nschichan@corp.free.fr> on Thu Oct 12 17:49:57 2006 5 #include <asm/assembly.h> !! 5 */ 6 #include <asm/asm-offsets.h> << 7 #include <asm/page.h> << 8 #include <asm/setup.h> << 9 #include <asm/psw.h> << 10 << 11 .level PA_ASM_LEVEL << 12 << 13 .macro kexec_param name << 14 .align 8 << 15 ENTRY(kexec\()_\name) << 16 #ifdef CONFIG_64BIT << 17 .dword 0 << 18 #else << 19 .word 0 << 20 #endif << 21 6 22 ENTRY(kexec\()_\name\()_offset) !! 7 #include <asm/asm.h> 23 .word kexec\()_\name - relocate_new_ke !! 8 #include <asm/asmmacro.h> 24 .endm !! 9 #include <asm/regdef.h> >> 10 #include <asm/mipsregs.h> >> 11 #include <asm/stackframe.h> >> 12 #include <asm/addrspace.h> >> 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 25 34 26 .text !! 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 27 84 28 /* args: !! 85 #ifdef CONFIG_CPU_CAVIUM_OCTEON 29 * r26 - kimage->head !! 86 /* We need to flush I-cache before jumping to new kernel. 30 * r25 - start address of kernel !! 87 * Unfortunately, this code is cpu-specific. 31 * r24 - physical address of relocate code !! 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 >> 103 /* >> 104 * Other CPUs should wait until code is relocated and >> 105 * then start at entry (?) point. 32 */ 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 */ 33 118 34 ENTRY_CFI(relocate_new_kernel) !! 119 bal 1f 35 0: copy %arg1, %rp !! 120 1: move t1,ra; 36 /* disable I and Q bit, so we are allo !! 121 PTR_LA t2,1b 37 rsm PSW_SM_I, %r0 !! 122 PTR_LA t0,kexec_flag 38 nop !! 123 PTR_SUB t0,t0,t2; 39 nop !! 124 PTR_ADD t0,t1,t0; 40 nop << 41 nop << 42 nop << 43 nop << 44 nop << 45 << 46 rsm PSW_SM_Q, %r0 << 47 nop << 48 nop << 49 nop << 50 nop << 51 nop << 52 nop << 53 nop << 54 125 55 /* !! 126 1: LONG_L s0, (t0) 56 * After return-from-interrupt, we wan !! 127 bne s0, zero,1b 57 * translation enabled just like on a << 58 */ << 59 128 60 /* calculate new physical execution ad !! 129 #ifdef USE_KEXEC_SMP_WAIT_FINAL 61 ldo 1f-0b(%arg2), %r1 !! 130 kexec_smp_wait_final 62 mtctl %r0, %cr17 /* IIASQ */ << 63 mtctl %r0, %cr17 /* IIASQ */ << 64 mtctl %r1, %cr18 /* IIAOQ */ << 65 ldo 4(%r1),%r1 << 66 mtctl %r1, %cr18 /* IIAOQ */ << 67 #ifdef CONFIG_64BIT << 68 depdi,z 1, PSW_W_BIT, 1, %r1 << 69 mtctl %r1, %cr22 /* IPSW */ << 70 #else 131 #else 71 mtctl %r0, %cr22 /* IPSW */ !! 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 72 #endif 141 #endif 73 /* lets go... */ !! 142 74 rfi !! 143 /* All parameters to new kernel are passed in registers a0-a3. 75 1: nop !! 144 * kexec_args[0..3] are used to prepare register values. 76 nop !! 145 */ 77 !! 146 78 .Lloop: !! 147 EXPORT(kexec_args) 79 LDREG,ma REG_SZ(%arg0), %r3 !! 148 arg0: PTR_WD 0x0 80 /* If crash kernel, no copy needed */ !! 149 arg1: PTR_WD 0x0 81 cmpib,COND(=),n 0,%r3,boot !! 150 arg2: PTR_WD 0x0 82 !! 151 arg3: PTR_WD 0x0 83 bb,<,n %r3, 31 - IND_DONE_BIT !! 152 .size kexec_args,PTRSIZE*4 84 bb,>=,n %r3, 31 - IND_INDIRECT !! 153 85 /* indirection, load and restart */ !! 154 #ifdef CONFIG_SMP 86 movb %r3, %arg0, .Lloop !! 155 /* 87 depi 0, 31, PAGE_SHIFT, %ar !! 156 * Secondary CPUs may have different kernel parameters in 88 !! 157 * their registers a0-a3. secondary_kexec_args[0..3] are used 89 .Lnotind: !! 158 * to prepare register values. 90 bb,>=,n %r3, 31 - IND_DESTINAT !! 159 */ 91 b .Lloop !! 160 EXPORT(secondary_kexec_args) 92 copy %r3, %r20 !! 161 s_arg0: PTR_WD 0x0 93 !! 162 s_arg1: PTR_WD 0x0 94 .Lnotdest: !! 163 s_arg2: PTR_WD 0x0 95 bb,>= %r3, 31 - IND_SOURCE_B !! 164 s_arg3: PTR_WD 0x0 96 depi 0, 31, PAGE_SHIFT, %r3 !! 165 .size secondary_kexec_args,PTRSIZE*4 97 copy %r3, %r21 !! 166 kexec_flag: 98 !! 167 LONG 0x1 99 /* copy page */ !! 168 100 copy %r0, %r18 !! 169 #endif 101 zdepi 1, 31 - PAGE_SHIFT, 1, !! 170 102 add %r20, %r18, %r17 !! 171 EXPORT(kexec_start_address) 103 !! 172 PTR_WD 0x0 104 depi 0, 31, PAGE_SHIFT, %r2 !! 173 .size kexec_start_address, PTRSIZE 105 .Lcopy: !! 174 106 copy %r20, %r12 !! 175 EXPORT(kexec_indirection_page) 107 LDREG,ma REG_SZ(%r21), %r8 !! 176 PTR_WD 0 108 LDREG,ma REG_SZ(%r21), %r9 !! 177 .size kexec_indirection_page, PTRSIZE 109 LDREG,ma REG_SZ(%r21), %r10 !! 178 110 LDREG,ma REG_SZ(%r21), %r11 !! 179 relocate_new_kernel_end: 111 STREG,ma %r8, REG_SZ(%r20) !! 180 112 STREG,ma %r9, REG_SZ(%r20) !! 181 EXPORT(relocate_new_kernel_size) 113 STREG,ma %r10, REG_SZ(%r20) !! 182 PTR_WD relocate_new_kernel_end - relocate_new_kernel 114 STREG,ma %r11, REG_SZ(%r20) !! 183 .size relocate_new_kernel_size, PTRSIZE 115 << 116 #ifndef CONFIG_64BIT << 117 LDREG,ma REG_SZ(%r21), %r8 << 118 LDREG,ma REG_SZ(%r21), %r9 << 119 LDREG,ma REG_SZ(%r21), %r10 << 120 LDREG,ma REG_SZ(%r21), %r11 << 121 STREG,ma %r8, REG_SZ(%r20) << 122 STREG,ma %r9, REG_SZ(%r20) << 123 STREG,ma %r10, REG_SZ(%r20) << 124 STREG,ma %r11, REG_SZ(%r20) << 125 #endif << 126 << 127 fdc %r0(%r12) << 128 cmpb,COND(<<) %r20,%r17,.Lcopy << 129 fic (%sr4, %r12) << 130 b,n .Lloop << 131 << 132 boot: << 133 mtctl %r0, %cr15 << 134 << 135 LDREG kexec_free_mem-0b(%arg2), %arg << 136 LDREG kexec_cmdline-0b(%arg2), %arg1 << 137 LDREG kexec_initrd_end-0b(%arg2), %a << 138 LDREG kexec_initrd_start-0b(%arg2), << 139 bv,n %r0(%rp) << 140 << 141 ENDPROC_CFI(relocate_new_kernel); << 142 << 143 ENTRY(relocate_new_kernel_size) << 144 .word relocate_new_kernel_size - reloca << 145 << 146 kexec_param cmdline << 147 kexec_param initrd_start << 148 kexec_param initrd_end << 149 kexec_param free_mem <<
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.