1 /* SPDX-License-Identifier: GPL-2.0 */
3 * Copyright (C) 2019 FORTH-ICS/CARV
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 */
13 SYM_CODE_START(riscv_kexec_relocate)
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) kernel_map.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
34 li s5, (PAGE_SIZE / RISCV_SZPTR)
42 /* Disable / cleanup interrupts */
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
59 /* Process entries in a loop */
63 REG_L t0, 0(s0) /* t0 = *image->entry */
64 addi s0, s0, RISCV_SZPTR /* image->entry++ */
66 /* IND_DESTINATION entry ? -> save destination address */
73 /* IND_INDIRECTION entry ? -> update next entry ptr (PA) */
82 /* IND_DONE entry ? -> jump to done label */
89 * IND_SOURCE entry ? -> copy page word by word to the
90 * destination address we got from IND_DESTINATION
93 beqz t1, 1b /* Unknown entry type, ignore it */
95 mv t3, s5 /* i = num words per page */
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 ? */
107 /* Pass the arguments to the next kernel / Cleanup*/
140 csrw CSR_SCAUSE, zero
141 csrw CSR_SSCRATCH, zero
144 * Make sure the relocated code is visible
145 * and jump to the new kernel
151 SYM_CODE_END(riscv_kexec_relocate)
152 riscv_kexec_relocate_end:
155 /* Used for jumping to crashkernel */
157 SYM_CODE_START(riscv_kexec_norelocate)
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) kernel_map.va_pa_offset, used when switching MMU off
169 /* Disable / cleanup interrupts */
173 /* Switch to physical addressing */
181 /* Pass the arguments to the next kernel / Cleanup*/
214 csrw CSR_SCAUSE, zero
215 csrw CSR_SSCRATCH, zero
218 SYM_CODE_END(riscv_kexec_norelocate)
221 SYM_DATA(riscv_kexec_relocate_size,
222 .long riscv_kexec_relocate_end - riscv_kexec_relocate)