/* SPDX-License-Identifier: GPL-2.0 */1/*2* Copyright (C) 2019 FORTH-ICS/CARV3* Nick Kossifidis <[email protected]>4*/56#include <asm/asm.h> /* For RISCV_* and REG_* macros */7#include <asm/csr.h> /* For CSR_* macros */8#include <asm/page.h> /* For PAGE_SIZE */9#include <linux/linkage.h> /* For SYM_* macros */1011.section ".rodata"12SYM_CODE_START(riscv_kexec_relocate)1314/*15* s0: Pointer to the current entry16* s1: (const) Phys address to jump to after relocation17* s2: (const) Phys address of the FDT image18* s3: (const) The hartid of the current hart19* s4: (const) kernel_map.va_pa_offset, used when switching MMU off20* s5: Pointer to the destination address for the relocation21* s6: (const) Physical address of the main loop22*/23mv s0, a024mv s1, a125mv s2, a226mv s3, a327mv s4, a428mv s5, zero29mv s6, zero3031/* Disable / cleanup interrupts */32csrw CSR_SIE, zero33csrw CSR_SIP, zero3435/*36* When we switch SATP.MODE to "Bare" we'll only37* play with physical addresses. However the first time38* we try to jump somewhere, the offset on the jump39* will be relative to pc which will still be on VA. To40* deal with this we set stvec to the physical address at41* the start of the loop below so that we jump there in42* any case.43*/44la s6, 1f45sub s6, s6, s446csrw CSR_STVEC, s64748/*49* With C-extension, here we get 42 Bytes and the next50* .align directive would pad zeros here up to 44 Bytes.51* So manually put a nop here to avoid zeros padding.52*/53nop5455/* Process entries in a loop */56.align 2571:58REG_L t0, 0(s0) /* t0 = *image->entry */59addi s0, s0, RISCV_SZPTR /* image->entry++ */6061/* IND_DESTINATION entry ? -> save destination address */62andi t1, t0, 0x163beqz t1, 2f64andi s5, t0, ~0x165j 1b66672:68/* IND_INDIRECTION entry ? -> update next entry ptr (PA) */69andi t1, t0, 0x270beqz t1, 2f71andi s0, t0, ~0x272csrw CSR_SATP, zero73jr s674752:76/* IND_DONE entry ? -> jump to done label */77andi t1, t0, 0x478beqz t1, 2f79j 4f80812:82/*83* IND_SOURCE entry ? -> copy page word by word to the84* destination address we got from IND_DESTINATION85*/86andi t1, t0, 0x887beqz t1, 1b /* Unknown entry type, ignore it */88andi t0, t0, ~0x889li t3, (PAGE_SIZE / RISCV_SZPTR) /* i = num words per page */903: /* copy loop */91REG_L t1, (t0) /* t1 = *src_ptr */92REG_S t1, (s5) /* *dst_ptr = *src_ptr */93addi t0, t0, RISCV_SZPTR /* stc_ptr++ */94addi s5, s5, RISCV_SZPTR /* dst_ptr++ */95addi t3, t3, -0x1 /* i-- */96beqz t3, 1b /* copy done ? */97j 3b98994:100/* Pass the arguments to the next kernel / Cleanup*/101mv a0, s3102mv a1, s2103mv a2, s1104105/* Cleanup */106mv a3, zero107mv a4, zero108mv a5, zero109mv a6, zero110mv a7, zero111112mv s0, zero113mv s1, zero114mv s2, zero115mv s3, zero116mv s4, zero117mv s5, zero118mv s6, zero119mv s7, zero120mv s8, zero121mv s9, zero122mv s10, zero123mv s11, zero124125mv t0, zero126mv t1, zero127mv t2, zero128mv t3, zero129mv t4, zero130mv t5, zero131mv t6, zero132csrw CSR_SEPC, zero133csrw CSR_SCAUSE, zero134csrw CSR_SSCRATCH, zero135136/*137* Make sure the relocated code is visible138* and jump to the new kernel139*/140fence.i141142jr a2143144SYM_CODE_END(riscv_kexec_relocate)145riscv_kexec_relocate_end:146147148/* Used for jumping to crashkernel */149.section ".text"150SYM_CODE_START(riscv_kexec_norelocate)151/*152* s0: (const) Phys address to jump to153* s1: (const) Phys address of the FDT image154* s2: (const) The hartid of the current hart155*/156mv s0, a1157mv s1, a2158mv s2, a3159160/* Disable / cleanup interrupts */161csrw CSR_SIE, zero162csrw CSR_SIP, zero163164/* Pass the arguments to the next kernel / Cleanup*/165mv a0, s2166mv a1, s1167mv a2, s0168169/* Cleanup */170mv a3, zero171mv a4, zero172mv a5, zero173mv a6, zero174mv a7, zero175176mv s0, zero177mv s1, zero178mv s2, zero179mv s3, zero180mv s4, zero181mv s5, zero182mv s6, zero183mv s7, zero184mv s8, zero185mv s9, zero186mv s10, zero187mv s11, zero188189mv t0, zero190mv t1, zero191mv t2, zero192mv t3, zero193mv t4, zero194mv t5, zero195mv t6, zero196csrw CSR_SEPC, zero197csrw CSR_SCAUSE, zero198csrw CSR_SSCRATCH, zero199200/*201* Switch to physical addressing202* This will also trigger a jump to CSR_STVEC203* which in this case is the address of the new204* kernel.205*/206csrw CSR_STVEC, a2207csrw CSR_SATP, zero208209SYM_CODE_END(riscv_kexec_norelocate)210211.section ".rodata"212SYM_DATA(riscv_kexec_relocate_size,213.long riscv_kexec_relocate_end - riscv_kexec_relocate)214215216217