Index: i386/genassym.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/genassym.c,v retrieving revision 1.148.2.2 diff -u -r1.148.2.2 genassym.c --- i386/genassym.c 18 Apr 2005 21:21:47 -0000 1.148.2.2 +++ i386/genassym.c 26 Apr 2005 18:09:55 -0000 @@ -134,6 +134,7 @@ ASSYM(PCB_DBREGS, PCB_DBREGS); ASSYM(PCB_EXT, offsetof(struct pcb, pcb_ext)); +ASSYM(PCB_FSD, offsetof(struct pcb, pcb_fsd)); ASSYM(PCB_VM86, offsetof(struct pcb, pcb_vm86)); ASSYM(PCB_FLAGS, offsetof(struct pcb, pcb_flags)); ASSYM(PCB_SAVEFPU, offsetof(struct pcb, pcb_save)); @@ -193,6 +194,7 @@ ASSYM(PC_COMMON_TSS, offsetof(struct pcpu, pc_common_tss)); ASSYM(PC_COMMON_TSSD, offsetof(struct pcpu, pc_common_tssd)); ASSYM(PC_TSS_GDT, offsetof(struct pcpu, pc_tss_gdt)); +ASSYM(PC_FSGS_GDT, offsetof(struct pcpu, pc_fsgs_gdt)); ASSYM(PC_CURRENTLDT, offsetof(struct pcpu, pc_currentldt)); ASSYM(PC_CPUID, offsetof(struct pcpu, pc_cpuid)); ASSYM(PC_CURPMAP, offsetof(struct pcpu, pc_curpmap)); Index: i386/machdep.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/machdep.c,v retrieving revision 1.597.2.6 diff -u -r1.597.2.6 machdep.c --- i386/machdep.c 25 Mar 2005 21:08:48 -0000 1.597.2.6 +++ i386/machdep.c 26 Apr 2005 18:27:06 -0000 @@ -1355,7 +1355,7 @@ 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, -/* GTGATE_SEL 7 Null Descriptor - Placeholder */ +/* GNDIS_SEL 7 NDIS Descriptor */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ @@ -1427,6 +1427,24 @@ 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, +/* GUFS_SEL 14 %fs Descriptor for user */ +{ 0x0, /* segment base address */ + 0xfffff, /* length - all address space */ + SDT_MEMRWA, /* segment type */ + SEL_UPL, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0, 0, + 1, /* default 32 vs 16 bit size */ + 1 /* limit granularity (byte/page units)*/ }, +/* GUGS_SEL 15 %gs Descriptor for user */ +{ 0x0, /* segment base address */ + 0xfffff, /* length - all address space */ + SDT_MEMRWA, /* segment type */ + SEL_UPL, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0, 0, + 1, /* default 32 vs 16 bit size */ + 1 /* limit granularity (byte/page units)*/ }, }; static struct soft_segment_descriptor ldt_segs[] = { @@ -2170,6 +2176,9 @@ PCPU_SET(common_tss.tss_ioopt, (sizeof (struct i386tss)) << 16); ltr(gsel_tss); + /* pointer to selector slot for %fs/%gs */ + PCPU_SET(fsgs_gdt, &gdt[GUFS_SEL].sd); + dblfault_tss.tss_esp = dblfault_tss.tss_esp0 = dblfault_tss.tss_esp1 = dblfault_tss.tss_esp2 = (int)&dblfault_stack[sizeof(dblfault_stack)]; dblfault_tss.tss_ss = dblfault_tss.tss_ss0 = dblfault_tss.tss_ss1 = Index: i386/mp_machdep.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/mp_machdep.c,v retrieving revision 1.235.2.6 diff -u -r1.235.2.6 mp_machdep.c --- i386/mp_machdep.c 14 Feb 2005 10:42:22 -0000 1.235.2.6 +++ i386/mp_machdep.c 26 Apr 2005 18:14:38 -0000 @@ -469,6 +469,8 @@ PCPU_SET(common_tssd, *PCPU_GET(tss_gdt)); ltr(gsel_tss); + PCPU_SET(fsgs_gdt, &gdt[myid * NGDT + GUFS_SEL].sd); + /* * Set to a known state: * Set by mpboot.s: CR0_PG, CR0_PE Index: i386/swtch.s =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/swtch.s,v retrieving revision 1.147 diff -u -r1.147 swtch.s --- i386/swtch.s 15 Jul 2004 16:37:48 -0000 1.147 +++ i386/swtch.s 26 Apr 2005 18:16:05 -0000 @@ -220,13 +220,25 @@ /* Move correct tss descriptor into GDT slot, then reload tr. */ movl PCPU(TSS_GDT), %ebx /* entry in GDT */ movl 0(%edi), %eax + movl 4(%edi), %esi movl %eax, 0(%ebx) - movl 4(%edi), %eax - movl %eax, 4(%ebx) + movl %esi, 4(%ebx) movl $GPROC0_SEL*8, %esi /* GSEL(entry, SEL_KPL) */ ltr %si 3: + /* Copy the %fs and %gs selectors into this pcpu gdt */ + leal PCB_FSD(%edx), %esi + movl PCPU(FSGS_GDT), %edi + movl 0(%esi), %eax /* %fs selector */ + movl 4(%esi), %ebx + movl %eax, 0(%edi) + movl %ebx, 4(%edi) + movl 8(%esi), %eax /* %gs selector, comes straight after */ + movl 12(%esi), %ebx + movl %eax, 8(%edi) + movl %ebx, 12(%edi) + /* Restore context. */ movl PCB_EBX(%edx),%ebx movl PCB_ESP(%edx),%esp 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 18:25:21 -0000 @@ -89,6 +89,9 @@ register struct sysarch_args *uap; { int error; + uint32_t base; + struct segment_descriptor sd, *sdp; + mtx_lock(&Giant); switch(uap->op) { @@ -108,6 +111,67 @@ case I386_VM86: error = vm86_sysarch(td, uap->parms); break; + case I386_GET_FSBASE: + sdp = (struct segment_descriptor *)&td->td_pcb->pcb_fsd; + base = sdp->sd_hibase << 24 | sdp->sd_lobase; + error = copyout(&base, uap->parms, sizeof(base)); + break; + case I386_SET_FSBASE: + error = copyin(uap->parms, &base, sizeof(base)); + if (!error) { + /* + * Construct a descriptor and store it in the pcb for + * the next context switch. Also store it in the gdt + * so that the load of tf_fs into %fs will activate it + * at return to userland. + */ + sd.sd_lobase = base & 0xffffff; + sd.sd_hibase = (base >> 24) & 0xff; + sd.sd_lolimit = 0xffff; /* 4GB limit, wraps around */ + sd.sd_hilimit = 0xf; + sd.sd_type = SDT_MEMRWA; + sd.sd_dpl = SEL_UPL; + sd.sd_p = 1; + sd.sd_xx = 0; + sd.sd_def32 = 1; + sd.sd_gran = 1; + mtx_lock_spin(&sched_lock); + *(struct segment_descriptor *)&td->td_pcb->pcb_fsd = sd; + PCPU_GET(fsgs_gdt)[0] = sd; + td->td_frame->tf_fs = GSEL(GUFS_SEL, SEL_UPL); + mtx_unlock_spin(&sched_lock); + } + break; + case I386_GET_GSBASE: + sdp = (struct segment_descriptor *)&td->td_pcb->pcb_gsd; + base = sdp->sd_hibase << 24 | sdp->sd_lobase; + error = copyout(&base, uap->parms, sizeof(base)); + break; + case I386_SET_GSBASE: + error = copyin(uap->parms, &base, sizeof(base)); + if (!error) { + /* + * Construct a descriptor and store it in the pcb for + * the next context switch. Also store it in the gdt + * because we have to do a load_gs() right now. + */ + sd.sd_lobase = base & 0xffffff; + sd.sd_hibase = (base >> 24) & 0xff; + sd.sd_lolimit = 0xffff; /* 4GB limit, wraps around */ + sd.sd_hilimit = 0xf; + sd.sd_type = SDT_MEMRWA; + sd.sd_dpl = SEL_UPL; + sd.sd_p = 1; + sd.sd_xx = 0; + sd.sd_def32 = 1; + sd.sd_gran = 1; + mtx_lock_spin(&sched_lock); + *(struct segment_descriptor *)&td->td_pcb->pcb_gsd = sd; + PCPU_GET(fsgs_gdt)[1] = sd; + load_gs(GSEL(GUGS_SEL, SEL_UPL)); + mtx_unlock_spin(&sched_lock); + } + break; default: error = EINVAL; break; 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 26 Apr 2005 18:19:13 -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 */ + u_long pcb_fsd[2]; + u_long pcb_gsd[2]; }; #ifdef _KERNEL Index: include/pcpu.h =================================================================== RCS file: /home/ncvs/src/sys/i386/include/pcpu.h,v retrieving revision 1.42 diff -u -r1.42 pcpu.h --- include/pcpu.h 12 Mar 2004 21:45:30 -0000 1.42 +++ include/pcpu.h 26 Apr 2005 18:19:56 -0000 @@ -49,7 +49,8 @@ struct segment_descriptor *pc_tss_gdt; \ int pc_currentldt; \ u_int pc_acpi_id; \ - u_int pc_apic_id + u_int pc_apic_id; \ + struct segment_descriptor *pc_fsgs_gdt #if defined(lint) Index: include/segments.h =================================================================== RCS file: /home/ncvs/src/sys/i386/include/segments.h,v retrieving revision 1.37 diff -u -r1.37 segments.h --- include/segments.h 7 Apr 2004 20:46:05 -0000 1.37 +++ include/segments.h 26 Apr 2005 18:22:20 -0000 @@ -207,7 +207,7 @@ #define GPROC0_SEL 4 /* Task state process slot zero and up */ #define GLDT_SEL 5 /* LDT - eventually one per process */ #define GUSERLDT_SEL 6 /* User LDT */ -#define GTGATE_SEL 7 /* Process task switch gate */ +#define GNDIS_SEL 7 /* For the NDIS layer */ #define GBIOSLOWMEM_SEL 8 /* BIOS low memory access (must be entry 8) */ #define GPANIC_SEL 9 /* Task state to consider panic from */ #define GBIOSCODE32_SEL 10 /* BIOS interface (32bit Code) */ @@ -215,8 +215,10 @@ #define GBIOSDATA_SEL 12 /* BIOS interface (Data) */ #define GBIOSUTIL_SEL 13 /* BIOS interface (Utility) */ #define GBIOSARGS_SEL 14 /* BIOS interface (Arguments) */ +#define GUFS_SEL 15 /* User %fs Descriptor (order critical: 1) */ +#define GUGS_SEL 16 /* User %gs Descriptor (order critical: 2) */ -#define NGDT 15 +#define NGDT 17 /* * Entries in the Local Descriptor Table (LDT)