diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 5d0a86be2c..c4ae414413 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -656,6 +656,11 @@ void store_40x_sler (CPUPPCState *env, uint32_t val); void store_booke_tcr (CPUPPCState *env, target_ulong val); void store_booke_tsr (CPUPPCState *env, target_ulong val); void ppc_tlb_invalidate_all (CPUPPCState *env); +void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr); +#if defined(TARGET_PPC64) +void ppc_slb_invalidate_all (CPUPPCState *env); +void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0); +#endif int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid); #endif #endif diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 10a51e93cb..8a54258271 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -100,14 +100,8 @@ void do_raise_exception (uint32_t exception); int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong vaddr, int rw, int access_type, int check_BATs); -void ppc6xx_tlb_invalidate_all (CPUState *env); -void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, - int is_code); void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code, target_ulong pte0, target_ulong pte1); -void ppc4xx_tlb_invalidate_all (CPUState *env); -void ppc4xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, - uint32_t pid); static inline void env_to_regs (void) { diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 3e6fb48cd6..66dc7b22a8 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -237,7 +237,7 @@ static int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr, return nr; } -void ppc6xx_tlb_invalidate_all (CPUState *env) +static void ppc6xx_tlb_invalidate_all (CPUState *env) { ppc6xx_tlb_t *tlb; int nr, max; @@ -253,14 +253,9 @@ void ppc6xx_tlb_invalidate_all (CPUState *env) max *= 2; for (nr = 0; nr < max; nr++) { tlb = &env->tlb[nr].tlb6; -#if !defined(FLUSH_ALL_TLBS) - tlb_flush_page(env, tlb->EPN); -#endif pte_invalidate(&tlb->pte0); } -#if defined(FLUSH_ALL_TLBS) tlb_flush(env, 1); -#endif } static inline void __ppc6xx_tlb_invalidate_virt (CPUState *env, @@ -292,8 +287,8 @@ static inline void __ppc6xx_tlb_invalidate_virt (CPUState *env, #endif } -void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, - int is_code) +static void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, + int is_code) { __ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0); } @@ -834,11 +829,13 @@ static int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb, return -1; } mask = ~(tlb->size - 1); +#if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> " ADDRX " " ADDRX " %d\n", __func__, i, address, pid, tlb->EPN, mask, (int)tlb->PID); } +#endif /* Check PID */ if (tlb->PID != 0 && tlb->PID != pid) return -1; @@ -876,9 +873,23 @@ int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid) return ret; } -void ppc4xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, - uint32_t pid) +/* Helpers specific to PowerPC 40x implementations */ +static void ppc4xx_tlb_invalidate_all (CPUState *env) { + ppcemb_tlb_t *tlb; + int i; + + for (i = 0; i < env->nb_tlb; i++) { + tlb = &env->tlb[i].tlbe; + tlb->prot &= ~PAGE_VALID; + } + tlb_flush(env, 1); +} + +static void ppc4xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, + uint32_t pid) +{ +#if !defined(FLUSH_ALL_TLBS) ppcemb_tlb_t *tlb; target_phys_addr_t raddr; target_ulong page, end; @@ -894,26 +905,9 @@ void ppc4xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, break; } } -} - -/* Helpers specific to PowerPC 40x implementations */ -void ppc4xx_tlb_invalidate_all (CPUState *env) -{ - ppcemb_tlb_t *tlb; - int i; - - for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->tlb[i].tlbe; - if (tlb->prot & PAGE_VALID) { -#if 0 // XXX: TLB have variable sizes then we flush all Qemu TLB. - end = tlb->EPN + tlb->size; - for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) - tlb_flush_page(env, page); +#else + ppc4xx_tlb_invalidate_all(env); #endif - tlb->prot &= ~PAGE_VALID; - } - } - tlb_flush(env, 1); } int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, @@ -932,10 +926,12 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, continue; zsel = (tlb->attr >> 4) & 0xF; zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3; +#if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { fprintf(logfile, "%s: TLB %d zsel %d zpr %d rw %d attr %08x\n", __func__, i, zsel, zpr, rw, tlb->attr); } +#endif if (access_type == ACCESS_CODE) { /* Check execute enable bit */ switch (zpr) { @@ -1009,19 +1005,23 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } if (ret >= 0) { ctx->raddr = raddr; +#if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { fprintf(logfile, "%s: access granted " ADDRX " => " REGX " %d %d\n", __func__, address, ctx->raddr, ctx->prot, ret); } +#endif return 0; } } +#if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { fprintf(logfile, "%s: access refused " ADDRX " => " REGX " %d %d\n", __func__, address, raddr, ctx->prot, ret); } +#endif return ret; } @@ -1569,15 +1569,77 @@ void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value) /* TLB management */ void ppc_tlb_invalidate_all (CPUPPCState *env) { - if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx)) { + switch (env->mmu_model) { + case POWERPC_MMU_SOFT_6xx: ppc6xx_tlb_invalidate_all(env); - } else if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_4xx)) { + break; + case POWERPC_MMU_SOFT_4xx: + case POWERPC_MMU_SOFT_4xx_Z: ppc4xx_tlb_invalidate_all(env); - } else { + break; + default: tlb_flush(env, 1); + break; } } +void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) +{ +#if !defined(FLUSH_ALL_TLBS) + addr &= TARGET_PAGE_MASK; + switch (env->mmu_model) { + case POWERPC_MMU_SOFT_6xx: + ppc6xx_tlb_invalidate_virt(env, addr, 0); + if (env->id_tlbs == 1) + ppc6xx_tlb_invalidate_virt(env, addr, 1); + break; + case POWERPC_MMU_SOFT_4xx: + case POWERPC_MMU_SOFT_4xx_Z: + ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]); + break; + default: + /* tlbie invalidate TLBs for all segments */ + addr &= ~((target_ulong)-1 << 28); + /* XXX: this case should be optimized, + * giving a mask to tlb_flush_page + */ + tlb_flush_page(env, addr | (0x0 << 28)); + tlb_flush_page(env, addr | (0x1 << 28)); + tlb_flush_page(env, addr | (0x2 << 28)); + tlb_flush_page(env, addr | (0x3 << 28)); + tlb_flush_page(env, addr | (0x4 << 28)); + tlb_flush_page(env, addr | (0x5 << 28)); + tlb_flush_page(env, addr | (0x6 << 28)); + tlb_flush_page(env, addr | (0x7 << 28)); + tlb_flush_page(env, addr | (0x8 << 28)); + tlb_flush_page(env, addr | (0x9 << 28)); + tlb_flush_page(env, addr | (0xA << 28)); + tlb_flush_page(env, addr | (0xB << 28)); + tlb_flush_page(env, addr | (0xC << 28)); + tlb_flush_page(env, addr | (0xD << 28)); + tlb_flush_page(env, addr | (0xE << 28)); + tlb_flush_page(env, addr | (0xF << 28)); + } +#else + ppc_tlb_invalidate_all(env); +#endif +} + +#if defined(TARGET_PPC64) +void ppc_slb_invalidate_all (CPUPPCState *env) +{ + /* XXX: TODO */ + tlb_flush(env, 1); +} + +void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0) +{ + /* XXX: TODO */ + tlb_flush(env, 1); +} +#endif + + /*****************************************************************************/ /* Special registers manipulation */ #if defined(TARGET_PPC64) diff --git a/target-ppc/op.c b/target-ppc/op.c index 8f0f11a66f..6ad68eabaa 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1985,21 +1985,21 @@ void OPPROTO op_td (void) /* tlbia */ void OPPROTO op_tlbia (void) { - do_tlbia(); + ppc_tlb_invalidate_all(env); RETURN(); } /* tlbie */ void OPPROTO op_tlbie (void) { - do_tlbie(); + ppc_tlb_invalidate_one(env, (uint32_t)T0); RETURN(); } #if defined(TARGET_PPC64) void OPPROTO op_tlbie_64 (void) { - do_tlbie_64(); + ppc_tlb_invalidate_one(env, T0); RETURN(); } #endif @@ -2007,13 +2007,19 @@ void OPPROTO op_tlbie_64 (void) #if defined(TARGET_PPC64) void OPPROTO op_slbia (void) { - do_slbia(); + ppc_slb_invalidate_all(env); RETURN(); } void OPPROTO op_slbie (void) { - do_slbie(); + ppc_slb_invalidate_one(env, (uint32_t)T0); + RETURN(); +} + +void OPPROTO op_slbie_64 (void) +{ + ppc_slb_invalidate_one(env, T0); RETURN(); } #endif @@ -2487,13 +2493,18 @@ void OPPROTO op_440_tlbre (void) void OPPROTO op_440_tlbsx (void) { - do_440_tlbsx(); + T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR] & 0xFF); RETURN(); } -void OPPROTO op_440_tlbsx_ (void) +void OPPROTO op_4xx_tlbsx_check (void) { - do_440_tlbsx_(); + int tmp; + + tmp = xer_so; + if (T0 != -1) + tmp |= 0x02; + env->crf[0] = tmp; RETURN(); } @@ -2517,13 +2528,7 @@ void OPPROTO op_4xx_tlbre_hi (void) void OPPROTO op_4xx_tlbsx (void) { - do_4xx_tlbsx(); - RETURN(); -} - -void OPPROTO op_4xx_tlbsx_ (void) -{ - do_4xx_tlbsx_(); + T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_40x_PID]); RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 5223b1543f..a7c81776fd 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -36,7 +36,6 @@ //#define DEBUG_OP //#define DEBUG_EXCEPTIONS //#define DEBUG_SOFTWARE_TLB -//#define FLUSH_ALL_TLBS /*****************************************************************************/ /* Exceptions processing helpers */ @@ -2336,118 +2335,6 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) env = saved_env; } -/* TLB invalidation helpers */ -void do_tlbia (void) -{ - ppc_tlb_invalidate_all(env); -} - -void do_tlbie (void) -{ - T0 = (uint32_t)T0; -#if !defined(FLUSH_ALL_TLBS) - /* XXX: Remove thoses tests */ - if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx)) { - ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 0); - if (env->id_tlbs == 1) - ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 1); - } else if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_4xx)) { - ppc4xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, - env->spr[SPR_40x_PID]); - } else { - /* tlbie invalidate TLBs for all segments */ - T0 &= TARGET_PAGE_MASK; - T0 &= ~((target_ulong)-1 << 28); - /* XXX: this case should be optimized, - * giving a mask to tlb_flush_page - */ - tlb_flush_page(env, T0 | (0x0 << 28)); - tlb_flush_page(env, T0 | (0x1 << 28)); - tlb_flush_page(env, T0 | (0x2 << 28)); - tlb_flush_page(env, T0 | (0x3 << 28)); - tlb_flush_page(env, T0 | (0x4 << 28)); - tlb_flush_page(env, T0 | (0x5 << 28)); - tlb_flush_page(env, T0 | (0x6 << 28)); - tlb_flush_page(env, T0 | (0x7 << 28)); - tlb_flush_page(env, T0 | (0x8 << 28)); - tlb_flush_page(env, T0 | (0x9 << 28)); - tlb_flush_page(env, T0 | (0xA << 28)); - tlb_flush_page(env, T0 | (0xB << 28)); - tlb_flush_page(env, T0 | (0xC << 28)); - tlb_flush_page(env, T0 | (0xD << 28)); - tlb_flush_page(env, T0 | (0xE << 28)); - tlb_flush_page(env, T0 | (0xF << 28)); - } -#else - do_tlbia(); -#endif -} - -#if defined(TARGET_PPC64) -void do_tlbie_64 (void) -{ - T0 = (uint64_t)T0; -#if !defined(FLUSH_ALL_TLBS) - if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx)) { - ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 0); - if (env->id_tlbs == 1) - ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 1); - } else if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_4xx)) { - /* XXX: TODO */ -#if 0 - ppcbooke_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, - env->spr[SPR_BOOKE_PID]); -#endif - } else { - /* tlbie invalidate TLBs for all segments - * As we have 2^36 segments, invalidate all qemu TLBs - */ -#if 0 - T0 &= TARGET_PAGE_MASK; - T0 &= ~((target_ulong)-1 << 28); - /* XXX: this case should be optimized, - * giving a mask to tlb_flush_page - */ - tlb_flush_page(env, T0 | (0x0 << 28)); - tlb_flush_page(env, T0 | (0x1 << 28)); - tlb_flush_page(env, T0 | (0x2 << 28)); - tlb_flush_page(env, T0 | (0x3 << 28)); - tlb_flush_page(env, T0 | (0x4 << 28)); - tlb_flush_page(env, T0 | (0x5 << 28)); - tlb_flush_page(env, T0 | (0x6 << 28)); - tlb_flush_page(env, T0 | (0x7 << 28)); - tlb_flush_page(env, T0 | (0x8 << 28)); - tlb_flush_page(env, T0 | (0x9 << 28)); - tlb_flush_page(env, T0 | (0xA << 28)); - tlb_flush_page(env, T0 | (0xB << 28)); - tlb_flush_page(env, T0 | (0xC << 28)); - tlb_flush_page(env, T0 | (0xD << 28)); - tlb_flush_page(env, T0 | (0xE << 28)); - tlb_flush_page(env, T0 | (0xF << 28)); -#else - tlb_flush(env, 1); -#endif - } -#else - do_tlbia(); -#endif -} -#endif - -#if defined(TARGET_PPC64) -void do_slbia (void) -{ - /* XXX: TODO */ - tlb_flush(env, 1); -} - -void do_slbie (void) -{ - /* XXX: TODO */ - tlb_flush(env, 1); -} -#endif - /* Software driven TLBs management */ /* PowerPC 602/603 software TLB load instructions helpers */ void do_load_6xx_tlb (int is_code) @@ -2575,21 +2462,6 @@ void do_4xx_tlbre_hi (void) T0 |= 0x100; } -void do_4xx_tlbsx (void) -{ - T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_40x_PID]); -} - -void do_4xx_tlbsx_ (void) -{ - int tmp = xer_so; - - T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_40x_PID]); - if (T0 != -1) - tmp |= 0x02; - env->crf[0] = tmp; -} - void do_4xx_tlbwe_hi (void) { ppcemb_tlb_t *tlb; @@ -2757,21 +2629,6 @@ void do_440_tlbwe (int word) } } -void do_440_tlbsx (void) -{ - T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR] & 0xFF); -} - -void do_440_tlbsx_ (void) -{ - int tmp = xer_so; - - T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR] & 0xFF); - if (T0 != -1) - tmp |= 0x02; - env->crf[0] = tmp; -} - void do_440_tlbre (int word) { ppcemb_tlb_t *tlb; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 6faf0b6717..d76a92a65d 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4991,10 +4991,9 @@ GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB) return; } gen_addr_reg_index(ctx); + gen_op_4xx_tlbsx(); if (Rc(ctx->opcode)) - gen_op_4xx_tlbsx_(); - else - gen_op_4xx_tlbsx(); + gen_op_4xx_tlbsx_check(); gen_op_store_T0_gpr(rD(ctx->opcode)); #endif } @@ -5064,10 +5063,9 @@ GEN_HANDLER(tlbsx_440, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE) return; } gen_addr_reg_index(ctx); + gen_op_440_tlbsx(); if (Rc(ctx->opcode)) - gen_op_440_tlbsx_(); - else - gen_op_440_tlbsx(); + gen_op_4xx_tlbsx_check(); gen_op_store_T0_gpr(rD(ctx->opcode)); #endif }