Change the segment limits to 4GB, we set the user accessible bit on all

of the kernel address space already.  Intel recommend this anyway, because
using a non-4GB limit adds an additional clock cycle to address generation.
We were able to install 4GB segments into the LDT, so any limits we imposed
on %cs and %ds were academic anyway.  More importantly, this allows us to
make a page in the kernel readable to user applications, for holding things
like the signal trampoline and other fun things.

Move the user %cs/%ds segments from the LDT to the GDT.  There was no good
reason for them to be there anyway.  The old LDT entries are still there
but we can now relax the restriction that prevented users from emptying
the default LDT entries.

Putting user and kernel %cs and %ds together allows us to access the fast
sysenter/sysexit/syscall/sysret instructions.  syscall/sysret in particular
require that the user/kernel segments be laid out this way.  Reserve a slot
specifically for NDIS while here.

Create two user controllable slots in the GDT that are context switched
with the (kernel) thread.  This allows user applications to set two
user privilige selectors to arbitary values.  Create
i386_set_fsbase(void *base) and friends. (get/set, fs/gs).  For i386,
%gs is used by tls and the thread libraries and this means that user
processes no longer have to have the cost of having a custom LDT, and
we will no longer to do a ldt switch when activating a kthread/ithread in
the usual case any more.

In other words, we can now set the base address for %fs and %gs to arbitary
addresses without the pain of messing with ldt segments.
This commit is contained in:
Peter Wemm 2005-04-13 22:57:17 +00:00
parent 640f692f57
commit e0ab2c6d10
9 changed files with 217 additions and 83 deletions

View File

@ -134,6 +134,7 @@ ASSYM(PCB_PSL, offsetof(struct pcb, pcb_psl));
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_CURPCB, offsetof(struct pcpu, pc_curpcb));
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));

View File

