2022-10-12 16:36:19 +08:00
|
|
|
/* 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)
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
|
LoongArch: Add kdump support
This patch adds support for kdump. In kdump case the normal kernel will
reserve a region for the crash kernel and jump there on panic.
Arch-specific functions are added to allow for implementing a crash dump
file interface, /proc/vmcore, which can be viewed as a ELF file.
A user-space tool, such as kexec-tools, is responsible for allocating a
separate region for the core's ELF header within the crash kdump kernel
memory and filling it in when executing kexec_load().
Then, its location will be advertised to the crash dump kernel via a
command line argument "elfcorehdr=", and the crash dump kernel will
preserve this region for later use with arch_reserve_vmcore() at boot
time.
At the same time, the crash kdump kernel is also limited within the
"crashkernel" area via a command line argument "mem=", so as not to
destroy the original kernel dump data.
In the crash dump kernel environment, /proc/vmcore is used to access the
primary kernel's memory with copy_oldmem_page().
I tested kdump on LoongArch machines (Loongson-3A5000) and it works as
expected (suggested crashkernel parameter is "crashkernel=512M@2560M"),
you may test it by triggering a crash through /proc/sysrq-trigger:
$ sudo kexec -p /boot/vmlinux-kdump --reuse-cmdline --append="nr_cpus=1"
# echo c > /proc/sysrq-trigger
Signed-off-by: Youling Tang <tangyouling@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
2022-10-12 16:36:19 +08:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
|
2022-10-12 16:36:19 +08:00
|
|
|
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
|
|
|
|
b process_entry
|
|
|
|
|
|
|
|
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)
|
|
|
|
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:
|
|
|
|
|
|
|
|
SYM_DATA_START(relocate_new_kernel_size)
|
|
|
|
PTR relocate_new_kernel_end - relocate_new_kernel
|
|
|
|
SYM_DATA_END(relocate_new_kernel_size)
|