/* SPDX-License-Identifier: GPL-2.0 *//* * relocate_kernel.S for kexec * * Copyright (C) 2022 Loongson Technology Corporation Limited */ #include <linux/kexec.h> #include <asm/asm.h>#include <asm/asmmacro.h>#include <asm/regdef.h>#include <asm/loongarch.h>#include <asm/stackframe.h>#include <asm/addrspace.h> SYM_CODE_START(relocate_new_kernel) UNWIND_HINT_UNDEFINED /* * a0: EFI boot flag for the new kernel * a1: Command line pointer for the new kernel * a2: System table pointer for the new kernel * a3: Start address to jump to after relocation * a4: Pointer to the current indirection page entry */ move s0, a4 /* * In case of a kdump/crash kernel, the indirection page is not * populated as the kernel is directly copied to a reserved location */ beqz s0, done process_entry: PTR_L s1, s0, 0 PTR_ADDI s0, s0, SZREG /* destination page */ andi s2, s1, IND_DESTINATION beqz s2, 1f li.w t0, ~0x1 and s3, s1, t0 /* store destination addr in s3 */ b process_entry 1: /* indirection page, update s0 */ andi s2, s1, IND_INDIRECTION beqz s2, 1f li.w t0, ~0x2 and s0, s1, t0 b process_entry 1: /* done page */ andi s2, s1, IND_DONE beqz s2, 1f b done 1: /* source page */ andi s2, s1, IND_SOURCE beqz s2, process_entry li.w t0, ~0x8 and s1, s1, t0 li.w s5, (1 << _PAGE_SHIFT) / SZREG copy_word: /* copy page word by word */ REG_L s4, s1, 0 REG_S s4, s3, 0 PTR_ADDI s3, s3, SZREG PTR_ADDI s1, s1, SZREG LONG_ADDI s5, s5, -1 beqz s5, process_entry b copy_word done: ibar 0 dbar 0 /* * Jump to the new kernel, * make sure the values of a0, a1, a2 and a3 are not changed. */ jr a3SYM_CODE_END(relocate_new_kernel) #ifdef CONFIG_SMP/* * Other CPUs should wait until code is relocated and * then start at the entry point from LOONGARCH_IOCSR_MBUF0. */SYM_CODE_START(kexec_smp_wait) UNWIND_HINT_UNDEFINED1: li.w t0, 0x100 /* wait for init loop */2: addi.w t0, t0, -1 /* limit mailbox access */ bnez t0, 2b li.w t1, LOONGARCH_IOCSR_MBUF0 iocsrrd.w s0, t1 /* check PC as an indicator */ beqz s0, 1b iocsrrd.d s0, t1 /* get PC via mailbox */ li.d t0, CACHE_BASE or s0, s0, t0 /* s0 = TO_CACHE(s0) */ jr s0 /* jump to initial PC */SYM_CODE_END(kexec_smp_wait)#endif relocate_new_kernel_end: .section ".data"SYM_DATA(relocate_new_kernel_size, .quad relocate_new_kernel_end - relocate_new_kernel)
/* SPDX-License-Identifier: GPL-2.0 */
/*
* relocate_kernel.S for kexec
*
* Copyright (C) 2022 Loongson Technology Corporation Limited
*/
#include <linux/kexec.h>
#include <asm/asm.h>
#include <asm/asmmacro.h>
#include <asm/regdef.h>
#include <asm/loongarch.h>
#include <asm/stackframe.h>
#include <asm/addrspace.h>
SYM_CODE_START(relocate_new_kernel)
UNWIND_HINT_UNDEFINED
/*
* a0: EFI boot flag for the new kernel
* a1: Command line pointer for the new kernel
* a2: System table pointer for the new kernel
* a3: Start address to jump to after relocation
* a4: Pointer to the current indirection page entry
*/
move s0, a4
/*
* In case of a kdump/crash kernel, the indirection page is not
* populated as the kernel is directly copied to a reserved location
*/
beqz s0, done
process_entry:
PTR_L s1, s0, 0
PTR_ADDI s0, s0, SZREG
/* destination page */
andi s2, s1, IND_DESTINATION
beqz s2, 1f
li.w t0, ~0x1
and s3, s1, t0 /* store destination addr in s3 */
b process_entry
1:
/* indirection page, update s0 */
andi s2, s1, IND_INDIRECTION
beqz s2, 1f
li.w t0, ~0x2
and s0, s1, t0
b process_entry
1:
/* done page */
andi s2, s1, IND_DONE
beqz s2, 1f
b done
1:
/* source page */
andi s2, s1, IND_SOURCE
beqz s2, process_entry
li.w t0, ~0x8
and s1, s1, t0
li.w s5, (1 << _PAGE_SHIFT) / SZREG
copy_word:
/* copy page word by word */
REG_L s4, s1, 0
REG_S s4, s3, 0
PTR_ADDI s3, s3, SZREG
PTR_ADDI s1, s1, SZREG
LONG_ADDI s5, s5, -1
beqz s5, process_entry
b copy_word
done:
ibar 0
dbar 0
/*
* Jump to the new kernel,
* make sure the values of a0, a1, a2 and a3 are not changed.
*/
jr a3
SYM_CODE_END(relocate_new_kernel)
#ifdef CONFIG_SMP
/*
* Other CPUs should wait until code is relocated and
* then start at the entry point from LOONGARCH_IOCSR_MBUF0.
*/
SYM_CODE_START(kexec_smp_wait)
UNWIND_HINT_UNDEFINED
1: li.w t0, 0x100 /* wait for init loop */
2: addi.w t0, t0, -1 /* limit mailbox access */
bnez t0, 2b
li.w t1, LOONGARCH_IOCSR_MBUF0
iocsrrd.w s0, t1 /* check PC as an indicator */
beqz s0, 1b
iocsrrd.d s0, t1 /* get PC via mailbox */
li.d t0, CACHE_BASE
or s0, s0, t0 /* s0 = TO_CACHE(s0) */
jr s0 /* jump to initial PC */
SYM_CODE_END(kexec_smp_wait)
#endif
relocate_new_kernel_end:
.section ".data"
SYM_DATA(relocate_new_kernel_size, .quad relocate_new_kernel_end - relocate_new_kernel)