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" 13SYM_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) 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 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 611: 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 722: 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 812: 82 /* IND_DONE entry ? -> jump to done label */ 83 andi t1, t0, 0x4 84 beqz t1, 2f 85 j 4f 86 872: 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 */ 963: /* 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 1064: 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 151SYM_CODE_END(riscv_kexec_relocate) 152riscv_kexec_relocate_end: 153 154 155/* Used for jumping to crashkernel */ 156.section ".text" 157SYM_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 */ 163 mv s0, a1 164 mv s1, a2 165 mv s2, a3 166 167 /* Disable / cleanup interrupts */ 168 csrw CSR_SIE, zero 169 csrw CSR_SIP, zero 170 171 /* Pass the arguments to the next kernel / Cleanup*/ 172 mv a0, s2 173 mv a1, s1 174 mv a2, s0 175 176 /* Cleanup */ 177 mv a3, zero 178 mv a4, zero 179 mv a5, zero 180 mv a6, zero 181 mv a7, zero 182 183 mv s0, zero 184 mv s1, zero 185 mv s2, zero 186 mv s3, zero 187 mv s4, zero 188 mv s5, zero 189 mv s6, zero 190 mv s7, zero 191 mv s8, zero 192 mv s9, zero 193 mv s10, zero 194 mv s11, zero 195 196 mv t0, zero 197 mv t1, zero 198 mv t2, zero 199 mv t3, zero 200 mv t4, zero 201 mv t5, zero 202 mv t6, zero 203 csrw CSR_SEPC, zero 204 csrw CSR_SCAUSE, zero 205 csrw CSR_SSCRATCH, zero 206 207 /* 208 * Switch to physical addressing 209 * This will also trigger a jump to CSR_STVEC 210 * which in this case is the address of the new 211 * kernel. 212 */ 213 csrw CSR_STVEC, a2 214 csrw CSR_SATP, zero 215 216SYM_CODE_END(riscv_kexec_norelocate) 217 218.section ".rodata" 219SYM_DATA(riscv_kexec_relocate_size, 220 .long riscv_kexec_relocate_end - riscv_kexec_relocate) 221 222