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