1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * relocate_kernel.S for kexec
4 * Created by <nschichan@corp.free.fr> on Thu Oct 12 17:49:57 2006
5 */
6
7#include <asm/asm.h>
8#include <asm/asmmacro.h>
9#include <asm/regdef.h>
10#include <asm/mipsregs.h>
11#include <asm/stackframe.h>
12#include <asm/addrspace.h>
13
14LEAF(relocate_new_kernel)
15	PTR_L a0,	arg0
16	PTR_L a1,	arg1
17	PTR_L a2,	arg2
18	PTR_L a3,	arg3
19
20	PTR_L		s0, kexec_indirection_page
21	PTR_L		s1, kexec_start_address
22
23process_entry:
24	PTR_L		s2, (s0)
25	PTR_ADDIU	s0, s0, SZREG
26
27	/*
28	 * In case of a kdump/crash kernel, the indirection page is not
29	 * populated as the kernel is directly copied to a reserved location
30	 */
31	beqz		s2, done
32
33	/* destination page */
34	and		s3, s2, 0x1
35	beq		s3, zero, 1f
36	and		s4, s2, ~0x1	/* store destination addr in s4 */
37	b		process_entry
38
391:
40	/* indirection page, update s0	*/
41	and		s3, s2, 0x2
42	beq		s3, zero, 1f
43	and		s0, s2, ~0x2
44	b		process_entry
45
461:
47	/* done page */
48	and		s3, s2, 0x4
49	beq		s3, zero, 1f
50	b		done
511:
52	/* source page */
53	and		s3, s2, 0x8
54	beq		s3, zero, process_entry
55	and		s2, s2, ~0x8
56	li		s6, (1 << _PAGE_SHIFT) / SZREG
57
58copy_word:
59	/* copy page word by word */
60	REG_L		s5, (s2)
61	REG_S		s5, (s4)
62	PTR_ADDIU	s4, s4, SZREG
63	PTR_ADDIU	s2, s2, SZREG
64	LONG_ADDIU	s6, s6, -1
65	beq		s6, zero, process_entry
66	b		copy_word
67	b		process_entry
68
69done:
70#ifdef CONFIG_SMP
71	/* kexec_flag reset is signal to other CPUs what kernel
72	   was moved to it's location. Note - we need relocated address
73	   of kexec_flag.  */
74
75	bal		1f
76 1:	move		t1,ra;
77	PTR_LA		t2,1b
78	PTR_LA		t0,kexec_flag
79	PTR_SUB		t0,t0,t2;
80	PTR_ADD		t0,t1,t0;
81	LONG_S		zero,(t0)
82#endif
83
84#ifdef CONFIG_CPU_CAVIUM_OCTEON
85	/* We need to flush I-cache before jumping to new kernel.
86	 * Unfortunately, this code is cpu-specific.
87	 */
88	.set push
89	.set noreorder
90	syncw
91	syncw
92	synci		0($0)
93	.set pop
94#else
95	sync
96#endif
97	/* jump to kexec_start_address */
98	j		s1
99	END(relocate_new_kernel)
100
101#ifdef CONFIG_SMP
102/*
103 * Other CPUs should wait until code is relocated and
104 * then start at entry (?) point.
105 */
106LEAF(kexec_smp_wait)
107	PTR_L		a0, s_arg0
108	PTR_L		a1, s_arg1
109	PTR_L		a2, s_arg2
110	PTR_L		a3, s_arg3
111	PTR_L		s1, kexec_start_address
112
113	/* Non-relocated address works for args and kexec_start_address ( old
114	 * kernel is not overwritten). But we need relocated address of
115	 * kexec_flag.
116	 */
117
118	bal		1f
1191:	move		t1,ra;
120	PTR_LA		t2,1b
121	PTR_LA		t0,kexec_flag
122	PTR_SUB		t0,t0,t2;
123	PTR_ADD		t0,t1,t0;
124
1251:	LONG_L		s0, (t0)
126	bne		s0, zero,1b
127
128#ifdef CONFIG_CPU_CAVIUM_OCTEON
129	.set push
130	.set noreorder
131	synci		0($0)
132	.set pop
133#else
134	sync
135#endif
136	j		s1
137	END(kexec_smp_wait)
138#endif
139
140#ifdef __mips64
141       /* all PTR's must be aligned to 8 byte in 64-bit mode */
142       .align  3
143#endif
144
145/* All parameters to new kernel are passed in registers a0-a3.
146 * kexec_args[0..3] are used to prepare register values.
147 */
148
149kexec_args:
150	EXPORT(kexec_args)
151arg0:	PTR		0x0
152arg1:	PTR		0x0
153arg2:	PTR		0x0
154arg3:	PTR		0x0
155	.size	kexec_args,PTRSIZE*4
156
157#ifdef CONFIG_SMP
158/*
159 * Secondary CPUs may have different kernel parameters in
160 * their registers a0-a3. secondary_kexec_args[0..3] are used
161 * to prepare register values.
162 */
163secondary_kexec_args:
164	EXPORT(secondary_kexec_args)
165s_arg0: PTR		0x0
166s_arg1: PTR		0x0
167s_arg2: PTR		0x0
168s_arg3: PTR		0x0
169	.size	secondary_kexec_args,PTRSIZE*4
170kexec_flag:
171	LONG		0x1
172
173#endif
174
175kexec_start_address:
176	EXPORT(kexec_start_address)
177	PTR		0x0
178	.size		kexec_start_address, PTRSIZE
179
180kexec_indirection_page:
181	EXPORT(kexec_indirection_page)
182	PTR		0
183	.size		kexec_indirection_page, PTRSIZE
184
185relocate_new_kernel_end:
186
187relocate_new_kernel_size:
188	EXPORT(relocate_new_kernel_size)
189	PTR		relocate_new_kernel_end - relocate_new_kernel
190	.size		relocate_new_kernel_size, PTRSIZE
191