summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorPhilip Guenthe <guenther@cvs.openbsd.org>2011-03-12 03:52:27 +0000
committerPhilip Guenthe <guenther@cvs.openbsd.org>2011-03-12 03:52:27 +0000
commitc62a833c3eed0faa13ce022b6d4eee3119bffd85 (patch)
treecf68d2b3fbd1afd58c33da5d40eee730557be64e /sys
parentcd06312d1f6bdbfe322dd8bf9ada43332f0d48e3 (diff)
Provide distinct segments for the %fs and %gs selectors to use by
default, with per-rthread base offsets and with sysarch() functions, I386_{GET,SET}_{FS,GS}BASE, for fetching and setting those base offsets. This is necessary for both rthread and Linux compat support. suggestions from kettenis@, prodding from pirofti@ and deraadt@
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/i386/i386/locore.s5
-rw-r--r--sys/arch/i386/i386/machdep.c26
-rw-r--r--sys/arch/i386/i386/pmap.c8
-rw-r--r--sys/arch/i386/i386/sys_machdep.c55
-rw-r--r--sys/arch/i386/include/pcb.h12
-rw-r--r--sys/arch/i386/include/segments.h9
-rw-r--r--sys/arch/i386/include/sysarch.h10
7 files changed, 103 insertions, 22 deletions
diff --git a/sys/arch/i386/i386/locore.s b/sys/arch/i386/i386/locore.s
index 3eedfb20b5b..1f90906ffa6 100644
--- a/sys/arch/i386/i386/locore.s
+++ b/sys/arch/i386/i386/locore.s
@@ -1,4 +1,4 @@
-/* $OpenBSD: locore.s,v 1.130 2010/07/03 04:54:32 kettenis Exp $ */
+/* $OpenBSD: locore.s,v 1.131 2011/03/12 03:52:26 guenther Exp $ */
/* $NetBSD: locore.s,v 1.145 1996/05/03 19:41:19 christos Exp $ */
/*-
@@ -112,6 +112,7 @@
movl $GSEL(GDATA_SEL, SEL_KPL),%eax ; \
movw %ax,%ds ; \
movw %ax,%es ; \
+ xorl %eax,%eax ; /* $GSEL(GNULL_SEL, SEL_KPL) == 0 */ \
movw %ax,%gs ; \
pushl %fs ; \
movl $GSEL(GCPU_SEL, SEL_KPL),%eax ; \
@@ -1495,7 +1496,7 @@ NENTRY(resume_pop_ds)
movw %ax,%es
NENTRY(resume_pop_es)
pushl %gs
- movl $GSEL(GDATA_SEL, SEL_KPL),%eax
+ xorl %eax,%eax /* $GSEL(GNULL_SEL, SEL_KPL) == 0 */
movw %ax,%gs
NENTRY(resume_pop_gs)
pushl %fs
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c
index ae0e8dc243a..b6af6b52eef 100644
--- a/sys/arch/i386/i386/machdep.c
+++ b/sys/arch/i386/i386/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.487 2011/01/27 21:27:44 jsg Exp $ */
+/* $OpenBSD: machdep.c,v 1.488 2011/03/12 03:52:26 guenther Exp $ */
/* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */
/*-
@@ -2282,8 +2282,8 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type,
/*
* Build context to run handler in.
*/
- tf->tf_fs = GSEL(GUDATA_SEL, SEL_UPL);
- tf->tf_gs = GSEL(GUDATA_SEL, SEL_UPL);
+ tf->tf_fs = GSEL(GUFS_SEL, SEL_UPL);
+ tf->tf_gs = GSEL(GUGS_SEL, SEL_UPL);
tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_eip = p->p_sigcode;
@@ -2708,25 +2708,33 @@ setregs(struct proc *p, struct exec_package *pack, u_long stack,
/*
* Reset the code segment limit to I386_MAX_EXE_ADDR in the pmap;
- * this gets copied into the GDT and LDT for {G,L}UCODE_SEL by
- * pmap_activate().
+ * this gets copied into the GDT for GUCODE_SEL by pmap_activate().
+ * Similarly, reset the base of each of the two thread data
+ * segments to zero in the pcb; they'll get copied into the
+ * GDT for GUFS_SEL and GUGS_SEL.
*/
setsegment(&pmap->pm_codeseg, 0, atop(I386_MAX_EXE_ADDR) - 1,
SDT_MEMERA, SEL_UPL, 1, 1);
+ setsegment(&pcb->pcb_threadsegs[TSEG_FS], 0,
+ atop(VM_MAXUSER_ADDRESS) - 1, SDT_MEMRWA, SEL_UPL, 1, 1);
+ setsegment(&pcb->pcb_threadsegs[TSEG_GS], 0,
+ atop(VM_MAXUSER_ADDRESS) - 1, SDT_MEMRWA, SEL_UPL, 1, 1);
/*
* And update the GDT since we return to the user process
* by leaving the syscall (we don't do another pmap_activate()).
*/
curcpu()->ci_gdt[GUCODE_SEL].sd = pmap->pm_codeseg;
+ curcpu()->ci_gdt[GUFS_SEL].sd = pcb->pcb_threadsegs[TSEG_FS];
+ curcpu()->ci_gdt[GUGS_SEL].sd = pcb->pcb_threadsegs[TSEG_GS];
/*
* And reset the hiexec marker in the pmap.
*/
pmap->pm_hiexec = 0;
- tf->tf_fs = GSEL(GUDATA_SEL, SEL_UPL);
- tf->tf_gs = GSEL(GUDATA_SEL, SEL_UPL);
+ tf->tf_fs = GSEL(GUFS_SEL, SEL_UPL);
+ tf->tf_gs = GSEL(GUGS_SEL, SEL_UPL);
tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_edi = 0;
@@ -2928,6 +2936,10 @@ init386(paddr_t first_avail)
SDT_MEMRWA, SEL_UPL, 1, 1);
setsegment(&gdt[GCPU_SEL].sd, &cpu_info_primary,
sizeof(struct cpu_info)-1, SDT_MEMRWA, SEL_KPL, 0, 0);
+ setsegment(&gdt[GUFS_SEL].sd, 0, atop(VM_MAXUSER_ADDRESS) - 1,
+ SDT_MEMRWA, SEL_UPL, 1, 1);
+ setsegment(&gdt[GUGS_SEL].sd, 0, atop(VM_MAXUSER_ADDRESS) - 1,
+ SDT_MEMRWA, SEL_UPL, 1, 1);
/* exceptions */
setgate(&idt[ 0], &IDTVEC(div), 0, SDT_SYS386TGT, SEL_KPL, GCODE_SEL);
diff --git a/sys/arch/i386/i386/pmap.c b/sys/arch/i386/i386/pmap.c
index 291c503799f..a27ee0c3f1a 100644
--- a/sys/arch/i386/i386/pmap.c
+++ b/sys/arch/i386/i386/pmap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pmap.c,v 1.151 2010/11/30 19:28:59 kettenis Exp $ */
+/* $OpenBSD: pmap.c,v 1.152 2011/03/12 03:52:26 guenther Exp $ */
/* $NetBSD: pmap.c,v 1.91 2000/06/02 17:46:37 thorpej Exp $ */
/*
@@ -1692,6 +1692,8 @@ pmap_switch(struct proc *o, struct proc *p)
* correct code segment X limit) in the GDT.
*/
self->ci_gdt[GUCODE_SEL].sd = pmap->pm_codeseg;
+ self->ci_gdt[GUFS_SEL].sd = pcb->pcb_threadsegs[TSEG_FS];
+ self->ci_gdt[GUGS_SEL].sd = pcb->pcb_threadsegs[TSEG_GS];
lldt(pcb->pcb_ldt_sel);
}
@@ -2297,7 +2299,7 @@ pmap_write_protect(struct pmap *pmap, vaddr_t sva, vaddr_t eva,
md_prot |= PG_u;
else if (va < VM_MAX_ADDRESS)
/* XXX: write-prot our PTES? never! */
- md_prot |= (PG_u | PG_RW);
+ md_prot |= PG_RW;
spte = &ptes[atop(va)];
epte = &ptes[atop(blockend)];
@@ -2576,7 +2578,7 @@ enter_now:
if (va < VM_MAXUSER_ADDRESS)
npte |= PG_u;
else if (va < VM_MAX_ADDRESS)
- npte |= (PG_u | PG_RW); /* XXXCDC: no longer needed? */
+ npte |= PG_RW; /* XXXCDC: no longer needed? */
if (pmap == pmap_kernel())
npte |= pmap_pg_g;
if (flags & VM_PROT_READ)
diff --git a/sys/arch/i386/i386/sys_machdep.c b/sys/arch/i386/i386/sys_machdep.c
index 16a28e3634d..f220dbafdff 100644
--- a/sys/arch/i386/i386/sys_machdep.c
+++ b/sys/arch/i386/i386/sys_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sys_machdep.c,v 1.27 2010/11/20 20:21:13 miod Exp $ */
+/* $OpenBSD: sys_machdep.c,v 1.28 2011/03/12 03:52:26 guenther Exp $ */
/* $NetBSD: sys_machdep.c,v 1.28 1996/05/03 19:42:29 christos Exp $ */
/*-
@@ -72,6 +72,8 @@ extern struct vm_map *kernel_map;
int i386_iopl(struct proc *, void *, register_t *);
int i386_get_ioperm(struct proc *, void *, register_t *);
int i386_set_ioperm(struct proc *, void *, register_t *);
+int i386_get_threadbase(struct proc *, void *, int);
+int i386_set_threadbase(struct proc *, void *, int);
#ifdef USER_LDT
@@ -395,6 +397,41 @@ i386_set_ioperm(struct proc *p, void *args, register_t *retval)
}
int
+i386_get_threadbase(struct proc *p, void *args, int which)
+{
+ struct segment_descriptor *sdp =
+ &p->p_addr->u_pcb.pcb_threadsegs[which];
+ uint32_t base = sdp->sd_hibase << 24 | sdp->sd_lobase;
+
+ return copyout(&base, args, sizeof(base));
+}
+
+int
+i386_set_threadbase(struct proc *p, void *args, int which)
+{
+ int error;
+ uint32_t base;
+ struct segment_descriptor *sdp;
+
+ if ((error = copyin(args, &base, sizeof(base))) != 0)
+ return error;
+
+ /*
+ * We can't place a limit on the segment used by the library
+ * thread register (%gs) because the ELF ABI for i386 places
+ * data structures both before and after base pointer, using
+ * negative offsets for some bits (the static (load-time)
+ * TLS slots) and non-negative for others (the TCB block,
+ * including the pointer to the TLS dynamic thread vector).
+ * Protection must be provided by the paging subsystem.
+ */
+ sdp = &p->p_addr->u_pcb.pcb_threadsegs[which];
+ setsegment(sdp, (void *)base, 0xfffff, SDT_MEMRWA, SEL_UPL, 1, 1);
+ curcpu()->ci_gdt[which == TSEG_FS ? GUFS_SEL : GUGS_SEL].sd = *sdp;
+ return 0;
+}
+
+int
sys_sysarch(struct proc *p, void *v, register_t *retval)
{
struct sys_sysarch_args /* {
@@ -432,6 +469,22 @@ sys_sysarch(struct proc *p, void *v, register_t *retval)
break;
#endif
+ case I386_GET_FSBASE:
+ error = i386_get_threadbase(p, SCARG(uap, parms), TSEG_FS);
+ break;
+
+ case I386_SET_FSBASE:
+ error = i386_set_threadbase(p, SCARG(uap, parms), TSEG_FS);
+ break;
+
+ case I386_GET_GSBASE:
+ error = i386_get_threadbase(p, SCARG(uap, parms), TSEG_GS);
+ break;
+
+ case I386_SET_GSBASE:
+ error = i386_set_threadbase(p, SCARG(uap, parms), TSEG_GS);
+ break;
+
default:
error = EINVAL;
break;
diff --git a/sys/arch/i386/include/pcb.h b/sys/arch/i386/include/pcb.h
index fa3623eafad..66c1b816a63 100644
--- a/sys/arch/i386/include/pcb.h
+++ b/sys/arch/i386/include/pcb.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pcb.h,v 1.14 2007/10/03 07:51:26 kettenis Exp $ */
+/* $OpenBSD: pcb.h,v 1.15 2011/03/12 03:52:26 guenther Exp $ */
/* $NetBSD: pcb.h,v 1.21 1996/01/08 13:51:42 mycroft Exp $ */
/*-
@@ -59,13 +59,13 @@ struct pcb {
#define pcb_ebp pcb_tss.tss_ebp
#define pcb_cs pcb_tss.tss_cs
#define pcb_ldt_sel pcb_tss.tss_ldt
- int pcb_tss_sel;
union descriptor *pcb_ldt; /* per process (user) LDT */
int pcb_ldt_len; /* number of LDT entries */
- int pcb_cr0; /* saved image of CR0 */
- int pcb_pad[2]; /* savefpu on 16-byte boundary */
union savefpu pcb_savefpu; /* floating point state for FPU */
+ int pcb_cr0; /* saved image of CR0 */
struct emcsts pcb_saveemc; /* Cyrix EMC state */
+ struct segment_descriptor pcb_threadsegs[2];
+ /* per-thread descriptors */
/*
* Software pcb (extension)
*/
@@ -81,6 +81,10 @@ struct pcb {
#define PCB_SAVECTX 0x00000001
};
+/* the indexes of the %fs/%gs segments in pcb_threadsegs */
+#define TSEG_FS 0
+#define TSEG_GS 1
+
/*
* The pcb is augmented with machine-dependent additional data for
* core dumps. For the i386, there is nothing to add.
diff --git a/sys/arch/i386/include/segments.h b/sys/arch/i386/include/segments.h
index a6932a4e0fd..1a56a1887e2 100644
--- a/sys/arch/i386/include/segments.h
+++ b/sys/arch/i386/include/segments.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: segments.h,v 1.18 2010/12/24 20:26:30 tedu Exp $ */
+/* $OpenBSD: segments.h,v 1.19 2011/03/12 03:52:26 guenther Exp $ */
/* $NetBSD: segments.h,v 1.23 1996/02/01 22:31:03 mycroft Exp $ */
/*-
@@ -215,15 +215,16 @@ void idt_vec_free(int);
#define GCODE_SEL 1 /* Kernel code descriptor */
#define GDATA_SEL 2 /* Kernel data descriptor */
#define GLDT_SEL 3 /* Default LDT descriptor */
-#define GUCODE1_SEL 4 /* User code descriptor */
+#define GCPU_SEL 4 /* per-CPU segment */
#define GUCODE_SEL 5 /* User code descriptor (a stack short) */
#define GUDATA_SEL 6 /* User data descriptor */
#define GAPM32CODE_SEL 7 /* 32 bit APM code descriptor */
#define GAPM16CODE_SEL 8 /* 16 bit APM code descriptor */
#define GAPMDATA_SEL 9 /* APM data descriptor */
#define GICODE_SEL 10 /* Interrupt code descriptor (same as Kernel code) */
-#define GCPU_SEL 11 /* per-CPU segment */
-#define NGDT 12
+#define GUFS_SEL 11 /* User per-thread (%fs) descriptor */
+#define GUGS_SEL 12 /* User per-thread (%gs) descriptor */
+#define NGDT 13
/*
* Entries in the Local Descriptor Table (LDT)
diff --git a/sys/arch/i386/include/sysarch.h b/sys/arch/i386/include/sysarch.h
index cae749a2b53..1115026c63d 100644
--- a/sys/arch/i386/include/sysarch.h
+++ b/sys/arch/i386/include/sysarch.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sysarch.h,v 1.5 2004/09/15 18:46:50 deraadt Exp $ */
+/* $OpenBSD: sysarch.h,v 1.6 2011/03/12 03:52:26 guenther Exp $ */
/* $NetBSD: sysarch.h,v 1.8 1996/01/08 13:51:44 mycroft Exp $ */
#ifndef _I386_SYSARCH_H_
@@ -13,6 +13,10 @@
#define I386_GET_IOPERM 3
#define I386_SET_IOPERM 4
#define I386_VM86 5
+#define I386_GET_FSBASE 6
+#define I386_SET_FSBASE 7
+#define I386_GET_GSBASE 8
+#define I386_SET_GSBASE 9
struct i386_get_ldt_args {
int start;
@@ -44,6 +48,10 @@ int i386_set_ldt(int, union descriptor *, int);
int i386_iopl(int);
int i386_get_ioperm(u_long *);
int i386_set_ioperm(u_long *);
+int i386_get_fsbase(void **);
+int i386_set_fsbase(void *);
+int i386_get_gsbase(void **);
+int i386_set_gsbase(void *);
int sysarch(int, void *);
#endif