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
193
194
195
196
197
| /*
| * arch/sh/kernel/cpu/sh5/switchto.S
| *
| * sh64 context switch
| *
| * Copyright (C) 2004 Richard Curnow
| *
| * This file is subject to the terms and conditions of the GNU General Public
| * License. See the file "COPYING" in the main directory of this archive
| * for more details.
| */
|
| .section .text..SHmedia32,"ax"
| .little
|
| .balign 32
|
| .type sh64_switch_to,@function
| .global sh64_switch_to
| .global __sh64_switch_to_end
| sh64_switch_to:
|
| /* Incoming args
| r2 - prev
| r3 - &prev->thread
| r4 - next
| r5 - &next->thread
|
| Outgoing results
| r2 - last (=prev) : this just stays in r2 throughout
|
| Want to create a full (struct pt_regs) on the stack to allow backtracing
| functions to work. However, we only need to populate the callee-save
| register slots in this structure; since we're a function our ancestors must
| have themselves preserved all caller saved state in the stack. This saves
| some wasted effort since we won't need to look at the values.
|
| In particular, all caller-save registers are immediately available for
| scratch use.
|
| */
|
| #define FRAME_SIZE (76*8 + 8)
|
| movi FRAME_SIZE, r0
| sub.l r15, r0, r15
| ! Do normal-style register save to support backtrace
|
| st.l r15, 0, r18 ! save link reg
| st.l r15, 4, r14 ! save fp
| add.l r15, r63, r14 ! setup frame pointer
|
| ! hopefully this looks normal to the backtrace now.
|
| addi.l r15, 8, r1 ! base of pt_regs
| addi.l r1, 24, r0 ! base of pt_regs.regs
| addi.l r0, (63*8), r8 ! base of pt_regs.trregs
|
| /* Note : to be fixed?
| struct pt_regs is really designed for holding the state on entry
| to an exception, i.e. pc,sr,regs etc. However, for the context
| switch state, some of this is not required. But the unwinder takes
| struct pt_regs * as an arg so we have to build this structure
| to allow unwinding switched tasks in show_state() */
|
| st.q r0, ( 9*8), r9
| st.q r0, (10*8), r10
| st.q r0, (11*8), r11
| st.q r0, (12*8), r12
| st.q r0, (13*8), r13
| st.q r0, (14*8), r14 ! for unwind, want to look as though we took a trap at
| ! the point where the process is left in suspended animation, i.e. current
| ! fp here, not the saved one.
| st.q r0, (16*8), r16
|
| st.q r0, (24*8), r24
| st.q r0, (25*8), r25
| st.q r0, (26*8), r26
| st.q r0, (27*8), r27
| st.q r0, (28*8), r28
| st.q r0, (29*8), r29
| st.q r0, (30*8), r30
| st.q r0, (31*8), r31
| st.q r0, (32*8), r32
| st.q r0, (33*8), r33
| st.q r0, (34*8), r34
| st.q r0, (35*8), r35
|
| st.q r0, (44*8), r44
| st.q r0, (45*8), r45
| st.q r0, (46*8), r46
| st.q r0, (47*8), r47
| st.q r0, (48*8), r48
| st.q r0, (49*8), r49
| st.q r0, (50*8), r50
| st.q r0, (51*8), r51
| st.q r0, (52*8), r52
| st.q r0, (53*8), r53
| st.q r0, (54*8), r54
| st.q r0, (55*8), r55
| st.q r0, (56*8), r56
| st.q r0, (57*8), r57
| st.q r0, (58*8), r58
| st.q r0, (59*8), r59
|
| ! do this early as pta->gettr has no pipeline forwarding (=> 5 cycle latency)
| ! Use a local label to avoid creating a symbol that will confuse the !
| ! backtrace
| pta .Lsave_pc, tr0
|
| gettr tr5, r45
| gettr tr6, r46
| gettr tr7, r47
| st.q r8, (5*8), r45
| st.q r8, (6*8), r46
| st.q r8, (7*8), r47
|
| ! Now switch context
| gettr tr0, r9
| st.l r3, 0, r15 ! prev->thread.sp
| st.l r3, 8, r1 ! prev->thread.kregs
| st.l r3, 4, r9 ! prev->thread.pc
| st.q r1, 0, r9 ! save prev->thread.pc into pt_regs->pc
|
| ! Load PC for next task (init value or save_pc later)
| ld.l r5, 4, r18 ! next->thread.pc
| ! Switch stacks
| ld.l r5, 0, r15 ! next->thread.sp
| ptabs r18, tr0
|
| ! Update current
| ld.l r4, 4, r9 ! next->thread_info (2nd element of next task_struct)
| putcon r9, kcr0 ! current = next->thread_info
|
| ! go to save_pc for a reschedule, or the initial thread.pc for a new process
| blink tr0, r63
|
| ! Restore (when we come back to a previously saved task)
| .Lsave_pc:
| addi.l r15, 32, r0 ! r0 = next's regs
| addi.l r0, (63*8), r8 ! r8 = next's tr_regs
|
| ld.q r8, (5*8), r45
| ld.q r8, (6*8), r46
| ld.q r8, (7*8), r47
| ptabs r45, tr5
| ptabs r46, tr6
| ptabs r47, tr7
|
| ld.q r0, ( 9*8), r9
| ld.q r0, (10*8), r10
| ld.q r0, (11*8), r11
| ld.q r0, (12*8), r12
| ld.q r0, (13*8), r13
| ld.q r0, (14*8), r14
| ld.q r0, (16*8), r16
|
| ld.q r0, (24*8), r24
| ld.q r0, (25*8), r25
| ld.q r0, (26*8), r26
| ld.q r0, (27*8), r27
| ld.q r0, (28*8), r28
| ld.q r0, (29*8), r29
| ld.q r0, (30*8), r30
| ld.q r0, (31*8), r31
| ld.q r0, (32*8), r32
| ld.q r0, (33*8), r33
| ld.q r0, (34*8), r34
| ld.q r0, (35*8), r35
|
| ld.q r0, (44*8), r44
| ld.q r0, (45*8), r45
| ld.q r0, (46*8), r46
| ld.q r0, (47*8), r47
| ld.q r0, (48*8), r48
| ld.q r0, (49*8), r49
| ld.q r0, (50*8), r50
| ld.q r0, (51*8), r51
| ld.q r0, (52*8), r52
| ld.q r0, (53*8), r53
| ld.q r0, (54*8), r54
| ld.q r0, (55*8), r55
| ld.q r0, (56*8), r56
| ld.q r0, (57*8), r57
| ld.q r0, (58*8), r58
| ld.q r0, (59*8), r59
|
| ! epilogue
| ld.l r15, 0, r18
| ld.l r15, 4, r14
| ptabs r18, tr0
| movi FRAME_SIZE, r0
| add r15, r0, r15
| blink tr0, r63
| __sh64_switch_to_end:
| .LFE1:
| .size sh64_switch_to,.LFE1-sh64_switch_to
|
|