1 /* SPDX-License-Identifier: GPL-2.0 */
3 * Copyright (C) 2019 FORTH-ICS/CARV
4 * Nick Kossifidis <mick@ics.forth.gr>
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: (const) kernel_map.va_pa_offset, used when switching MMU off
21 * s5: Pointer to the destination address for the relocation
22 * s6: (const) Physical address of the main loop
32 /* Disable / cleanup interrupts */
37 * When we switch SATP.MODE to "Bare" we'll only
38 * play with physical addresses. However the first time
39 * we try to jump somewhere, the offset on the jump
40 * will be relative to pc which will still be on VA. To
41 * deal with this we set stvec to the physical address at
42 * the start of the loop below so that we jump there in
50 * With C-extension, here we get 42 Bytes and the next
51 * .align directive would pad zeros here up to 44 Bytes.
52 * So manually put a nop here to avoid zeros padding.
56 /* Process entries in a loop */
59 REG_L t0, 0(s0) /* t0 = *image->entry */
60 addi s0, s0, RISCV_SZPTR /* image->entry++ */
62 /* IND_DESTINATION entry ? -> save destination address */
69 /* IND_INDIRECTION entry ? -> update next entry ptr (PA) */
77 /* IND_DONE entry ? -> jump to done label */
84 * IND_SOURCE entry ? -> copy page word by word to the
85 * destination address we got from IND_DESTINATION
88 beqz t1, 1b /* Unknown entry type, ignore it */
90 li t3, (PAGE_SIZE / RISCV_SZPTR) /* i = num words per page */
92 REG_L t1, (t0) /* t1 = *src_ptr */
93 REG_S t1, (s5) /* *dst_ptr = *src_ptr */
94 addi t0, t0, RISCV_SZPTR /* stc_ptr++ */
95 addi s5, s5, RISCV_SZPTR /* dst_ptr++ */
96 addi t3, t3, -0x1 /* i-- */
97 beqz t3, 1b /* copy done ? */
101 /* Pass the arguments to the next kernel / Cleanup*/
134 csrw CSR_SCAUSE, zero
135 csrw CSR_SSCRATCH, zero
138 * Make sure the relocated code is visible
139 * and jump to the new kernel
145 SYM_CODE_END(riscv_kexec_relocate)
146 riscv_kexec_relocate_end:
149 /* Used for jumping to crashkernel */
151 SYM_CODE_START(riscv_kexec_norelocate)
153 * s0: (const) Phys address to jump to
154 * s1: (const) Phys address of the FDT image
155 * s2: (const) The hartid of the current hart
161 /* Disable / cleanup interrupts */
165 /* Pass the arguments to the next kernel / Cleanup*/
198 csrw CSR_SCAUSE, zero
199 csrw CSR_SSCRATCH, zero
202 * Switch to physical addressing
203 * This will also trigger a jump to CSR_STVEC
204 * which in this case is the address of the new
210 SYM_CODE_END(riscv_kexec_norelocate)
213 SYM_DATA(riscv_kexec_relocate_size,
214 .long riscv_kexec_relocate_end - riscv_kexec_relocate)