Replace pmap_fault_fixup() with an access flag fault handler on armv7.
authorkettenis <kettenis@openbsd.org>
Wed, 24 Aug 2016 13:09:52 +0000 (13:09 +0000)
committerkettenis <kettenis@openbsd.org>
Wed, 24 Aug 2016 13:09:52 +0000 (13:09 +0000)
ok tom@

sys/arch/arm/arm/fault.c
sys/arch/arm/arm/pmap7.c
sys/arch/arm/include/armreg.h

index 0cb36ae..a2b4806 100644 (file)
@@ -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)) {
index 402393c..0dc9fd9 100644 (file)
@@ -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;
 }
 
 /*
index e0ab251..542e29b 100644 (file)
@@ -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 $     */
 
 /*
 #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 */