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 * s3: (const) kernel_map.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 1801: 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 218SYM_CODE_END(riscv_kexec_norelocate) 219 220.section ".rodata" 221SYM_DATA(riscv_kexec_relocate_size, 222 .long riscv_kexec_relocate_end - riscv_kexec_relocate) 223 224