mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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>
		
	
			
		
			
				
	
	
		
			189 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			189 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
/* 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>
 | 
						|
 | 
						|
#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
 | 
						|
 | 
						|
#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		0x0
 | 
						|
arg1:	PTR		0x0
 | 
						|
arg2:	PTR		0x0
 | 
						|
arg3:	PTR		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		0x0
 | 
						|
s_arg1: PTR		0x0
 | 
						|
s_arg2: PTR		0x0
 | 
						|
s_arg3: PTR		0x0
 | 
						|
	.size	secondary_kexec_args,PTRSIZE*4
 | 
						|
kexec_flag:
 | 
						|
	LONG		0x1
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
kexec_start_address:
 | 
						|
	EXPORT(kexec_start_address)
 | 
						|
	PTR		0x0
 | 
						|
	.size		kexec_start_address, PTRSIZE
 | 
						|
 | 
						|
kexec_indirection_page:
 | 
						|
	EXPORT(kexec_indirection_page)
 | 
						|
	PTR		0
 | 
						|
	.size		kexec_indirection_page, PTRSIZE
 | 
						|
 | 
						|
relocate_new_kernel_end:
 | 
						|
 | 
						|
relocate_new_kernel_size:
 | 
						|
	EXPORT(relocate_new_kernel_size)
 | 
						|
	PTR		relocate_new_kernel_end - relocate_new_kernel
 | 
						|
	.size		relocate_new_kernel_size, PTRSIZE
 |