Optionally include saving and restoring the 64bit %gs and %fs base register

values in the PCB. Do this in pmap_activate for now (XXX not a good place
for it, but a convenient one).
This commit is contained in:
fvdl 2005-05-15 21:37:46 +00:00
parent 4de0ea44a5
commit 69aa2aa9e8
6 changed files with 147 additions and 29 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: machdep.c,v 1.33 2005/04/25 15:02:02 lukem Exp $ */
/* $NetBSD: machdep.c,v 1.34 2005/05/15 21:37:46 fvdl Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998, 2000 The NetBSD Foundation, Inc.
@ -72,7 +72,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.33 2005/04/25 15:02:02 lukem Exp $");
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.34 2005/05/15 21:37:46 fvdl Exp $");
#include "opt_user_ldt.h"
#include "opt_ddb.h"
@ -1669,7 +1669,7 @@ cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
int64_t rflags;
if ((flags & _UC_CPU) != 0) {
error = check_mcontext(mcp, tf);
error = check_mcontext(l, mcp, tf);
if (error != 0)
return error;
/*
@ -1703,35 +1703,64 @@ cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
}
int
check_mcontext(const mcontext_t *mcp, struct trapframe *tf)
check_mcontext(struct lwp *l, const mcontext_t *mcp, struct trapframe *tf)
{
const __greg_t *gr;
uint16_t sel;
int error;
struct pmap *pmap = l->l_proc->p_vmspace->vm_map.pmap;
gr = mcp->__gregs;
if (((gr[_REG_RFL] ^ tf->tf_rflags) & PSL_USERSTATIC) != 0)
return EINVAL;
sel = gr[_REG_ES] & 0xffff;
if (sel != 0 && !VALID_USER_DSEL(sel))
return EINVAL;
if (__predict_false((pmap->pm_flags & PMF_USER_LDT) != 0)) {
error = valid_user_selector(l, gr[_REG_ES], NULL, 0);
if (error != 0)
return error;
sel = gr[_REG_FS] & 0xffff;
if (sel != 0 && !VALID_USER_DSEL(sel))
return EINVAL;
error = valid_user_selector(l, gr[_REG_FS], NULL, 0);
if (error != 0)
return error;
sel = gr[_REG_GS] & 0xffff;
if (sel != 0 && !VALID_USER_DSEL(sel))
return EINVAL;
error = valid_user_selector(l, gr[_REG_GS], NULL, 0);
if (error != 0)
return error;
sel = gr[_REG_DS] & 0xffff;
if (!VALID_USER_DSEL(sel))
return EINVAL;
if ((gr[_REG_DS] & 0xffff) == 0)
return EINVAL;
error = valid_user_selector(l, gr[_REG_DS], NULL, 0);
if (error != 0)
return error;
sel = gr[_REG_SS] & 0xffff;
if (!VALID_USER_DSEL(sel))
return EINVAL;
if ((gr[_REG_SS] & 0xffff) == 0)
return EINVAL;
error = valid_user_selector(l, gr[_REG_SS], NULL, 0);
if (error != 0)
return error;
} else {
sel = gr[_REG_ES] & 0xffff;
if (sel != 0 && !VALID_USER_DSEL(sel))
return EINVAL;
sel = gr[_REG_FS] & 0xffff;
if (sel != 0 && !VALID_USER_DSEL(sel))
return EINVAL;
sel = gr[_REG_GS] & 0xffff;
if (sel != 0 && !VALID_USER_DSEL(sel))
return EINVAL;
sel = gr[_REG_DS] & 0xffff;
if (!VALID_USER_DSEL(sel))
return EINVAL;
sel = gr[_REG_SS] & 0xffff;
if (!VALID_USER_DSEL(sel))
return EINVAL;
}
sel = gr[_REG_CS] & 0xffff;
if (!VALID_USER_CSEL(sel))
@ -1806,6 +1835,70 @@ idt_vec_free(vec)
simple_unlock(&idt_lock);
}
int
memseg_baseaddr(struct lwp *l, uint64_t seg, char *ldtp, int llen,
uint64_t *addr)
{
int off, len;
char *dt;
struct mem_segment_descriptor *sdp;
struct proc *p = l->l_proc;
struct pmap *pmap= p->p_vmspace->vm_map.pmap;
uint64_t base;
seg &= 0xffff;
if (seg == 0) {
if (addr != NULL)
*addr = 0;
return 0;
}
off = (seg & 0xfff8);
if (seg & SEL_LDT) {
if (ldtp != NULL) {
dt = ldtp;
len = llen;
} else if (pmap->pm_flags & PMF_USER_LDT) {
len = pmap->pm_ldt_len;
dt = (char *)pmap->pm_ldt;
} else {
dt = ldtstore;
len = LDT_SIZE;
}
if (off > (len - 8))
return EINVAL;
} else {
if (seg != GUDATA_SEL || seg != GUDATA32_SEL)
return EINVAL;
}
sdp = (struct mem_segment_descriptor *)(dt + off);
if (sdp->sd_type < SDT_MEMRO || sdp->sd_p == 0)
return EINVAL;
base = ((uint64_t)sdp->sd_hibase << 32) | ((uint64_t)sdp->sd_lobase);
if (sdp->sd_gran == 1)
base <<= PAGE_SHIFT;
if (base >= VM_MAXUSER_ADDRESS)
return EINVAL;
if (addr == NULL)
return 0;
*addr = base;
return 0;
}
int
valid_user_selector(struct lwp *l, uint64_t seg, char *ldtp, int len)
{
return memseg_baseaddr(l, seg, ldtp, len, NULL);
}
/*
* Number of processes is limited by number of available GDT slots.
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: pmap.c,v 1.16 2005/04/01 11:59:23 yamt Exp $ */
/* $NetBSD: pmap.c,v 1.17 2005/05/15 21:37:46 fvdl Exp $ */
/*
*
@ -108,7 +108,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.16 2005/04/01 11:59:23 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.17 2005/05/15 21:37:46 fvdl Exp $");
#ifndef __x86_64__
#include "opt_cputype.h"
@ -2051,7 +2051,8 @@ pmap_fork(pmap1, pmap2)
size_t len;
len = pmap1->pm_ldt_len;
new_ldt = (char *)uvm_km_alloc(kernel_map, len, UVM_KMF_WIRED);
new_ldt = (char *)uvm_km_alloc(kernel_map, len, 0,
UVM_KMF_WIRED);
memcpy(new_ldt, pmap1->pm_ldt, len);
pmap2->pm_ldt = new_ldt;
pmap2->pm_ldt_len = pmap1->pm_ldt_len;
@ -2128,6 +2129,10 @@ pmap_activate(l)
*/
x86_atomic_setbits_ul(&pmap->pm_cpus, (1U << cpu_number()));
}
if (pcb->pcb_flags & PCB_GS64)
wrmsr(MSR_KERNELGSBASE, pcb->pcb_gs);
if (pcb->pcb_flags & PCB_GS64)
wrmsr(MSR_FSBASE, pcb->pcb_fs);
}
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: process_machdep.c,v 1.4 2003/11/30 12:59:30 fvdl Exp $ */
/* $NetBSD: process_machdep.c,v 1.5 2005/05/15 21:37:46 fvdl Exp $ */
/*-
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@ -60,7 +60,7 @@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.4 2003/11/30 12:59:30 fvdl Exp $");
__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.5 2005/05/15 21:37:46 fvdl Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -161,7 +161,7 @@ process_write_regs(l, regp)
* Note that struct regs is compatible with
* the __gregs array in mcontext_t.
*/
error = check_mcontext((mcontext_t *)regs, tf);
error = check_mcontext(l, (mcontext_t *)regs, tf);
if (error != 0)
return error;

