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