MP Implementation 2/4: Implement a poor-man's IPI messaging subsystem,
[dragonfly.git] / sys / i386 / i386 / swtch.s
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  * LWKT threads Copyright (c) 2003 Matthew Dillon
5  *
6  * This code is derived from software contributed to Berkeley by
7  * William Jolitz.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by the University of
20  *      California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  * $FreeBSD: src/sys/i386/i386/swtch.s,v 1.89.2.10 2003/01/23 03:36:24 ps Exp $
38  * $DragonFly: src/sys/i386/i386/Attic/swtch.s,v 1.22 2003/07/08 06:27:26 dillon Exp $
39  */
40
41 #include "npx.h"
42 #include "opt_user_ldt.h"
43
44 #include <sys/rtprio.h>
45
46 #include <machine/asmacros.h>
47 #include <machine/ipl.h>
48
49 #ifdef SMP
50 #include <machine/pmap.h>
51 #include <machine/smptests.h>           /** GRAB_LOPRIO */
52 #include <machine/apic.h>
53 #include <machine/lock.h>
54 #endif /* SMP */
55
56 #include "assym.s"
57
58         .data
59
60         .globl  panic
61
62 #if defined(SWTCH_OPTIM_STATS)
63         .globl  swtch_optim_stats, tlb_flush_count
64 swtch_optim_stats:      .long   0               /* number of _swtch_optims */
65 tlb_flush_count:        .long   0
66 #endif
67
68         .text
69
70
71 /*
72  * cpu_heavy_switch(next_thread)
73  *
74  *      Switch from the current thread to a new thread.  This entry
75  *      is normally called via the thread->td_switch function, and will
76  *      only be called when the current thread is a heavy weight process.
77  *
78  *      YYY disable interrupts once giant is removed.
79  */
80 ENTRY(cpu_heavy_switch)
81         movl    PCPU(curthread),%ecx
82         movl    TD_PROC(%ecx),%ecx
83
84         cli
85         movl    P_VMSPACE(%ecx), %edx
86         movl    PCPU(cpuid), %eax
87         btrl    %eax, VM_PMAP+PM_ACTIVE(%edx)
88
89         /*
90          * Save general regs
91          */
92         movl    P_THREAD(%ecx),%edx
93         movl    TD_PCB(%edx),%edx
94         movl    (%esp),%eax                     /* Hardware registers */
95         movl    %eax,PCB_EIP(%edx)
96         movl    %ebx,PCB_EBX(%edx)
97         movl    %esp,PCB_ESP(%edx)
98         movl    %ebp,PCB_EBP(%edx)
99         movl    %esi,PCB_ESI(%edx)
100         movl    %edi,PCB_EDI(%edx)
101         movl    %gs,PCB_GS(%edx)
102
103         /*
104          * Push the LWKT switch restore function, which resumes a heavy
105          * weight process.  Note that the LWKT switcher is based on
106          * TD_SP, while the heavy weight process switcher is based on
107          * PCB_ESP.  TD_SP is usually one pointer pushed relative to
108          * PCB_ESP.
109          */
110         movl    P_THREAD(%ecx),%eax
111         pushl   $cpu_heavy_restore
112         movl    %esp,TD_SP(%eax)
113
114         /*
115          * Save debug regs if necessary
116          */
117         movb    PCB_FLAGS(%edx),%al
118         andb    $PCB_DBREGS,%al
119         jz      1f                              /* no, skip over */
120         movl    %dr7,%eax                       /* yes, do the save */
121         movl    %eax,PCB_DR7(%edx)
122         andl    $0x0000fc00, %eax               /* disable all watchpoints */
123         movl    %eax,%dr7
124         movl    %dr6,%eax
125         movl    %eax,PCB_DR6(%edx)
126         movl    %dr3,%eax
127         movl    %eax,PCB_DR3(%edx)
128         movl    %dr2,%eax
129         movl    %eax,PCB_DR2(%edx)
130         movl    %dr1,%eax
131         movl    %eax,PCB_DR1(%edx)
132         movl    %dr0,%eax
133         movl    %eax,PCB_DR0(%edx)
134 1:
135  
136         /*
137          * Save the FP state if we have used the FP.
138          */
139 #if NNPX > 0
140         movl    P_THREAD(%ecx),%ecx
141         cmpl    %ecx,PCPU(npxthread)
142         jne     1f
143         addl    $PCB_SAVEFPU,%edx               /* h/w bugs make saving complicated */
144         pushl   %edx
145         call    npxsave                 /* do it in a big C function */
146         addl    $4,%esp
147 1:
148         /* %ecx,%edx trashed */
149 #endif  /* NNPX > 0 */
150
151         /*
152          * Switch to the next thread, which was passed as an argument
153          * to cpu_heavy_switch().  Due to the switch-restore function we pushed,
154          * the argument is at 8(%esp).  Set the current thread, load the
155          * stack pointer, and 'ret' into the switch-restore function.
156          */
157         movl    8(%esp),%eax
158         movl    %eax,PCPU(curthread)
159         movl    TD_SP(%eax),%esp
160         ret
161
162 /*
163  *  cpu_exit_switch()
164  *
165  *      The switch function is changed to this when a thread is going away
166  *      for good.  We have to ensure that the MMU state is not cached, and
167  *      we don't bother saving the existing thread state before switching.
168  *
169  *      At this point we are in a critical section and this cpu owns the
170  *      thread's token, which serves as an interlock until the switchout is
171  *      complete.
172  */
173 ENTRY(cpu_exit_switch)
174         /*
175          * Get us out of the vmspace
176          */
177         movl    IdlePTD,%ecx
178         movl    %cr3,%eax
179         cmpl    %ecx,%eax
180         je      1f
181         movl    %ecx,%cr3
182 1:
183         movl    PCPU(curthread),%ecx
184         /*
185          * Switch to the next thread.
186          */
187         cli
188         movl    4(%esp),%eax
189         movl    %eax,PCPU(curthread)
190         movl    TD_SP(%eax),%esp
191
192         /*
193          * We are now the next thread, set the exited flag and wakeup
194          * any waiters.
195          */
196         orl     $TDF_EXITED,TD_FLAGS(%ecx)
197 #if 0                   /* YYY MP lock may not be held by new target */
198         pushl   %eax
199         pushl   %ecx    /* wakeup(oldthread) */
200         call    wakeup
201         addl    $4,%esp
202         popl    %eax    /* note: next thread expects curthread in %eax */
203 #endif
204
205         /*
206          * Restore the next thread's state and resume it.  Note: the
207          * restore function assumes that the next thread's address is
208          * in %eax.
209          */
210         ret
211
212 /*
213  * cpu_heavy_restore()  (current thread in %eax on entry)
214  *
215  *      Restore the thread after an LWKT switch.  This entry is normally
216  *      called via the LWKT switch restore function, which was pulled 
217  *      off the thread stack and jumped to.
218  *
219  *      This entry is only called if the thread was previously saved
220  *      using cpu_heavy_switch() (the heavy weight process thread switcher).
221  *
222  *      YYY theoretically we do not have to restore everything here, a lot
223  *      of this junk can wait until we return to usermode.  But for now
224  *      we restore everything.
225  *
226  *      YYY STI/CLI sequencing.
227  *      YYY the PCB crap is really crap, it makes startup a bitch because
228  *      we can't switch away.
229  *
230  *      YYY note: spl check is done in mi_switch when it splx()'s.
231  */
232
233 ENTRY(cpu_heavy_restore)
234         /* interrupts are disabled */
235         movl    TD_PCB(%eax),%edx
236         movl    TD_PROC(%eax),%ecx
237 #ifdef  DIAGNOSTIC
238         cmpb    $SRUN,P_STAT(%ecx)
239         jne     badsw2
240 #endif
241
242 #if defined(SWTCH_OPTIM_STATS)
243         incl    _swtch_optim_stats
244 #endif
245         /*
246          * Restore the MMU address space
247          */
248         movl    %cr3,%ebx
249         cmpl    PCB_CR3(%edx),%ebx
250         je      4f
251 #if defined(SWTCH_OPTIM_STATS)
252         decl    _swtch_optim_stats
253         incl    _tlb_flush_count
254 #endif
255         movl    PCB_CR3(%edx),%ebx
256         movl    %ebx,%cr3
257 4:
258
259         /*
260          * Deal with the PCB extension, restore the private tss
261          */
262         movl    PCPU(cpuid), %esi
263         cmpl    $0, PCB_EXT(%edx)               /* has pcb extension? */
264         je      1f
265         btsl    %esi, private_tss               /* mark use of private tss */
266         movl    PCB_EXT(%edx), %edi             /* new tss descriptor */
267         jmp     2f
268 1:
269
270         /*
271          * update common_tss.tss_esp0 pointer.  This is the supervisor
272          * stack pointer on entry from user mode.  Since the pcb is
273          * at the top of the supervisor stack esp0 starts just below it.
274          * We leave enough space for vm86 (16 bytes).
275          *
276          * common_tss.tss_esp0 is needed when user mode traps into the
277          * kernel.
278          */
279         leal    -16(%edx),%ebx
280         movl    %ebx, PCPU(common_tss) + TSS_ESP0
281
282         btrl    %esi, private_tss
283         jae     3f
284
285         /*
286          * There is no way to get the address of a segment-accessed variable
287          * so we store a self-referential pointer at the base of the per-cpu
288          * data area and add the appropriate offset.
289          */
290         movl    $gd_common_tssd, %edi
291         addl    %fs:0, %edi
292
293         /*
294          * Move the correct TSS descriptor into the GDT slot, then reload
295          * tr.   YYY not sure what is going on here
296          */
297 2:
298         movl    PCPU(tss_gdt), %ebx             /* entry in GDT */
299         movl    0(%edi), %eax
300         movl    %eax, 0(%ebx)
301         movl    4(%edi), %eax
302         movl    %eax, 4(%ebx)
303         movl    $GPROC0_SEL*8, %esi             /* GSEL(entry, SEL_KPL) */
304         ltr     %si
305
306         /*
307          * Tell the pmap that our cpu is using the VMSPACE now.
308          */
309 3:
310         movl    P_VMSPACE(%ecx), %ebx
311         movl    PCPU(cpuid), %eax
312         btsl    %eax, VM_PMAP+PM_ACTIVE(%ebx)
313
314         /*
315          * Restore general registers.
316          */
317         movl    PCB_EBX(%edx),%ebx
318         movl    PCB_ESP(%edx),%esp
319         movl    PCB_EBP(%edx),%ebp
320         movl    PCB_ESI(%edx),%esi
321         movl    PCB_EDI(%edx),%edi
322         movl    PCB_EIP(%edx),%eax
323         movl    %eax,(%esp)
324
325         /*
326          * Restore the user LDT if we have one
327          */
328 #ifdef  USER_LDT
329         cmpl    $0, PCB_USERLDT(%edx)
330         jnz     1f
331         movl    _default_ldt,%eax
332         cmpl    PCPU(currentldt),%eax
333         je      2f
334         lldt    _default_ldt
335         movl    %eax,PCPU(currentldt)
336         jmp     2f
337 1:      pushl   %edx
338         call    set_user_ldt
339         popl    %edx
340 2:
341 #endif
342         /*
343          * Restore the %gs segment register, which must be done after
344          * loading the user LDT.  Since user processes can modify the
345          * register via procfs, this may result in a fault which is
346          * detected by checking the fault address against cpu_switch_load_gs
347          * in i386/i386/trap.c
348          */
349         .globl  cpu_switch_load_gs
350 cpu_switch_load_gs:
351         movl    PCB_GS(%edx),%gs
352
353         /*
354          * Restore the DEBUG register state if necessary.
355          */
356         movb    PCB_FLAGS(%edx),%al
357         andb    $PCB_DBREGS,%al
358         jz      1f                              /* no, skip over */
359         movl    PCB_DR6(%edx),%eax              /* yes, do the restore */
360         movl    %eax,%dr6
361         movl    PCB_DR3(%edx),%eax
362         movl    %eax,%dr3
363         movl    PCB_DR2(%edx),%eax
364         movl    %eax,%dr2
365         movl    PCB_DR1(%edx),%eax
366         movl    %eax,%dr1
367         movl    PCB_DR0(%edx),%eax
368         movl    %eax,%dr0
369         movl    %dr7,%eax                /* load dr7 so as not to disturb */
370         andl    $0x0000fc00,%eax         /*   reserved bits               */
371         pushl   %ebx
372         movl    PCB_DR7(%edx),%ebx
373         andl    $~0x0000fc00,%ebx
374         orl     %ebx,%eax
375         popl    %ebx
376         movl    %eax,%dr7
377 1:
378
379         sti                     /* XXX */
380         ret
381
382 CROSSJUMPTARGET(sw1a)
383
384 badsw0:
385         pushl   %eax
386         pushl   $sw0_1
387         call    panic
388
389 sw0_1:  .asciz  "cpu_switch: panic: %p"
390
391 #ifdef DIAGNOSTIC
392 badsw1:
393         pushl   $sw0_1
394         call    panic
395
396 sw0_1:  .asciz  "cpu_switch: has wchan"
397
398 badsw2:
399         pushl   $sw0_2
400         call    panic
401
402 sw0_2:  .asciz  "cpu_switch: not SRUN"
403 #endif
404
405 #if defined(SMP) && defined(DIAGNOSTIC)
406 badsw4:
407         pushl   $sw0_4
408         call    panic
409
410 sw0_4:  .asciz  "cpu_switch: do not have lock"
411 #endif /* SMP && DIAGNOSTIC */
412
413 string: .asciz  "SWITCHING\n"
414
415 /*
416  * savectx(pcb)
417  * Update pcb, saving current processor state.
418  */
419 ENTRY(savectx)
420         /* fetch PCB */
421         movl    4(%esp),%ecx
422
423         /* caller's return address - child won't execute this routine */
424         movl    (%esp),%eax
425         movl    %eax,PCB_EIP(%ecx)
426
427         movl    %cr3,%eax
428         movl    %eax,PCB_CR3(%ecx)
429
430         movl    %ebx,PCB_EBX(%ecx)
431         movl    %esp,PCB_ESP(%ecx)
432         movl    %ebp,PCB_EBP(%ecx)
433         movl    %esi,PCB_ESI(%ecx)
434         movl    %edi,PCB_EDI(%ecx)
435         movl    %gs,PCB_GS(%ecx)
436
437 #if NNPX > 0
438         /*
439          * If npxthread == NULL, then the npx h/w state is irrelevant and the
440          * state had better already be in the pcb.  This is true for forks
441          * but not for dumps (the old book-keeping with FP flags in the pcb
442          * always lost for dumps because the dump pcb has 0 flags).
443          *
444          * If npxthread != NULL, then we have to save the npx h/w state to
445          * npxthread's pcb and copy it to the requested pcb, or save to the
446          * requested pcb and reload.  Copying is easier because we would
447          * have to handle h/w bugs for reloading.  We used to lose the
448          * parent's npx state for forks by forgetting to reload.
449          */
450         movl    PCPU(npxthread),%eax
451         testl   %eax,%eax
452         je      1f
453
454         pushl   %ecx
455         movl    TD_PCB(%eax),%eax
456         leal    PCB_SAVEFPU(%eax),%eax
457         pushl   %eax
458         pushl   %eax
459         call    npxsave
460         addl    $4,%esp
461         popl    %eax
462         popl    %ecx
463
464         pushl   $PCB_SAVEFPU_SIZE
465         leal    PCB_SAVEFPU(%ecx),%ecx
466         pushl   %ecx
467         pushl   %eax
468         call    bcopy
469         addl    $12,%esp
470 #endif  /* NNPX > 0 */
471
472 1:
473         ret
474
475 /*
476  * cpu_idle_restore()   (current thread in %eax on entry)
477  *
478  *      Don't bother setting up any regs other then %ebp so backtraces
479  *      don't die.  This restore function is used to bootstrap into the
480  *      cpu_idle() LWKT only, after that cpu_lwkt_*() will be used for
481  *      switching.
482  *
483  *      If we are an AP we have to call ap_init() before jumping to
484  *      cpu_idle().  ap_init() will synchronize with the BP and finish
485  *      setting up various ncpu-dependant globaldata fields.  This may
486  *      happen on UP as well as SMP if we happen to be simulating multiple
487  *      cpus.
488  */
489 ENTRY(cpu_idle_restore)
490         movl    $0,%ebp
491         pushl   $0
492 #ifdef SMP
493         cmpl    $0,PCPU(cpuid)
494         je      1f
495         call    ap_init
496 1:
497 #endif
498         sti
499         jmp     cpu_idle
500
501 /*
502  * cpu_kthread_restore()        (current thread is %eax on entry)
503  *
504  *      Don't bother setting up any regs other then %ebp so backtraces
505  *      don't die.  This restore function is used to bootstrap into an
506  *      LWKT based kernel thread only.  cpu_lwkt_switch() will be used
507  *      after this.
508  *
509  *      Since all of our context is on the stack we are reentrant and
510  *      we can release our critical section and enable interrupts early.
511  */
512 ENTRY(cpu_kthread_restore)
513         movl    TD_PCB(%eax),%ebx
514         movl    $0,%ebp
515         subl    $TDPRI_CRIT,TD_PRI(%eax)
516         sti
517         popl    %edx            /* kthread exit function */
518         pushl   PCB_EBX(%ebx)   /* argument to ESI function */
519         pushl   %edx            /* set exit func as return address */
520         movl    PCB_ESI(%ebx),%eax
521         jmp     *%eax
522
523 /*
524  * cpu_lwkt_switch()
525  *
526  *      Standard LWKT switching function.  Only non-scratch registers are
527  *      saved and we don't bother with the MMU state or anything else.
528  *
529  *      This function is always called while in a critical section.
530  *
531  *      YYY BGL, SPL
532  */
533 ENTRY(cpu_lwkt_switch)
534         movl    4(%esp),%eax
535         pushl   %ebp
536         pushl   %ebx
537         pushl   %esi
538         pushl   %edi
539         pushfl
540         movl    PCPU(curthread),%ecx
541         pushl   $cpu_lwkt_restore
542         cli
543         movl    %esp,TD_SP(%ecx)
544         movl    %eax,PCPU(curthread)
545         movl    TD_SP(%eax),%esp
546         ret
547
548 /*
549  * cpu_lwkt_restore()   (current thread in %eax on entry)
550  *
551  *      Standard LWKT restore function.  This function is always called
552  *      while in a critical section.
553  *      
554  *      Warning: due to preemption the restore function can be used to 
555  *      'return' to the original thread.  Interrupt disablement must be
556  *      protected through the switch so we cannot run splz here.
557  */
558 ENTRY(cpu_lwkt_restore)
559         popfl
560         popl    %edi
561         popl    %esi
562         popl    %ebx
563         popl    %ebp
564         ret
565