View File

@ -1,4 +1,4 @@
/* $NetBSD: mcontext.h,v 1.5 2004/10/21 16:49:47 fvdl Exp $ */
/* $NetBSD: mcontext.h,v 1.6 2005/05/15 21:37:46 fvdl Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@ -151,7 +151,8 @@ typedef struct {
#define _UC_MACHINE_PAD32 5
struct trapframe;
int check_mcontext(const mcontext_t *, struct trapframe *);
struct lwp;
int check_mcontext(struct lwp *, const mcontext_t *, struct trapframe *);
#endif /* _KERNEL */

View File

@ -1,4 +1,4 @@
/* $NetBSD: pcb.h,v 1.2 2003/08/07 16:26:36 agc Exp $ */
/* $NetBSD: pcb.h,v 1.3 2005/05/15 21:37:46 fvdl Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -109,10 +109,14 @@ struct pcb {
int pcb_cr0; /* saved image of CR0 */
int pcb_flags;
#define PCB_USER_LDT 0x01 /* has user-set LDT */
#define PCB_GS64 0x02
#define PCB_FS64 0x04
caddr_t pcb_onfault; /* copyin/out fault recovery */
struct cpu_info *pcb_fpcpu; /* cpu holding our fp state. */
unsigned pcb_iomap[NIOPORTS/32]; /* I/O bitmap */
struct pmap *pcb_pmap; /* back pointer to our pmap */
uint64_t pcb_gs;
uint64_t pcb_fs;
};
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: segments.h,v 1.4 2004/02/13 11:36:20 wiz Exp $ */
/* $NetBSD: segments.h,v 1.5 2005/05/15 21:37:46 fvdl Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
@ -162,6 +162,16 @@ struct mem_segment_descriptor {
unsigned sd_hibase:8; /* segment base address (msb) */
} __attribute__((packed));
/*
* Common part of the above structures. Used to walk descriptor tables.
*/
struct common_segment_descriptor {
unsigned sdc_lolimit:16;
unsigned sdc_lobase:24;
unsigned sdc_type:5;
unsigned sdc_other:19;
} __attribute__((packed));
/*
* Gate descriptors (e.g. indirect descriptors)
*/
@ -207,6 +217,11 @@ void idt_vec_set __P((int, void (*)(void)));
void idt_vec_free __P((int));
void cpu_init_idt __P((void));
struct lwp;
int memseg_baseaddr(struct lwp *, uint64_t, char *, int, uint64_t *);
int valid_user_selector(struct lwp *, uint64_t, char *, int);
#endif /* _KERNEL */
#endif /* !_LOCORE */