Deleted Added
sdiff udiff text old ( 72276 ) new ( 72358 )
full compact
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: head/sys/amd64/amd64/cpu_switch.S 72276 2001-02-10 02:20:34Z jhb $
37 */
38
39#include "opt_npx.h"
40#include "opt_user_ldt.h"
41
42#include <sys/rtprio.h>
43
44#include <machine/asmacros.h>
45#include <machine/ipl.h>
46
47#ifdef SMP
48#include <machine/pmap.h>
49#include <machine/apic.h>
50#include <machine/smptests.h> /** GRAB_LOPRIO */
51#include <machine/lock.h>
52#endif /* SMP */
53
54#include "assym.s"
55
56
57/*****************************************************************************/
58/* Scheduling */
59/*****************************************************************************/
60
61 .data
62
63 .globl _panic
64
65#if defined(SWTCH_OPTIM_STATS)
66 .globl _swtch_optim_stats, _tlb_flush_count
67_swtch_optim_stats: .long 0 /* number of _swtch_optims */
68_tlb_flush_count: .long 0
69#endif
70
71 .text
72
73/*
74 * cpu_throw()
75 */
76ENTRY(cpu_throw)
77 jmp sw1
78
79/*
80 * cpu_switch()
81 */
82ENTRY(cpu_switch)
83
84 /* switch to new process. first, save context as needed */
85 movl PCPU(CURPROC),%ecx
86
87 /* if no process to save, don't bother */
88 testl %ecx,%ecx
89 jz sw1
90
91#ifdef SMP
92 movb P_ONCPU(%ecx), %al /* save "last" cpu */
93 movb %al, P_LASTCPU(%ecx)
94 movb $0xff, P_ONCPU(%ecx) /* "leave" the cpu */
95#endif /* SMP */
96 movl P_VMSPACE(%ecx), %edx
97#ifdef SMP
98 movl PCPU(CPUID), %eax
99#else
100 xorl %eax, %eax
101#endif /* SMP */
102 btrl %eax, VM_PMAP+PM_ACTIVE(%edx)
103
104 movl P_ADDR(%ecx),%edx
105
106 movl (%esp),%eax /* Hardware registers */
107 movl %eax,PCB_EIP(%edx)
108 movl %ebx,PCB_EBX(%edx)
109 movl %esp,PCB_ESP(%edx)
110 movl %ebp,PCB_EBP(%edx)
111 movl %esi,PCB_ESI(%edx)
112 movl %edi,PCB_EDI(%edx)
113 movl %gs,PCB_GS(%edx)
114
115 /* test if debug registers should be saved */
116 movb PCB_FLAGS(%edx),%al
117 andb $PCB_DBREGS,%al
118 jz 1f /* no, skip over */
119 movl %dr7,%eax /* yes, do the save */
120 movl %eax,PCB_DR7(%edx)
121 andl $0x0000ff00, %eax /* disable all watchpoints */
122 movl %eax,%dr7
123 movl %dr6,%eax
124 movl %eax,PCB_DR6(%edx)
125 movl %dr3,%eax
126 movl %eax,PCB_DR3(%edx)
127 movl %dr2,%eax
128 movl %eax,PCB_DR2(%edx)
129 movl %dr1,%eax
130 movl %eax,PCB_DR1(%edx)
131 movl %dr0,%eax
132 movl %eax,PCB_DR0(%edx)
1331:
134
135 /* save sched_lock recursion count */
136 movl _sched_lock+MTX_RECURSECNT,%eax
137 movl %eax,PCB_SCHEDNEST(%edx)
138
139#ifdef SMP
140 /* XXX FIXME: we should be saving the local APIC TPR */
141#endif /* SMP */
142
143#ifdef DEV_NPX
144 /* have we used fp, and need a save? */
145 cmpl %ecx,PCPU(NPXPROC)
146 jne 1f
147 addl $PCB_SAVEFPU,%edx /* h/w bugs make saving complicated */
148 pushl %edx
149 call _npxsave /* do it in a big C function */
150 popl %eax
1511:
152#endif /* DEV_NPX */
153
154 /* save is done, now choose a new process */
155sw1:
156
157#ifdef SMP
158 /* Stop scheduling if smp_active goes zero and we are not BSP */
159 cmpl $0,_smp_active
160 jne 1f
161 cmpl $0,PCPU(CPUID)
162 je 1f
163
164 movl PCPU(IDLEPROC), %eax
165 jmp sw1b
1661:
167#endif
168
169 /*
170 * Choose a new process to schedule. chooseproc() returns idleproc
171 * if it cannot find another process to run.
172 */
173sw1a:
174 call _chooseproc /* trash ecx, edx, ret eax*/
175
176#ifdef INVARIANTS
177 testl %eax,%eax /* no process? */
178 jz badsw3 /* no, panic */
179#endif
180sw1b:
181 movl %eax,%ecx
182
183#ifdef INVARIANTS
184 cmpb $SRUN,P_STAT(%ecx)
185 jne badsw2
186#endif
187
188 movl P_ADDR(%ecx),%edx
189
190#if defined(SWTCH_OPTIM_STATS)
191 incl _swtch_optim_stats
192#endif
193 /* switch address space */
194 movl %cr3,%ebx
195 cmpl PCB_CR3(%edx),%ebx
196 je 4f
197#if defined(SWTCH_OPTIM_STATS)
198 decl _swtch_optim_stats
199 incl _tlb_flush_count
200#endif
201 movl PCB_CR3(%edx),%ebx
202 movl %ebx,%cr3
2034:
204
205#ifdef SMP
206 movl PCPU(CPUID), %esi
207#else
208 xorl %esi, %esi
209#endif
210 cmpl $0, PCB_EXT(%edx) /* has pcb extension? */
211 je 1f
212 btsl %esi, _private_tss /* mark use of private tss */
213 movl PCB_EXT(%edx), %edi /* new tss descriptor */
214 jmp 2f
2151:
216
217 /* update common_tss.tss_esp0 pointer */
218 movl %edx, %ebx /* pcb */
219 addl $(UPAGES * PAGE_SIZE - 16), %ebx
220 movl %ebx, PCPU(COMMON_TSS) + TSS_ESP0
221
222 btrl %esi, _private_tss
223 jae 3f
224 PCPU_ADDR(COMMON_TSSD, %edi)
2252:
226 /* move correct tss descriptor into GDT slot, then reload tr */
227 movl PCPU(TSS_GDT), %ebx /* entry in GDT */
228 movl 0(%edi), %eax
229 movl %eax, 0(%ebx)
230 movl 4(%edi), %eax
231 movl %eax, 4(%ebx)
232 movl $GPROC0_SEL*8, %esi /* GSEL(entry, SEL_KPL) */
233 ltr %si
2343:
235 movl P_VMSPACE(%ecx), %ebx
236#ifdef SMP
237 movl PCPU(CPUID), %eax
238#else
239 xorl %eax, %eax
240#endif
241 btsl %eax, VM_PMAP+PM_ACTIVE(%ebx)
242
243 /* restore context */
244 movl PCB_EBX(%edx),%ebx
245 movl PCB_ESP(%edx),%esp
246 movl PCB_EBP(%edx),%ebp
247 movl PCB_ESI(%edx),%esi
248 movl PCB_EDI(%edx),%edi
249 movl PCB_EIP(%edx),%eax
250 movl %eax,(%esp)
251
252#ifdef SMP
253#ifdef GRAB_LOPRIO /* hold LOPRIO for INTs */
254#ifdef CHEAP_TPR
255 movl $0, _lapic+LA_TPR
256#else
257 andl $~APIC_TPR_PRIO, _lapic+LA_TPR
258#endif /** CHEAP_TPR */
259#endif /** GRAB_LOPRIO */
260 movl PCPU(CPUID),%eax
261 movb %al, P_ONCPU(%ecx)
262#endif /* SMP */
263 movl %edx, PCPU(CURPCB)
264 movl %ecx, PCPU(CURPROC) /* into next process */
265
266#ifdef SMP
267 /* XXX FIXME: we should be restoring the local APIC TPR */
268#endif /* SMP */
269
270#ifdef USER_LDT
271 cmpl $0, PCB_USERLDT(%edx)
272 jnz 1f
273 movl __default_ldt,%eax
274 cmpl PCPU(CURRENTLDT),%eax
275 je 2f
276 lldt __default_ldt
277 movl %eax,PCPU(CURRENTLDT)
278 jmp 2f
2791: pushl %edx
280 call _set_user_ldt
281 popl %edx
2822:
283#endif
284
285 /* This must be done after loading the user LDT. */
286 .globl cpu_switch_load_gs
287cpu_switch_load_gs:
288 movl PCB_GS(%edx),%gs
289
290 /* test if debug regisers should be restored */
291 movb PCB_FLAGS(%edx),%al
292 andb $PCB_DBREGS,%al
293 jz 1f /* no, skip over */
294 movl PCB_DR6(%edx),%eax /* yes, do the restore */
295 movl %eax,%dr6
296 movl PCB_DR3(%edx),%eax
297 movl %eax,%dr3
298 movl PCB_DR2(%edx),%eax
299 movl %eax,%dr2
300 movl PCB_DR1(%edx),%eax
301 movl %eax,%dr1
302 movl PCB_DR0(%edx),%eax
303 movl %eax,%dr0
304 movl PCB_DR7(%edx),%eax
305 movl %eax,%dr7
3061:
307
308 /*
309 * restore sched_lock recursion count and transfer ownership to
310 * new process
311 */
312 movl PCB_SCHEDNEST(%edx),%eax
313 movl %eax,_sched_lock+MTX_RECURSECNT
314
315 movl PCPU(CURPROC),%eax
316 movl %eax,_sched_lock+MTX_LOCK
317
318 ret
319
320CROSSJUMPTARGET(sw1a)
321
322#ifdef INVARIANTS
323badsw2:
324 pushl $sw0_2
325 call _panic
326
327sw0_2: .asciz "cpu_switch: not SRUN"
328
329badsw3:
330 pushl $sw0_3
331 call _panic
332
333sw0_3: .asciz "cpu_switch: chooseproc returned NULL"
334#endif
335
336/*
337 * savectx(pcb)
338 * Update pcb, saving current processor state.
339 */
340ENTRY(savectx)
341 /* fetch PCB */
342 movl 4(%esp),%ecx
343
344 /* caller's return address - child won't execute this routine */
345 movl (%esp),%eax
346 movl %eax,PCB_EIP(%ecx)
347
348 movl %cr3,%eax
349 movl %eax,PCB_CR3(%ecx)
350
351 movl %ebx,PCB_EBX(%ecx)
352 movl %esp,PCB_ESP(%ecx)
353 movl %ebp,PCB_EBP(%ecx)
354 movl %esi,PCB_ESI(%ecx)
355 movl %edi,PCB_EDI(%ecx)
356 movl %gs,PCB_GS(%ecx)
357
358#ifdef DEV_NPX
359 /*
360 * If npxproc == NULL, then the npx h/w state is irrelevant and the
361 * state had better already be in the pcb. This is true for forks
362 * but not for dumps (the old book-keeping with FP flags in the pcb
363 * always lost for dumps because the dump pcb has 0 flags).
364 *
365 * If npxproc != NULL, then we have to save the npx h/w state to
366 * npxproc's pcb and copy it to the requested pcb, or save to the
367 * requested pcb and reload. Copying is easier because we would
368 * have to handle h/w bugs for reloading. We used to lose the
369 * parent's npx state for forks by forgetting to reload.
370 */
371 movl PCPU(NPXPROC),%eax
372 testl %eax,%eax
373 je 1f
374
375 pushl %ecx
376 movl P_ADDR(%eax),%eax
377 leal PCB_SAVEFPU(%eax),%eax
378 pushl %eax
379 pushl %eax
380 call _npxsave
381 addl $4,%esp
382 popl %eax
383 popl %ecx
384
385 pushl $PCB_SAVEFPU_SIZE
386 leal PCB_SAVEFPU(%ecx),%ecx
387 pushl %ecx
388 pushl %eax
389 call _bcopy
390 addl $12,%esp
391#endif /* DEV_NPX */
392
3931:
394 ret