relocate_kernel.S 3.7 KB
Newer Older
N
Nicolas Schichan 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * relocate_kernel.S for kexec
 * Created by <nschichan@corp.free.fr> on Thu Oct 12 17:49:57 2006
 *
 * This source code is licensed under the GNU General Public License,
 * Version 2.  See the file COPYING for more details.
 */

#include <asm/asm.h>
#include <asm/asmmacro.h>
#include <asm/regdef.h>
#include <asm/mipsregs.h>
#include <asm/stackframe.h>
#include <asm/addrspace.h>

16
LEAF(relocate_new_kernel)
R
Ralf Baechle 已提交
17 18 19 20 21
	PTR_L a0,	arg0
	PTR_L a1,	arg1
	PTR_L a2,	arg2
	PTR_L a3,	arg3

22 23
	PTR_L		s0, kexec_indirection_page
	PTR_L		s1, kexec_start_address
N
Nicolas Schichan 已提交
24 25

process_entry:
26
	PTR_L		s2, (s0)
27
	PTR_ADDIU	s0, s0, SZREG
N
Nicolas Schichan 已提交
28

29 30 31 32 33 34
	/*
	 * 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

N
Nicolas Schichan 已提交
35
	/* destination page */
36 37 38 39
	and		s3, s2, 0x1
	beq		s3, zero, 1f
	and		s4, s2, ~0x1	/* store destination addr in s4 */
	b		process_entry
N
Nicolas Schichan 已提交
40 41

1:
R
Ralf Baechle 已提交
42
	/* indirection page, update s0	*/
43 44 45 46
	and		s3, s2, 0x2
	beq		s3, zero, 1f
	and		s0, s2, ~0x2
	b		process_entry
N
Nicolas Schichan 已提交
47 48 49

1:
	/* done page */
50 51 52
	and		s3, s2, 0x4
	beq		s3, zero, 1f
	b		done
N
Nicolas Schichan 已提交
53 54
1:
	/* source page */
55 56 57
	and		s3, s2, 0x8
	beq		s3, zero, process_entry
	and		s2, s2, ~0x8
58
	li		s6, (1 << _PAGE_SHIFT) / SZREG
N
Nicolas Schichan 已提交
59 60 61

copy_word:
	/* copy page word by word */
62 63
	REG_L		s5, (s2)
	REG_S		s5, (s4)
64 65 66
	PTR_ADDIU	s4, s4, SZREG
	PTR_ADDIU	s2, s2, SZREG
	LONG_ADDIU	s6, s6, -1
67 68 69
	beq		s6, zero, process_entry
	b		copy_word
	b		process_entry
N
Nicolas Schichan 已提交
70 71

done:
R
Ralf Baechle 已提交
72 73 74 75 76 77
#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
R
Ralf Baechle 已提交
78
 1:	move		t1,ra;
R
Ralf Baechle 已提交
79 80 81 82 83 84 85
	PTR_LA		t2,1b
	PTR_LA		t0,kexec_flag
	PTR_SUB		t0,t0,t2;
	PTR_ADD		t0,t1,t0;
	LONG_S		zero,(t0)
#endif

86 87 88 89 90 91 92 93 94 95 96
#ifdef CONFIG_CPU_CAVIUM_OCTEON
	/* We need to flush I-cache before jumping to new kernel.
	 * Unfortunatelly, this code is cpu-specific.
	 */
	.set push
	.set noreorder
	syncw
	syncw
	synci		0($0)
	.set pop
#else
R
Ralf Baechle 已提交
97
	sync
98
#endif
N
Nicolas Schichan 已提交
99
	/* jump to kexec_start_address */
100 101
	j		s1
	END(relocate_new_kernel)
N
Nicolas Schichan 已提交
102

R
Ralf Baechle 已提交
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
#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

130 131 132 133 134 135
#ifdef CONFIG_CPU_CAVIUM_OCTEON
	.set push
	.set noreorder
	synci		0($0)
	.set pop
#else
R
Ralf Baechle 已提交
136
	sync
137
#endif
R
Ralf Baechle 已提交
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
	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 uses 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)
R
Ralf Baechle 已提交
167 168 169 170
s_arg0: PTR		0x0
s_arg1: PTR		0x0
s_arg2: PTR		0x0
s_arg3: PTR		0x0
R
Ralf Baechle 已提交
171 172 173 174 175 176
	.size	secondary_kexec_args,PTRSIZE*4
kexec_flag:
	LONG		0x1

#endif

N
Nicolas Schichan 已提交
177
kexec_start_address:
178 179 180
	EXPORT(kexec_start_address)
	PTR		0x0
	.size		kexec_start_address, PTRSIZE
N
Nicolas Schichan 已提交
181 182

kexec_indirection_page:
183 184 185
	EXPORT(kexec_indirection_page)
	PTR		0
	.size		kexec_indirection_page, PTRSIZE
N
Nicolas Schichan 已提交
186 187 188 189

relocate_new_kernel_end:

relocate_new_kernel_size:
190 191 192
	EXPORT(relocate_new_kernel_size)
	PTR		relocate_new_kernel_end - relocate_new_kernel
	.size		relocate_new_kernel_size, PTRSIZE