From: kettenis Date: Wed, 24 Aug 2016 13:09:52 +0000 (+0000) Subject: Replace pmap_fault_fixup() with an access flag fault handler on armv7. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=31d7de9f2b354275b78a7406ca051e4b9752c15d;p=openbsd Replace pmap_fault_fixup() with an access flag fault handler on armv7. ok tom@ --- 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 */ +/* + * 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 */