linux-stable/arch/mips/kernel/relocate_kernel.S

190 lines
3.7 KiB
ArmAsm
Raw Normal View History

/* SPDX-License-Identifier: GPL-2.0-only */
/*
* relocate_kernel.S for kexec
* Created by <nschichan@corp.free.fr> on Thu Oct 12 17:49:57 2006
*/
#include <asm/asm.h>
#include <asm/asmmacro.h>
#include <asm/regdef.h>
#include <asm/mipsregs.h>
#include <asm/stackframe.h>
#include <asm/addrspace.h>
MIPS: Loongson64: Add kexec/kdump support Add kexec/kdump support for Loongson64 by: 1, Provide Loongson-specific kexec functions: loongson_kexec_prepare(), loongson_kexec_shutdown() and loongson_crash_shutdown(); 2, Provide Loongson-specific assembly code in kexec_smp_wait(); To start Loongson64, The boot CPU needs 3 parameters: fw_arg0: the number of arguments in cmdline (i.e., argc). fw_arg1: structure holds cmdline such as "root=/dev/sda1 console=tty" (i.e., argv). fw_arg2: environment (i.e., envp, additional boot parameters from LEFI). Non-boot CPUs do not need one parameter as the IPI mailbox base address. They query their own IPI mailbox to get PC, SP and GP in a loopi, until the boot CPU brings them up. loongson_kexec_prepare(): Setup cmdline for kexec/kdump. The kexec/kdump cmdline comes from kexec's "append" option string. This structure will be parsed in fw_init_cmdline() of arch/mips/fw/lib/cmdline.c. Both image ->control_code_page and the cmdline need to be in a safe memory region (memory allocated by the old kernel may be corrupted by the new kernel). In order to maintain compatibility for the old firmware, the low 2MB is reserverd and safe for Loongson. So let KEXEC_CTRL_CODE and KEXEC_ARGV_ ADDR be here. LEFI parameters may be corrupted at runtime, so backup it at mips_reboot_setup(), and then restore it at loongson_kexec_shutdown() /loongson_crash_shutdown(). loongson_kexec_shutdown(): Wake up all present CPUs and let them go to reboot_code_buffer. Pass the kexec parameters to kexec_args. loongson_crash_shutdown(): Pass the kdump parameters to kexec_args. The assembly part in kexec_smp_wait provide a routine as BIOS does, in order to keep secondary CPUs in a querying loop. The layout of low 2MB memory in our design: 0x80000000, the first MB, the first 64K, Exception vectors 0x80010000, the first MB, the second 64K, STR (suspend) data 0x80020000, the first MB, the third and fourth 64K, UEFI HOB 0x80040000, the first MB, the fifth 64K, RT-Thread for SMC 0x80100000, the second MB, the first 64K, KEXEC code 0x80108000, the second MB, the second 64K, KEXEC data Cc: Eric Biederman <ebiederm@xmission.com> Tested-by: Jinyang He <hejinyang@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@kernel.org> Signed-off-by: Jinyang He <hejinyang@loongson.cn> Signed-off-by: Youling Tang <tangyouling@loongson.cn> Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2021-04-13 08:57:23 +00:00
#include <kernel-entry-init.h>
LEAF(relocate_new_kernel)
PTR_L a0, arg0
PTR_L a1, arg1
PTR_L a2, arg2
PTR_L a3, arg3
PTR_L s0, kexec_indirection_page
PTR_L s1, kexec_start_address
process_entry:
PTR_L s2, (s0)
PTR_ADDIU s0, s0, SZREG
/*
* In case of a kdump/crash kernel, the indirection page is not
* populated as the kernel is directly copied to a reserved location
*/
beqz s2, done
/* destination page */
and s3, s2, 0x1
beq s3, zero, 1f
and s4, s2, ~0x1 /* store destination addr in s4 */
b process_entry
1:
/* indirection page, update s0 */
and s3, s2, 0x2
beq s3, zero, 1f
and s0, s2, ~0x2
b process_entry
1:
/* done page */
and s3, s2, 0x4
beq s3, zero, 1f
b done
1:
/* source page */
and s3, s2, 0x8
beq s3, zero, process_entry
and s2, s2, ~0x8
li s6, (1 << _PAGE_SHIFT) / SZREG
copy_word:
/* copy page word by word */
REG_L s5, (s2)
REG_S s5, (s4)
PTR_ADDIU s4, s4, SZREG
PTR_ADDIU s2, s2, SZREG
LONG_ADDIU s6, s6, -1
beq s6, zero, process_entry
b copy_word
b process_entry
done:
#ifdef CONFIG_SMP
/* kexec_flag reset is signal to other CPUs what kernel
was moved to it's location. Note - we need relocated address
of kexec_flag. */
bal 1f
1: move t1,ra;
PTR_LA t2,1b
PTR_LA t0,kexec_flag
PTR_SUB t0,t0,t2;
PTR_ADD t0,t1,t0;
LONG_S zero,(t0)
#endif
#ifdef CONFIG_CPU_CAVIUM_OCTEON
/* We need to flush I-cache before jumping to new kernel.
* Unfortunately, this code is cpu-specific.
*/
.set push
.set noreorder
syncw
syncw
synci 0($0)
.set pop
#else
sync
#endif
/* jump to kexec_start_address */
j s1
END(relocate_new_kernel)
#ifdef CONFIG_SMP
/*
* Other CPUs should wait until code is relocated and
* then start at entry (?) point.
*/
LEAF(kexec_smp_wait)
PTR_L a0, s_arg0
PTR_L a1, s_arg1
PTR_L a2, s_arg2
PTR_L a3, s_arg3
PTR_L s1, kexec_start_address
/* Non-relocated address works for args and kexec_start_address ( old
* kernel is not overwritten). But we need relocated address of
* kexec_flag.
*/
bal 1f
1: move t1,ra;
PTR_LA t2,1b
PTR_LA t0,kexec_flag
PTR_SUB t0,t0,t2;
PTR_ADD t0,t1,t0;
1: LONG_L s0, (t0)
bne s0, zero,1b
MIPS: Loongson64: Add kexec/kdump support Add kexec/kdump support for Loongson64 by: 1, Provide Loongson-specific kexec functions: loongson_kexec_prepare(), loongson_kexec_shutdown() and loongson_crash_shutdown(); 2, Provide Loongson-specific assembly code in kexec_smp_wait(); To start Loongson64, The boot CPU needs 3 parameters: fw_arg0: the number of arguments in cmdline (i.e., argc). fw_arg1: structure holds cmdline such as "root=/dev/sda1 console=tty" (i.e., argv). fw_arg2: environment (i.e., envp, additional boot parameters from LEFI). Non-boot CPUs do not need one parameter as the IPI mailbox base address. They query their own IPI mailbox to get PC, SP and GP in a loopi, until the boot CPU brings them up. loongson_kexec_prepare(): Setup cmdline for kexec/kdump. The kexec/kdump cmdline comes from kexec's "append" option string. This structure will be parsed in fw_init_cmdline() of arch/mips/fw/lib/cmdline.c. Both image ->control_code_page and the cmdline need to be in a safe memory region (memory allocated by the old kernel may be corrupted by the new kernel). In order to maintain compatibility for the old firmware, the low 2MB is reserverd and safe for Loongson. So let KEXEC_CTRL_CODE and KEXEC_ARGV_ ADDR be here. LEFI parameters may be corrupted at runtime, so backup it at mips_reboot_setup(), and then restore it at loongson_kexec_shutdown() /loongson_crash_shutdown(). loongson_kexec_shutdown(): Wake up all present CPUs and let them go to reboot_code_buffer. Pass the kexec parameters to kexec_args. loongson_crash_shutdown(): Pass the kdump parameters to kexec_args. The assembly part in kexec_smp_wait provide a routine as BIOS does, in order to keep secondary CPUs in a querying loop. The layout of low 2MB memory in our design: 0x80000000, the first MB, the first 64K, Exception vectors 0x80010000, the first MB, the second 64K, STR (suspend) data 0x80020000, the first MB, the third and fourth 64K, UEFI HOB 0x80040000, the first MB, the fifth 64K, RT-Thread for SMC 0x80100000, the second MB, the first 64K, KEXEC code 0x80108000, the second MB, the second 64K, KEXEC data Cc: Eric Biederman <ebiederm@xmission.com> Tested-by: Jinyang He <hejinyang@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@kernel.org> Signed-off-by: Jinyang He <hejinyang@loongson.cn> Signed-off-by: Youling Tang <tangyouling@loongson.cn> Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2021-04-13 08:57:23 +00:00
#ifdef USE_KEXEC_SMP_WAIT_FINAL
kexec_smp_wait_final
#else
sync
#endif
j s1
END(kexec_smp_wait)
#endif
#ifdef __mips64
/* all PTR's must be aligned to 8 byte in 64-bit mode */
.align 3
#endif
/* All parameters to new kernel are passed in registers a0-a3.
* kexec_args[0..3] are used to prepare register values.
*/
kexec_args:
EXPORT(kexec_args)
arg0: PTR_WD 0x0
arg1: PTR_WD 0x0
arg2: PTR_WD 0x0
arg3: PTR_WD 0x0
.size kexec_args,PTRSIZE*4
#ifdef CONFIG_SMP
/*
* Secondary CPUs may have different kernel parameters in
* their registers a0-a3. secondary_kexec_args[0..3] are used
* to prepare register values.
*/
secondary_kexec_args:
EXPORT(secondary_kexec_args)
s_arg0: PTR_WD 0x0
s_arg1: PTR_WD 0x0
s_arg2: PTR_WD 0x0
s_arg3: PTR_WD 0x0
.size secondary_kexec_args,PTRSIZE*4
kexec_flag:
LONG 0x1
#endif
kexec_start_address:
EXPORT(kexec_start_address)
PTR_WD 0x0
.size kexec_start_address, PTRSIZE
kexec_indirection_page:
EXPORT(kexec_indirection_page)
PTR_WD 0
.size kexec_indirection_page, PTRSIZE
relocate_new_kernel_end:
relocate_new_kernel_size:
EXPORT(relocate_new_kernel_size)
PTR_WD relocate_new_kernel_end - relocate_new_kernel
.size relocate_new_kernel_size, PTRSIZE