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:
parent
4de0ea44a5
commit
69aa2aa9e8
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue