Hi, The attached patch is to sys/i386/* code. It's basically 50%, albeit the easy 50%, of the Junior Kernel Hacker task from jhb last month. I finished it and tested awhile ago (~1 month) but my current box died. My current box is still dead, so I've yet to test it any further, but Peter Wemm and jhb both looked at it and said it looked "ok" and to get people to test it.
The attached patch is for current from 9/19/01 -- Yes, Im sorry, this sucks. I have a 4.3 release CD here so Im going to have to use that to rebuild a box back to current (FTP installs with 4.4 floppies have really sucked). If you're willing to test and don't mind this patch, thanks. If you are willing to test and want a newer patch, let me know and I'll get you one tonight or tomorrow. Btw, the patch is also located at http://www.watson.org/~arr/fbsd-patches/ldt-2-mdproc.diff Cheers, Andrew *-------------................................................. | Andrew R. Reiter | [EMAIL PROTECTED] | "It requires a very unusual mind | to undertake the analysis of the obvious" -- A.N. Whitehead
--- include/pcb.h.orig Wed Sep 19 02:07:48 2001 +++ include/pcb.h Wed Sep 19 02:08:37 2001 @@ -61,7 +61,6 @@ int pcb_dr6; int pcb_dr7; - struct pcb_ldt *pcb_ldt; /* per process (user) LDT */ union savefpu pcb_save; u_char pcb_flags; #define FP_SOFTFP 0x01 /* process using software fltng pnt emulator */ --- include/pcb_ext.h.orig Wed Sep 19 02:07:54 2001 +++ include/pcb_ext.h Wed Sep 19 02:10:37 2001 @@ -43,20 +43,9 @@ struct vm86_kernel ext_vm86; /* vm86 area */ }; -struct pcb_ldt { - caddr_t ldt_base; - int ldt_len; - int ldt_refcnt; - u_long ldt_active; - struct segment_descriptor ldt_sd; -}; - #ifdef _KERNEL int i386_extend_pcb __P((struct thread *)); -void set_user_ldt __P((struct pcb *)); -struct pcb_ldt *user_ldt_alloc __P((struct pcb *, int)); -void user_ldt_free __P((struct pcb *)); #endif --- include/proc.h.orig Wed Sep 19 02:07:59 2001 +++ include/proc.h Wed Sep 19 03:28:55 2001 @@ -38,6 +38,15 @@ #define _MACHINE_PROC_H_ #include <machine/globals.h> +#include <machine/segments.h> + +struct proc_ldt { + caddr_t ldt_base; + int ldt_len; + int ldt_refcnt; + u_long ldt_active; + struct segment_descriptor ldt_sd; +}; /* * Machine-dependent part of the proc structure for i386. @@ -46,6 +55,15 @@ }; struct mdproc { + struct proc_ldt *md_ldt; /* per-process ldt */ }; + +#ifdef _KERNEL + +void set_user_ldt __P((struct mdproc *)); +struct proc_ldt *user_ldt_alloc __P((struct mdproc *, int)); +void user_ldt_free __P((struct thread *)); + +#endif /* _KERNEL */ #endif /* !_MACHINE_PROC_H_ */ --- i386/genassym.c.orig Wed Sep 19 02:16:34 2001 +++ i386/genassym.c Wed Sep 19 13:03:45 2001 @@ -63,6 +63,7 @@ #include <vm/pmap.h> #include <vm/vm_map.h> #include <sys/user.h> +#include <sys/proc.h> #include <net/if.h> #include <netinet/in.h> #include <nfs/nfsproto.h> @@ -76,6 +77,7 @@ #include <machine/sigframe.h> #include <machine/globaldata.h> #include <machine/vm86.h> +#include <machine/proc.h> ASSYM(P_VMSPACE, offsetof(struct proc, p_vmspace)); ASSYM(VM_PMAP, offsetof(struct vmspace, vm_pmap)); @@ -92,6 +94,9 @@ ASSYM(TD_PROC, offsetof(struct thread, td_proc)); ASSYM(TD_INTR_NESTING_LEVEL, offsetof(struct thread, td_intr_nesting_level)); +ASSYM(P_MD, offsetof(struct proc, p_md)); +ASSYM(MD_LDT, offsetof(struct mdproc, md_ldt)); + ASSYM(KE_FLAGS, offsetof(struct kse, ke_flags)); ASSYM(KEF_ASTPENDING, KEF_ASTPENDING); @@ -126,7 +131,6 @@ ASSYM(PCB_EIP, offsetof(struct pcb, pcb_eip)); ASSYM(TSS_ESP0, offsetof(struct i386tss, tss_esp0)); -ASSYM(PCB_USERLDT, offsetof(struct pcb, pcb_ldt)); ASSYM(PCB_GS, offsetof(struct pcb, pcb_gs)); ASSYM(PCB_DR0, offsetof(struct pcb, pcb_dr0)); ASSYM(PCB_DR1, offsetof(struct pcb, pcb_dr1)); --- i386/machdep.c.orig Wed Sep 19 02:16:39 2001 +++ i386/machdep.c Wed Sep 19 04:57:31 2001 @@ -103,6 +103,7 @@ #include <machine/md_var.h> #include <machine/pc/bios.h> #include <machine/pcb_ext.h> /* pcb.h included via sys/user.h */ +#include <machine/proc.h> #include <machine/globals.h> #ifdef PERFMON #include <machine/perfmon.h> @@ -880,8 +881,8 @@ struct trapframe *regs = td->td_frame; struct pcb *pcb = td->td_pcb; - if (pcb->pcb_ldt) - user_ldt_free(pcb); + if (td->td_proc->p_md.md_ldt) + user_ldt_free(td); bzero((char *)regs, sizeof(struct trapframe)); regs->tf_eip = entry; --- i386/swtch.s.orig Wed Sep 19 02:16:14 2001 +++ i386/swtch.s Thu Sep 20 03:51:55 2001 @@ -246,7 +246,8 @@ /* XXX FIXME: we should be restoring the local APIC TPR */ #endif /* SMP */ - cmpl $0, PCB_USERLDT(%edx) /* if there is one */ + movl TD_PROC(%ecx), %eax /* load struct proc from CURTHREAD */ + cmpl $0, P_MD+MD_LDT(%eax) /* see if md_ldt == 0 */ jnz 1f /* then use it */ movl _default_ldt,%eax /* We will use the default */ cmpl PCPU(CURRENTLDT),%eax /* check to see if already loaded */ @@ -255,9 +256,11 @@ movl %eax,PCPU(CURRENTLDT) /* store what we have */ jmp 2f -1: pushl %edx /* call a non-trusting routine */ - call set_user_ldt /* to check and load the ldt */ - popl %edx +1: pushl %edx /* save edx */ + pushl P_MD+MD_LDT(%eax) /* passing p_md -> set_user_ldt */ + call set_user_ldt /* check and load the ldt */ + popl %eax /* get p_md off stack */ + popl %edx /* restore edx */ 2: /* This must be done after loading the user LDT. */ --- i386/sys_machdep.c.orig Wed Sep 19 02:16:22 2001 +++ i386/sys_machdep.c Wed Sep 19 04:34:30 2001 @@ -54,6 +54,7 @@ #include <machine/cpu.h> #include <machine/pcb_ext.h> /* pcb.h included by sys/user.h */ +#include <machine/proc.h> #include <machine/sysarch.h> #include <vm/vm_kern.h> /* for kernel_map */ @@ -70,7 +71,7 @@ static int i386_get_ioperm __P((struct thread *, char *)); static int i386_set_ioperm __P((struct thread *, char *)); #ifdef SMP -static void set_user_ldt_rv __P((struct pcb *)); +static void set_user_ldt_rv __P((struct thread *)); #endif #ifndef _SYS_SYSPROTO_H_ @@ -257,15 +258,15 @@ * curproc but before sched_lock's owner is updated in mi_switch(). */ void -set_user_ldt(struct pcb *pcb) +set_user_ldt(struct mdproc *mdp) { - struct pcb_ldt *pcb_ldt; + struct proc_ldt *pldt; - pcb_ldt = pcb->pcb_ldt; + pldt = mdp->md_ldt; #ifdef SMP - gdt[PCPU_GET(cpuid) * NGDT + GUSERLDT_SEL].sd = pcb_ldt->ldt_sd; + gdt[PCPU_GET(cpuid) * NGDT + GUSERLDT_SEL].sd = pldt->ldt_sd; #else - gdt[GUSERLDT_SEL].sd = pcb_ldt->ldt_sd; + gdt[GUSERLDT_SEL].sd = pldt->ldt_sd; #endif lldt(GSEL(GUSERLDT_SEL, SEL_KPL)); PCPU_SET(currentldt, GSEL(GUSERLDT_SEL, SEL_KPL)); @@ -273,14 +274,14 @@ #ifdef SMP static void -set_user_ldt_rv(struct pcb *pcb) +set_user_ldt_rv(struct thread *td) { - if (pcb != PCPU_GET(curpcb)) + if (td != PCPU_GET(curthread)) return; mtx_lock_spin(&sched_lock); - set_user_ldt(pcb); + set_user_ldt(&td->td_proc->p_md); mtx_unlock_spin(&sched_lock); } #endif @@ -289,15 +290,15 @@ * Must be called with either sched_lock free or held but not recursed. * If it does not return NULL, it will return with it owned. */ -struct pcb_ldt * -user_ldt_alloc(struct pcb *pcb, int len) +struct proc_ldt * +user_ldt_alloc(struct mdproc *mdp, int len) { - struct pcb_ldt *pcb_ldt, *new_ldt; + struct proc_ldt *pldt, *new_ldt; if (mtx_owned(&sched_lock)) mtx_unlock_spin(&sched_lock); mtx_assert(&sched_lock, MA_NOTOWNED); - MALLOC(new_ldt, struct pcb_ldt *, sizeof(struct pcb_ldt), + MALLOC(new_ldt, struct proc_ldt *, sizeof(struct proc_ldt), M_SUBPROC, M_WAITOK); new_ldt->ldt_len = len = NEW_MAX_LD(len); @@ -315,11 +316,11 @@ gdt_segs[GUSERLDT_SEL].ssd_limit = len * sizeof(union descriptor) - 1; ssdtosd(&gdt_segs[GUSERLDT_SEL], &new_ldt->ldt_sd); - if ((pcb_ldt = pcb->pcb_ldt)) { - if (len > pcb_ldt->ldt_len) - len = pcb_ldt->ldt_len; - bcopy(pcb_ldt->ldt_base, new_ldt->ldt_base, - len * sizeof(union descriptor)); + if ((pldt = mdp->md_ldt)) { + if (len > pldt->ldt_len) + len = pldt->ldt_len; + bcopy(pldt->ldt_base, new_ldt->ldt_base, + len * sizeof(union descriptor)); } else { bcopy(ldt, new_ldt->ldt_base, sizeof(ldt)); } @@ -328,30 +329,31 @@ /* * Must be called either with sched_lock free or held but not recursed. - * If pcb->pcb_ldt is not NULL, it will return with sched_lock released. + * If md_ldt is not NULL, it will return with sched_lock released. */ void -user_ldt_free(struct pcb *pcb) +user_ldt_free(struct thread *td) { - struct pcb_ldt *pcb_ldt = pcb->pcb_ldt; + struct mdproc *mdp = &td->td_proc->p_md; + struct proc_ldt *pldt = mdp->md_ldt; - if (pcb_ldt == NULL) + if (pldt == NULL) return; if (!mtx_owned(&sched_lock)) mtx_lock_spin(&sched_lock); mtx_assert(&sched_lock, MA_OWNED | MA_NOTRECURSED); - if (pcb == PCPU_GET(curpcb)) { + if (td == PCPU_GET(curthread)) { lldt(_default_ldt); PCPU_SET(currentldt, _default_ldt); } - pcb->pcb_ldt = NULL; - if (--pcb_ldt->ldt_refcnt == 0) { + mdp->md_ldt = NULL; + if (--pldt->ldt_refcnt == 0) { mtx_unlock_spin(&sched_lock); - kmem_free(kernel_map, (vm_offset_t)pcb_ldt->ldt_base, - pcb_ldt->ldt_len * sizeof(union descriptor)); - FREE(pcb_ldt, M_SUBPROC); + kmem_free(kernel_map, (vm_offset_t)pldt->ldt_base, + pldt->ldt_len * sizeof(union descriptor)); + FREE(pldt, M_SUBPROC); } else mtx_unlock_spin(&sched_lock); } @@ -362,8 +364,7 @@ char *args; { int error = 0; - struct pcb *pcb = td->td_pcb; - struct pcb_ldt *pcb_ldt = pcb->pcb_ldt; + struct proc_ldt *pldt = td->td_proc->p_md.md_ldt; int nldt, num; union descriptor *lp; struct i386_ldt_args ua, *uap = &ua; @@ -380,10 +381,10 @@ if ((uap->start < 0) || (uap->num <= 0)) return(EINVAL); - if (pcb_ldt) { - nldt = pcb_ldt->ldt_len; + if (pldt) { + nldt = pldt->ldt_len; num = min(uap->num, nldt); - lp = &((union descriptor *)(pcb_ldt->ldt_base))[uap->start]; + lp = &((union descriptor *)(pldt->ldt_base))[uap->start]; } else { nldt = sizeof(ldt)/sizeof(ldt[0]); num = min(uap->num, nldt); @@ -406,8 +407,9 @@ { int error = 0, i, n; int largest_ld; + struct mdproc *mdp = &td->td_proc->p_md; struct pcb *pcb = td->td_pcb; - struct pcb_ldt *pcb_ldt = pcb->pcb_ldt; + struct proc_ldt *pldt = mdp->md_ldt; struct i386_ldt_args ua, *uap = &ua; caddr_t old_ldt_base; int old_ldt_len; @@ -432,16 +434,16 @@ return(EINVAL); /* allocate user ldt */ - if (!pcb_ldt || largest_ld >= pcb_ldt->ldt_len) { - struct pcb_ldt *new_ldt = user_ldt_alloc(pcb, largest_ld); + if (!pldt || largest_ld >= pldt->ldt_len) { + struct proc_ldt *new_ldt = user_ldt_alloc(mdp, largest_ld); if (new_ldt == NULL) return ENOMEM; - if (pcb_ldt) { - old_ldt_base = pcb_ldt->ldt_base; - old_ldt_len = pcb_ldt->ldt_len; - pcb_ldt->ldt_sd = new_ldt->ldt_sd; - pcb_ldt->ldt_base = new_ldt->ldt_base; - pcb_ldt->ldt_len = new_ldt->ldt_len; + if (pldt) { + old_ldt_base = pldt->ldt_base; + old_ldt_len = pldt->ldt_len; + pldt->ldt_sd = new_ldt->ldt_sd; + pldt->ldt_base = new_ldt->ldt_base; + pldt->ldt_len = new_ldt->ldt_len; mtx_unlock_spin(&sched_lock); kmem_free(kernel_map, (vm_offset_t)old_ldt_base, old_ldt_len * sizeof(union descriptor)); @@ -450,16 +452,17 @@ mtx_lock_spin(&sched_lock); #endif } else { - pcb->pcb_ldt = pcb_ldt = new_ldt; + mdp->md_ldt = pldt = new_ldt; #ifdef SMP mtx_unlock_spin(&sched_lock); #endif } #ifdef SMP /* signal other cpus to reload ldt */ - smp_rendezvous(NULL, (void (*)(void *))set_user_ldt_rv, NULL, pcb); + smp_rendezvous(NULL, (void (*)(void *))set_user_ldt_rv, + NULL, td); #else - set_user_ldt(pcb); + set_user_ldt(mdp); mtx_unlock_spin(&sched_lock); #endif } @@ -533,7 +536,7 @@ /* Fill in range */ savecrit = critical_enter(); error = copyin(uap->descs, - &((union descriptor *)(pcb_ldt->ldt_base))[uap->start], + &((union descriptor *)(pldt->ldt_base))[uap->start], uap->num * sizeof(union descriptor)); if (!error) td->td_retval[0] = uap->start; --- i386/vm_machdep.c.orig Wed Sep 19 02:16:28 2001 +++ i386/vm_machdep.c Wed Sep 19 03:39:14 2001 @@ -125,6 +125,7 @@ register struct proc *p1; struct thread *td2; struct pcb *pcb2; + struct mdproc *mdp2; #ifdef DEV_NPX int savecrit; #endif @@ -134,15 +135,15 @@ if ((flags & RFPROC) == 0) { if ((flags & RFMEM) == 0) { /* unshare user LDT */ - struct pcb *pcb1 = td1->td_pcb; - struct pcb_ldt *pcb_ldt = pcb1->pcb_ldt; - if (pcb_ldt && pcb_ldt->ldt_refcnt > 1) { - pcb_ldt = user_ldt_alloc(pcb1,pcb_ldt->ldt_len); - if (pcb_ldt == NULL) + struct mdproc *mdp1 = &td1->td_proc->p_md; + struct proc_ldt *pldt = mdp1->md_ldt; + if (pldt && pldt->ldt_refcnt > 1) { + pldt = user_ldt_alloc(mdp1, pldt->ldt_len); + if (pldt == NULL) panic("could not copy LDT"); - pcb1->pcb_ldt = pcb_ldt; - set_user_ldt(pcb1); - user_ldt_free(pcb1); + mdp1->md_ldt = pldt; + set_user_ldt(mdp1); + user_ldt_free(td1); } } return; @@ -162,9 +163,13 @@ pcb2 = (struct pcb *)(td2->td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1; td2->td_pcb = pcb2; - /* Copy p1's pcb. */ + /* Copy p1's pcb */ bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); + /* Point mdproc and then copy over td1's contents */ + mdp2 = &td2->td_proc->p_md; + bcopy(&td1->td_proc->p_md, mdp2, sizeof(*mdp2)); + /* * Create a new fresh stack for the new process. * Copy the trap frame for the return to user mode as if from a @@ -190,7 +195,6 @@ pcb2->pcb_eip = (int)fork_trampoline; /*- * pcb2->pcb_dr*: cloned above. - * pcb2->pcb_ldt: duplicated below, if necessary. * pcb2->pcb_savefpu: cloned above. * pcb2->pcb_flags: cloned above. * pcb2->pcb_onfault: cloned above (always NULL here?). @@ -205,13 +209,13 @@ /* Copy the LDT, if necessary. */ mtx_lock_spin(&sched_lock); - if (pcb2->pcb_ldt != 0) { + if (mdp2->md_ldt != 0) { if (flags & RFMEM) { - pcb2->pcb_ldt->ldt_refcnt++; + mdp2->md_ldt->ldt_refcnt++; } else { - pcb2->pcb_ldt = user_ldt_alloc(pcb2, - pcb2->pcb_ldt->ldt_len); - if (pcb2->pcb_ldt == NULL) + mdp2->md_ldt = user_ldt_alloc(mdp2, + mdp2->md_ldt->ldt_len); + if (mdp2->md_ldt == NULL) panic("could not copy LDT"); } } @@ -253,7 +257,7 @@ register struct thread *td; { struct pcb *pcb = td->td_pcb; - + struct mdproc *mdp = &td->td_proc->p_md; #ifdef DEV_NPX npxexit(td); #endif @@ -266,8 +270,8 @@ ctob(IOPAGES + 1)); pcb->pcb_ext = 0; } - if (pcb->pcb_ldt) - user_ldt_free(pcb); + if (mdp->md_ldt) + user_ldt_free(td); if (pcb->pcb_flags & PCB_DBREGS) { /* * disable all hardware breakpoints