/* * arch/xtensa/mm/tlb.c * * Logic that manipulates the Xtensa MMU. Derived from MIPS. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2001 - 2003 Tensilica Inc. * * Joe Taylor * Chris Zankel <chris@zankel.net> * Marc Gauthier
*/
staticinlinevoid __flush_itlb_all (void)
{ int w, i;
for (w = 0; w < ITLB_ARF_WAYS; w++) { for (i = 0; i < (1 << XCHAL_ITLB_ARF_ENTRIES_LOG2); i++) { int e = w + (i << PAGE_SHIFT);
invalidate_itlb_entry_no_isync(e);
}
} asmvolatile ("isync\n");
}
staticinlinevoid __flush_dtlb_all (void)
{ int w, i;
for (w = 0; w < DTLB_ARF_WAYS; w++) { for (i = 0; i < (1 << XCHAL_DTLB_ARF_ENTRIES_LOG2); i++) { int e = w + (i << PAGE_SHIFT);
invalidate_dtlb_entry_no_isync(e);
}
} asmvolatile ("isync\n");
}
/* If mm is current, we simply assign the current task a new ASID, thus, * invalidating all previous tlb entries. If mm is someone else's user mapping, * wie invalidate the context, thus, when that user mapping is swapped in, * a new context will be assigned to it.
*/
void local_flush_tlb_mm(struct mm_struct *mm)
{ int cpu = smp_processor_id();
void local_flush_tlb_page(struct vm_area_struct *vma, unsignedlong page)
{ int cpu = smp_processor_id(); struct mm_struct* mm = vma->vm_mm; unsignedlong flags; int oldpid;
if (!mm)
mm = task->active_mm;
pgd = pgd_offset(mm, vaddr); if (pgd_none_or_clear_bad(pgd)) return 0;
p4d = p4d_offset(pgd, vaddr); if (p4d_none_or_clear_bad(p4d)) return 0;
pud = pud_offset(p4d, vaddr); if (pud_none_or_clear_bad(pud)) return 0;
pmd = pmd_offset(pud, vaddr); if (pmd_none_or_clear_bad(pmd)) return 0;
pte = pte_offset_map(pmd, vaddr); if (!pte) return 0;
pteval = pte_val(*pte);
pte_unmap(pte); return pteval;
}
enum {
TLB_SUSPICIOUS = 1,
TLB_INSANE = 2,
};
staticvoid tlb_insane(void)
{
BUG_ON(1);
}
staticvoid tlb_suspicious(void)
{
WARN_ON(1);
}
/* * Check that TLB entries with kernel ASID (1) have kernel VMA (>= TASK_SIZE), * and TLB entries with user ASID (>=4) have VMA < TASK_SIZE. * * Check that valid TLB entries either have the same PA as the PTE, or PTE is * marked as non-present. Non-present PTE and the page with non-zero refcount * and zero mapcount is normal for batched TLB flush operation. Zero refcount * means that the page was freed prematurely. Non-zero mapcount is unusual, * but does not necessary means an error, thus marked as suspicious.
*/ staticint check_tlb_entry(unsigned w, unsigned e, bool dtlb)
{ unsigned tlbidx = w | (e << PAGE_SHIFT); unsigned r0 = dtlb ?
read_dtlb_virtual(tlbidx) : read_itlb_virtual(tlbidx); unsigned r1 = dtlb ?
read_dtlb_translation(tlbidx) : read_itlb_translation(tlbidx); unsigned vpn = (r0 & PAGE_MASK) | (e << PAGE_SHIFT); unsigned pte = get_pte_for_vaddr(vpn); unsigned mm_asid = (get_rasid_register() >> 8) & ASID_MASK; unsigned tlb_asid = r0 & ASID_MASK; bool kernel = tlb_asid == 1; int rc = 0;
local_irq_save(flags); for (w = 0; w < DTLB_ARF_WAYS; ++w) for (e = 0; e < (1 << XCHAL_DTLB_ARF_ENTRIES_LOG2); ++e)
bug |= check_tlb_entry(w, e, true); for (w = 0; w < ITLB_ARF_WAYS; ++w) for (e = 0; e < (1 << XCHAL_ITLB_ARF_ENTRIES_LOG2); ++e)
bug |= check_tlb_entry(w, e, false); if (bug & TLB_INSANE)
tlb_insane(); if (bug & TLB_SUSPICIOUS)
tlb_suspicious();
local_irq_restore(flags);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.