proc->thread stage 4: rework the VFS and DEVICE subsystems to take thread
[dragonfly.git] / sys / i386 / i386 / machdep.c
index 9be7e9f..c96a536 100644 (file)
@@ -36,6 +36,7 @@
  *
  *     from: @(#)machdep.c     7.4 (Berkeley) 6/3/91
  * $FreeBSD: src/sys/i386/i386/machdep.c,v 1.385.2.30 2003/05/31 08:48:05 alc Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/machdep.c,v 1.12 2003/06/25 03:55:53 dillon Exp $
  */
 
 #include "apm.h"
 #include <machine/pcb_ext.h>           /* pcb.h included via sys/user.h */
 #ifdef SMP
 #include <machine/smp.h>
-#include <machine/globaldata.h>
 #endif
 #ifdef PERFMON
 #include <machine/perfmon.h>
@@ -568,7 +568,7 @@ osendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
         */
        if (regs->tf_eflags & PSL_VM) {
                struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
-               struct vm86_kernel *vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86;
+               struct vm86_kernel *vm86 = &p->p_thread->td_pcb->pcb_ext->ext_vm86;
 
                sf.sf_siginfo.si_sc.sc_gs = tf->tf_vm86_gs;
                sf.sf_siginfo.si_sc.sc_fs = tf->tf_vm86_fs;
@@ -675,7 +675,7 @@ sendsig(catcher, sig, mask, code)
         */
        if (regs->tf_eflags & PSL_VM) {
                struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
-               struct vm86_kernel *vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86;
+               struct vm86_kernel *vm86 = &p->p_thread->td_pcb->pcb_ext->ext_vm86;
 
                sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs;
                sf.sf_uc.uc_mcontext.mc_fs = tf->tf_vm86_fs;
@@ -720,6 +720,8 @@ sendsig(catcher, sig, mask, code)
 }
 
 /*
+ * osigreturn_args(struct osigcontext *sigcntxp)
+ *
  * System call to cleanup state after a signal
  * has been taken.  Reset signal mask and
  * stack state from context left by sendsig (above).
@@ -732,14 +734,11 @@ sendsig(catcher, sig, mask, code)
 #define        CS_SECURE(cs)           (ISPL(cs) == SEL_UPL)
 
 int
-osigreturn(p, uap)
-       struct proc *p;
-       struct osigreturn_args /* {
-               struct osigcontext *sigcntxp;
-       } */ *uap;
+osigreturn(struct osigreturn_args *uap)
 {
-       register struct osigcontext *scp;
-       register struct trapframe *regs = p->p_md.md_regs;
+       struct proc *p = curproc;
+       struct osigcontext *scp;
+       struct trapframe *regs = p->p_md.md_regs;
        int eflags;
 
        scp = uap->sigcntxp;
@@ -756,9 +755,9 @@ osigreturn(p, uap)
                 * if pcb_ext == 0 or vm86_inited == 0, the user hasn't
                 * set up the vm86 area, and we can't enter vm86 mode.
                 */
-               if (p->p_addr->u_pcb.pcb_ext == 0)
+               if (p->p_thread->td_pcb->pcb_ext == 0)
                        return (EINVAL);
-               vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86;
+               vm86 = &p->p_thread->td_pcb->pcb_ext->ext_vm86;
                if (vm86->vm86_inited == 0)
                        return (EINVAL);
 
@@ -837,13 +836,13 @@ osigreturn(p, uap)
        return(EJUSTRETURN);
 }
 
+/*
+ * sigreturn(ucontext_t *sigcntxp)
+ */
 int
-sigreturn(p, uap)
-       struct proc *p;
-       struct sigreturn_args /* {
-               ucontext_t *sigcntxp;
-       } */ *uap;
+sigreturn(struct sigreturn_args *uap)
 {
+       struct proc *p = curproc;
        struct trapframe *regs;
        ucontext_t *ucp;
        int cs, eflags;
@@ -853,7 +852,7 @@ sigreturn(p, uap)
        if (!useracc((caddr_t)ucp, sizeof(struct osigcontext), VM_PROT_READ))
                return (EFAULT);
        if (((struct osigcontext *)ucp)->sc_trapno == 0x01d516)
-               return (osigreturn(p, (struct osigreturn_args *)uap));
+               return (osigreturn((struct osigreturn_args *)uap));
 
        /*
         * Since ucp is not an osigcontext but a ucontext_t, we have to
@@ -876,9 +875,9 @@ sigreturn(p, uap)
                 * if pcb_ext == 0 or vm86_inited == 0, the user hasn't
                 * set up the vm86 area, and we can't enter vm86 mode.
                 */
-               if (p->p_addr->u_pcb.pcb_ext == 0)
+               if (p->p_thread->td_pcb->pcb_ext == 0)
                        return (EINVAL);
-               vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86;
+               vm86 = &p->p_thread->td_pcb->pcb_ext->ext_vm86;
                if (vm86->vm86_inited == 0)
                        return (EINVAL);
 
@@ -967,13 +966,12 @@ cpu_halt(void)
 }
 
 /*
- * Hook to idle the CPU when possible.   This is disabled by default for
- * the SMP case as there is a small window of opportunity whereby a ready
- * process is delayed to the next clock tick.  It should be safe to enable
- * for SMP if power is a concern.
+ * cpu_idle() represents the idle LWKT.  You cannot return from this function
+ * (unless you want to blow things up!).  Instead we look for runnable threads
+ * and loop or halt as appropriate.  Giant is not held on entry to the thread.
  *
- * On -stable, cpu_idle() is called with interrupts disabled and must
- * return with them enabled.
+ * Note on cpu_idle_hlt:  On an SMP system this may cause the system to 
+ * halt until the next clock tick, even if a thread is ready YYY
  */
 #ifdef SMP
 static int     cpu_idle_hlt = 0;
@@ -986,14 +984,19 @@ SYSCTL_INT(_machdep, OID_AUTO, cpu_idle_hlt, CTLFLAG_RW,
 void
 cpu_idle(void)
 {
-       if (cpu_idle_hlt) {
-               /*
-                * We must guarentee that hlt is exactly the instruction
-                * following the sti.
-                */
-               __asm __volatile("sti; hlt");
-       } else {
-               __asm __volatile("sti");
+       spl0();
+       for (;;) {
+               lwkt_switch();
+               if (cpu_idle_hlt) {
+                       /*
+                        * We must guarentee that hlt is exactly the instruction
+                        * following the sti.
+                        */
+                       __asm __volatile("sti; hlt");
+               } else {
+                       __asm __volatile("sti");
+               }
+               /* YYY BGL */
        }
 }
 
@@ -1008,7 +1011,7 @@ setregs(p, entry, stack, ps_strings)
        u_long ps_strings;
 {
        struct trapframe *regs = p->p_md.md_regs;
-       struct pcb *pcb = &p->p_addr->u_pcb;
+       struct pcb *pcb = p->p_thread->td_pcb;
 
        /* Reset pc->pcb_gs and %gs before possibly invalidating it. */
        pcb->pcb_gs = _udatasel;
@@ -1043,7 +1046,7 @@ setregs(p, entry, stack, ps_strings)
                 pcb->pcb_dr3 = 0;
                 pcb->pcb_dr6 = 0;
                 pcb->pcb_dr7 = 0;
-                if (pcb == curpcb) {
+                if (pcb == curthread->td_pcb) {
                        /*
                         * Clear the debug registers on the running
                         * CPU, otherwise they will end up affecting
@@ -1061,7 +1064,7 @@ setregs(p, entry, stack, ps_strings)
         * traps to the emulator (if it is done at all) mainly because
         * emulators don't provide an entry point for initialization.
         */
-       p->p_addr->u_pcb.pcb_flags &= ~FP_SOFTFP;
+       p->p_thread->td_pcb->pcb_flags &= ~FP_SOFTFP;
 
        /*
         * Arrange to trap the next npx or `fwait' instruction (see npx.c
@@ -1856,13 +1859,21 @@ init386(first)
        /* table descriptors - used to load tables by microp */
        struct region_descriptor r_gdt, r_idt;
 #endif
+       struct globaldata *gd;
 
        /*
         * Prevent lowering of the ipl if we call tsleep() early.
         */
-       safepri = cpl;
+       gd = &CPU_prvspace[0].globaldata;
 
-       proc0.p_addr = proc0paddr;
+       lwkt_init_thread(&thread0, proc0paddr);
+       gd->gd_curthread = &thread0;
+       safepri = thread0.td_cpl = SWI_MASK | HWI_MASK;
+       thread0.td_switch = cpu_heavy_switch;   /* YYY eventually LWKT */
+       proc0.p_addr = (void *)thread0.td_kstack;
+       proc0.p_thread = &thread0;
+       thread0.td_proc = &proc0;
+       thread0.td_flags = TDF_RUNNING;
 
        atdevbase = ISA_HOLE_START + KERNBASE;
 
@@ -1893,14 +1904,22 @@ init386(first)
 #ifdef SMP
        gdt_segs[GPRIV_SEL].ssd_limit =
                atop(sizeof(struct privatespace) - 1);
-       gdt_segs[GPRIV_SEL].ssd_base = (int) &SMP_prvspace[0];
+       gdt_segs[GPRIV_SEL].ssd_base = (int) &CPU_prvspace[0];
        gdt_segs[GPROC0_SEL].ssd_base =
-               (int) &SMP_prvspace[0].globaldata.gd_common_tss;
-       SMP_prvspace[0].globaldata.gd_prvspace = &SMP_prvspace[0];
+               (int) &CPU_prvspace[0].globaldata.gd_common_tss;
 #else
        gdt_segs[GPRIV_SEL].ssd_limit = atop(0 - 1);
        gdt_segs[GPROC0_SEL].ssd_base = (int) &common_tss;
 #endif
+       gd->gd_prvspace = &CPU_prvspace[0];
+       /*
+        * Note: on both UP and SMP curthread must be set non-NULL
+        * early in the boot sequence because the system assumes
+        * that 'curthread' is never NULL.
+        */
+       /* YYY use prvspace for UP too and set here rather then later */
+       mi_gdinit(gd, 0);
+       cpu_gdinit(gd, 0);
 
        for (x = 0; x < NGDT; x++) {
 #ifdef BDE_DEBUGGER
@@ -1986,8 +2005,11 @@ init386(first)
        setidt(13, &IDTVEC(prot),  SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
        initializecpu();        /* Initialize CPU registers */
 
-       /* make an initial tss so cpu can get interrupt stack on syscall! */
-       common_tss.tss_esp0 = (int) proc0.p_addr + UPAGES*PAGE_SIZE - 16;
+       /*
+        * make an initial tss so cpu can get interrupt stack on syscall!
+        * The 16 bytes is to save room for a VM86 context.
+        */
+       common_tss.tss_esp0 = (int) thread0.td_pcb - 16;
        common_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ;
        gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
        private_tss = 0;
@@ -2043,15 +2065,35 @@ init386(first)
        _udatasel = LSEL(LUDATA_SEL, SEL_UPL);
 
        /* setup proc 0's pcb */
-       proc0.p_addr->u_pcb.pcb_flags = 0;
-       proc0.p_addr->u_pcb.pcb_cr3 = (int)IdlePTD;
+       thread0.td_pcb->pcb_flags = 0;
+       thread0.td_pcb->pcb_cr3 = (int)IdlePTD; /* should already be setup */
 #ifdef SMP
-       proc0.p_addr->u_pcb.pcb_mpnest = 1;
+       thread0.td_pcb->pcb_mpnest = 1;
 #endif
-       proc0.p_addr->u_pcb.pcb_ext = 0;
+       thread0.td_pcb->pcb_ext = 0;
        proc0.p_md.md_regs = &proc0_tf;
 }
 
+/*
+ * Initialize machine-dependant portions of the global data structure
+ *
+ *     YYY do we need to reserve pcb space for idlethread?
+ */
+void
+cpu_gdinit(struct globaldata *gd, int cpu)
+{
+       char *sp;
+
+       TAILQ_INIT(&gd->gd_tdfreeq);    /* for pmap_{new,dispose}_thread() */
+       if (cpu)
+           gd->gd_curthread = &gd->gd_idlethread;
+       sp = gd->gd_prvspace->idlestack;
+       lwkt_init_thread(&gd->gd_idlethread, sp);
+       gd->gd_idlethread.td_switch = cpu_lwkt_switch;
+       gd->gd_idlethread.td_sp -= sizeof(void *);
+       *(void **)gd->gd_idlethread.td_sp = cpu_idle_restore;
+}
+
 #if defined(I586_CPU) && !defined(NO_F00F_HACK)
 static void f00f_hack(void *unused);
 SYSINIT(f00f_hack, SI_SUB_INTRINSIC, SI_ORDER_FIRST, f00f_hack, NULL);
@@ -2152,7 +2194,12 @@ int ptrace_write_u(p, off, data)
                *(int*)((char *)p->p_addr + off) = data;
                return (0);
        }
-       min = offsetof(struct user, u_pcb) + offsetof(struct pcb, pcb_save);
+
+       /*
+        * The PCB is at the end of the user area YYY
+        */
+       min = (char *)p->p_thread->td_pcb - (char *)p->p_addr;
+       min += offsetof(struct pcb, pcb_save);
        if (off >= min && off <= min + sizeof(union savefpu) - sizeof(int)) {
                *(int*)((char *)p->p_addr + off) = data;
                return (0);
@@ -2184,7 +2231,7 @@ fill_regs(p, regs)
        regs->r_eflags = tp->tf_eflags;
        regs->r_esp = tp->tf_esp;
        regs->r_ss = tp->tf_ss;
-       pcb = &p->p_addr->u_pcb;
+       pcb = p->p_thread->td_pcb;
        regs->r_gs = pcb->pcb_gs;
        return (0);
 }
@@ -2216,7 +2263,7 @@ set_regs(p, regs)
        tp->tf_eflags = regs->r_eflags;
        tp->tf_esp = regs->r_esp;
        tp->tf_ss = regs->r_ss;
-       pcb = &p->p_addr->u_pcb;
+       pcb = p->p_thread->td_pcb;
        pcb->pcb_gs = regs->r_gs;
        return (0);
 }
@@ -2282,12 +2329,12 @@ fill_fpregs(p, fpregs)
 {
 #ifdef CPU_ENABLE_SSE
        if (cpu_fxsr) {
-               fill_fpregs_xmm(&p->p_addr->u_pcb.pcb_save.sv_xmm,
+               fill_fpregs_xmm(&p->p_thread->td_pcb->pcb_save.sv_xmm,
                                                (struct save87 *)fpregs);
                return (0);
        }
 #endif /* CPU_ENABLE_SSE */
-       bcopy(&p->p_addr->u_pcb.pcb_save.sv_87, fpregs, sizeof *fpregs);
+       bcopy(&p->p_thread->td_pcb->pcb_save.sv_87, fpregs, sizeof *fpregs);
        return (0);
 }
 
@@ -2299,11 +2346,11 @@ set_fpregs(p, fpregs)
 #ifdef CPU_ENABLE_SSE
        if (cpu_fxsr) {
                set_fpregs_xmm((struct save87 *)fpregs,
-                                          &p->p_addr->u_pcb.pcb_save.sv_xmm);
+                                      &p->p_thread->td_pcb->pcb_save.sv_xmm);
                return (0);
        }
 #endif /* CPU_ENABLE_SSE */
-       bcopy(fpregs, &p->p_addr->u_pcb.pcb_save.sv_87, sizeof *fpregs);
+       bcopy(fpregs, &p->p_thread->td_pcb->pcb_save.sv_87, sizeof *fpregs);
        return (0);
 }
 
@@ -2325,7 +2372,7 @@ fill_dbregs(p, dbregs)
                 dbregs->dr7 = rdr7();
         }
         else {
-                pcb = &p->p_addr->u_pcb;
+                pcb = p->p_thread->td_pcb;
                 dbregs->dr0 = pcb->pcb_dr0;
                 dbregs->dr1 = pcb->pcb_dr1;
                 dbregs->dr2 = pcb->pcb_dr2;
@@ -2369,7 +2416,7 @@ set_dbregs(p, dbregs)
                        if ((dbregs->dr7 & mask1) == mask2)
                                return (EINVAL);
                
-               pcb = &p->p_addr->u_pcb;
+               pcb = p->p_thread->td_pcb;
                
                /*
                 * Don't let a process set a breakpoint that is not within the
@@ -2386,7 +2433,7 @@ set_dbregs(p, dbregs)
                 * from within kernel mode?
                 */
                
-               if (suser(p) != 0) {
+               if (suser_cred(p->p_ucred, 0) != 0) {
                        if (dbregs->dr7 & 0x3) {
                                /* dr0 is enabled */
                                if (dbregs->dr0 >= VM_MAXUSER_ADDRESS)