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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
|
/* $OpenBSD: process.S,v 1.1 2004/04/21 15:24:13 aoyama Exp $ */
/*
* Copyright (c) 1996 Nivas Madhur
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Nivas Madhur.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "assym.h"
#include <machine/asm.h>
#include <machine/psl.h>
#include <machine/intr.h>
data
align 4
ASLOCAL(swchanpanic)
string "switch wchan %x\0"
align 4
ASLOCAL(swsrunpanic)
string "switch SRUN %x\0"
#ifdef DEBUG
align 4
ASLOCAL(boguspsr)
string "Invalid PSR in idle loop 0x%x\n\0"
#endif
text
align 8
ASLOCAL(Lswchanpanic)
or.u r2, r0, hi16(_ASM_LABEL(swchanpanic))
or r2, r2, lo16(_ASM_LABEL(swchanpanic))
bsr.n _C_LABEL(panic)
or r3, r0, r9
ASLOCAL(Lswsrunpanic)
or.u r2, r0, hi16(_ASM_LABEL(swsrunpanic))
or r2, r2, lo16(_ASM_LABEL(swsrunpanic))
bsr.n _C_LABEL(panic)
or r3, r0, r9
/*
* At exit of a process, do a cpu_switch for the last time.
* The mapping of the pcb at p->p_addr has already been deleted,
* and the memory for the pcb+stack has been freed.
* The ipl is high enough to prevent the memory from being reallocated.
* switch_exit(proc * p)
*/
ENTRY(switch_exit)
/*
* Change pcb to idle u. area, i.e., set r31 to top of stack
* and set curpcb to point to _idle_u. r2 contains proc *p.
*/
or.u r30, r0, hi16(_C_LABEL(idle_u))
or r30, r30,lo16(_C_LABEL(idle_u))
addu r31, r30, USIZE /* now on idle_u stack */
or.u r10, r0, hi16(_C_LABEL(curpcb))
st r30, r10,lo16(_C_LABEL(curpcb)) /* curpcb = &idle_u */
or.u r10, r0, hi16(_C_LABEL(curproc))
st r0, r10, lo16(_C_LABEL(curproc)) /* curproc = NULL */
/* Schedule the vmspace and stack to be freed. */
bsr.n _C_LABEL(exit2)
subu r31, r31, 48 /* allocate stack */
addu r31, r31, 48 /* restore stack */
bsr _C_LABEL(cpu_switch) /* goto final switch */
/*
* cpu_switch()
* XXX - Arg 1 is a proc pointer (curproc) but this doesn't use it.
* XXX - how about using stack for saving spl and last proc?
* XXX rewrite this whole mess in C nivas
*/
ENTRY(cpu_switch)
/*
* Save state of previous process in its pcb.
*/
or.u r2, r0, hi16(_C_LABEL(curpcb))
ld r2, r2, lo16(_C_LABEL(curpcb))
st r1, r2, PCB_PC /* save return address */
bsr _ASM_LABEL(__savectx)
/* note that we don't need to recover r1 at this point */
or.u r11, r0, hi16(_C_LABEL(curproc))
ld r2, r11, lo16(_C_LABEL(curproc))
bcnd eq0, r2, 1f
bsr.n _C_LABEL(pmap_deactivate)
subu r31, r31,48
addu r31, r31,48
or.u r11, r0, hi16(_C_LABEL(curproc))
1:
st r0, r11, lo16(_C_LABEL(curproc)) /* curproc = NULL */
ASLOCAL(Lidleloop)
/*
* Find the highest-priority queue that isn't empty,
* then take the first proc from that queue.
*/
or.u r7, r0, hi16(_C_LABEL(whichqs))
ld r7, r7, lo16(_C_LABEL(whichqs))
bcnd ne0, r7, _ASM_LABEL(Ldoneloop)
ASLOCAL(Lloopchk) /* if whichqs is zero, keep checking */
bsr.n _C_LABEL(setipl) /* unmask all ints... */
or r2, r0, IPL_NONE
ldcr r2, PSR
bb0 PSR_INTERRUPT_DISABLE_BIT, r2, 1f
#ifdef DEBUG
or r3, r2, r0
or.u r2, r0, hi16(_ASM_LABEL(boguspsr))
bsr.n _C_LABEL(printf)
or r2, r2, lo16(_ASM_LABEL(boguspsr))
ldcr r2, PSR
#endif
clr r2, r2, 1<PSR_INTERRUPT_DISABLE_BIT> /* ...and enable them */
stcr r2, PSR
FLUSH_PIPELINE
1:
br _ASM_LABEL(Lidleloop)
ASLOCAL(Ldoneloop)
bsr.n _C_LABEL(setipl) /* disable ints */
or r2, r0, IPL_HIGH
or.u r7, r0, hi16(_C_LABEL(whichqs)) /* reload whichqs */
ld r7, r7, lo16(_C_LABEL(whichqs))
bcnd eq0, r7, _ASM_LABEL(Lloopchk) /* keep spinning for whichqs to be != 0 */
xor r6, r6, r6 /* set r6 to 0 */
1: bb1 0, r7, 2f /* if rightmost bit set, done */
extu r7, r7, 0<1> /* else, right shift whichqs, */
br.n 1b /* increment r6, and repeat */
addu r6, r6, 1
2:
or.u r7, r0, hi16(_qs)
or r7, r7, lo16(_qs)
/*
* Need to make
* p->p_forw->p_back = p->p_back and
* p->p_back->p_forw = p->p_forw where
* p is q->p_forw.
* Remember that q->p_forw == p and p->p_back == q.
*/
lda.d r8, r7[r6] /* r8 = &qs[ff1(whichqs)] */
ld r9, r8, P_FORW /* r8 is q, r9 is p */
ld r12, r9, P_FORW /* r12 = p->p_forw */
st r8, r12, P_BACK /* p->p_forw->p_back = q (p->p_back) */
st r12, r8, P_FORW /* q->p_forw = p->p_forw */
lda.d r8, r7[r6] /* reload r8 with qs[ff1(whichqs)] */
ld r12, r8, P_FORW /* q->p_forw */
cmp r12, r12, r8 /* q == q->p_forw; anyone left on queue? */
bb1 ne, r12, 3f /* yes, skip clearing bit in whichqs */
or r12, r0, 1 /* r12 is 1 now */
1: bcnd eq0, r6, 2f
mak r12, r12, 0<1> /* shift left by 1 */
br.n 1b
subu r6, r6, 1 /* keep doing this while r6 != 0 */
2:
/*
* NOTE: we could have just used "mak r12, r12, r6" instead of the
* loop above. But that will break if NQS is made > 32. I can use
* preprocessor to do the right thing, but that means I have to
* include sys/proc.h in this file. XXX nivas
*/
or.u r7, r0, hi16(_C_LABEL(whichqs))
ld r8, r7, lo16(_C_LABEL(whichqs))
and.c r8, r8, r12 /* whichqs &= ~the bit */
st r8, r7, lo16(_C_LABEL(whichqs))
3:
ld r2, r9, P_WCHAN
bcnd ne0, r2, _ASM_LABEL(Lswchanpanic)
ld.b r2, r9, P_STAT
cmp r2, r2, SRUN
bb1 ne, r2, _ASM_LABEL(Lswsrunpanic)
or.u r11, r0, hi16(_C_LABEL(want_resched))
st r0, r11, lo16(_C_LABEL(want_resched)) /* clear want_resched */
or.u r11, r0, hi16(_C_LABEL(curproc))
st r9, r11,lo16(_C_LABEL(curproc)) /* curproc = p */
/* r9 is curproc */
st r0, r9, P_BACK /* p->p_back = 0 */
ld r3, r9, P_ADDR
or.u r10, r0, hi16(_C_LABEL(curpcb))
st r3, r10, lo16(_C_LABEL(curpcb)) /* curpcb = p->p_addr */
/* pmap_activate() the process' pmap */
or r2, r0, r9 /* r2 = p */
or r14, r0, r9 /* save p in r14 */
bsr.n _C_LABEL(pmap_activate)
subu r31, r31,48
addu r31, r31,48
or r9, r0, r14 /* restore p saved in r14 */
or.u r31, r0, hi16(_ASM_LABEL(intstack_end))
or r31,r31, lo16(_ASM_LABEL(intstack_end))
subu r31, r31,48
bsr.n _C_LABEL(load_u_area)
or r2, r0, r9
addu r31, r31,48
or.u r10, r0, hi16(_C_LABEL(curpcb))
ld r10, r10, lo16(_C_LABEL(curpcb))
/* XXX Is this correct/necessary? */
st r10, r14, P_ADDR /* p->p_addr = curpcb; restore p_addr */
/* restore from the current context */
ld r2, r10, PCB_FCR62
ld r3, r10, PCB_FCR63
fstcr r2, fcr62
fstcr r3, fcr63
ld r1, r10, PCB_PC
ld r14,r10, PCB_R14
ld r15,r10, PCB_R15
ld r16,r10, PCB_R16
ld r17,r10, PCB_R17
ld r18,r10, PCB_R18
ld r19,r10, PCB_R19
ld r20,r10, PCB_R20
ld r21,r10, PCB_R21
ld r22,r10, PCB_R22
ld r23,r10, PCB_R23
ld r24,r10, PCB_R24
ld r25,r10, PCB_R25
ld r26,r10, PCB_R26
ld r27,r10, PCB_R27
ld r28,r10, PCB_R28
ld r29,r10, PCB_R29
ld r30,r10, PCB_R30 /* restore frame pointer & stack */
ld r31,r10, PCB_SP
/* XXX
* Should we postpone restoring stack till after ipl is restored?
* The stack access could fault
*/
subu r31,r31,48
st r1, r31,36 /* save r1 on stack */
bsr.n _C_LABEL(setipl)
ld r2, r10, PCB_IPL /* restore interrupt mask */
ld r1, r31,36 /* restore r1 from stack */
addu r31,r31,48
jmp.n r1
or r2, r0, 1 /* return 1 (for alternate returns) */
/*
* savectx(pcb)
* Update pcb, saving current processor state.
*/
ENTRY(savectx)
/*
* Save preserved general register set.
*/
st r1, r2, PCB_PC /* save return address */
ASENTRY(__savectx)
st r14, r2, PCB_R14
st r15, r2, PCB_R15
st r16, r2, PCB_R16
st r17, r2, PCB_R17
st r18, r2, PCB_R18
st r19, r2, PCB_R19
st r20, r2, PCB_R20
st r21, r2, PCB_R21
st r22, r2, PCB_R22
st r23, r2, PCB_R23
st r24, r2, PCB_R24
st r25, r2, PCB_R25
st r26, r2, PCB_R26
st r27, r2, PCB_R27
st r28, r2, PCB_R28
st r29, r2, PCB_R29
st r30, r2, PCB_R30 /* save frame pointer & stack pointer */
st r31, r2, PCB_SP
/*
* Get the current spl.
* We need to save r1 on the stack because we don't know if we were
* called as savectx or __savectx.
*/
subu r31, r31, 40 /* allocate stack for r1 and args */
st r1, r31, 32
bsr.n _C_LABEL(getipl) /* get the current interrupt mask */
or r14, r0, r2
st r2, r14, PCB_IPL /* save interrupt mask */
ld r1, r31, 32 /* recover return address */
addu r31, r31, 40 /* put stack pointer back */
/*
* Save FP state.
*/
fldcr r2, fcr62
fldcr r3, fcr63
st r2, r14, PCB_FCR62
jmp.n r1
st r3, r14, PCB_FCR63
|