Loading target-mips/cpu.h +2 −1 Original line number Diff line number Diff line Loading @@ -94,7 +94,8 @@ struct CPUMIPSState { #endif #if defined(MIPS_USES_R4K_TLB) tlb_t tlb[MIPS_TLB_NB]; tlb_t tlb[MIPS_TLB_MAX]; uint32_t tlb_in_use; #endif uint32_t CP0_index; uint32_t CP0_random; Loading target-mips/exec.h +1 −0 Original line number Diff line number Diff line Loading @@ -115,5 +115,6 @@ uint32_t cpu_mips_get_count (CPUState *env); void cpu_mips_store_count (CPUState *env, uint32_t value); void cpu_mips_store_compare (CPUState *env, uint32_t value); void cpu_mips_clock_init (CPUState *env); void cpu_mips_tlb_flush (CPUState *env, int flush_global); #endif /* !defined(__QEMU_MIPS_EXEC_H__) */ target-mips/helper.c +1 −1 Original line number Diff line number Diff line Loading @@ -46,7 +46,7 @@ static int map_address (CPUState *env, target_ulong *physical, int *prot, tlb_t *tlb; int i, n; for (i = 0; i < MIPS_TLB_NB; i++) { for (i = 0; i < env->tlb_in_use; i++) { tlb = &env->tlb[i]; /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && Loading target-mips/mips-defs.h +1 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ /* Uses MIPS R4Kc TLB model */ #define MIPS_USES_R4K_TLB #define MIPS_TLB_NB 16 #define MIPS_TLB_MAX 128 /* basic FPU register support */ #define MIPS_USES_FPU 1 /* Define a implementation number of 1. Loading target-mips/op_helper.c +48 −6 Original line number Diff line number Diff line Loading @@ -367,7 +367,7 @@ void do_mtc0 (int reg, int sel) env->CP0_EntryHi = val; /* If the ASID changes, flush qemu's TLB. */ if ((old & 0xFF) != (val & 0xFF)) tlb_flush (env, 1); cpu_mips_tlb_flush (env, 1); rn = "EntryHi"; break; case 11: Loading Loading @@ -568,7 +568,14 @@ void fpu_handle_exception(void) /* TLB management */ #if defined(MIPS_USES_R4K_TLB) static void invalidate_tlb (int idx) void cpu_mips_tlb_flush (CPUState *env, int flush_global) { /* Flush qemu's TLB and discard all shadowed entries. */ tlb_flush (env, flush_global); env->tlb_in_use = MIPS_TLB_NB; } static void invalidate_tlb (int idx, int use_extra) { tlb_t *tlb; target_ulong addr; Loading @@ -583,6 +590,15 @@ static void invalidate_tlb (int idx) 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) { tb_invalidate_page_range(tlb->PFN[0], tlb->end - tlb->VPN); addr = tlb->VPN; Loading @@ -601,6 +617,14 @@ static void invalidate_tlb (int idx) } } static void mips_tlb_flush_extra (CPUState *env, int first) { /* Discard entries from env->tlb[first] onwards. */ while (env->tlb_in_use > first) { invalidate_tlb(--env->tlb_in_use, 0); } } static void fill_tlb (int idx) { tlb_t *tlb; Loading @@ -627,9 +651,14 @@ static void fill_tlb (int idx) void do_tlbwi (void) { /* Discard cached TLB entries. We could avoid doing this if the tlbwi is just upgrading access permissions on the current entry; that might be a further win. */ mips_tlb_flush_extra (env, MIPS_TLB_NB); /* Wildly undefined effects for CP0_index containing a too high value and MIPS_TLB_NB not being a power of two. But so does real silicon. */ invalidate_tlb(env->CP0_index & (MIPS_TLB_NB - 1)); invalidate_tlb(env->CP0_index & (MIPS_TLB_NB - 1), 0); fill_tlb(env->CP0_index & (MIPS_TLB_NB - 1)); } Loading @@ -637,7 +666,7 @@ void do_tlbwr (void) { int r = cpu_mips_get_random(env); invalidate_tlb(r); invalidate_tlb(r, 1); fill_tlb(r); } Loading @@ -660,6 +689,17 @@ void do_tlbp (void) } } if (i == MIPS_TLB_NB) { /* No match. Discard any shadow entries, if any of them match. */ for (i = MIPS_TLB_NB; i < env->tlb_in_use; i++) { tlb = &env->tlb[i]; /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { mips_tlb_flush_extra (env, i); break; } } env->CP0_index |= 0x80000000; } } Loading @@ -674,8 +714,10 @@ void do_tlbr (void) tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)]; /* If this will change the current ASID, flush qemu's TLB. */ if (ASID != tlb->ASID && tlb->G != 1) tlb_flush (env, 1); if (ASID != tlb->ASID) cpu_mips_tlb_flush (env, 1); mips_tlb_flush_extra(env, MIPS_TLB_NB); env->CP0_EntryHi = tlb->VPN | tlb->ASID; size = (tlb->end - tlb->VPN) >> 12; Loading Loading
target-mips/cpu.h +2 −1 Original line number Diff line number Diff line Loading @@ -94,7 +94,8 @@ struct CPUMIPSState { #endif #if defined(MIPS_USES_R4K_TLB) tlb_t tlb[MIPS_TLB_NB]; tlb_t tlb[MIPS_TLB_MAX]; uint32_t tlb_in_use; #endif uint32_t CP0_index; uint32_t CP0_random; Loading
target-mips/exec.h +1 −0 Original line number Diff line number Diff line Loading @@ -115,5 +115,6 @@ uint32_t cpu_mips_get_count (CPUState *env); void cpu_mips_store_count (CPUState *env, uint32_t value); void cpu_mips_store_compare (CPUState *env, uint32_t value); void cpu_mips_clock_init (CPUState *env); void cpu_mips_tlb_flush (CPUState *env, int flush_global); #endif /* !defined(__QEMU_MIPS_EXEC_H__) */
target-mips/helper.c +1 −1 Original line number Diff line number Diff line Loading @@ -46,7 +46,7 @@ static int map_address (CPUState *env, target_ulong *physical, int *prot, tlb_t *tlb; int i, n; for (i = 0; i < MIPS_TLB_NB; i++) { for (i = 0; i < env->tlb_in_use; i++) { tlb = &env->tlb[i]; /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && Loading
target-mips/mips-defs.h +1 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ /* Uses MIPS R4Kc TLB model */ #define MIPS_USES_R4K_TLB #define MIPS_TLB_NB 16 #define MIPS_TLB_MAX 128 /* basic FPU register support */ #define MIPS_USES_FPU 1 /* Define a implementation number of 1. Loading
target-mips/op_helper.c +48 −6 Original line number Diff line number Diff line Loading @@ -367,7 +367,7 @@ void do_mtc0 (int reg, int sel) env->CP0_EntryHi = val; /* If the ASID changes, flush qemu's TLB. */ if ((old & 0xFF) != (val & 0xFF)) tlb_flush (env, 1); cpu_mips_tlb_flush (env, 1); rn = "EntryHi"; break; case 11: Loading Loading @@ -568,7 +568,14 @@ void fpu_handle_exception(void) /* TLB management */ #if defined(MIPS_USES_R4K_TLB) static void invalidate_tlb (int idx) void cpu_mips_tlb_flush (CPUState *env, int flush_global) { /* Flush qemu's TLB and discard all shadowed entries. */ tlb_flush (env, flush_global); env->tlb_in_use = MIPS_TLB_NB; } static void invalidate_tlb (int idx, int use_extra) { tlb_t *tlb; target_ulong addr; Loading @@ -583,6 +590,15 @@ static void invalidate_tlb (int idx) 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) { tb_invalidate_page_range(tlb->PFN[0], tlb->end - tlb->VPN); addr = tlb->VPN; Loading @@ -601,6 +617,14 @@ static void invalidate_tlb (int idx) } } static void mips_tlb_flush_extra (CPUState *env, int first) { /* Discard entries from env->tlb[first] onwards. */ while (env->tlb_in_use > first) { invalidate_tlb(--env->tlb_in_use, 0); } } static void fill_tlb (int idx) { tlb_t *tlb; Loading @@ -627,9 +651,14 @@ static void fill_tlb (int idx) void do_tlbwi (void) { /* Discard cached TLB entries. We could avoid doing this if the tlbwi is just upgrading access permissions on the current entry; that might be a further win. */ mips_tlb_flush_extra (env, MIPS_TLB_NB); /* Wildly undefined effects for CP0_index containing a too high value and MIPS_TLB_NB not being a power of two. But so does real silicon. */ invalidate_tlb(env->CP0_index & (MIPS_TLB_NB - 1)); invalidate_tlb(env->CP0_index & (MIPS_TLB_NB - 1), 0); fill_tlb(env->CP0_index & (MIPS_TLB_NB - 1)); } Loading @@ -637,7 +666,7 @@ void do_tlbwr (void) { int r = cpu_mips_get_random(env); invalidate_tlb(r); invalidate_tlb(r, 1); fill_tlb(r); } Loading @@ -660,6 +689,17 @@ void do_tlbp (void) } } if (i == MIPS_TLB_NB) { /* No match. Discard any shadow entries, if any of them match. */ for (i = MIPS_TLB_NB; i < env->tlb_in_use; i++) { tlb = &env->tlb[i]; /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { mips_tlb_flush_extra (env, i); break; } } env->CP0_index |= 0x80000000; } } Loading @@ -674,8 +714,10 @@ void do_tlbr (void) tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)]; /* If this will change the current ASID, flush qemu's TLB. */ if (ASID != tlb->ASID && tlb->G != 1) tlb_flush (env, 1); if (ASID != tlb->ASID) cpu_mips_tlb_flush (env, 1); mips_tlb_flush_extra(env, MIPS_TLB_NB); env->CP0_EntryHi = tlb->VPN | tlb->ASID; size = (tlb->end - tlb->VPN) >> 12; Loading