blob: 804ebb2c34a6c9cd556acf3e0048f974641eb32f [file] [log] [blame]
Nicolas Schichan583bb862006-10-18 15:14:55 +02001/*
2 * relocate_kernel.S for kexec
3 * Created by <nschichan@corp.free.fr> on Thu Oct 12 17:49:57 2006
4 *
5 * This source code is licensed under the GNU General Public License,
6 * Version 2. See the file COPYING for more details.
7 */
8
9#include <asm/asm.h>
10#include <asm/asmmacro.h>
11#include <asm/regdef.h>
Nicolas Schichan583bb862006-10-18 15:14:55 +020012#include <asm/mipsregs.h>
13#include <asm/stackframe.h>
14#include <asm/addrspace.h>
15
Ralf Baechle00be0f32007-07-31 15:17:21 +010016LEAF(relocate_new_kernel)
Ralf Baechle7aa1c8f2012-10-11 18:14:58 +020017 PTR_L a0, arg0
18 PTR_L a1, arg1
19 PTR_L a2, arg2
20 PTR_L a3, arg3
21
Ralf Baechle00be0f32007-07-31 15:17:21 +010022 PTR_L s0, kexec_indirection_page
23 PTR_L s1, kexec_start_address
Nicolas Schichan583bb862006-10-18 15:14:55 +020024
25process_entry:
Ralf Baechle00be0f32007-07-31 15:17:21 +010026 PTR_L s2, (s0)
27 PTR_ADD s0, s0, SZREG
Nicolas Schichan583bb862006-10-18 15:14:55 +020028
29 /* destination page */
Ralf Baechle00be0f32007-07-31 15:17:21 +010030 and s3, s2, 0x1
31 beq s3, zero, 1f
32 and s4, s2, ~0x1 /* store destination addr in s4 */
Ralf Baechle00be0f32007-07-31 15:17:21 +010033 b process_entry
Nicolas Schichan583bb862006-10-18 15:14:55 +020034
351:
36 /* indirection page, update s0 */
Ralf Baechle00be0f32007-07-31 15:17:21 +010037 and s3, s2, 0x2
38 beq s3, zero, 1f
39 and s0, s2, ~0x2
40 b process_entry
Nicolas Schichan583bb862006-10-18 15:14:55 +020041
421:
43 /* done page */
Ralf Baechle00be0f32007-07-31 15:17:21 +010044 and s3, s2, 0x4
45 beq s3, zero, 1f
46 b done
Nicolas Schichan583bb862006-10-18 15:14:55 +0200471:
48 /* source page */
Ralf Baechle00be0f32007-07-31 15:17:21 +010049 and s3, s2, 0x8
50 beq s3, zero, process_entry
51 and s2, s2, ~0x8
Ralf Baechlebef9ae32012-12-28 15:15:25 +010052 li s6, (1 << _PAGE_SHIFT) / SZREG
Nicolas Schichan583bb862006-10-18 15:14:55 +020053
54copy_word:
55 /* copy page word by word */
Ralf Baechle00be0f32007-07-31 15:17:21 +010056 REG_L s5, (s2)
57 REG_S s5, (s4)
58 PTR_ADD s4, s4, SZREG
59 PTR_ADD s2, s2, SZREG
60 LONG_SUB s6, s6, 1
61 beq s6, zero, process_entry
62 b copy_word
63 b process_entry
Nicolas Schichan583bb862006-10-18 15:14:55 +020064
65done:
Ralf Baechle7aa1c8f2012-10-11 18:14:58 +020066#ifdef CONFIG_SMP
67 /* kexec_flag reset is signal to other CPUs what kernel
68 was moved to it's location. Note - we need relocated address
69 of kexec_flag. */
70
71 bal 1f
72 1: move t1,ra;
73 PTR_LA t2,1b
74 PTR_LA t0,kexec_flag
75 PTR_SUB t0,t0,t2;
76 PTR_ADD t0,t1,t0;
77 LONG_S zero,(t0)
78#endif
79
Ralf Baechleabe77f92012-10-25 16:23:31 +020080#ifdef CONFIG_CPU_CAVIUM_OCTEON
81 /* We need to flush I-cache before jumping to new kernel.
82 * Unfortunatelly, this code is cpu-specific.
83 */
84 .set push
85 .set noreorder
86 syncw
87 syncw
88 synci 0($0)
89 .set pop
90#else
Ralf Baechle7aa1c8f2012-10-11 18:14:58 +020091 sync
Ralf Baechleabe77f92012-10-25 16:23:31 +020092#endif
Nicolas Schichan583bb862006-10-18 15:14:55 +020093 /* jump to kexec_start_address */
Ralf Baechle00be0f32007-07-31 15:17:21 +010094 j s1
95 END(relocate_new_kernel)
Nicolas Schichan583bb862006-10-18 15:14:55 +020096
Ralf Baechle7aa1c8f2012-10-11 18:14:58 +020097#ifdef CONFIG_SMP
98/*
99 * Other CPUs should wait until code is relocated and
100 * then start at entry (?) point.
101 */
102LEAF(kexec_smp_wait)
103 PTR_L a0, s_arg0
104 PTR_L a1, s_arg1
105 PTR_L a2, s_arg2
106 PTR_L a3, s_arg3
107 PTR_L s1, kexec_start_address
108
109 /* Non-relocated address works for args and kexec_start_address ( old
110 * kernel is not overwritten). But we need relocated address of
111 * kexec_flag.
112 */
113
114 bal 1f
1151: move t1,ra;
116 PTR_LA t2,1b
117 PTR_LA t0,kexec_flag
118 PTR_SUB t0,t0,t2;
119 PTR_ADD t0,t1,t0;
120
1211: LONG_L s0, (t0)
122 bne s0, zero,1b
123
Ralf Baechleabe77f92012-10-25 16:23:31 +0200124#ifdef CONFIG_CPU_CAVIUM_OCTEON
125 .set push
126 .set noreorder
127 synci 0($0)
128 .set pop
129#else
Ralf Baechle7aa1c8f2012-10-11 18:14:58 +0200130 sync
Ralf Baechleabe77f92012-10-25 16:23:31 +0200131#endif
Ralf Baechle7aa1c8f2012-10-11 18:14:58 +0200132 j s1
133 END(kexec_smp_wait)
134#endif
135
136#ifdef __mips64
137 /* all PTR's must be aligned to 8 byte in 64-bit mode */
138 .align 3
139#endif
140
141/* All parameters to new kernel are passed in registers a0-a3.
142 * kexec_args[0..3] are uses to prepare register values.
143 */
144
145kexec_args:
146 EXPORT(kexec_args)
147arg0: PTR 0x0
148arg1: PTR 0x0
149arg2: PTR 0x0
150arg3: PTR 0x0
151 .size kexec_args,PTRSIZE*4
152
153#ifdef CONFIG_SMP
154/*
155 * Secondary CPUs may have different kernel parameters in
156 * their registers a0-a3. secondary_kexec_args[0..3] are used
157 * to prepare register values.
158 */
159secondary_kexec_args:
160 EXPORT(secondary_kexec_args)
161s_arg0: PTR 0x0
162s_arg1: PTR 0x0
163s_arg2: PTR 0x0
164s_arg3: PTR 0x0
165 .size secondary_kexec_args,PTRSIZE*4
166kexec_flag:
167 LONG 0x1
168
169#endif
170
Nicolas Schichan583bb862006-10-18 15:14:55 +0200171kexec_start_address:
Ralf Baechle00be0f32007-07-31 15:17:21 +0100172 EXPORT(kexec_start_address)
173 PTR 0x0
174 .size kexec_start_address, PTRSIZE
Nicolas Schichan583bb862006-10-18 15:14:55 +0200175
Nicolas Schichan583bb862006-10-18 15:14:55 +0200176kexec_indirection_page:
Ralf Baechle00be0f32007-07-31 15:17:21 +0100177 EXPORT(kexec_indirection_page)
178 PTR 0
179 .size kexec_indirection_page, PTRSIZE
Nicolas Schichan583bb862006-10-18 15:14:55 +0200180
181relocate_new_kernel_end:
182
Nicolas Schichan583bb862006-10-18 15:14:55 +0200183relocate_new_kernel_size:
Ralf Baechle00be0f32007-07-31 15:17:21 +0100184 EXPORT(relocate_new_kernel_size)
185 PTR relocate_new_kernel_end - relocate_new_kernel
186 .size relocate_new_kernel_size, PTRSIZE