Index: i386/sys_machdep.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/sys_machdep.c,v retrieving revision 1.92.2.1 diff -u -r1.92.2.1 sys_machdep.c --- i386/sys_machdep.c 5 Feb 2005 01:02:49 -0000 1.92.2.1 +++ i386/sys_machdep.c 26 Apr 2005 01:46:09 -0000 @@ -75,6 +75,9 @@ #ifdef SMP static void set_user_ldt_rv(struct thread *); #endif +static int i386_allocbase_ldt(struct thread *td, int sel, uint32_t base); + +extern int _udatasel; #ifndef _SYS_SYSPROTO_H_ struct sysarch_args { @@ -88,14 +91,16 @@ struct thread *td; register struct sysarch_args *uap; { - int error; + int error, sel; + uint32_t base; + struct proc_ldt *pldt; + union descriptor *dp; mtx_lock(&Giant); switch(uap->op) { case I386_GET_LDT: error = i386_get_ldt(td, uap->parms); break; - case I386_SET_LDT: error = i386_set_ldt(td, uap->parms); break; @@ -108,6 +113,74 @@ case I386_VM86: error = vm86_sysarch(td, uap->parms); break; + case I386_GET_FSBASE: + base = 0; + sel = td->td_pcb->pcb_fsbase; + pldt = td->td_proc->p_md.md_ldt; + if (sel != 0 && sel < pldt->ldt_len) { + dp = &((union descriptor *)(pldt->ldt_base))[sel]; + base = dp->sd.sd_hibase << 24 | dp->sd.sd_lobase; + } + error = copyout(&base, uap->parms, sizeof(base)); + break; + case I386_SET_FSBASE: + error = copyin(uap->parms, &base, sizeof(base)); + if (error) + break; + sel = td->td_pcb->pcb_fsbase; + if (base == 0) { + pldt = td->td_proc->p_md.md_ldt; + if (sel == 0 || sel >= pldt->ldt_len) + break; + dp = &((union descriptor *)(pldt->ldt_base))[sel]; + bzero(dp, sizeof(*dp)); + dp->sd.sd_type = SDT_SYSNULL; + td->td_frame->tf_fs = _udatasel; + break; + } + sel = i386_allocbase_ldt(td, sel, base); + if (sel) { + td->td_pcb->pcb_fsbase = sel; + td->td_frame->tf_fs = LSEL(sel, SEL_UPL); + } else { + error = EINVAL; + } + break; + case I386_GET_GSBASE: + base = 0; + sel = td->td_pcb->pcb_gsbase; + pldt = td->td_proc->p_md.md_ldt; + if (sel != 0 && sel < pldt->ldt_len) { + dp = &((union descriptor *)(pldt->ldt_base))[sel]; + base = dp->sd.sd_hibase << 24 | dp->sd.sd_lobase; + } + error = copyout(&base, uap->parms, sizeof(base)); + break; + case I386_SET_GSBASE: + error = copyin(uap->parms, &base, sizeof(base)); + if (error) + break; + sel = td->td_pcb->pcb_gsbase; + if (base == 0) { + pldt = td->td_proc->p_md.md_ldt; + if (sel == 0 || sel >= pldt->ldt_len) + break; + dp = &((union descriptor *)(pldt->ldt_base))[sel]; + bzero(dp, sizeof(*dp)); + dp->sd.sd_type = SDT_SYSNULL; + td->td_pcb->pcb_gs = _udatasel; + load_gs(td->td_pcb->pcb_gs); + break; + } + sel = i386_allocbase_ldt(td, sel, base); + if (sel) { + td->td_pcb->pcb_gsbase = sel; + td->td_pcb->pcb_gs = LSEL(sel, SEL_UPL); + load_gs(td->td_pcb->pcb_gs); + } else { + error = EINVAL; + } + break; default: error = EINVAL; break; @@ -679,3 +752,80 @@ } return (0); } + +int i386_dupbase_ldt(struct thread *td, int sel); +int +i386_dupbase_ldt(struct thread *td, int sel) +{ + struct mdproc *mdp = &td->td_proc->p_md; + struct proc_ldt *pldt = mdp->md_ldt; + union descriptor *dp; + uint32_t base; + + if (pldt == NULL || sel >= pldt->ldt_len) + return (0); + dp = &((union descriptor *)(pldt->ldt_base))[sel]; + base = dp->sd.sd_hibase << 24 | dp->sd.sd_lobase; + return (i386_allocbase_ldt(td, 0, base)); +} + +static int +i386_allocbase_ldt(struct thread *td, int sel, uint32_t base) +{ + struct mdproc *mdp = &td->td_proc->p_md; + struct proc_ldt *pldt = 0; + union descriptor *dp; + union descriptor sdu; + int error = 0; + + sdu.sd.sd_lobase = base & 0xffffff; + sdu.sd.sd_hibase = (base >> 24) & 0xff; + sdu.sd.sd_lolimit = 0xffff; /* 4GB limit, wraps around */ + sdu.sd.sd_hilimit = 0xf; + sdu.sd.sd_type = SDT_MEMRWA; + sdu.sd.sd_dpl = SEL_UPL; + sdu.sd.sd_p = 1; + sdu.sd.sd_xx = 0; + sdu.sd.sd_def32 = 1; + sdu.sd.sd_gran = 1; + + /* Create LDT if needed, starting with a free slot */ + pldt = mdp->md_ldt; + if (pldt == NULL) { + error = i386_ldt_grow(td, NLDT+1); + if (error) + return (0); + pldt = mdp->md_ldt; + } + /* Use specific slot if requested, growing ldt if needed */ + if (sel) { + if (sel >= pldt->ldt_len) { + error = i386_ldt_grow(td, pldt->ldt_len+1); + if (error) + return (0); + } + mtx_lock_spin(&sched_lock); + i386_set_ldt_data(td, sel, 1, &sdu); + mtx_unlock_spin(&sched_lock); + return (sel); + } + /* Allocate first free slot, and make more room if needed */ +again: + mtx_lock_spin(&sched_lock); + dp = &((union descriptor *)(pldt->ldt_base))[NLDT]; + for (sel = NLDT; sel < pldt->ldt_len; ++sel) { + if (dp->sd.sd_type == SDT_SYSNULL) + break; + dp++; + } + if (sel >= pldt->ldt_len) { + mtx_unlock_spin(&sched_lock); + error = i386_ldt_grow(td, pldt->ldt_len+1); + if (error) + return (0); + goto again; + } + i386_set_ldt_data(td, sel, 1, &sdu); + mtx_unlock_spin(&sched_lock); + return (sel); +} Index: i386/vm_machdep.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/vm_machdep.c,v retrieving revision 1.241.2.3 diff -u -r1.241.2.3 vm_machdep.c --- i386/vm_machdep.c 9 Mar 2005 18:59:19 -0000 1.241.2.3 +++ i386/vm_machdep.c 26 Apr 2005 01:34:38 -0000 @@ -100,6 +100,8 @@ #define NSFBUFS (512 + maxusers * 16) #endif +int i386_dupbase_ldt(struct thread *td, int sel); + static void cpu_reset_real(void); #ifdef SMP static void cpu_reset_proxy(void); @@ -248,6 +250,7 @@ if (mdp2->md_ldt != 0) { if (flags & RFMEM) { mdp2->md_ldt->ldt_refcnt++; + /* XXX dup fsbase/gsbase slots */ } else { mdp2->md_ldt = user_ldt_alloc(mdp2, mdp2->md_ldt->ldt_len); @@ -365,7 +368,7 @@ /* * Initialize machine state (pcb and trap frame) for a new thread about to - * upcall. Pu t enough state in the new thread's PCB to get it to go back + * upcall. Put enough state in the new thread's PCB to get it to go back * userret(), where we can intercept it again to set the return (upcall) * Address and stack, along with those from upcals that are from other sources * such as those generated in thread_userret() itself. @@ -374,6 +377,7 @@ cpu_set_upcall(struct thread *td, struct thread *td0) { struct pcb *pcb2; + int sel; /* Point the pcb to the top of the stack. */ pcb2 = td->td_pcb; @@ -401,6 +405,16 @@ * upcall as only then do we know which KSE we got. */ bcopy(td0->td_frame, td->td_frame, sizeof(struct trapframe)); + if (pcb2->pcb_fsbase) { + sel = i386_dupbase_ldt(td, pcb2->pcb_fsbase); + if (sel) { + pcb2->pcb_fsbase = sel; + td->td_frame->tf_fs = LSEL(sel, SEL_UPL); + } else { + td->td_frame->tf_fs = _udatasel; + pcb2->pcb_fsbase = 0; + } + } /* * Set registers for trampoline to user mode. Leave space for the @@ -418,7 +432,19 @@ pcb2->pcb_ebx = (int)td; /* trampoline arg */ pcb2->pcb_eip = (int)fork_trampoline; pcb2->pcb_psl &= ~(PSL_I); /* interrupts must be disabled */ - pcb2->pcb_gs = rgs(); + if (pcb2->pcb_gsbase) { + sel = i386_dupbase_ldt(td, pcb2->pcb_gsbase); + if (sel) { + pcb2->pcb_gsbase = sel; + pcb2->pcb_gs = LSEL(sel, SEL_UPL); + } else { + pcb2->pcb_gsbase = 0; + pcb2->pcb_gs = _udatasel; + } + load_gs(pcb2->pcb_gs); + } else { + pcb2->pcb_gs = rgs(); + } /* * If we didn't copy the pcb, we'd need to do the following registers: * pcb2->pcb_dr*: cloned above. Index: include/pcb.h =================================================================== RCS file: /home/ncvs/src/sys/i386/include/pcb.h,v retrieving revision 1.52.2.1 diff -u -r1.52.2.1 pcb.h --- include/pcb.h 18 Apr 2005 21:21:47 -0000 1.52.2.1 +++ include/pcb.h 25 Apr 2005 21:33:02 -0000 @@ -71,6 +71,8 @@ int pcb_psl; /* process status long */ void (*pcb_switchout)(void); /* Special switchout function. */ u_long pcb_vm86[2]; /* vm86bios scratch space */ + int pcb_fsbase; + int pcb_gsbase; }; #ifdef _KERNEL