summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/i386/i386/freebsd_machdep.c4
-rw-r--r--sys/arch/i386/i386/linux_machdep.c4
-rw-r--r--sys/arch/i386/i386/machdep.c6
-rw-r--r--sys/arch/i386/i386/pmap.c85
-rw-r--r--sys/arch/i386/i386/svr4_machdep.c4
-rw-r--r--sys/arch/i386/i386/trap.c17
-rw-r--r--sys/arch/i386/include/pmap.h21
7 files changed, 91 insertions, 50 deletions
diff --git a/sys/arch/i386/i386/freebsd_machdep.c b/sys/arch/i386/i386/freebsd_machdep.c
index 58f605738a8..0923b38ee98 100644
--- a/sys/arch/i386/i386/freebsd_machdep.c
+++ b/sys/arch/i386/i386/freebsd_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: freebsd_machdep.c,v 1.15 2003/05/04 05:01:04 drahn Exp $ */
+/* $OpenBSD: freebsd_machdep.c,v 1.16 2003/05/13 03:49:04 art Exp $ */
/* $NetBSD: freebsd_machdep.c,v 1.10 1996/05/03 19:42:05 christos Exp $ */
/*-
@@ -161,7 +161,7 @@ freebsd_sendsig(catcher, sig, mask, code, type, val)
tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_eip = p->p_sigcode;
- tf->tf_cs = pmap->pm_nxpages > 0?
+ tf->tf_cs = pmap->pm_hiexec > I386_MAX_EXE_ADDR ?
GSEL(GUCODE1_SEL, SEL_UPL) : GSEL(GUCODE_SEL, SEL_UPL);
tf->tf_eflags &= ~(PSL_T|PSL_VM|PSL_AC);
tf->tf_esp = (int)fp;
diff --git a/sys/arch/i386/i386/linux_machdep.c b/sys/arch/i386/i386/linux_machdep.c
index 366b51bb92a..865767cec23 100644
--- a/sys/arch/i386/i386/linux_machdep.c
+++ b/sys/arch/i386/i386/linux_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: linux_machdep.c,v 1.27 2003/05/04 05:01:04 drahn Exp $ */
+/* $OpenBSD: linux_machdep.c,v 1.28 2003/05/13 03:49:04 art Exp $ */
/* $NetBSD: linux_machdep.c,v 1.29 1996/05/03 19:42:11 christos Exp $ */
/*
@@ -185,7 +185,7 @@ linux_sendsig(catcher, sig, mask, code, type, val)
tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_eip = p->p_sigcode;
- tf->tf_cs = pmap->pm_nxpages > 0?
+ tf->tf_cs = pmap->pm_hiexec > I386_MAX_EXE_ADDR ?
GSEL(GUCODE1_SEL, SEL_UPL) : GSEL(GUCODE_SEL, SEL_UPL);
tf->tf_eflags &= ~(PSL_T|PSL_VM|PSL_AC);
tf->tf_esp = (int)fp;
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c
index 02b1d8453f1..58807149298 100644
--- a/sys/arch/i386/i386/machdep.c
+++ b/sys/arch/i386/i386/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.228 2003/05/05 17:54:59 drahn Exp $ */
+/* $OpenBSD: machdep.c,v 1.229 2003/05/13 03:49:04 art Exp $ */
/* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */
/*-
@@ -1674,7 +1674,7 @@ sendsig(catcher, sig, mask, code, type, val)
tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_eip = p->p_sigcode;
- tf->tf_cs = pmap->pm_nxpages > 0?
+ tf->tf_cs = pmap->pm_hiexec > I386_MAX_EXE_ADDR ?
GSEL(GUCODE1_SEL, SEL_UPL) : GSEL(GUCODE_SEL, SEL_UPL);
tf->tf_eflags &= ~(PSL_T|PSL_VM|PSL_AC);
tf->tf_esp = (int)fp;
@@ -2078,7 +2078,7 @@ setregs(p, pack, stack, retval)
tf->tf_ebp = 0;
tf->tf_ebx = (int)PS_STRINGS;
tf->tf_eip = pack->ep_entry;
- tf->tf_cs = pmap->pm_nxpages > 0?
+ tf->tf_cs = pmap->pm_hiexec > I386_MAX_EXE_ADDR ?
LSEL(LUCODE1_SEL, SEL_UPL) : LSEL(LUCODE_SEL, SEL_UPL);
tf->tf_eflags = PSL_USERSET;
tf->tf_esp = stack;
diff --git a/sys/arch/i386/i386/pmap.c b/sys/arch/i386/i386/pmap.c
index ad1e141b4eb..a6f02c0b7b0 100644
--- a/sys/arch/i386/i386/pmap.c
+++ b/sys/arch/i386/i386/pmap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pmap.c,v 1.71 2003/05/09 23:51:23 art Exp $ */
+/* $OpenBSD: pmap.c,v 1.72 2003/05/13 03:49:04 art Exp $ */
/* $NetBSD: pmap.c,v 1.91 2000/06/02 17:46:37 thorpej Exp $ */
/*
@@ -572,31 +572,67 @@ pmap_unmap_ptes(pmap)
}
__inline static void
-pmap_nxstack_account(struct pmap *pmap, vaddr_t va,
+pmap_exec_account(struct pmap *pm, vaddr_t va,
pt_entry_t opte, pt_entry_t npte)
{
- if (((opte ^ npte) & PG_X) &&
- va < VM_MAXUSER_ADDRESS && va >= I386_MAX_EXE_ADDR) {
+ if (curproc == NULL || curproc->p_vmspace == NULL ||
+ pm != vm_map_pmap(&curproc->p_vmspace->vm_map))
+ return;
+
+ if ((opte ^ npte) & PG_X)
+ pmap_update_pg(va);
+
+ /*
+ * Executability was removed on the last executable change.
+ * Reset the code segment to something conservative and
+ * let the trap handler deal with setting the right limit.
+ * We can't do that because of locking constraints on the vm map.
+ *
+ * XXX - floating cs - set this _really_ low.
+ */
+ if ((opte & PG_X) && (npte & PG_X) == 0 && va == pm->pm_hiexec) {
struct trapframe *tf = curproc->p_md.md_regs;
- struct vm_map *map = &curproc->p_vmspace->vm_map;
struct pcb *pcb = &curproc->p_addr->u_pcb;
- if (npte & PG_X && !(opte & PG_X)) {
- if (++pmap->pm_nxpages == 1 &&
- pmap == vm_map_pmap(map)) {
- pcb->pcb_cs = tf->tf_cs =
- GSEL(GUCODE1_SEL, SEL_UPL);
- pmap_update_pg(va);
- }
- } else {
- if (!--pmap->pm_nxpages &&
- pmap == vm_map_pmap(map)) {
- pcb->pcb_cs = tf->tf_cs =
- GSEL(GUCODE_SEL, SEL_UPL);
- pmap_update_pg(va);
- }
- }
+ pcb->pcb_cs = tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL);
+ pm->pm_hiexec = I386_MAX_EXE_ADDR;
+ }
+}
+
+/*
+ * Fixup the code segment to cover all potential executable mappings.
+ * returns 0 if no changes to the code segment were made.
+ */
+int
+pmap_exec_fixup(struct vm_map *map, struct trapframe *tf, struct pcb *pcb)
+{
+ struct vm_map_entry *ent;
+ struct pmap *pm = vm_map_pmap(map);
+ vaddr_t va = 0;
+
+ vm_map_lock(map);
+ for (ent = (&map->header)->next; ent != &map->header; ent = ent->next) {
+ /*
+ * This entry has greater va than the entries before.
+ * We need to make it point to the last page, not past it.
+ */
+ if (ent->protection & VM_PROT_EXECUTE)
+ va = trunc_page(ent->end) - PAGE_SIZE;
+ }
+ vm_map_unlock(map);
+
+ if (va == pm->pm_hiexec)
+ return (0);
+
+ pm->pm_hiexec = va;
+
+ if (pm->pm_hiexec > (vaddr_t)I386_MAX_EXE_ADDR) {
+ pcb->pcb_cs = tf->tf_cs = GSEL(GUCODE1_SEL, SEL_UPL);
+ } else {
+ pcb->pcb_cs = tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL);
}
+
+ return (1);
}
/*
@@ -1728,7 +1764,7 @@ pmap_pinit(pmap)
pmap->pm_stats.wired_count = 0;
pmap->pm_stats.resident_count = 1; /* count the PDP allocd below */
pmap->pm_ptphint = NULL;
- pmap->pm_nxpages = 0;
+ pmap->pm_hiexec = 0;
pmap->pm_flags = 0;
/* allocate PDP */
@@ -2243,7 +2279,7 @@ pmap_remove_pte(pmap, ptp, pte, va)
opte = *pte; /* save the old PTE */
*pte = 0; /* zap! */
- pmap_nxstack_account(pmap, va, opte, 0);
+ pmap_exec_account(pmap, va, opte, 0);
if (opte & PG_W)
pmap->pm_stats.wired_count--;
@@ -2828,8 +2864,7 @@ pmap_write_protect(pmap, sva, eva, prot)
npte = (*spte & ~PG_PROT) | md_prot;
if (npte != *spte) {
- /* account for executable pages on the stack */
- pmap_nxstack_account(pmap, sva, *spte, npte);
+ pmap_exec_account(pmap, sva, *spte, npte);
*spte = npte; /* zap! */
@@ -3125,7 +3160,7 @@ enter_now:
*/
npte = pa | protection_codes[prot] | PG_V;
- pmap_nxstack_account(pmap, va, opte, npte);
+ pmap_exec_account(pmap, va, opte, npte);
if (pvh)
npte |= PG_PVLIST;
if (wired)
diff --git a/sys/arch/i386/i386/svr4_machdep.c b/sys/arch/i386/i386/svr4_machdep.c
index 27f5aa6f109..b50246f2108 100644
--- a/sys/arch/i386/i386/svr4_machdep.c
+++ b/sys/arch/i386/i386/svr4_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: svr4_machdep.c,v 1.19 2003/05/04 05:01:04 drahn Exp $ */
+/* $OpenBSD: svr4_machdep.c,v 1.20 2003/05/13 03:49:04 art Exp $ */
/* $NetBSD: svr4_machdep.c,v 1.24 1996/05/03 19:42:26 christos Exp $ */
/*
@@ -379,7 +379,7 @@ svr4_sendsig(catcher, sig, mask, code, type, val)
tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_eip = p->p_sigcode;
- tf->tf_cs = pmap->pm_nxpages > 0?
+ tf->tf_cs = pmap->pm_hiexec > I386_MAX_EXE_ADDR ?
GSEL(GUCODE1_SEL, SEL_UPL) : GSEL(GUCODE_SEL, SEL_UPL);
tf->tf_eflags &= ~(PSL_T|PSL_VM|PSL_AC);
tf->tf_esp = (int)fp;
diff --git a/sys/arch/i386/i386/trap.c b/sys/arch/i386/i386/trap.c
index fc54a2430c0..fb730187ae7 100644
--- a/sys/arch/i386/i386/trap.c
+++ b/sys/arch/i386/i386/trap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.56 2003/05/04 15:56:34 mickey Exp $ */
+/* $OpenBSD: trap.c,v 1.57 2003/05/13 03:49:04 art Exp $ */
/* $NetBSD: trap.c,v 1.95 1996/05/05 06:50:02 mycroft Exp $ */
/*-
@@ -325,12 +325,14 @@ trap(frame)
goto out;
}
#endif
- if (ftype == VM_PROT_READ) {
- ftype |= VM_PROT_EXECUTE;
- /* XXX force %cr2 register have fault address */
- __asm __volatile("movl %0,%%cr2" :: "r" (frame.tf_eip));
- }
- goto page_fault;
+ /* If pmap_exec_fixup does something, let's retry the trap. */
+ if (pmap_exec_fixup(&p->p_vmspace->vm_map, &frame,
+ &p->p_addr->u_pcb))
+ goto out;
+
+ sv.sival_int = frame.tf_eip;
+ trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv);
+ goto out;
case T_TSSFLT|T_USER:
sv.sival_int = frame.tf_eip;
@@ -414,7 +416,6 @@ trap(frame)
goto we_re_toast;
#endif
/* FALLTHROUGH */
- page_fault:
case T_PAGEFLT|T_USER: { /* page fault */
vaddr_t va, fa;
struct vmspace *vm = p->p_vmspace;
diff --git a/sys/arch/i386/include/pmap.h b/sys/arch/i386/include/pmap.h
index 8e086787f4f..cc806191c88 100644
--- a/sys/arch/i386/include/pmap.h
+++ b/sys/arch/i386/include/pmap.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pmap.h,v 1.31 2003/04/09 07:53:57 niklas Exp $ */
+/* $OpenBSD: pmap.h,v 1.32 2003/05/13 03:49:04 art Exp $ */
/* $NetBSD: pmap.h,v 1.44 2000/04/24 17:18:18 thorpej Exp $ */
/*
@@ -266,7 +266,7 @@ struct pmap {
struct vm_page *pm_ptphint; /* pointer to a PTP in our pmap */
struct pmap_statistics pm_stats; /* pmap stats (lck by object lock) */
- int pm_nxpages; /* # of executable pages on stack */
+ vaddr_t pm_hiexec; /* highest executable mapping */
int pm_flags; /* see below */
union descriptor *pm_ldt; /* user-set LDT */
@@ -387,6 +387,8 @@ static void pmap_update_pg(vaddr_t);
static void pmap_update_2pg(vaddr_t,vaddr_t);
void pmap_write_protect(struct pmap *, vaddr_t,
vaddr_t, vm_prot_t);
+int pmap_exec_fixup(struct vm_map *, struct trapframe *,
+ struct pcb *);
vaddr_t reserve_dumppages(vaddr_t); /* XXX: not a pmap fn */
@@ -475,12 +477,15 @@ pmap_protect(pmap, sva, eva, prot)
vaddr_t sva, eva;
vm_prot_t prot;
{
- if ((prot & VM_PROT_WRITE) == 0) {
- if (prot & (VM_PROT_READ|VM_PROT_EXECUTE)) {
- pmap_write_protect(pmap, sva, eva, prot);
- } else {
- pmap_remove(pmap, sva, eva);
- }
+ if ((prot & (VM_PROT_WRITE|VM_PROT_EXECUTE)) ==
+ (VM_PROT_WRITE|VM_PROT_EXECUTE))
+ return;
+
+ if ((prot & (VM_PROT_READ|VM_PROT_EXECUTE)) ==
+ (VM_PROT_READ|VM_PROT_EXECUTE)) {
+ pmap_write_protect(pmap, sva, eva, prot);
+ } else {
+ pmap_remove(pmap, sva, eva);
}
}