hc
2023-02-13 e440ec23c5a540cdd3f7464e8779219be6fd3d95
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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
130
131
132
133
134
135
136
137
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/*
 * 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>
 
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 CONFIG_CPU_CAVIUM_OCTEON
   .set push
   .set noreorder
   synci        0($0)
   .set pop
#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