diff options
Diffstat (limited to 'target-mips/helper.c')
-rw-r--r-- | target-mips/helper.c | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/target-mips/helper.c b/target-mips/helper.c index e70dc1a99e..43038c2d7e 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -416,3 +416,44 @@ void do_interrupt (CPUState *env) env->exception_index = EXCP_NONE; } #endif /* !defined(CONFIG_USER_ONLY) */ + +void invalidate_tlb (CPUState *env, int idx, int use_extra) +{ + tlb_t *tlb; + target_ulong addr; + uint8_t ASID; + + ASID = env->CP0_EntryHi & 0xFF; + + tlb = &env->tlb[idx]; + /* The qemu TLB is flushed then the ASID changes, so no need to + flush these entries again. */ + if (tlb->G == 0 && tlb->ASID != ASID) { + return; + } + + if (use_extra && env->tlb_in_use < MIPS_TLB_MAX) { + /* For tlbwr, we can shadow the discarded entry into + a new (fake) TLB entry, as long as the guest can not + tell that it's there. */ + env->tlb[env->tlb_in_use] = *tlb; + env->tlb_in_use++; + return; + } + + if (tlb->V0) { + addr = tlb->VPN; + while (addr < tlb->end) { + tlb_flush_page (env, addr); + addr += TARGET_PAGE_SIZE; + } + } + if (tlb->V1) { + addr = tlb->end; + while (addr < tlb->end2) { + tlb_flush_page (env, addr); + addr += TARGET_PAGE_SIZE; + } + } +} + |