140b0b3f8SThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-only */ 2583bb86fSNicolas Schichan/* 3583bb86fSNicolas Schichan * relocate_kernel.S for kexec 4583bb86fSNicolas Schichan * Created by <[email protected]> on Thu Oct 12 17:49:57 2006 5583bb86fSNicolas Schichan */ 6583bb86fSNicolas Schichan 7583bb86fSNicolas Schichan#include <asm/asm.h> 8583bb86fSNicolas Schichan#include <asm/asmmacro.h> 9583bb86fSNicolas Schichan#include <asm/regdef.h> 10583bb86fSNicolas Schichan#include <asm/mipsregs.h> 11583bb86fSNicolas Schichan#include <asm/stackframe.h> 12583bb86fSNicolas Schichan#include <asm/addrspace.h> 13583bb86fSNicolas Schichan 146ce48897SHuacai Chen#include <kernel-entry-init.h> 156ce48897SHuacai Chen 1600be0f30SRalf BaechleLEAF(relocate_new_kernel) 177aa1c8f4SRalf Baechle PTR_L a0, arg0 187aa1c8f4SRalf Baechle PTR_L a1, arg1 197aa1c8f4SRalf Baechle PTR_L a2, arg2 207aa1c8f4SRalf Baechle PTR_L a3, arg3 217aa1c8f4SRalf Baechle 22583bb86fSNicolas Schichan PTR_L s0, kexec_indirection_page 23583bb86fSNicolas Schichan PTR_L s1, kexec_start_address 24583bb86fSNicolas Schichan 25583bb86fSNicolas Schichanprocess_entry: 26583bb86fSNicolas Schichan PTR_L s2, (s0) 27a4504755SJames Cowgill PTR_ADDIU s0, s0, SZREG 28583bb86fSNicolas Schichan 29273463b7SPrem Mallappa /* 30273463b7SPrem Mallappa * In case of a kdump/crash kernel, the indirection page is not 31273463b7SPrem Mallappa * populated as the kernel is directly copied to a reserved location 32273463b7SPrem Mallappa */ 33273463b7SPrem Mallappa beqz s2, done 34273463b7SPrem Mallappa 35583bb86fSNicolas Schichan /* destination page */ 36583bb86fSNicolas Schichan and s3, s2, 0x1 37583bb86fSNicolas Schichan beq s3, zero, 1f 38583bb86fSNicolas Schichan and s4, s2, ~0x1 /* store destination addr in s4 */ 39583bb86fSNicolas Schichan b process_entry 40583bb86fSNicolas Schichan 41583bb86fSNicolas Schichan1: 42583bb86fSNicolas Schichan /* indirection page, update s0 */ 43583bb86fSNicolas Schichan and s3, s2, 0x2 44583bb86fSNicolas Schichan beq s3, zero, 1f 45583bb86fSNicolas Schichan and s0, s2, ~0x2 46583bb86fSNicolas Schichan b process_entry 47583bb86fSNicolas Schichan 48583bb86fSNicolas Schichan1: 49583bb86fSNicolas Schichan /* done page */ 50583bb86fSNicolas Schichan and s3, s2, 0x4 51583bb86fSNicolas Schichan beq s3, zero, 1f 52583bb86fSNicolas Schichan b done 53583bb86fSNicolas Schichan1: 54583bb86fSNicolas Schichan /* source page */ 55583bb86fSNicolas Schichan and s3, s2, 0x8 56583bb86fSNicolas Schichan beq s3, zero, process_entry 57583bb86fSNicolas Schichan and s2, s2, ~0x8 58bef9ae3dSRalf Baechle li s6, (1 << _PAGE_SHIFT) / SZREG 59583bb86fSNicolas Schichan 60583bb86fSNicolas Schichancopy_word: 61583bb86fSNicolas Schichan /* copy page word by word */ 62583bb86fSNicolas Schichan REG_L s5, (s2) 63583bb86fSNicolas Schichan REG_S s5, (s4) 64a4504755SJames Cowgill PTR_ADDIU s4, s4, SZREG 65a4504755SJames Cowgill PTR_ADDIU s2, s2, SZREG 66a4504755SJames Cowgill LONG_ADDIU s6, s6, -1 67583bb86fSNicolas Schichan beq s6, zero, process_entry 68583bb86fSNicolas Schichan b copy_word 69583bb86fSNicolas Schichan 70583bb86fSNicolas Schichandone: 717aa1c8f4SRalf Baechle#ifdef CONFIG_SMP 727aa1c8f4SRalf Baechle /* kexec_flag reset is signal to other CPUs what kernel 73*2f9060b1SBjorn Helgaas was moved to its location. Note - we need relocated address 747aa1c8f4SRalf Baechle of kexec_flag. */ 757aa1c8f4SRalf Baechle 767aa1c8f4SRalf Baechle bal 1f 777aa1c8f4SRalf Baechle 1: move t1,ra; 787aa1c8f4SRalf Baechle PTR_LA t2,1b 797aa1c8f4SRalf Baechle PTR_LA t0,kexec_flag 807aa1c8f4SRalf Baechle PTR_SUB t0,t0,t2; 817aa1c8f4SRalf Baechle PTR_ADD t0,t1,t0; 827aa1c8f4SRalf Baechle LONG_S zero,(t0) 837aa1c8f4SRalf Baechle#endif 847aa1c8f4SRalf Baechle 85abe77f90SRalf Baechle#ifdef CONFIG_CPU_CAVIUM_OCTEON 86abe77f90SRalf Baechle /* We need to flush I-cache before jumping to new kernel. 8728a87b45SYegor Yefremov * Unfortunately, this code is cpu-specific. 88abe77f90SRalf Baechle */ 89abe77f90SRalf Baechle .set push 90abe77f90SRalf Baechle .set noreorder 91abe77f90SRalf Baechle syncw 92abe77f90SRalf Baechle syncw 93abe77f90SRalf Baechle synci 0($0) 94abe77f90SRalf Baechle .set pop 95abe77f90SRalf Baechle#else 967aa1c8f4SRalf Baechle sync 97abe77f90SRalf Baechle#endif 98583bb86fSNicolas Schichan /* jump to kexec_start_address */ 99583bb86fSNicolas Schichan j s1 10000be0f30SRalf Baechle END(relocate_new_kernel) 101583bb86fSNicolas Schichan 1027aa1c8f4SRalf Baechle#ifdef CONFIG_SMP 1037aa1c8f4SRalf Baechle/* 1047aa1c8f4SRalf Baechle * Other CPUs should wait until code is relocated and 1057aa1c8f4SRalf Baechle * then start at entry (?) point. 1067aa1c8f4SRalf Baechle */ 1077aa1c8f4SRalf BaechleLEAF(kexec_smp_wait) 1087aa1c8f4SRalf Baechle PTR_L a0, s_arg0 1097aa1c8f4SRalf Baechle PTR_L a1, s_arg1 1107aa1c8f4SRalf Baechle PTR_L a2, s_arg2 1117aa1c8f4SRalf Baechle PTR_L a3, s_arg3 1127aa1c8f4SRalf Baechle PTR_L s1, kexec_start_address 1137aa1c8f4SRalf Baechle 1147aa1c8f4SRalf Baechle /* Non-relocated address works for args and kexec_start_address ( old 1157aa1c8f4SRalf Baechle * kernel is not overwritten). But we need relocated address of 1167aa1c8f4SRalf Baechle * kexec_flag. 1177aa1c8f4SRalf Baechle */ 1187aa1c8f4SRalf Baechle 1197aa1c8f4SRalf Baechle bal 1f 1207aa1c8f4SRalf Baechle1: move t1,ra; 1217aa1c8f4SRalf Baechle PTR_LA t2,1b 1227aa1c8f4SRalf Baechle PTR_LA t0,kexec_flag 1237aa1c8f4SRalf Baechle PTR_SUB t0,t0,t2; 1247aa1c8f4SRalf Baechle PTR_ADD t0,t1,t0; 1257aa1c8f4SRalf Baechle 1267aa1c8f4SRalf Baechle1: LONG_L s0, (t0) 1277aa1c8f4SRalf Baechle bne s0, zero,1b 1287aa1c8f4SRalf Baechle 1296ce48897SHuacai Chen#ifdef USE_KEXEC_SMP_WAIT_FINAL 1306ce48897SHuacai Chen kexec_smp_wait_final 131abe77f90SRalf Baechle#else 1327aa1c8f4SRalf Baechle sync 133abe77f90SRalf Baechle#endif 1347aa1c8f4SRalf Baechle j s1 1357aa1c8f4SRalf Baechle END(kexec_smp_wait) 1367aa1c8f4SRalf Baechle#endif 1377aa1c8f4SRalf Baechle 1387aa1c8f4SRalf Baechle#ifdef __mips64 1397aa1c8f4SRalf Baechle /* all PTR's must be aligned to 8 byte in 64-bit mode */ 1407aa1c8f4SRalf Baechle .align 3 1417aa1c8f4SRalf Baechle#endif 1427aa1c8f4SRalf Baechle 1437aa1c8f4SRalf Baechle/* All parameters to new kernel are passed in registers a0-a3. 14428a87b45SYegor Yefremov * kexec_args[0..3] are used to prepare register values. 1457aa1c8f4SRalf Baechle */ 1467aa1c8f4SRalf Baechle 1477aa1c8f4SRalf BaechleEXPORT(kexec_args) 148fa62f39dSThomas Bogendoerferarg0: PTR_WD 0x0 149fa62f39dSThomas Bogendoerferarg1: PTR_WD 0x0 150fa62f39dSThomas Bogendoerferarg2: PTR_WD 0x0 151fa62f39dSThomas Bogendoerferarg3: PTR_WD 0x0 1527aa1c8f4SRalf Baechle .size kexec_args,PTRSIZE*4 1537aa1c8f4SRalf Baechle 1547aa1c8f4SRalf Baechle#ifdef CONFIG_SMP 1557aa1c8f4SRalf Baechle/* 1567aa1c8f4SRalf Baechle * Secondary CPUs may have different kernel parameters in 1577aa1c8f4SRalf Baechle * their registers a0-a3. secondary_kexec_args[0..3] are used 1587aa1c8f4SRalf Baechle * to prepare register values. 1597aa1c8f4SRalf Baechle */ 1607aa1c8f4SRalf BaechleEXPORT(secondary_kexec_args) 161fa62f39dSThomas Bogendoerfers_arg0: PTR_WD 0x0 162fa62f39dSThomas Bogendoerfers_arg1: PTR_WD 0x0 163fa62f39dSThomas Bogendoerfers_arg2: PTR_WD 0x0 164fa62f39dSThomas Bogendoerfers_arg3: PTR_WD 0x0 1657aa1c8f4SRalf Baechle .size secondary_kexec_args,PTRSIZE*4 1667aa1c8f4SRalf Baechlekexec_flag: 1677aa1c8f4SRalf Baechle LONG 0x1 1687aa1c8f4SRalf Baechle 1697aa1c8f4SRalf Baechle#endif 1707aa1c8f4SRalf Baechle 17100be0f30SRalf BaechleEXPORT(kexec_start_address) 172fa62f39dSThomas Bogendoerfer PTR_WD 0x0 17300be0f30SRalf Baechle .size kexec_start_address, PTRSIZE 174583bb86fSNicolas Schichan 17500be0f30SRalf BaechleEXPORT(kexec_indirection_page) 176fa62f39dSThomas Bogendoerfer PTR_WD 0 17700be0f30SRalf Baechle .size kexec_indirection_page, PTRSIZE 178583bb86fSNicolas Schichan 179583bb86fSNicolas Schichanrelocate_new_kernel_end: 180583bb86fSNicolas Schichan 18100be0f30SRalf BaechleEXPORT(relocate_new_kernel_size) 182fa62f39dSThomas Bogendoerfer PTR_WD relocate_new_kernel_end - relocate_new_kernel 18300be0f30SRalf Baechle .size relocate_new_kernel_size, PTRSIZE 184