1/* SPDX-License-Identifier: GPL-2.0 */ 2/* 3 * relocate_kernel.S for kexec 4 * 5 * Copyright (C) 2022 Loongson Technology Corporation Limited 6 */ 7 8#include <linux/kexec.h> 9 10#include <asm/asm.h> 11#include <asm/asmmacro.h> 12#include <asm/regdef.h> 13#include <asm/loongarch.h> 14#include <asm/stackframe.h> 15#include <asm/addrspace.h> 16 17SYM_CODE_START(relocate_new_kernel) 18 UNWIND_HINT_UNDEFINED 19 /* 20 * a0: EFI boot flag for the new kernel 21 * a1: Command line pointer for the new kernel 22 * a2: System table pointer for the new kernel 23 * a3: Start address to jump to after relocation 24 * a4: Pointer to the current indirection page entry 25 */ 26 move s0, a4 27 28 /* 29 * In case of a kdump/crash kernel, the indirection page is not 30 * populated as the kernel is directly copied to a reserved location 31 */ 32 beqz s0, done 33 34process_entry: 35 PTR_L s1, s0, 0 36 PTR_ADDI s0, s0, SZREG 37 38 /* destination page */ 39 andi s2, s1, IND_DESTINATION 40 beqz s2, 1f 41 li.w t0, ~0x1 42 and s3, s1, t0 /* store destination addr in s3 */ 43 b process_entry 44 451: 46 /* indirection page, update s0 */ 47 andi s2, s1, IND_INDIRECTION 48 beqz s2, 1f 49 li.w t0, ~0x2 50 and s0, s1, t0 51 b process_entry 52 531: 54 /* done page */ 55 andi s2, s1, IND_DONE 56 beqz s2, 1f 57 b done 58 591: 60 /* source page */ 61 andi s2, s1, IND_SOURCE 62 beqz s2, process_entry 63 li.w t0, ~0x8 64 and s1, s1, t0 65 li.w s5, (1 << _PAGE_SHIFT) / SZREG 66 67copy_word: 68 /* copy page word by word */ 69 REG_L s4, s1, 0 70 REG_S s4, s3, 0 71 PTR_ADDI s3, s3, SZREG 72 PTR_ADDI s1, s1, SZREG 73 LONG_ADDI s5, s5, -1 74 beqz s5, process_entry 75 b copy_word 76 77done: 78 ibar 0 79 dbar 0 80 81 /* 82 * Jump to the new kernel, 83 * make sure the values of a0, a1, a2 and a3 are not changed. 84 */ 85 jr a3 86SYM_CODE_END(relocate_new_kernel) 87 88#ifdef CONFIG_SMP 89/* 90 * Other CPUs should wait until code is relocated and 91 * then start at the entry point from LOONGARCH_IOCSR_MBUF0. 92 */ 93SYM_CODE_START(kexec_smp_wait) 94 UNWIND_HINT_UNDEFINED 951: li.w t0, 0x100 /* wait for init loop */ 962: addi.w t0, t0, -1 /* limit mailbox access */ 97 bnez t0, 2b 98 li.w t1, LOONGARCH_IOCSR_MBUF0 99 iocsrrd.w s0, t1 /* check PC as an indicator */ 100 beqz s0, 1b 101 iocsrrd.d s0, t1 /* get PC via mailbox */ 102 103 li.d t0, CACHE_BASE 104 or s0, s0, t0 /* s0 = TO_CACHE(s0) */ 105 jr s0 /* jump to initial PC */ 106SYM_CODE_END(kexec_smp_wait) 107#endif 108 109relocate_new_kernel_end: 110 111 .section ".data" 112SYM_DATA(relocate_new_kernel_size, .long relocate_new_kernel_end - relocate_new_kernel) 113