Merge branch 'for-next' of git://git.pengutronix.de/git/ukl/linux into devel-stable
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / mips / kernel / relocate_kernel.S
1 /*
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>
12 #include <asm/mipsregs.h>
13 #include <asm/stackframe.h>
14 #include <asm/addrspace.h>
15
16 LEAF(relocate_new_kernel)
17 PTR_L a0, arg0
18 PTR_L a1, arg1
19 PTR_L a2, arg2
20 PTR_L a3, arg3
21
22 PTR_L s0, kexec_indirection_page
23 PTR_L s1, kexec_start_address
24
25 process_entry:
26 PTR_L s2, (s0)
27 PTR_ADD s0, s0, SZREG
28
29 /* destination page */
30 and s3, s2, 0x1
31 beq s3, zero, 1f
32 and s4, s2, ~0x1 /* store destination addr in s4 */
33 b process_entry
34
35 1:
36 /* indirection page, update s0 */
37 and s3, s2, 0x2
38 beq s3, zero, 1f
39 and s0, s2, ~0x2
40 b process_entry
41
42 1:
43 /* done page */
44 and s3, s2, 0x4
45 beq s3, zero, 1f
46 b done
47 1:
48 /* source page */
49 and s3, s2, 0x8
50 beq s3, zero, process_entry
51 and s2, s2, ~0x8
52 li s6, (1 << _PAGE_SHIFT) / SZREG
53
54 copy_word:
55 /* copy page word by word */
56 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
64
65 done:
66 #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
80 #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
91 sync
92 #endif
93 /* jump to kexec_start_address */
94 j s1
95 END(relocate_new_kernel)
96
97 #ifdef CONFIG_SMP
98 /*
99 * Other CPUs should wait until code is relocated and
100 * then start at entry (?) point.
101 */
102 LEAF(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
115 1: 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
121 1: LONG_L s0, (t0)
122 bne s0, zero,1b
123
124 #ifdef CONFIG_CPU_CAVIUM_OCTEON
125 .set push
126 .set noreorder
127 synci 0($0)
128 .set pop
129 #else
130 sync
131 #endif
132 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
145 kexec_args:
146 EXPORT(kexec_args)
147 arg0: PTR 0x0
148 arg1: PTR 0x0
149 arg2: PTR 0x0
150 arg3: 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 */
159 secondary_kexec_args:
160 EXPORT(secondary_kexec_args)
161 s_arg0: PTR 0x0
162 s_arg1: PTR 0x0
163 s_arg2: PTR 0x0
164 s_arg3: PTR 0x0
165 .size secondary_kexec_args,PTRSIZE*4
166 kexec_flag:
167 LONG 0x1
168
169 #endif
170
171 kexec_start_address:
172 EXPORT(kexec_start_address)
173 PTR 0x0
174 .size kexec_start_address, PTRSIZE
175
176 kexec_indirection_page:
177 EXPORT(kexec_indirection_page)
178 PTR 0
179 .size kexec_indirection_page, PTRSIZE
180
181 relocate_new_kernel_end:
182
183 relocate_new_kernel_size:
184 EXPORT(relocate_new_kernel_size)
185 PTR relocate_new_kernel_end - relocate_new_kernel
186 .size relocate_new_kernel_size, PTRSIZE