@ -1286,7 +1286,12 @@ static char dblfault_stack[PAGE_SIZE];
extern vm_offset_t proc0kstack;
/* software prototypes -- in more palatable form */
/*
* software prototypes -- in more palatable form.
*
* GCODE_SEL through GUDATA_SEL must be in this order for syscall/sysret
* GUFS_SEL and GUGS_SEL must be in this order (swtch.s knows it)
*/
struct soft_segment_descriptor gdt_segs[] = {
/* GNULL_SEL 0 Null Descriptor */
{ 0x0, /* segment base address */
@ -1297,7 +1302,34 @@ struct soft_segment_descriptor gdt_segs[] = {
0, 0,
0, /* default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
/* GCODE_SEL 1 Code Descriptor for kernel */
/* GPRIV_SEL 1 SMP Per-Processor Private Data Descriptor */
{ 0x0, /* segment base address */
0xfffff, /* length - all address space */
SDT_MEMRWA, /* segment type */
0, /* segment descriptor priority level */
1, /* segment descriptor present */
0, 0,
1, /* default 32 vs 16 bit size */
1 /* limit granularity (byte/page units)*/ },
/* GUFS_SEL 2 %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 3 %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)*/ },
/* GCODE_SEL 4 Code Descriptor for kernel */
{ 0x0, /* segment base address */
0xfffff, /* length - all address space */
SDT_MEMERA, /* segment type */
@ -1306,7 +1338,7 @@ struct soft_segment_descriptor gdt_segs[] = {
0, 0,
1, /* default 32 vs 16 bit size */
1 /* limit granularity (byte/page units)*/ },
/* GDATA_SEL 2 Data Descriptor for kernel */
/* GDATA_SEL 5 Data Descriptor for kernel */
{ 0x0, /* segment base address */
0xfffff, /* length - all address space */
SDT_MEMRWA, /* segment type */
@ -1315,52 +1347,24 @@ struct soft_segment_descriptor gdt_segs[] = {
0, 0,
1, /* default 32 vs 16 bit size */
1 /* limit granularity (byte/page units)*/ },
/* GPRIV_SEL 3 SMP Per-Processor Private Data Descriptor */
/* GUCODE_SEL 6 Code Descriptor for user */
{ 0x0, /* segment base address */
0xfffff, /* length - all address space */
SDT_MEMRWA, /* segment type */
0, /* segment descriptor priority level */
1, /* segment descriptor present */
0, 0,
1, /* default 32 vs 16 bit size */
1 /* limit granularity (byte/page units)*/ },
/* GPROC0_SEL 4 Proc 0 Tss Descriptor */
{
0x0, /* segment base address */
sizeof(struct i386tss)-1,/* length */
SDT_SYS386TSS, /* segment type */
0, /* segment descriptor priority level */
1, /* segment descriptor present */
0, 0,
0, /* unused - default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
/* GLDT_SEL 5 LDT Descriptor */
{ (int) ldt, /* segment base address */
sizeof(ldt)-1, /* length - all address space */
SDT_SYSLDT, /* segment type */
SDT_MEMERA, /* segment type */
SEL_UPL, /* segment descriptor priority level */
1, /* segment descriptor present */
0, 0,
0, /* unused - default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
/* GUSERLDT_SEL 6 User LDT Descriptor per process */
{ (int) ldt, /* segment base address */
(512 * sizeof(union descriptor)-1), /* length */
SDT_SYSLDT, /* segment type */
0, /* segment descriptor priority level */
1, /* default 32 vs 16 bit size */
1 /* limit granularity (byte/page units)*/ },
/* GUDATA_SEL 7 Data 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,
0, /* unused - default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
/* GTGATE_SEL 7 Null Descriptor - Placeholder */
{ 0x0, /* segment base address */
0x0, /* length - all address space */
0, /* segment type */
0, /* segment descriptor priority level */
0, /* segment descriptor present */
0, 0,
0, /* default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
1, /* default 32 vs 16 bit size */
1 /* limit granularity (byte/page units)*/ },
/* GBIOSLOWMEM_SEL 8 BIOS access to realmode segment 0x40, must be #8 in GDT */
{ 0x400, /* segment base address */
0xfffff, /* length */
@ -1370,7 +1374,35 @@ struct soft_segment_descriptor gdt_segs[] = {
0, 0,
1, /* default 32 vs 16 bit size */
1 /* limit granularity (byte/page units)*/ },
/* GPANIC_SEL 9 Panic Tss Descriptor */
/* GPROC0_SEL 9 Proc 0 Tss Descriptor */
{
0x0, /* segment base address */
sizeof(struct i386tss)-1,/* length */
SDT_SYS386TSS, /* segment type */
0, /* segment descriptor priority level */
1, /* segment descriptor present */
0, 0,
0, /* unused - default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
/* GLDT_SEL 10 LDT Descriptor */
{ (int) ldt, /* segment base address */
sizeof(ldt)-1, /* length - all address space */
SDT_SYSLDT, /* segment type */
SEL_UPL, /* segment descriptor priority level */
1, /* segment descriptor present */
0, 0,
0, /* unused - default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
/* GUSERLDT_SEL 11 User LDT Descriptor per process */
{ (int) ldt, /* segment base address */
(512 * sizeof(union descriptor)-1), /* length */
SDT_SYSLDT, /* segment type */
0, /* segment descriptor priority level */
1, /* segment descriptor present */
0, 0,
0, /* unused - default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
/* GPANIC_SEL 12 Panic Tss Descriptor */
{ (int) &dblfault_tss, /* segment base address */
sizeof(struct i386tss)-1,/* length - all address space */
SDT_SYS386TSS, /* segment type */
@ -1379,7 +1411,7 @@ struct soft_segment_descriptor gdt_segs[] = {
0, 0,
0, /* unused - default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
/* GBIOSCODE32_SEL 10 BIOS 32-bit interface (32bit Code) */
/* GBIOSCODE32_SEL 13 BIOS 32-bit interface (32bit Code) */
{ 0, /* segment base address (overwritten) */
0xfffff, /* length */
SDT_MEMERA, /* segment type */
@ -1388,7 +1420,7 @@ struct soft_segment_descriptor gdt_segs[] = {
0, 0,
0, /* default 32 vs 16 bit size */
1 /* limit granularity (byte/page units)*/ },
/* GBIOSCODE16_SEL 11 BIOS 32-bit interface (16bit Code) */
/* GBIOSCODE16_SEL 14 BIOS 32-bit interface (16bit Code) */
{ 0, /* segment base address (overwritten) */
0xfffff, /* length */
SDT_MEMERA, /* segment type */
@ -1397,7 +1429,7 @@ struct soft_segment_descriptor gdt_segs[] = {
0, 0,
0, /* default 32 vs 16 bit size */
1 /* limit granularity (byte/page units)*/ },
/* GBIOSDATA_SEL 12 BIOS 32-bit interface (Data) */
/* GBIOSDATA_SEL 15 BIOS 32-bit interface (Data) */
{ 0, /* segment base address (overwritten) */
0xfffff, /* length */
SDT_MEMRWA, /* segment type */
@ -1406,7 +1438,7 @@ struct soft_segment_descriptor gdt_segs[] = {
0, 0,
1, /* default 32 vs 16 bit size */
1 /* limit granularity (byte/page units)*/ },
/* GBIOSUTIL_SEL 13 BIOS 16-bit interface (Utility) */
/* GBIOSUTIL_SEL 16 BIOS 16-bit interface (Utility) */
{ 0, /* segment base address (overwritten) */
0xfffff, /* length */
SDT_MEMRWA, /* segment type */
@ -1415,7 +1447,7 @@ struct soft_segment_descriptor gdt_segs[] = {
0, 0,
0, /* default 32 vs 16 bit size */
1 /* limit granularity (byte/page units)*/ },
/* GBIOSARGS_SEL 14 BIOS 16-bit interface (Arguments) */
/* GBIOSARGS_SEL 17 BIOS 16-bit interface (Arguments) */
{ 0, /* segment base address (overwritten) */
0xfffff, /* length */
SDT_MEMRWA, /* segment type */
@ -1424,6 +1456,15 @@ struct soft_segment_descriptor gdt_segs[] = {
0, 0,
0, /* default 32 vs 16 bit size */
1 /* limit granularity (byte/page units)*/ },
/* GNDIS_SEL 18 NDIS Descriptor */
{ 0x0, /* segment base address */
0x0, /* length */
0, /* segment type */
0, /* segment descriptor priority level */
0, /* segment descriptor present */
0, 0,
0, /* default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
};
static struct soft_segment_descriptor ldt_segs[] = {
@ -1999,25 +2040,22 @@ init386(first)
init_param1();
/*
* make gdt memory segments, the code segment goes up to end of the
* page with etext in it, the data segment goes to the end of
* the address space
*/
/*
* XXX text protection is temporarily (?) disabled. The limit was
* i386_btop(round_page(etext)) - 1.
* Make gdt memory segments. All segments cover the full 4GB
* of address space and permissions are enforced at page level.
*/
gdt_segs[GCODE_SEL].ssd_limit = atop(0 - 1);
gdt_segs[GDATA_SEL].ssd_limit = atop(0 - 1);
gdt_segs[GUCODE_SEL].ssd_limit = atop(0 - 1);
gdt_segs[GUDATA_SEL].ssd_limit = atop(0 - 1);
gdt_segs[GUFS_SEL].ssd_limit = atop(0 - 1);
gdt_segs[GUGS_SEL].ssd_limit = atop(0 - 1);
#ifdef SMP
pc = &SMP_prvspace[0].pcpu;
gdt_segs[GPRIV_SEL].ssd_limit =
atop(sizeof(struct privatespace) - 1);
#else
pc = &__pcpu;
gdt_segs[GPRIV_SEL].ssd_limit =
atop(sizeof(struct pcpu) - 1);
#endif
gdt_segs[GPRIV_SEL].ssd_limit = atop(0 - 1);
gdt_segs[GPRIV_SEL].ssd_base = (int) pc;
gdt_segs[GPROC0_SEL].ssd_base = (int) &pc->pc_common_tss;
@ -2046,12 +2084,8 @@ init386(first)
mtx_init(&icu_lock, "icu", NULL, MTX_SPIN | MTX_NOWITNESS);
/* make ldt memory segments */
/*
* XXX - VM_MAXUSER_ADDRESS is an end address, not a max. And it
* should be spelled ...MAX_USER...
*/
ldt_segs[LUCODE_SEL].ssd_limit = atop(VM_MAXUSER_ADDRESS - 1);
ldt_segs[LUDATA_SEL].ssd_limit = atop(VM_MAXUSER_ADDRESS - 1);
ldt_segs[LUCODE_SEL].ssd_limit = atop(0 - 1);
ldt_segs[LUDATA_SEL].ssd_limit = atop(0 - 1);
for (x = 0; x < sizeof ldt_segs / sizeof ldt_segs[0]; x++)
ssdtosd(&ldt_segs[x], &ldt[x].sd);
@ -2151,6 +2185,9 @@ init386(first)
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 =
@ -2193,13 +2230,14 @@ init386(first)
gdp->gd_hioffset = x >> 16;
/* XXX does this work? */
/* XXX yes! */
ldt[LBSDICALLS_SEL] = ldt[LSYS5CALLS_SEL];
ldt[LSOL26CALLS_SEL] = ldt[LSYS5CALLS_SEL];
/* transfer to user mode */
_ucodesel = LSEL(LUCODE_SEL, SEL_UPL);
_udatasel = LSEL(LUDATA_SEL, SEL_UPL);
_ucodesel = GSEL(GUCODE_SEL, SEL_UPL);
_udatasel = GSEL(GUDATA_SEL, SEL_UPL);
/* setup proc 0's pcb */
thread0.td_pcb->pcb_flags = 0; /* XXXKSE */

View File

@ -467,6 +467,8 @@ init_secondary(void)
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

View File

@ -220,13 +220,25 @@ sw1:
/* 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

View File

@ -90,6 +90,8 @@ sysarch(td, uap)
struct i386_ldt_args largs;
struct i386_ioperm_args iargs;
} kargs;
uint32_t base;
struct segment_descriptor sd, *sdp;
switch (uap->op) {
case I386_GET_IOPERM:
@ -145,6 +147,67 @@ sysarch(td, uap)
case I386_VM86:
error = vm86_sysarch(td, uap->parms);
break;
case I386_GET_FSBASE:
sdp = &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);
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 = &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);
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;

View File

@ -67,6 +67,8 @@ struct pcb {
caddr_t pcb_onfault; /* copyin/out fault recovery */
int pcb_gs;
struct segment_descriptor pcb_fsd;
struct segment_descriptor pcb_gsd;
struct pcb_ext *pcb_ext; /* optional pcb extension */
int pcb_psl; /* process status long */
void (*pcb_switchout)(void); /* Special switchout function. */

View File

@ -51,6 +51,7 @@
struct i386tss pc_common_tss; \
struct segment_descriptor pc_common_tssd; \
struct segment_descriptor *pc_tss_gdt; \
struct segment_descriptor *pc_fsgs_gdt; \
int pc_currentldt; \
u_int pc_acpi_id; \
u_int pc_apic_id

View File

@ -199,24 +199,30 @@ struct region_descriptor {
/*
* Entries in the Global Descriptor Table (GDT)
* Note that each 4 entries share a single 32 byte L1 cache line.
* Some of the fast syscall instructions require a specific order here.
*/
#define GNULL_SEL 0 /* Null Descriptor */
#define GCODE_SEL 1 /* Kernel Code Descriptor */
#define GDATA_SEL 2 /* Kernel Data Descriptor */
#define GPRIV_SEL 3 /* SMP Per-Processor Private Data */
#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 GPRIV_SEL 1 /* SMP Per-Processor Private Data */
#define GUFS_SEL 2 /* User %fs Descriptor (order critical: 1) */
#define GUGS_SEL 3 /* User %gs Descriptor (order critical: 2) */
#define GCODE_SEL 4 /* Kernel Code Descriptor (order critical: 1) */
#define GDATA_SEL 5 /* Kernel Data Descriptor (order critical: 2) */
#define GUCODE_SEL 6 /* User Code Descriptor (order critical: 3) */
#define GUDATA_SEL 7 /* User Data Descriptor (order critical: 4) */
#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) */
#define GBIOSCODE16_SEL 11 /* BIOS interface (16bit Code) */
#define GBIOSDATA_SEL 12 /* BIOS interface (Data) */
#define GBIOSUTIL_SEL 13 /* BIOS interface (Utility) */
#define GBIOSARGS_SEL 14 /* BIOS interface (Arguments) */
#define GPROC0_SEL 9 /* Task state process slot zero and up */
#define GLDT_SEL 10 /* Default User LDT */
#define GUSERLDT_SEL 11 /* User LDT */
#define GPANIC_SEL 12 /* Task state to consider panic from */
#define GBIOSCODE32_SEL 13 /* BIOS interface (32bit Code) */
#define GBIOSCODE16_SEL 14 /* BIOS interface (16bit Code) */
#define GBIOSDATA_SEL 15 /* BIOS interface (Data) */
#define GBIOSUTIL_SEL 16 /* BIOS interface (Utility) */
#define GBIOSARGS_SEL 17 /* BIOS interface (Arguments) */
#define GNDIS_SEL 18 /* For the NDIS layer */
#define NGDT 15
#define NGDT 19
/*
* Entries in the Local Descriptor Table (LDT)

View File

@ -43,6 +43,10 @@
#define I386_SET_IOPERM 4
/* xxxxx */
#define I386_VM86 6
#define I386_GET_FSBASE 7
#define I386_SET_FSBASE 8
#define I386_GET_GSBASE 9
#define I386_SET_GSBASE 10
/* These four only exist when running an i386 binary on amd64 */
#define _AMD64_GET_FSBASE 128
@ -84,6 +88,10 @@ int i386_set_ldt(int, union descriptor *, int);
int i386_get_ioperm(unsigned int, unsigned int *, int *);
int i386_set_ioperm(unsigned int, unsigned int, int);
int i386_vm86(int, void *);
int i386_get_fsbase(void **);
int i386_get_gsbase(void **);
int i386_set_fsbase(void *);
int i386_set_gsbase(void *);
int i386_set_watch(int, unsigned int, int, int, struct dbreg *);
int i386_clr_watch(int, struct dbreg *);
int sysarch(int, void *);