FreeBSD/Linux Kernel Cross Reference
sys/i386/i386/swtch.s
1 /*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * William Jolitz.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * $FreeBSD: src/sys/i386/i386/swtch.s,v 1.41.2.1 1999/09/05 08:11:17 peter Exp $
37 */
38
39 #include "apm.h"
40 #include "npx.h"
41 #include "opt_user_ldt.h"
42
43 #include <sys/rtprio.h>
44
45 #include <machine/asmacros.h>
46 #include <machine/spl.h>
47
48 #include "assym.s"
49
50
51 /*****************************************************************************/
52 /* Scheduling */
53 /*****************************************************************************/
54
55 /*
56 * The following primitives manipulate the run queues.
57 * _whichqs tells which of the 32 queues _qs
58 * have processes in them. setrunqueue puts processes into queues, Remrq
59 * removes them from queues. The running process is on no queue,
60 * other processes are on a queue related to p->p_priority, divided by 4
61 * actually to shrink the 0-127 range of priorities into the 32 available
62 * queues.
63 */
64 .data
65 .globl _curpcb
66 _curpcb: .long 0 /* pointer to curproc's PCB area */
67 _whichqs: .long 0 /* which run queues have data */
68 _whichrtqs: .long 0 /* which realtime run queues have data */
69 _whichidqs: .long 0 /* which idletime run queues have data */
70
71 .globl _qs,_cnt,_panic
72
73 .globl _want_resched
74 _want_resched: .long 0 /* we need to re-run the scheduler */
75
76 .text
77 /*
78 * setrunqueue(p)
79 *
80 * Call should be made at spl6(), and p->p_stat should be SRUN
81 */
82 ENTRY(setrunqueue)
83 movl 4(%esp),%eax
84 #ifdef DIAGNOSTIC
85 cmpb $SRUN,P_STAT(%eax)
86 je set1
87 pushl $set2
88 call _panic
89 set1:
90 #endif
91 cmpw $RTP_PRIO_NORMAL,P_RTPRIO_TYPE(%eax) /* normal priority process? */
92 je set_nort
93
94 movzwl P_RTPRIO_PRIO(%eax),%edx
95
96 cmpw $RTP_PRIO_REALTIME,P_RTPRIO_TYPE(%eax) /* realtime priority? */
97 jne set_id /* must be idle priority */
98
99 set_rt:
100 btsl %edx,_whichrtqs /* set q full bit */
101 shll $3,%edx
102 addl $_rtqs,%edx /* locate q hdr */
103 movl %edx,P_FORW(%eax) /* link process on tail of q */
104 movl P_BACK(%edx),%ecx
105 movl %ecx,P_BACK(%eax)
106 movl %eax,P_BACK(%edx)
107 movl %eax,P_FORW(%ecx)
108 ret
109
110 set_id:
111 btsl %edx,_whichidqs /* set q full bit */
112 shll $3,%edx
113 addl $_idqs,%edx /* locate q hdr */
114 movl %edx,P_FORW(%eax) /* link process on tail of q */
115 movl P_BACK(%edx),%ecx
116 movl %ecx,P_BACK(%eax)
117 movl %eax,P_BACK(%edx)
118 movl %eax,P_FORW(%ecx)
119 ret
120
121 set_nort: /* Normal (RTOFF) code */
122 movzbl P_PRI(%eax),%edx
123 shrl $2,%edx
124 btsl %edx,_whichqs /* set q full bit */
125 shll $3,%edx
126 addl $_qs,%edx /* locate q hdr */
127 movl %edx,P_FORW(%eax) /* link process on tail of q */
128 movl P_BACK(%edx),%ecx
129 movl %ecx,P_BACK(%eax)
130 movl %eax,P_BACK(%edx)
131 movl %eax,P_FORW(%ecx)
132 ret
133
134 set2: .asciz "setrunqueue"
135
136 /*
137 * Remrq(p)
138 *
139 * Call should be made at spl6().
140 */
141 ENTRY(remrq)
142 movl 4(%esp),%eax
143 cmpw $RTP_PRIO_NORMAL,P_RTPRIO_TYPE(%eax) /* normal priority process? */
144 je rem_nort
145
146 movzwl P_RTPRIO_PRIO(%eax),%edx
147
148 cmpw $RTP_PRIO_REALTIME,P_RTPRIO_TYPE(%eax) /* normal priority process? */
149 jne rem_id
150
151 btrl %edx,_whichrtqs /* clear full bit, panic if clear already */
152 jb rem1rt
153 pushl $rem3rt
154 call _panic
155 rem1rt:
156 pushl %edx
157 movl P_FORW(%eax),%ecx /* unlink process */
158 movl P_BACK(%eax),%edx
159 movl %edx,P_BACK(%ecx)
160 movl P_BACK(%eax),%ecx
161 movl P_FORW(%eax),%edx
162 movl %edx,P_FORW(%ecx)
163 popl %edx
164 movl $_rtqs,%ecx
165 shll $3,%edx
166 addl %edx,%ecx
167 cmpl P_FORW(%ecx),%ecx /* q still has something? */
168 je rem2rt
169 shrl $3,%edx /* yes, set bit as still full */
170 btsl %edx,_whichrtqs
171 rem2rt:
172 ret
173 rem_id:
174 btrl %edx,_whichidqs /* clear full bit, panic if clear already */
175 jb rem1id
176 pushl $rem3id
177 call _panic
178 rem1id:
179 pushl %edx
180 movl P_FORW(%eax),%ecx /* unlink process */
181 movl P_BACK(%eax),%edx
182 movl %edx,P_BACK(%ecx)
183 movl P_BACK(%eax),%ecx
184 movl P_FORW(%eax),%edx
185 movl %edx,P_FORW(%ecx)
186 popl %edx
187 movl $_idqs,%ecx
188 shll $3,%edx
189 addl %edx,%ecx
190 cmpl P_FORW(%ecx),%ecx /* q still has something? */
191 je rem2id
192 shrl $3,%edx /* yes, set bit as still full */
193 btsl %edx,_whichidqs
194 rem2id:
195 ret
196
197 rem_nort:
198 movzbl P_PRI(%eax),%edx
199 shrl $2,%edx
200 btrl %edx,_whichqs /* clear full bit, panic if clear already */
201 jb rem1
202 pushl $rem3
203 call _panic
204 rem1:
205 pushl %edx
206 movl P_FORW(%eax),%ecx /* unlink process */
207 movl P_BACK(%eax),%edx
208 movl %edx,P_BACK(%ecx)
209 movl P_BACK(%eax),%ecx
210 movl P_FORW(%eax),%edx
211 movl %edx,P_FORW(%ecx)
212 popl %edx
213 movl $_qs,%ecx
214 shll $3,%edx
215 addl %edx,%ecx
216 cmpl P_FORW(%ecx),%ecx /* q still has something? */
217 je rem2
218 shrl $3,%edx /* yes, set bit as still full */
219 btsl %edx,_whichqs
220 rem2:
221 ret
222
223 rem3: .asciz "remrq"
224 rem3rt: .asciz "remrq.rt"
225 rem3id: .asciz "remrq.id"
226
227 /*
228 * When no processes are on the runq, cpu_switch() branches to _idle
229 * to wait for something to come ready.
230 */
231 ALIGN_TEXT
232 _idle:
233 xorl %ebp,%ebp
234 movl $tmpstk,%esp
235 movl _IdlePTD,%ecx
236 movl %ecx,%cr3
237 sti
238
239 /*
240 * XXX callers of cpu_switch() do a bogus splclock(). Locking should
241 * be left to cpu_switch().
242 */
243 movl $SWI_AST_MASK,_cpl
244 testl $~SWI_AST_MASK,_ipending
245 je idle_loop
246 call _splz
247
248 ALIGN_TEXT
249 idle_loop:
250 cli
251 movb $1,_intr_nesting_level /* charge Intr if we leave */
252 cmpl $0,_whichrtqs /* real-time queue */
253 CROSSJUMP(jne, sw1a, je)
254 cmpl $0,_whichqs /* normal queue */
255 CROSSJUMP(jne, nortqr, je)
256 cmpl $0,_whichidqs /* 'idle' queue */
257 CROSSJUMP(jne, idqr, je)
258 movb $0,_intr_nesting_level /* charge Idle for this loop */
259 call _vm_page_zero_idle
260 testl %eax, %eax
261 jnz idle_loop
262 sti
263 #if NAPM > 0 && defined(APM_IDLE_CPU)
264 call _apm_cpu_idle
265 call _apm_cpu_busy
266 #else
267 hlt /* wait for interrupt */
268 #endif
269 jmp idle_loop
270
271 CROSSJUMPTARGET(_idle)
272
273 /*
274 * cpu_switch()
275 */
276 ENTRY(cpu_switch)
277 /* switch to new process. first, save context as needed */
278 movl _curproc,%ecx
279
280 /* if no process to save, don't bother */
281 testl %ecx,%ecx
282 je sw1
283
284 movl P_ADDR(%ecx),%ecx
285
286 movl (%esp),%eax /* Hardware registers */
287 movl %eax,PCB_EIP(%ecx)
288 movl %ebx,PCB_EBX(%ecx)
289 movl %esp,PCB_ESP(%ecx)
290 movl %ebp,PCB_EBP(%ecx)
291 movl %esi,PCB_ESI(%ecx)
292 movl %edi,PCB_EDI(%ecx)
293
294 #if NNPX > 0
295 /* have we used fp, and need a save? */
296 mov _curproc,%eax
297 cmp %eax,_npxproc
298 jne 1f
299 addl $PCB_SAVEFPU,%ecx /* h/w bugs make saving complicated */
300 pushl %ecx
301 call _npxsave /* do it in a big C function */
302 popl %eax
303 1:
304 #endif /* NNPX > 0 */
305
306 movb $1,_intr_nesting_level /* charge Intr, not Sys/Idle */
307
308 movl $0,_curproc /* out of process */
309
310 /* save is done, now choose a new process or idle */
311 sw1:
312 cli
313 sw1a:
314 movl _whichrtqs,%edi /* pick next p. from rtqs */
315 testl %edi,%edi
316 jz nortqr /* no realtime procs */
317
318 /* XXX - bsf is sloow */
319 bsfl %edi,%ebx /* find a full q */
320 jz nortqr /* no proc on rt q - try normal ... */
321
322 /* XX update whichqs? */
323 btrl %ebx,%edi /* clear q full status */
324 leal _rtqs(,%ebx,8),%eax /* select q */
325 movl %eax,%esi
326
327 movl P_FORW(%eax),%ecx /* unlink from front of process q */
328 movl P_FORW(%ecx),%edx
329 movl %edx,P_FORW(%eax)
330 movl P_BACK(%ecx),%eax
331 movl %eax,P_BACK(%edx)
332
333 cmpl P_FORW(%ecx),%esi /* q empty */
334 je rt3
335 btsl %ebx,%edi /* nope, set to indicate not empty */
336 rt3:
337 movl %edi,_whichrtqs /* update q status */
338 jmp swtch_com
339
340 /* old sw1a */
341 /* Normal process priority's */
342 nortqr:
343 movl _whichqs,%edi
344 2:
345 /* XXX - bsf is sloow */
346 bsfl %edi,%ebx /* find a full q */
347 jz idqr /* if none, idle */
348
349 /* XX update whichqs? */
350 btrl %ebx,%edi /* clear q full status */
351 leal _qs(,%ebx,8),%eax /* select q */
352 movl %eax,%esi
353
354 movl P_FORW(%eax),%ecx /* unlink from front of process q */
355 movl P_FORW(%ecx),%edx
356 movl %edx,P_FORW(%eax)
357 movl P_BACK(%ecx),%eax
358 movl %eax,P_BACK(%edx)
359
360 cmpl P_FORW(%ecx),%esi /* q empty */
361 je 3f
362 btsl %ebx,%edi /* nope, set to indicate not empty */
363 3:
364 movl %edi,_whichqs /* update q status */
365 jmp swtch_com
366
367 idqr: /* was sw1a */
368 movl _whichidqs,%edi /* pick next p. from idqs */
369
370 /* XXX - bsf is sloow */
371 bsfl %edi,%ebx /* find a full q */
372 CROSSJUMP(je, _idle, jne) /* if no proc, idle */
373
374 /* XX update whichqs? */
375 btrl %ebx,%edi /* clear q full status */
376 leal _idqs(,%ebx,8),%eax /* select q */
377 movl %eax,%esi
378
379 movl P_FORW(%eax),%ecx /* unlink from front of process q */
380 movl P_FORW(%ecx),%edx
381 movl %edx,P_FORW(%eax)
382 movl P_BACK(%ecx),%eax
383 movl %eax,P_BACK(%edx)
384
385 cmpl P_FORW(%ecx),%esi /* q empty */
386 je id3
387 btsl %ebx,%edi /* nope, set to indicate not empty */
388 id3:
389 movl %edi,_whichidqs /* update q status */
390
391 swtch_com:
392 movl $0,%eax
393 movl %eax,_want_resched
394
395 #ifdef DIAGNOSTIC
396 cmpl %eax,P_WCHAN(%ecx)
397 jne badsw
398 cmpb $SRUN,P_STAT(%ecx)
399 jne badsw
400 #endif
401
402 movl %eax,P_BACK(%ecx) /* isolate process to run */
403 movl P_ADDR(%ecx),%edx
404 movl PCB_CR3(%edx),%ebx
405
406 /* switch address space */
407 movl %ebx,%cr3
408
409 /* restore context */
410 movl PCB_EBX(%edx),%ebx
411 movl PCB_ESP(%edx),%esp
412 movl PCB_EBP(%edx),%ebp
413 movl PCB_ESI(%edx),%esi
414 movl PCB_EDI(%edx),%edi
415 movl PCB_EIP(%edx),%eax
416 movl %eax,(%esp)
417
418 movl %edx,_curpcb
419 movl %ecx,_curproc /* into next process */
420 movb $0,_intr_nesting_level
421
422 #ifdef USER_LDT
423 cmpl $0, PCB_USERLDT(%edx)
424 jnz 1f
425 movl __default_ldt,%eax
426 cmpl _currentldt,%eax
427 je 2f
428 lldt __default_ldt
429 movl %eax,_currentldt
430 jmp 2f
431 1: pushl %edx
432 call _set_user_ldt
433 popl %edx
434 2:
435 #endif
436
437 sti
438 ret
439
440 CROSSJUMPTARGET(idqr)
441 CROSSJUMPTARGET(nortqr)
442 CROSSJUMPTARGET(sw1a)
443
444 badsw:
445 pushl $sw0
446 call _panic
447
448 sw0: .asciz "cpu_switch"
449
450 /*
451 * savectx(pcb)
452 * Update pcb, saving current processor state.
453 */
454 ENTRY(savectx)
455 /* fetch PCB */
456 movl 4(%esp),%ecx
457
458 /* caller's return address - child won't execute this routine */
459 movl (%esp),%eax
460 movl %eax,PCB_EIP(%ecx)
461
462 movl %ebx,PCB_EBX(%ecx)
463 movl %esp,PCB_ESP(%ecx)
464 movl %ebp,PCB_EBP(%ecx)
465 movl %esi,PCB_ESI(%ecx)
466 movl %edi,PCB_EDI(%ecx)
467
468 #if NNPX > 0
469 /*
470 * If npxproc == NULL, then the npx h/w state is irrelevant and the
471 * state had better already be in the pcb. This is true for forks
472 * but not for dumps (the old book-keeping with FP flags in the pcb
473 * always lost for dumps because the dump pcb has 0 flags).
474 *
475 * If npxproc != NULL, then we have to save the npx h/w state to
476 * npxproc's pcb and copy it to the requested pcb, or save to the
477 * requested pcb and reload. Copying is easier because we would
478 * have to handle h/w bugs for reloading. We used to lose the
479 * parent's npx state for forks by forgetting to reload.
480 */
481 mov _npxproc,%eax
482 testl %eax,%eax
483 je 1f
484
485 pushl %ecx
486 movl P_ADDR(%eax),%eax
487 leal PCB_SAVEFPU(%eax),%eax
488 pushl %eax
489 pushl %eax
490 call _npxsave
491 addl $4,%esp
492 popl %eax
493 popl %ecx
494
495 pushl $PCB_SAVEFPU_SIZE
496 leal PCB_SAVEFPU(%ecx),%ecx
497 pushl %ecx
498 pushl %eax
499 call _bcopy
500 addl $12,%esp
501 #endif /* NNPX > 0 */
502
503 1:
504 ret
Cache object: e7bebf09d90fc73af29301d463f107b8
|