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 25 Apr 2005 21:57:57 -0000 @@ -75,6 +75,7 @@ #ifdef SMP static void set_user_ldt_rv(struct thread *); #endif +static int i386_allocbase_ldt(struct thread *td, int sel, uint32_t base); #ifndef _SYS_SYSPROTO_H_ struct sysarch_args { @@ -88,14 +89,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 +111,51 @@ 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 = i386_allocbase_ldt(td, td->td_pcb->pcb_fsbase, 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 = i386_allocbase_ldt(td, td->td_pcb->pcb_gsbase, 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 +727,64 @@ } return (0); } + +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: 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