Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / arch / mips / kernel / relocate_kernel.S
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
14 LEAF(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
23 process_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
39 1:
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
46 1:
47         /* done page */
48         and             s3, s2, 0x4
49         beq             s3, zero, 1f
50         b               done
51 1:
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
58 copy_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
69 done:
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  */
106 LEAF(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
119 1:      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
125 1:      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
149 kexec_args:
150         EXPORT(kexec_args)
151 arg0:   PTR             0x0
152 arg1:   PTR             0x0
153 arg2:   PTR             0x0
154 arg3:   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  */
163 secondary_kexec_args:
164         EXPORT(secondary_kexec_args)
165 s_arg0: PTR             0x0
166 s_arg1: PTR             0x0
167 s_arg2: PTR             0x0
168 s_arg3: PTR             0x0
169         .size   secondary_kexec_args,PTRSIZE*4
170 kexec_flag:
171         LONG            0x1
172
173 #endif
174
175 kexec_start_address:
176         EXPORT(kexec_start_address)
177         PTR             0x0
178         .size           kexec_start_address, PTRSIZE
179
180 kexec_indirection_page:
181         EXPORT(kexec_indirection_page)
182         PTR             0
183         .size           kexec_indirection_page, PTRSIZE
184
185 relocate_new_kernel_end:
186
187 relocate_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