/** Try to find PTE for faulting address * * @param as Address space. * @param badvaddr Faulting virtual address. * @param access Access mode that caused the fault. * @param istate Pointer to interrupted state. * * @return PTE on success, NULL otherwise. * */ static pte_t *find_mapping_and_check(as_t *as, uintptr_t badvaddr, int access, istate_t *istate) { /* * Check if the mapping exists in page tables. */ pte_t *pte = page_mapping_find(as, badvaddr, true); if ((pte) && (pte->present)) { /* * Mapping found in page tables. * Immediately succeed. */ return pte; } /* * Mapping not found in page tables. * Resort to higher-level page fault handler. */ if (as_page_fault(badvaddr, access, istate) == AS_PF_OK) { /* * The higher-level page fault handler succeeded, * The mapping ought to be in place. */ pte = page_mapping_find(as, badvaddr, true); ASSERT((pte) && (pte->present)); return pte; } return NULL; }
/** Try to find PTE for faulting address. * * @param badvaddr Faulting virtual address. * @param access Access mode that caused the fault. * @param istate Pointer to interrupted state. * @param pfrc Pointer to variable where as_page_fault() * return code will be stored. * * @return PTE on success, NULL otherwise. * */ static pte_t *find_mapping_and_check(uintptr_t badvaddr, int access, istate_t *istate, int *pfrc) { entry_hi_t hi; hi.value = cp0_entry_hi_read(); /* * Handler cannot succeed if the ASIDs don't match. */ if (hi.asid != AS->asid) { printf("EntryHi.asid=%d, AS->asid=%d\n", hi.asid, AS->asid); return NULL; } /* * Check if the mapping exists in page tables. */ pte_t *pte = page_mapping_find(AS, badvaddr, true); if ((pte) && (pte->p) && ((pte->w) || (access != PF_ACCESS_WRITE))) { /* * Mapping found in page tables. * Immediately succeed. */ return pte; } else { int rc; /* * Mapping not found in page tables. * Resort to higher-level page fault handler. */ switch (rc = as_page_fault(badvaddr, access, istate)) { case AS_PF_OK: /* * The higher-level page fault handler succeeded, * The mapping ought to be in place. */ pte = page_mapping_find(AS, badvaddr, true); ASSERT(pte); ASSERT(pte->p); ASSERT((pte->w) || (access != PF_ACCESS_WRITE)); return pte; case AS_PF_DEFER: *pfrc = AS_PF_DEFER; return NULL; case AS_PF_FAULT: *pfrc = AS_PF_FAULT; return NULL; default: panic("Unexpected return code (%d).", rc); } } }
void page_fault(unsigned int n __attribute__((unused)), istate_t *istate) { uint32_t fault_status = asi_u32_read(ASI_MMUREGS, MMU_FAULT_STATUS); uintptr_t fault_address = asi_u32_read(ASI_MMUREGS, MMU_FAULT_ADDRESS); mmu_fault_status_t *fault = (mmu_fault_status_t *) &fault_status; mmu_fault_type_t type = (mmu_fault_type_t) fault->at; if ((type == FAULT_TYPE_LOAD_USER_DATA) || (type == FAULT_TYPE_LOAD_SUPERVISOR_DATA)) as_page_fault(fault_address, PF_ACCESS_READ, istate); if ((type == FAULT_TYPE_EXECUTE_USER) || (type == FAULT_TYPE_EXECUTE_SUPERVISOR)) as_page_fault(fault_address, PF_ACCESS_EXEC, istate); if ((type == FAULT_TYPE_STORE_USER_DATA) || (type == FAULT_TYPE_STORE_USER_INSTRUCTION) || (type == FAULT_TYPE_STORE_SUPERVISOR_INSTRUCTION) || (type == FAULT_TYPE_STORE_SUPERVISOR_DATA)) as_page_fault(fault_address, PF_ACCESS_WRITE, istate); }
void page_fault(unsigned int n, istate_t *istate) { uintptr_t badvaddr = read_cr2(); if (istate->error_word & PFERR_CODE_RSVD) panic("Reserved bit set in page table entry."); pf_access_t access; if (istate->error_word & PFERR_CODE_RW) access = PF_ACCESS_WRITE; else if (istate->error_word & PFERR_CODE_ID) access = PF_ACCESS_EXEC; else access = PF_ACCESS_READ; (void) as_page_fault(badvaddr, access, istate); }
/** Try to find PTE for faulting address * * @param as Address space. * @param badvaddr Faulting virtual address. * @param access Access mode that caused the fault. * @param istate Pointer to interrupted state. * @param pfrc Pointer to variable where as_page_fault() return code * will be stored. * * @return PTE on success, NULL otherwise. * */ static pte_t *find_mapping_and_check(as_t *as, uintptr_t badvaddr, int access, istate_t *istate, int *pfrc) { /* * Check if the mapping exists in page tables. */ pte_t *pte = page_mapping_find(as, badvaddr, true); if ((pte) && (pte->present)) { /* * Mapping found in page tables. * Immediately succeed. */ return pte; } else { /* * Mapping not found in page tables. * Resort to higher-level page fault handler. */ int rc = as_page_fault(badvaddr, access, istate); switch (rc) { case AS_PF_OK: /* * The higher-level page fault handler succeeded, * The mapping ought to be in place. */ pte = page_mapping_find(as, badvaddr, true); ASSERT((pte) && (pte->present)); *pfrc = 0; return pte; case AS_PF_DEFER: *pfrc = rc; return NULL; case AS_PF_FAULT: *pfrc = rc; return NULL; default: panic("Unexpected rc (%d).", rc); } } }
/** Try to find PTE for faulting address. * * @param badvaddr Faulting virtual address. * @param access Access mode that caused the fault. * @param istate Pointer to interrupted state. * * @return PTE on success, NULL otherwise. * */ static pte_t *find_mapping_and_check(uintptr_t badvaddr, int access, istate_t *istate) { entry_hi_t hi; hi.value = cp0_entry_hi_read(); ASSERT(hi.asid == AS->asid); /* * Check if the mapping exists in page tables. */ pte_t *pte = page_mapping_find(AS, badvaddr, true); if ((pte) && (pte->p) && ((pte->w) || (access != PF_ACCESS_WRITE))) { /* * Mapping found in page tables. * Immediately succeed. */ return pte; } /* * Mapping not found in page tables. * Resort to higher-level page fault handler. */ if (as_page_fault(badvaddr, access, istate) == AS_PF_OK) { /* * The higher-level page fault handler succeeded, * The mapping ought to be in place. */ pte = page_mapping_find(AS, badvaddr, true); ASSERT(pte); ASSERT(pte->p); ASSERT((pte->w) || (access != PF_ACCESS_WRITE)); return pte; } return NULL; }