diff --git a/target-mips/helper.c b/target-mips/helper.c index cb568f11a5..484834a592 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -73,19 +73,18 @@ int r4k_map_address (CPUState *env, target_ulong *physical, int *prot, for (i = 0; i < env->tlb_in_use; i++) { r4k_tlb_t *tlb = &env->mmu.r4k.tlb[i]; /* 1k pages are not supported. */ - target_ulong mask = tlb->PageMask | 0x1FFF; + target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); target_ulong tag = address & ~mask; - int n; + target_ulong VPN = tlb->VPN & ~mask; /* Check ASID, virtual page number & size */ - if ((tlb->G == 1 || tlb->ASID == ASID) && - tlb->VPN == tag) { + if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) { /* TLB match */ - n = !!(address & mask & ~(mask >> 1)); + int n = !!(address & mask & ~(mask >> 1)); /* Check access rights */ - if (!(n ? tlb->V1 : tlb->V0)) + if (!(n ? tlb->V1 : tlb->V0)) return TLBRET_INVALID; - if (rw == 0 || (n ? tlb->D1 : tlb->D0)) { + if (rw == 0 || (n ? tlb->D1 : tlb->D0)) { *physical = tlb->PFN[n] | (address & (mask >> 1)); *prot = PAGE_READ; if (n ? tlb->D1 : tlb->D0) @@ -502,7 +501,7 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) target_ulong mask; tlb = &env->mmu.r4k.tlb[idx]; - /* The qemu TLB is flushed then the ASID changes, so no need to + /* The qemu TLB is flushed when the ASID changes, so no need to flush these entries again. */ if (tlb->G == 0 && tlb->ASID != ASID) { return; @@ -518,9 +517,9 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) } /* 1k pages are not supported. */ - mask = tlb->PageMask | 0x1FFF; + mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); if (tlb->V0) { - addr = tlb->VPN; + addr = tlb->VPN & ~mask; end = addr | (mask >> 1); while (addr < end) { tlb_flush_page (env, addr); @@ -528,8 +527,7 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) } } if (tlb->V1) { - addr = tlb->VPN | ((mask >> 1) + 1); - addr = tlb->VPN + TARGET_PAGE_SIZE; + addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1); end = addr | mask; while (addr < end) { tlb_flush_page (env, addr); diff --git a/target-mips/op.c b/target-mips/op.c index a0611e01c1..835b02a646 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1283,7 +1283,7 @@ void op_mtc0_context (void) void op_mtc0_pagemask (void) { /* 1k pages not implemented */ - env->CP0_PageMask = T0 & 0x1FFFE000; + env->CP0_PageMask = T0 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1)); RETURN(); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 9d7a560001..895ca7ff8f 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -390,7 +390,7 @@ static void r4k_fill_tlb (int idx) /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ tlb = &env->mmu.r4k.tlb[idx]; - tlb->VPN = env->CP0_EntryHi & ~(target_ulong)0x1FFF; + tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); tlb->ASID = env->CP0_EntryHi & 0xFF; tlb->PageMask = env->CP0_PageMask; tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; @@ -426,16 +426,21 @@ void r4k_do_tlbwr (void) void r4k_do_tlbp (void) { r4k_tlb_t *tlb; + target_ulong mask; target_ulong tag; + target_ulong VPN; uint8_t ASID; int i; - tag = env->CP0_EntryHi & (int32_t)0xFFFFE000; ASID = env->CP0_EntryHi & 0xFF; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->mmu.r4k.tlb[i]; + /* 1k pages are not supported. */ + mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); + tag = env->CP0_EntryHi & ~mask; + VPN = tlb->VPN & ~mask; /* Check ASID, virtual page number & size */ - if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { + if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) { /* TLB match */ env->CP0_Index = i; break; @@ -445,9 +450,12 @@ void r4k_do_tlbp (void) /* No match. Discard any shadow entries, if any of them match. */ for (i = env->nb_tlb; i < env->tlb_in_use; i++) { tlb = &env->mmu.r4k.tlb[i]; - + /* 1k pages are not supported. */ + mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); + tag = env->CP0_EntryHi & ~mask; + VPN = tlb->VPN & ~mask; /* Check ASID, virtual page number & size */ - if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { + if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) { r4k_mips_tlb_flush_extra (env, i); break; }