/* Embedded type MMU with HW exec support. This is a bit more complicated * as we don't have two bits to spare for _PAGE_EXEC and _PAGE_HWEXEC so * instead we "filter out" the exec permission for non clean pages. */ static pte_t set_pte_filter(pte_t pte) { struct page *pg; /* No exec permission in the first place, move on */ if (!(pte_val(pte) & _PAGE_EXEC) || !pte_looks_normal(pte)) return pte; /* If you set _PAGE_EXEC on weird pages you're on your own */ pg = maybe_pte_to_page(pte); if (unlikely(!pg)) return pte; /* If the page clean, we move on */ if (test_bit(PG_arch_1, &pg->flags)) return pte; /* If it's an exec fault, we flush the cache and make it clean */ if (is_exec_fault()) { flush_dcache_icache_page(pg); set_bit(PG_arch_1, &pg->flags); return pte; } /* Else, we filter out _PAGE_EXEC */ return __pte(pte_val(pte) & ~_PAGE_EXEC); }
static pte_t set_pte_filter(pte_t pte, unsigned long addr) { struct page *pg; if (!(pte_val(pte) & _PAGE_EXEC) || !pte_looks_normal(pte)) return pte; pg = maybe_pte_to_page(pte); if (unlikely(!pg)) return pte; if (test_bit(PG_arch_1, &pg->flags)) return pte; if (is_exec_fault()) { flush_dcache_icache_page(pg); set_bit(PG_arch_1, &pg->flags); return pte; } return __pte(pte_val(pte) & ~_PAGE_EXEC); }
static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma, int dirty) { struct page *pg; if (dirty || (pte_val(pte) & _PAGE_EXEC) || !is_exec_fault()) return pte; #ifdef CONFIG_DEBUG_VM if (WARN_ON(!(vma->vm_flags & VM_EXEC))) return pte; #endif pg = maybe_pte_to_page(pte); if (unlikely(!pg)) goto bail; if (test_bit(PG_arch_1, &pg->flags)) goto bail; flush_dcache_icache_page(pg); set_bit(PG_arch_1, &pg->flags); bail: return __pte(pte_val(pte) | _PAGE_EXEC); }
static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma, int dirty) { struct page *pg; /* So here, we only care about exec faults, as we use them * to recover lost _PAGE_EXEC and perform I$/D$ coherency * if necessary. Also if _PAGE_EXEC is already set, same deal, * we just bail out */ if (dirty || (pte_val(pte) & _PAGE_EXEC) || !is_exec_fault()) return pte; #ifdef CONFIG_DEBUG_VM /* So this is an exec fault, _PAGE_EXEC is not set. If it was * an error we would have bailed out earlier in do_page_fault() * but let's make sure of it */ if (WARN_ON(!(vma->vm_flags & VM_EXEC))) return pte; #endif /* CONFIG_DEBUG_VM */ /* If you set _PAGE_EXEC on weird pages you're on your own */ pg = maybe_pte_to_page(pte); if (unlikely(!pg)) goto bail; /* If the page is already clean, we move on */ if (test_bit(PG_arch_1, &pg->flags)) goto bail; /* Clean the page and set PG_arch_1 */ flush_dcache_icache_page(pg); set_bit(PG_arch_1, &pg->flags); bail: return __pte(pte_val(pte) | _PAGE_EXEC); }
/* Other embedded CPUs with HW exec support per-page, we flush on exec * fault if HWEXEC is not set */ static inline int pte_need_exec_flush(pte_t pte, int set_pte) { return pte_looks_normal(pte) && is_exec_fault() && !(pte_val(pte) & _PAGE_HWEXEC); }