88c3beabe9b4690b4a7b2837136ecf4c765a50b5
[linux-2.6-microblaze.git] / arch / riscv / kernel / kexec_relocate.S
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Copyright (C) 2019 FORTH-ICS/CARV
4  *  Nick Kossifidis <mick@ics.forth.gr>
5  */
6
7 #include <asm/asm.h>    /* For RISCV_* and REG_* macros */
8 #include <asm/csr.h>    /* For CSR_* macros */
9 #include <asm/page.h>   /* For PAGE_SIZE */
10 #include <linux/linkage.h> /* For SYM_* macros */
11
12 .section ".rodata"
13 SYM_CODE_START(riscv_kexec_relocate)
14
15         /*
16          * s0: Pointer to the current entry
17          * s1: (const) Phys address to jump to after relocation
18          * s2: (const) Phys address of the FDT image
19          * s3: (const) The hartid of the current hart
20          * s4: Pointer to the destination address for the relocation
21          * s5: (const) Number of words per page
22          * s6: (const) 1, used for subtraction
23          * s7: (const) va_pa_offset, used when switching MMU off
24          * s8: (const) Physical address of the main loop
25          * s9: (debug) indirection page counter
26          * s10: (debug) entry counter
27          * s11: (debug) copied words counter
28          */
29         mv      s0, a0
30         mv      s1, a1
31         mv      s2, a2
32         mv      s3, a3
33         mv      s4, zero
34         li      s5, (PAGE_SIZE / RISCV_SZPTR)
35         li      s6, 1
36         mv      s7, a4
37         mv      s8, zero
38         mv      s9, zero
39         mv      s10, zero
40         mv      s11, zero
41
42         /* Disable / cleanup interrupts */
43         csrw    CSR_SIE, zero
44         csrw    CSR_SIP, zero
45
46         /*
47          * When we switch SATP.MODE to "Bare" we'll only
48          * play with physical addresses. However the first time
49          * we try to jump somewhere, the offset on the jump
50          * will be relative to pc which will still be on VA. To
51          * deal with this we set stvec to the physical address at
52          * the start of the loop below so that we jump there in
53          * any case.
54          */
55         la      s8, 1f
56         sub     s8, s8, s7
57         csrw    CSR_STVEC, s8
58
59         /* Process entries in a loop */
60 .align 2
61 1:
62         addi    s10, s10, 1
63         REG_L   t0, 0(s0)               /* t0 = *image->entry */
64         addi    s0, s0, RISCV_SZPTR     /* image->entry++ */
65
66         /* IND_DESTINATION entry ? -> save destination address */
67         andi    t1, t0, 0x1
68         beqz    t1, 2f
69         andi    s4, t0, ~0x1
70         j       1b
71
72 2:
73         /* IND_INDIRECTION entry ? -> update next entry ptr (PA) */
74         andi    t1, t0, 0x2
75         beqz    t1, 2f
76         andi    s0, t0, ~0x2
77         addi    s9, s9, 1
78         csrw    CSR_SATP, zero
79         jalr    zero, s8, 0
80
81 2:
82         /* IND_DONE entry ? -> jump to done label */
83         andi    t1, t0, 0x4
84         beqz    t1, 2f
85         j       4f
86
87 2:
88         /*
89          * IND_SOURCE entry ? -> copy page word by word to the
90          * destination address we got from IND_DESTINATION
91          */
92         andi    t1, t0, 0x8
93         beqz    t1, 1b          /* Unknown entry type, ignore it */
94         andi    t0, t0, ~0x8
95         mv      t3, s5          /* i = num words per page */
96 3:      /* copy loop */
97         REG_L   t1, (t0)        /* t1 = *src_ptr */
98         REG_S   t1, (s4)        /* *dst_ptr = *src_ptr */
99         addi    t0, t0, RISCV_SZPTR /* stc_ptr++ */
100         addi    s4, s4, RISCV_SZPTR /* dst_ptr++ */
101         sub     t3, t3, s6      /* i-- */
102         addi    s11, s11, 1     /* c++ */
103         beqz    t3, 1b          /* copy done ? */
104         j       3b
105
106 4:
107         /* Pass the arguments to the next kernel  / Cleanup*/
108         mv      a0, s3
109         mv      a1, s2
110         mv      a2, s1
111
112         /* Cleanup */
113         mv      a3, zero
114         mv      a4, zero
115         mv      a5, zero
116         mv      a6, zero
117         mv      a7, zero
118
119         mv      s0, zero
120         mv      s1, zero
121         mv      s2, zero
122         mv      s3, zero
123         mv      s4, zero
124         mv      s5, zero
125         mv      s6, zero
126         mv      s7, zero
127         mv      s8, zero
128         mv      s9, zero
129         mv      s10, zero
130         mv      s11, zero
131
132         mv      t0, zero
133         mv      t1, zero
134         mv      t2, zero
135         mv      t3, zero
136         mv      t4, zero
137         mv      t5, zero
138         mv      t6, zero
139         csrw    CSR_SEPC, zero
140         csrw    CSR_SCAUSE, zero
141         csrw    CSR_SSCRATCH, zero
142
143         /*
144          * Make sure the relocated code is visible
145          * and jump to the new kernel
146          */
147         fence.i
148
149         jalr    zero, a2, 0
150
151 SYM_CODE_END(riscv_kexec_relocate)
152 riscv_kexec_relocate_end:
153
154
155 /* Used for jumping to crashkernel */
156 .section ".text"
157 SYM_CODE_START(riscv_kexec_norelocate)
158         /*
159          * s0: (const) Phys address to jump to
160          * s1: (const) Phys address of the FDT image
161          * s2: (const) The hartid of the current hart
162          * s3: (const) va_pa_offset, used when switching MMU off
163          */
164         mv      s0, a1
165         mv      s1, a2
166         mv      s2, a3
167         mv      s3, a4
168
169         /* Disable / cleanup interrupts */
170         csrw    CSR_SIE, zero
171         csrw    CSR_SIP, zero
172
173         /* Switch to physical addressing */
174         la      s4, 1f
175         sub     s4, s4, s3
176         csrw    CSR_STVEC, s4
177         csrw    CSR_SATP, zero
178
179 .align 2
180 1:
181         /* Pass the arguments to the next kernel  / Cleanup*/
182         mv      a0, s2
183         mv      a1, s1
184         mv      a2, s0
185
186         /* Cleanup */
187         mv      a3, zero
188         mv      a4, zero
189         mv      a5, zero
190         mv      a6, zero
191         mv      a7, zero
192
193         mv      s0, zero
194         mv      s1, zero
195         mv      s2, zero
196         mv      s3, zero
197         mv      s4, zero
198         mv      s5, zero
199         mv      s6, zero
200         mv      s7, zero
201         mv      s8, zero
202         mv      s9, zero
203         mv      s10, zero
204         mv      s11, zero
205
206         mv      t0, zero
207         mv      t1, zero
208         mv      t2, zero
209         mv      t3, zero
210         mv      t4, zero
211         mv      t5, zero
212         mv      t6, zero
213         csrw    CSR_SEPC, zero
214         csrw    CSR_SCAUSE, zero
215         csrw    CSR_SSCRATCH, zero
216
217         jalr    zero, a2, 0
218 SYM_CODE_END(riscv_kexec_norelocate)
219
220 .section ".rodata"
221 SYM_DATA(riscv_kexec_relocate_size,
222         .long riscv_kexec_relocate_end - riscv_kexec_relocate)
223