From daf4f96ece7dc4abdfe29c9a7fdd694ffd8969bb Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 1 Oct 2007 01:51:12 +0000 Subject: Avoid op helpers that would just call helpers for TLB & SLB management: call the helpers directly from the micro-ops. Avoid duplicated code for tlbsx. implementation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3302 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 118 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 90 insertions(+), 28 deletions(-) (limited to 'target-ppc/helper.c') 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,44 +873,41 @@ 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; - target_phys_addr_t raddr; - target_ulong page, end; int i; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; - if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) { - end = tlb->EPN + tlb->size; - for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) - tlb_flush_page(env, page); - tlb->prot &= ~PAGE_VALID; - break; - } + tlb->prot &= ~PAGE_VALID; } + tlb_flush(env, 1); } -/* Helpers specific to PowerPC 40x implementations */ -void ppc4xx_tlb_invalidate_all (CPUState *env) +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; 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. + if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) { end = tlb->EPN + tlb->size; for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) tlb_flush_page(env, page); -#endif tlb->prot &= ~PAGE_VALID; + break; } } - tlb_flush(env, 1); +#else + ppc4xx_tlb_invalidate_all(env); +#endif } 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) -- cgit v1.2.1