summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2016-08-24 13:09:53 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2016-08-24 13:09:53 +0000
commit81a250269621f2dc44c4c16e6f887063bd0be941 (patch)
tree8e7bb7625af74be79e784bd0941afd0bf07c3f54 /sys
parentf2af420bab206415820fe965a32fc7b0c8970fdf (diff)
Replace pmap_fault_fixup() with an access flag fault handler on armv7.
ok tom@
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/arm/arm/fault.c22
-rw-r--r--sys/arch/arm/arm/pmap7.c145
-rw-r--r--sys/arch/arm/include/armreg.h6
3 files changed, 54 insertions, 119 deletions
diff --git a/sys/arch/arm/arm/fault.c b/sys/arch/arm/arm/fault.c
index 0cb36aea8f2..a2b48069ed1 100644
--- a/sys/arch/arm/arm/fault.c
+++ b/sys/arch/arm/arm/fault.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fault.c,v 1.22 2016/08/19 19:07:37 kettenis Exp $ */
+/* $OpenBSD: fault.c,v 1.23 2016/08/24 13:09:52 kettenis Exp $ */
/* $NetBSD: fault.c,v 1.46 2004/01/21 15:39:21 skrll Exp $ */
/*
@@ -131,6 +131,8 @@ static int dab_align(trapframe_t *, u_int, u_int, struct proc *,
struct sigdata *sd);
static int dab_buserr(trapframe_t *, u_int, u_int, struct proc *,
struct sigdata *sd);
+extern int dab_access(trapframe_t *, u_int, u_int, struct proc *,
+ struct sigdata *sd);
static const struct data_abort data_aborts[] = {
#ifndef CPU_ARMv7
@@ -154,10 +156,10 @@ static const struct data_abort data_aborts[] = {
{dab_fatal, "V7 fault 00000"},
{dab_align, "Alignment fault"},
{dab_fatal, "Debug event"},
- {NULL, "Access flag fault (L1)"},
+ {dab_fatal, "Access flag fault (L1)"},
{dab_buserr, "Fault on instruction cache maintenance"},
{NULL, "Translation fault (L1)"},
- {NULL, "Access flag fault (L2)"},
+ {dab_access, "Access flag fault (L2)"},
{NULL, "Translation fault (L2)"},
{dab_buserr, "Synchronous external abort"},
{NULL, "Domain fault (L1)"},
@@ -361,6 +363,7 @@ data_abort_handler(trapframe_t *tf)
ftype = fsr & FAULT_WNR ? PROT_WRITE : PROT_READ;
#endif
+#ifndef CPU_ARMv7
/*
* See if the fault is as a result of ref/mod emulation,
* or domain mismatch.
@@ -375,6 +378,7 @@ data_abort_handler(trapframe_t *tf)
#endif
goto out;
}
+#endif
if (__predict_false(curcpu()->ci_idepth > 0)) {
if (pcb->pcb_onfault) {
@@ -668,8 +672,16 @@ prefetch_abort_handler(trapframe_t *tf)
if (__predict_true((tf->tf_spsr & PSR_I) == 0))
enable_interrupts(PSR_I);
- /* Get fault address */
p = curproc;
+
+#ifdef CPU_ARMv7
+ /* Invoke access fault handler if appropriate */
+ if (FAULT_TYPE_V7(fsr) == FAULT_ACCESS_2) {
+ dab_access(tf, fsr, far, p, NULL);
+ goto out;
+ }
+#endif
+
p->p_addr->u_pcb.pcb_tf = tf;
/* Ok validate the address, can only execute in USER space */
@@ -683,6 +695,7 @@ prefetch_abort_handler(trapframe_t *tf)
map = &p->p_vmspace->vm_map;
va = trunc_page(far);
+#ifndef CPU_ARMv7
/*
* See if the pmap can handle this fault on its own...
*/
@@ -691,6 +704,7 @@ prefetch_abort_handler(trapframe_t *tf)
#endif
if (pmap_fault_fixup(map->pmap, va, PROT_READ | PROT_EXEC, 1))
goto out;
+#endif
#ifdef DIAGNOSTIC
if (__predict_false(curcpu()->ci_idepth > 0)) {
diff --git a/sys/arch/arm/arm/pmap7.c b/sys/arch/arm/arm/pmap7.c
index 402393cd07f..0dc9fd9f978 100644
--- a/sys/arch/arm/arm/pmap7.c
+++ b/sys/arch/arm/arm/pmap7.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pmap7.c,v 1.46 2016/08/20 21:08:16 kettenis Exp $ */
+/* $OpenBSD: pmap7.c,v 1.47 2016/08/24 13:09:52 kettenis Exp $ */
/* $NetBSD: pmap.c,v 1.147 2004/01/18 13:03:50 scw Exp $ */
/*
@@ -1699,153 +1699,70 @@ pmap_clear_reference(struct vm_page *pg)
*/
/* See <arm/pmap.h> */
+/*
+ * dab_access() handles the following data aborts:
+ *
+ * FAULT_ACCESS_2 - Access flag fault -- Level 2
+ *
+ * Set the Access Flag and mark the page as referenced.
+ */
int
-pmap_fault_fixup(pmap_t pm, vaddr_t va, vm_prot_t ftype, int user)
+dab_access(trapframe_t *tf, u_int fsr, u_int far, struct proc *p)
{
+ struct pmap *pm = p->p_vmspace->vm_map.pmap;
+ vaddr_t va = trunc_page(far);
struct l2_dtable *l2;
struct l2_bucket *l2b;
- pd_entry_t *pl1pd, l1pd;
pt_entry_t *ptep, pte;
+ struct pv_entry *pv;
+ struct vm_page *pg;
paddr_t pa;
u_int l1idx;
- int rv = 0;
l1idx = L1_IDX(va);
/*
* If there is no l2_dtable for this address, then the process
* has no business accessing it.
- *
- * Note: This will catch userland processes trying to access
- * kernel addresses.
*/
l2 = pm->pm_l2[L2_IDX(l1idx)];
- if (l2 == NULL)
- goto out;
+ KASSERT(l2 != NULL);
/*
* Likewise if there is no L2 descriptor table
*/
l2b = &l2->l2_bucket[L2_BUCKET(l1idx)];
- if (l2b->l2b_kva == NULL)
- goto out;
+ KASSERT(l2b->l2b_kva != NULL);
/*
* Check the PTE itself.
*/
ptep = &l2b->l2b_kva[l2pte_index(va)];
pte = *ptep;
- if (pte == L2_TYPE_INV)
- goto out;
+ KASSERT(pte != L2_TYPE_INV);
- if ((ftype & PROT_EXEC) && (pte & L2_V7_S_XN))
- goto out;
+ pa = l2pte_pa(pte);
- /* only if vectors are low ?? */
/*
- * Catch a userland access to the vector page mapped at 0x0
+ * Perform page referenced emulation.
*/
- if (user) {
- if ((pte & L2_V7_AP(0x2)) == 0)
- goto out;
- }
-
- pa = l2pte_pa(pte);
-
- if ((ftype & PROT_WRITE) && !l2pte_is_writeable(pte, pm)) {
- /*
- * This looks like a good candidate for "page modified"
- * emulation...
- */
- struct pv_entry *pv;
- struct vm_page *pg;
-
- /* Extract the physical address of the page */
- if ((pg = PHYS_TO_VM_PAGE(pa)) == NULL)
- goto out;
-
- /* Get the current flags for this page. */
- pv = pmap_find_pv(pg, pm, va);
- if (pv == NULL)
- goto out;
-
- /*
- * Do the flags say this page is writable? If not then it
- * is a genuine write fault. If yes then the write fault is
- * our fault as we did not reflect the write access in the
- * PTE. Now we know a write has occurred we can correct this
- * and also set the modified bit
- */
- if ((pv->pv_flags & PVF_WRITE) == 0)
- goto out;
-
- NPDEBUG(PDB_FOLLOW,
- printf("pmap_fault_fixup: mod emul. pm %p, va 0x%08lx, pa 0x%08lx\n",
- pm, va, pg->phys_addr));
-
- pg->mdpage.pvh_attrs |= PVF_REF | PVF_MOD;
- pv->pv_flags |= PVF_REF | PVF_MOD;
-
- /*
- * Re-enable write permissions for the page.
- * We've already set the cacheable bits based on
- * the assumption that we can write to this page.
- */
- *ptep = (pte & ~L2_V7_AP(0x4));
- PTE_SYNC(ptep);
- rv = 1;
- } else if ((pte & L2_V7_AF) == 0) {
- /*
- * This looks like a good candidate for "page referenced"
- * emulation.
- */
- struct pv_entry *pv;
- struct vm_page *pg;
-
- /* Extract the physical address of the page */
- if ((pg = PHYS_TO_VM_PAGE(pa)) == NULL)
- goto out;
+ KASSERT((pte & L2_V7_AF) == 0);
- /* Get the current flags for this page. */
- pv = pmap_find_pv(pg, pm, va);
- if (pv == NULL)
- goto out;
-
- pg->mdpage.pvh_attrs |= PVF_REF;
- pv->pv_flags |= PVF_REF;
- pte |= L2_V7_AF;
-
- NPDEBUG(PDB_FOLLOW,
- printf("pmap_fault_fixup: ref emul. pm %p, va 0x%08lx, pa 0x%08lx\n",
- pm, va, pg->phys_addr));
-
- *ptep = pte;
- PTE_SYNC(ptep);
- rv = 1;
- } else {
-printf("%s: va %08lx ftype %x %c pte %08x\n", __func__, va, ftype, user ? 'u' : 's', pte);
- goto out;
- }
+ /* Extract the physical address of the page */
+ pg = PHYS_TO_VM_PAGE(pa);
+ KASSERT(pg != NULL);
- /*
- * We know there is a valid mapping here, so simply
- * fix up the L1 if necessary.
- */
- pl1pd = &pm->pm_l1->l1_kva[l1idx];
- l1pd = l2b->l2b_phys | L1_C_DOM(pm->pm_domain) | L1_C_PROTO;
- if (*pl1pd != l1pd) {
- *pl1pd = l1pd;
- PTE_SYNC(pl1pd);
- rv = 1;
- }
+ /* Get the current flags for this page. */
+ pv = pmap_find_pv(pg, pm, va);
+ KASSERT(pv != NULL);
- if (rv) {
- cpu_tlb_flushID_SE(va);
- cpu_cpwait();
- }
+ pg->mdpage.pvh_attrs |= PVF_REF;
+ pv->pv_flags |= PVF_REF;
+ pte |= L2_V7_AF;
-out:
- return (rv);
+ *ptep = pte;
+ PTE_SYNC(ptep);
+ return 0;
}
/*
diff --git a/sys/arch/arm/include/armreg.h b/sys/arch/arm/include/armreg.h
index e0ab251ed2f..542e29bb4c7 100644
--- a/sys/arch/arm/include/armreg.h
+++ b/sys/arch/arm/include/armreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: armreg.h,v 1.35 2016/08/14 11:30:54 jsg Exp $ */
+/* $OpenBSD: armreg.h,v 1.36 2016/08/24 13:09:52 kettenis Exp $ */
/* $NetBSD: armreg.h,v 1.27 2003/09/06 08:43:02 rearnsha Exp $ */
/*
@@ -314,6 +314,10 @@
#define FAULT_PERM_S 0x0d /* Permission -- Section */
#define FAULT_PERM_P 0x0f /* Permission -- Page */
+/* Fault type definitions for ARM v7 */
+#define FAULT_ACCESS_1 0x03 /* Access flag fault -- Level 1 */
+#define FAULT_ACCESS_2 0x06 /* Access flag fault -- Level 2 */
+
#define FAULT_IMPRECISE 0x400 /* Imprecise exception (XSCALE) */
#define FAULT_EXT 0x00001000 /* external abort */