summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2017-01-11 13:00:50 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2017-01-11 13:00:50 +0000
commit294cb8250b3fe23e8e14d0cd6f225d6dca7fac29 (patch)
treeb933c767b3f4217f6ed335b13a14545efc520d0b
parentf737ce8d8b25116c258728b727af49ba44660ca4 (diff)
A data abort caused by an execution access fault should propagate its
fault as execution fault. This is especially needed as in comparison to ARMv7 we can have execute-only user pages on ARMv8. This means that there is a distinction between executing and reading pages, which we did not have before. We need to treat PROT_EXEC separate but similar to PROT_READ. Additionally, use pte_insert() to manage a page's pagetable entry instead of manually accessing and modifying the pagetable.
-rw-r--r--sys/arch/arm64/arm64/pmap.c44
-rw-r--r--sys/arch/arm64/arm64/trap.c4
2 files changed, 23 insertions, 25 deletions
diff --git a/sys/arch/arm64/arm64/pmap.c b/sys/arch/arm64/arm64/pmap.c
index 93636c4c956..7b82671110a 100644
--- a/sys/arch/arm64/arm64/pmap.c
+++ b/sys/arch/arm64/arm64/pmap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pmap.c,v 1.4 2017/01/11 09:32:31 patrick Exp $ */
+/* $OpenBSD: pmap.c,v 1.5 2017/01/11 13:00:49 patrick Exp $ */
/*
* Copyright (c) 2008-2009,2014-2016 Dale Rahn <drahn@dalerahn.com>
*
@@ -573,7 +573,7 @@ pmap_enter(pmap_t pm, vaddr_t va, paddr_t pa, vm_prot_t prot, int flags)
* Insert into table, if this mapping said it needed to be mapped
* now.
*/
- if (flags & (PROT_READ|PROT_WRITE|PMAP_WIRED)) {
+ if (flags & (PROT_READ|PROT_WRITE|PROT_EXEC|PMAP_WIRED)) {
pte_insert(pted);
}
@@ -841,7 +841,7 @@ pmap_fill_pte(pmap_t pm, vaddr_t va, paddr_t pa, struct pte_desc *pted,
}
pted->pted_pte = pa & PTE_RPGN;
- pted->pted_pte |= (flags & (PROT_READ|PROT_WRITE)) | (prot & PROT_EXEC);
+ pted->pted_pte |= flags & (PROT_READ|PROT_WRITE|PROT_EXEC);
}
@@ -1810,18 +1810,17 @@ int pmap_fault_fixup(pmap_t pm, vaddr_t va, vm_prot_t ftype, int user)
(pted->pted_va & PROT_WRITE)) { /* but is supposedly allowed */
/*
- * Page modified emulation. A write always
- * includes a reference.
+ * Page modified emulation. A write always includes
+ * a reference. This means that we can enable read and
+ * exec as well, akin to the page reference emulation.
*/
pg->pg_flags |= PG_PMAP_MOD;
pg->pg_flags |= PG_PMAP_REF;
- /* Thus, enable read and write. */
- pted->pted_pte |= (pted->pted_va & (PROT_READ|PROT_WRITE));
-
- pted->pted_pte |= PROT_WRITE;
- *pl3 &= ~ATTR_AP(2);
- *pl3 |= ATTR_AF;
+ /* Thus, enable read, write and exec. */
+ pted->pted_pte |=
+ (pted->pted_va & (PROT_READ|PROT_WRITE|PROT_EXEC));
+ pte_insert(pted);
/* Flush tlb. */
ttlb_flush(pm, va & PTE_RPGN);
@@ -1832,18 +1831,15 @@ int pmap_fault_fixup(pmap_t pm, vaddr_t va, vm_prot_t ftype, int user)
(pted->pted_va & PROT_EXEC)) { /* but is supposedly allowed */
/*
- * Exec always includes a read/reference.
+ * Exec always includes a reference. Since we now know
+ * the page has been accesed, we can enable read as well
+ * if UVM allows it.
*/
pg->pg_flags |= PG_PMAP_REF;
/* Thus, enable read and exec. */
pted->pted_pte |= (pted->pted_va & (PROT_READ|PROT_EXEC));
- if (pted->pted_pmap == pmap_kernel()) {
- *pl3 &= ~ATTR_PXN;
- } else {
- *pl3 &= ~ATTR_UXN;
- }
- *pl3 |= ATTR_AF;
+ pte_insert(pted);
/* Flush tlb. */
ttlb_flush(pm, va & PTE_RPGN);
@@ -1854,13 +1850,15 @@ int pmap_fault_fixup(pmap_t pm, vaddr_t va, vm_prot_t ftype, int user)
(pted->pted_va & PROT_READ)) { /* but is supposedly allowed */
/*
- * Page referenced emulation.
+ * Page referenced emulation. Since we now know the page
+ * has been accessed, we can enable exec as well if UVM
+ * allows it.
*/
pg->pg_flags |= PG_PMAP_REF;
- /* Thus, enable read. */
- pted->pted_pte |= (pted->pted_va & PROT_READ);
- *pl3 |= ATTR_AF;
+ /* Thus, enable read and exec. */
+ pted->pted_pte |= (pted->pted_va & (PROT_READ|PROT_EXEC));
+ pte_insert(pted);
/* Flush tlb. */
ttlb_flush(pm, pted->pted_va & PTE_RPGN);
@@ -1990,7 +1988,7 @@ int pmap_clear_reference(struct vm_page *pg)
pted->pted_pte &= ~PROT_MASK;
*pl3 |= ATTR_AP(2); // turns of write as well !?!?
*pl3 &= ~ATTR_AF;
- pted->pted_pte &= ~PROT_WRITE|PROT_READ;
+ pted->pted_pte &= ~PROT_WRITE|PROT_READ|PROT_EXEC;
ttlb_flush(pted->pted_pmap, pted->pted_va & PTE_RPGN);
}
diff --git a/sys/arch/arm64/arm64/trap.c b/sys/arch/arm64/arm64/trap.c
index 306e5854f5e..f31d155ee6c 100644
--- a/sys/arch/arm64/arm64/trap.c
+++ b/sys/arch/arm64/arm64/trap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.3 2016/12/26 21:30:10 jca Exp $ */
+/* $OpenBSD: trap.c,v 1.4 2017/01/11 13:00:49 patrick Exp $ */
/*-
* Copyright (c) 2014 Andrew Turner
* All rights reserved.
@@ -166,7 +166,7 @@ data_abort(struct trapframe *frame, uint64_t esr, int lower, int exe)
va = trunc_page(far);
if (exe)
- access_type = PROT_READ;
+ access_type = PROT_EXEC;
else
access_type = ((esr >> 6) & 1) ? PROT_WRITE : PROT_READ;