1fba8a867SNick Kossifidis/* SPDX-License-Identifier: GPL-2.0 */ 2fba8a867SNick Kossifidis/* 3fba8a867SNick Kossifidis * Copyright (C) 2019 FORTH-ICS/CARV 4fba8a867SNick Kossifidis * Nick Kossifidis <mick@ics.forth.gr> 5fba8a867SNick Kossifidis */ 6fba8a867SNick Kossifidis 7fba8a867SNick Kossifidis#include <asm/asm.h> /* For RISCV_* and REG_* macros */ 8fba8a867SNick Kossifidis#include <asm/csr.h> /* For CSR_* macros */ 9fba8a867SNick Kossifidis#include <asm/page.h> /* For PAGE_SIZE */ 10fba8a867SNick Kossifidis#include <linux/linkage.h> /* For SYM_* macros */ 11fba8a867SNick Kossifidis 12fba8a867SNick Kossifidis.section ".rodata" 13fba8a867SNick KossifidisSYM_CODE_START(riscv_kexec_relocate) 14fba8a867SNick Kossifidis 15fba8a867SNick Kossifidis /* 16fba8a867SNick Kossifidis * s0: Pointer to the current entry 17fba8a867SNick Kossifidis * s1: (const) Phys address to jump to after relocation 18fba8a867SNick Kossifidis * s2: (const) Phys address of the FDT image 19fba8a867SNick Kossifidis * s3: (const) The hartid of the current hart 20fba8a867SNick Kossifidis * s4: Pointer to the destination address for the relocation 21fba8a867SNick Kossifidis * s5: (const) Number of words per page 22fba8a867SNick Kossifidis * s6: (const) 1, used for subtraction 23658e2c51SAlexandre Ghiti * s7: (const) kernel_map.va_pa_offset, used when switching MMU off 24fba8a867SNick Kossifidis * s8: (const) Physical address of the main loop 25fba8a867SNick Kossifidis * s9: (debug) indirection page counter 26fba8a867SNick Kossifidis * s10: (debug) entry counter 27fba8a867SNick Kossifidis * s11: (debug) copied words counter 28fba8a867SNick Kossifidis */ 29fba8a867SNick Kossifidis mv s0, a0 30fba8a867SNick Kossifidis mv s1, a1 31fba8a867SNick Kossifidis mv s2, a2 32fba8a867SNick Kossifidis mv s3, a3 33fba8a867SNick Kossifidis mv s4, zero 34fba8a867SNick Kossifidis li s5, (PAGE_SIZE / RISCV_SZPTR) 35fba8a867SNick Kossifidis li s6, 1 36fba8a867SNick Kossifidis mv s7, a4 37fba8a867SNick Kossifidis mv s8, zero 38fba8a867SNick Kossifidis mv s9, zero 39fba8a867SNick Kossifidis mv s10, zero 40fba8a867SNick Kossifidis mv s11, zero 41fba8a867SNick Kossifidis 42fba8a867SNick Kossifidis /* Disable / cleanup interrupts */ 43fba8a867SNick Kossifidis csrw CSR_SIE, zero 44fba8a867SNick Kossifidis csrw CSR_SIP, zero 45fba8a867SNick Kossifidis 46fba8a867SNick Kossifidis /* 47fba8a867SNick Kossifidis * When we switch SATP.MODE to "Bare" we'll only 48fba8a867SNick Kossifidis * play with physical addresses. However the first time 49fba8a867SNick Kossifidis * we try to jump somewhere, the offset on the jump 50fba8a867SNick Kossifidis * will be relative to pc which will still be on VA. To 51fba8a867SNick Kossifidis * deal with this we set stvec to the physical address at 52fba8a867SNick Kossifidis * the start of the loop below so that we jump there in 53fba8a867SNick Kossifidis * any case. 54fba8a867SNick Kossifidis */ 55fba8a867SNick Kossifidis la s8, 1f 56fba8a867SNick Kossifidis sub s8, s8, s7 57fba8a867SNick Kossifidis csrw CSR_STVEC, s8 58fba8a867SNick Kossifidis 59fba8a867SNick Kossifidis /* Process entries in a loop */ 60fba8a867SNick Kossifidis.align 2 61fba8a867SNick Kossifidis1: 62fba8a867SNick Kossifidis addi s10, s10, 1 63fba8a867SNick Kossifidis REG_L t0, 0(s0) /* t0 = *image->entry */ 64fba8a867SNick Kossifidis addi s0, s0, RISCV_SZPTR /* image->entry++ */ 65fba8a867SNick Kossifidis 66fba8a867SNick Kossifidis /* IND_DESTINATION entry ? -> save destination address */ 67fba8a867SNick Kossifidis andi t1, t0, 0x1 68fba8a867SNick Kossifidis beqz t1, 2f 69fba8a867SNick Kossifidis andi s4, t0, ~0x1 70fba8a867SNick Kossifidis j 1b 71fba8a867SNick Kossifidis 72fba8a867SNick Kossifidis2: 73fba8a867SNick Kossifidis /* IND_INDIRECTION entry ? -> update next entry ptr (PA) */ 74fba8a867SNick Kossifidis andi t1, t0, 0x2 75fba8a867SNick Kossifidis beqz t1, 2f 76fba8a867SNick Kossifidis andi s0, t0, ~0x2 77fba8a867SNick Kossifidis addi s9, s9, 1 78fba8a867SNick Kossifidis csrw CSR_SATP, zero 79fba8a867SNick Kossifidis jalr zero, s8, 0 80fba8a867SNick Kossifidis 81fba8a867SNick Kossifidis2: 82fba8a867SNick Kossifidis /* IND_DONE entry ? -> jump to done label */ 83fba8a867SNick Kossifidis andi t1, t0, 0x4 84fba8a867SNick Kossifidis beqz t1, 2f 85fba8a867SNick Kossifidis j 4f 86fba8a867SNick Kossifidis 87fba8a867SNick Kossifidis2: 88fba8a867SNick Kossifidis /* 89fba8a867SNick Kossifidis * IND_SOURCE entry ? -> copy page word by word to the 90fba8a867SNick Kossifidis * destination address we got from IND_DESTINATION 91fba8a867SNick Kossifidis */ 92fba8a867SNick Kossifidis andi t1, t0, 0x8 93fba8a867SNick Kossifidis beqz t1, 1b /* Unknown entry type, ignore it */ 94fba8a867SNick Kossifidis andi t0, t0, ~0x8 95fba8a867SNick Kossifidis mv t3, s5 /* i = num words per page */ 96fba8a867SNick Kossifidis3: /* copy loop */ 97fba8a867SNick Kossifidis REG_L t1, (t0) /* t1 = *src_ptr */ 98fba8a867SNick Kossifidis REG_S t1, (s4) /* *dst_ptr = *src_ptr */ 99fba8a867SNick Kossifidis addi t0, t0, RISCV_SZPTR /* stc_ptr++ */ 100fba8a867SNick Kossifidis addi s4, s4, RISCV_SZPTR /* dst_ptr++ */ 101fba8a867SNick Kossifidis sub t3, t3, s6 /* i-- */ 102fba8a867SNick Kossifidis addi s11, s11, 1 /* c++ */ 103fba8a867SNick Kossifidis beqz t3, 1b /* copy done ? */ 104fba8a867SNick Kossifidis j 3b 105fba8a867SNick Kossifidis 106fba8a867SNick Kossifidis4: 107fba8a867SNick Kossifidis /* Pass the arguments to the next kernel / Cleanup*/ 108fba8a867SNick Kossifidis mv a0, s3 109fba8a867SNick Kossifidis mv a1, s2 110fba8a867SNick Kossifidis mv a2, s1 111fba8a867SNick Kossifidis 112fba8a867SNick Kossifidis /* Cleanup */ 113fba8a867SNick Kossifidis mv a3, zero 114fba8a867SNick Kossifidis mv a4, zero 115fba8a867SNick Kossifidis mv a5, zero 116fba8a867SNick Kossifidis mv a6, zero 117fba8a867SNick Kossifidis mv a7, zero 118fba8a867SNick Kossifidis 119fba8a867SNick Kossifidis mv s0, zero 120fba8a867SNick Kossifidis mv s1, zero 121fba8a867SNick Kossifidis mv s2, zero 122fba8a867SNick Kossifidis mv s3, zero 123fba8a867SNick Kossifidis mv s4, zero 124fba8a867SNick Kossifidis mv s5, zero 125fba8a867SNick Kossifidis mv s6, zero 126fba8a867SNick Kossifidis mv s7, zero 127fba8a867SNick Kossifidis mv s8, zero 128fba8a867SNick Kossifidis mv s9, zero 129fba8a867SNick Kossifidis mv s10, zero 130fba8a867SNick Kossifidis mv s11, zero 131fba8a867SNick Kossifidis 132fba8a867SNick Kossifidis mv t0, zero 133fba8a867SNick Kossifidis mv t1, zero 134fba8a867SNick Kossifidis mv t2, zero 135fba8a867SNick Kossifidis mv t3, zero 136fba8a867SNick Kossifidis mv t4, zero 137fba8a867SNick Kossifidis mv t5, zero 138fba8a867SNick Kossifidis mv t6, zero 139fba8a867SNick Kossifidis csrw CSR_SEPC, zero 140fba8a867SNick Kossifidis csrw CSR_SCAUSE, zero 141fba8a867SNick Kossifidis csrw CSR_SSCRATCH, zero 142fba8a867SNick Kossifidis 143fba8a867SNick Kossifidis /* 144fba8a867SNick Kossifidis * Make sure the relocated code is visible 145fba8a867SNick Kossifidis * and jump to the new kernel 146fba8a867SNick Kossifidis */ 147fba8a867SNick Kossifidis fence.i 148fba8a867SNick Kossifidis 149fba8a867SNick Kossifidis jalr zero, a2, 0 150fba8a867SNick Kossifidis 151fba8a867SNick KossifidisSYM_CODE_END(riscv_kexec_relocate) 152fba8a867SNick Kossifidisriscv_kexec_relocate_end: 153fba8a867SNick Kossifidis 154e53d2818SNick Kossifidis 155e53d2818SNick Kossifidis/* Used for jumping to crashkernel */ 156e53d2818SNick Kossifidis.section ".text" 157e53d2818SNick KossifidisSYM_CODE_START(riscv_kexec_norelocate) 158e53d2818SNick Kossifidis /* 159e53d2818SNick Kossifidis * s0: (const) Phys address to jump to 160e53d2818SNick Kossifidis * s1: (const) Phys address of the FDT image 161e53d2818SNick Kossifidis * s2: (const) The hartid of the current hart 162e53d2818SNick Kossifidis */ 163e53d2818SNick Kossifidis mv s0, a1 164e53d2818SNick Kossifidis mv s1, a2 165e53d2818SNick Kossifidis mv s2, a3 166e53d2818SNick Kossifidis 167e53d2818SNick Kossifidis /* Disable / cleanup interrupts */ 168e53d2818SNick Kossifidis csrw CSR_SIE, zero 169e53d2818SNick Kossifidis csrw CSR_SIP, zero 170e53d2818SNick Kossifidis 171e53d2818SNick Kossifidis /* Pass the arguments to the next kernel / Cleanup*/ 172e53d2818SNick Kossifidis mv a0, s2 173e53d2818SNick Kossifidis mv a1, s1 174e53d2818SNick Kossifidis mv a2, s0 175e53d2818SNick Kossifidis 176e53d2818SNick Kossifidis /* Cleanup */ 177e53d2818SNick Kossifidis mv a3, zero 178e53d2818SNick Kossifidis mv a4, zero 179e53d2818SNick Kossifidis mv a5, zero 180e53d2818SNick Kossifidis mv a6, zero 181e53d2818SNick Kossifidis mv a7, zero 182e53d2818SNick Kossifidis 183e53d2818SNick Kossifidis mv s0, zero 184e53d2818SNick Kossifidis mv s1, zero 185e53d2818SNick Kossifidis mv s2, zero 186e53d2818SNick Kossifidis mv s3, zero 187e53d2818SNick Kossifidis mv s4, zero 188e53d2818SNick Kossifidis mv s5, zero 189e53d2818SNick Kossifidis mv s6, zero 190e53d2818SNick Kossifidis mv s7, zero 191e53d2818SNick Kossifidis mv s8, zero 192e53d2818SNick Kossifidis mv s9, zero 193e53d2818SNick Kossifidis mv s10, zero 194e53d2818SNick Kossifidis mv s11, zero 195e53d2818SNick Kossifidis 196e53d2818SNick Kossifidis mv t0, zero 197e53d2818SNick Kossifidis mv t1, zero 198e53d2818SNick Kossifidis mv t2, zero 199e53d2818SNick Kossifidis mv t3, zero 200e53d2818SNick Kossifidis mv t4, zero 201e53d2818SNick Kossifidis mv t5, zero 202e53d2818SNick Kossifidis mv t6, zero 203e53d2818SNick Kossifidis csrw CSR_SEPC, zero 204e53d2818SNick Kossifidis csrw CSR_SCAUSE, zero 205e53d2818SNick Kossifidis csrw CSR_SSCRATCH, zero 206e53d2818SNick Kossifidis 207*b9f3e769SNick Kossifidis /* 208*b9f3e769SNick Kossifidis * Switch to physical addressing 209*b9f3e769SNick Kossifidis * This will also trigger a jump to CSR_STVEC 210*b9f3e769SNick Kossifidis * which in this case is the address of the new 211*b9f3e769SNick Kossifidis * kernel. 212*b9f3e769SNick Kossifidis */ 213*b9f3e769SNick Kossifidis csrw CSR_STVEC, a2 214*b9f3e769SNick Kossifidis csrw CSR_SATP, zero 215*b9f3e769SNick Kossifidis 216e53d2818SNick KossifidisSYM_CODE_END(riscv_kexec_norelocate) 217e53d2818SNick Kossifidis 218fba8a867SNick Kossifidis.section ".rodata" 219fba8a867SNick KossifidisSYM_DATA(riscv_kexec_relocate_size, 220fba8a867SNick Kossifidis .long riscv_kexec_relocate_end - riscv_kexec_relocate) 221fba8a867SNick Kossifidis 222