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: (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 23 */ 24 mv s0, a0 25 mv s1, a1 26 mv s2, a2 27 mv s3, a3 28 mv s4, a4 29 mv s5, zero 30 mv s6, zero 31 32 /* Disable / cleanup interrupts */ 33 csrw CSR_SIE, zero 34 csrw CSR_SIP, zero 35 36 /* 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 43 * any case. 44 */ 45 la s6, 1f 46 sub s6, s6, s4 47 csrw CSR_STVEC, s6 48 49 /* 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. 53 */ 54 nop 55 56 /* Process entries in a loop */ 57.align 2 581: 59 REG_L t0, 0(s0) /* t0 = *image->entry */ 60 addi s0, s0, RISCV_SZPTR /* image->entry++ */ 61 62 /* IND_DESTINATION entry ? -> save destination address */ 63 andi t1, t0, 0x1 64 beqz t1, 2f 65 andi s5, t0, ~0x1 66 j 1b 67 682: 69 /* IND_INDIRECTION entry ? -> update next entry ptr (PA) */ 70 andi t1, t0, 0x2 71 beqz t1, 2f 72 andi s0, t0, ~0x2 73 csrw CSR_SATP, zero 74 jr s6 75 762: 77 /* IND_DONE entry ? -> jump to done label */ 78 andi t1, t0, 0x4 79 beqz t1, 2f 80 j 4f 81 822: 83 /* 84 * IND_SOURCE entry ? -> copy page word by word to the 85 * destination address we got from IND_DESTINATION 86 */ 87 andi t1, t0, 0x8 88 beqz t1, 1b /* Unknown entry type, ignore it */ 89 andi t0, t0, ~0x8 90 li t3, (PAGE_SIZE / RISCV_SZPTR) /* i = num words per page */ 913: /* copy loop */ 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 ? */ 98 j 3b 99 1004: 101 /* Pass the arguments to the next kernel / Cleanup*/ 102 mv a0, s3 103 mv a1, s2 104 mv a2, s1 105 106 /* Cleanup */ 107 mv a3, zero 108 mv a4, zero 109 mv a5, zero 110 mv a6, zero 111 mv a7, zero 112 113 mv s0, zero 114 mv s1, zero 115 mv s2, zero 116 mv s3, zero 117 mv s4, zero 118 mv s5, zero 119 mv s6, zero 120 mv s7, zero 121 mv s8, zero 122 mv s9, zero 123 mv s10, zero 124 mv s11, zero 125 126 mv t0, zero 127 mv t1, zero 128 mv t2, zero 129 mv t3, zero 130 mv t4, zero 131 mv t5, zero 132 mv t6, zero 133 csrw CSR_SEPC, zero 134 csrw CSR_SCAUSE, zero 135 csrw CSR_SSCRATCH, zero 136 137 /* 138 * Make sure the relocated code is visible 139 * and jump to the new kernel 140 */ 141 fence.i 142 143 jr a2 144 145SYM_CODE_END(riscv_kexec_relocate) 146riscv_kexec_relocate_end: 147 148 149/* Used for jumping to crashkernel */ 150.section ".text" 151SYM_CODE_START(riscv_kexec_norelocate) 152 /* 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 156 */ 157 mv s0, a1 158 mv s1, a2 159 mv s2, a3 160 161 /* Disable / cleanup interrupts */ 162 csrw CSR_SIE, zero 163 csrw CSR_SIP, zero 164 165 /* Pass the arguments to the next kernel / Cleanup*/ 166 mv a0, s2 167 mv a1, s1 168 mv a2, s0 169 170 /* Cleanup */ 171 mv a3, zero 172 mv a4, zero 173 mv a5, zero 174 mv a6, zero 175 mv a7, zero 176 177 mv s0, zero 178 mv s1, zero 179 mv s2, zero 180 mv s3, zero 181 mv s4, zero 182 mv s5, zero 183 mv s6, zero 184 mv s7, zero 185 mv s8, zero 186 mv s9, zero 187 mv s10, zero 188 mv s11, zero 189 190 mv t0, zero 191 mv t1, zero 192 mv t2, zero 193 mv t3, zero 194 mv t4, zero 195 mv t5, zero 196 mv t6, zero 197 csrw CSR_SEPC, zero 198 csrw CSR_SCAUSE, zero 199 csrw CSR_SSCRATCH, zero 200 201 /* 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 205 * kernel. 206 */ 207 csrw CSR_STVEC, a2 208 csrw CSR_SATP, zero 209 210SYM_CODE_END(riscv_kexec_norelocate) 211 212.section ".rodata" 213SYM_DATA(riscv_kexec_relocate_size, 214 .long riscv_kexec_relocate_end - riscv_kexec_relocate) 215 216