From c55e9aefa7c151176e2e88c0f79044580930a970 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 16 Apr 2007 09:21:46 +0000 Subject: [PATCH] PowerPC 4xx software driven TLB fixes + debug traces. Add code provision for more MMU models support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2683 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 12 ++-- target-ppc/helper.c | 138 +++++++++++++++++++++++++++++++++-------- target-ppc/op_helper.c | 52 ++++++++++++++-- 3 files changed, 163 insertions(+), 39 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 5cd1b6008c..eb3340c528 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -581,12 +581,12 @@ struct ppc6xx_tlb_t { typedef struct ppcemb_tlb_t ppcemb_tlb_t; struct ppcemb_tlb_t { - target_ulong RPN; + target_phys_addr_t RPN; target_ulong EPN; target_ulong PID; - int size; - int prot; - int attr; /* Storage attributes */ + target_ulong size; + uint32_t prot; + uint32_t attr; /* Storage attributes */ }; union ppc_tlb_t { @@ -765,10 +765,6 @@ struct CPUPPCState { int id_tlbs; /* If 1, MMU has separated TLBs for instructions & data */ int nb_pids; /* Number of available PID registers */ ppc_tlb_t *tlb; /* TLB is optional. Allocate them only if needed */ - /* Callbacks for specific checks on some implementations */ - int (*tlb_check_more)(CPUPPCState *env, ppc_tlb_t *tlb, int *prot, - target_ulong vaddr, int rw, int acc_type, - int is_user); /* 403 dedicated access protection registers */ target_ulong pb[4]; diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 5f46ae0fdc..2fc5ecd120 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -657,7 +657,8 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong mask; int i, ret, zsel, zpr; - ret = -6; + ret = -1; + raddr = -1; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; /* Check valid flag */ @@ -691,8 +692,8 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, switch (zpr) { case 0x0: if (msr_pr) { - ret = -3; ctx->prot = 0; + ret = -3; break; } /* No break here */ @@ -702,25 +703,26 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, if (!(tlb->prot & PAGE_EXEC)) { ret = -3; } else { - if (tlb->prot & PAGE_WRITE) + if (tlb->prot & PAGE_WRITE) { ctx->prot = PAGE_READ | PAGE_WRITE; - else + } else { ctx->prot = PAGE_READ; + } ret = 0; } break; case 0x3: /* All accesses granted */ - ret = 0; ctx->prot = PAGE_READ | PAGE_WRITE; + ret = 0; break; } } else { switch (zpr) { case 0x0: if (msr_pr) { - ret = -2; ctx->prot = 0; + ret = -2; break; } /* No break here */ @@ -728,20 +730,21 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, case 0x2: /* Check from TLB entry */ /* Check write protection bit */ - if (rw && !(tlb->prot & PAGE_WRITE)) { - ret = -2; + if (tlb->prot & PAGE_WRITE) { + ctx->prot = PAGE_READ | PAGE_WRITE; + ret = 0; } else { - ret = 2; - if (tlb->prot & PAGE_WRITE) - ctx->prot = PAGE_READ | PAGE_WRITE; + ctx->prot = PAGE_READ; + if (rw) + ret = -2; else - ctx->prot = PAGE_READ; + ret = 0; } break; case 0x3: /* All accesses granted */ - ret = 2; ctx->prot = PAGE_READ | PAGE_WRITE; + ret = 0; break; } } @@ -749,11 +752,17 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, ctx->raddr = raddr; if (loglevel) { fprintf(logfile, "%s: access granted " ADDRX " => " REGX - " %d\n", __func__, address, ctx->raddr, ctx->prot); + " %d %d\n", __func__, address, ctx->raddr, ctx->prot, + ret); } - return i; + return 0; } } + if (loglevel) { + fprintf(logfile, "%s: access refused " ADDRX " => " REGX + " %d %d\n", __func__, address, raddr, ctx->prot, + ret); + } return ret; } @@ -808,32 +817,49 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, /* No address translation */ ret = check_physical(env, ctx, eaddr, rw); } else { + ret = -1; switch (PPC_MMU(env)) { case PPC_FLAGS_MMU_32B: case PPC_FLAGS_MMU_SOFT_6xx: /* Try to find a BAT */ - ret = -1; if (check_BATs) ret = get_bat(env, ctx, eaddr, rw, access_type); + /* No break here */ +#if defined(TARGET_PPC64) + case PPC_FLAGS_MMU_64B: + case PPC_FLAGS_MMU_64BRIDGE: +#endif if (ret < 0) { - /* We didn't match any BAT entry */ + /* We didn't match any BAT entry or don't have BATs */ ret = get_segment(env, ctx, eaddr, rw, access_type); } break; case PPC_FLAGS_MMU_SOFT_4xx: + case PPC_FLAGS_MMU_403: ret = mmu4xx_get_physical_address(env, ctx, eaddr, rw, access_type); break; - default: + case PPC_FLAGS_MMU_601: /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); + cpu_abort(env, "601 MMU model not implemented\n"); + return -1; + case PPC_FLAGS_MMU_BOOKE: + /* XXX: TODO */ + cpu_abort(env, "BookeE MMU model not implemented\n"); + return -1; + case PPC_FLAGS_MMU_BOOKE_FSL: + /* XXX: TODO */ + cpu_abort(env, "BookE FSL MMU model not implemented\n"); + return -1; + default: + cpu_abort(env, "Unknown or invalid MMU model\n"); return -1; } } #if 0 if (loglevel > 0) { - fprintf(logfile, "%s address " ADDRX " => " ADDRX "\n", - __func__, eaddr, ctx->raddr); + fprintf(logfile, "%s address " ADDRX " => %d " ADDRX "\n", + __func__, eaddr, ret, ctx->raddr); } #endif @@ -885,19 +911,48 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, switch (ret) { case -1: /* No matches in page tables or TLB */ - if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { + switch (PPC_MMU(env)) { + case PPC_FLAGS_MMU_SOFT_6xx: exception = EXCP_I_TLBMISS; env->spr[SPR_IMISS] = address; env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem; error_code = 1 << 18; goto tlb_miss; - } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { + case PPC_FLAGS_MMU_SOFT_4xx: + case PPC_FLAGS_MMU_403: exception = EXCP_40x_ITLBMISS; error_code = 0; env->spr[SPR_40x_DEAR] = address; env->spr[SPR_40x_ESR] = 0x00000000; - } else { + break; + case PPC_FLAGS_MMU_32B: error_code = 0x40000000; + break; +#if defined(TARGET_PPC64) + case PPC_FLAGS_MMU_64B: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; + case PPC_FLAGS_MMU_64BRIDGE: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; +#endif + case PPC_FLAGS_MMU_601: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; + case PPC_FLAGS_MMU_BOOKE: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; + case PPC_FLAGS_MMU_BOOKE_FSL: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; + default: + cpu_abort(env, "Unknown or invalid MMU model\n"); + return -1; } break; case -2: @@ -924,7 +979,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, switch (ret) { case -1: /* No matches in page tables or TLB */ - if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { + switch (PPC_MMU(env)) { + case PPC_FLAGS_MMU_SOFT_6xx: if (rw == 1) { exception = EXCP_DS_TLBMISS; error_code = 1 << 16; @@ -940,7 +996,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->spr[SPR_HASH2] = ctx.pg_addr[1]; /* Do not alter DAR nor DSISR */ goto out; - } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { + case PPC_FLAGS_MMU_SOFT_4xx: + case PPC_FLAGS_MMU_403: exception = EXCP_40x_DTLBMISS; error_code = 0; env->spr[SPR_40x_DEAR] = address; @@ -948,8 +1005,35 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->spr[SPR_40x_ESR] = 0x00800000; else env->spr[SPR_40x_ESR] = 0x00000000; - } else { + break; + case PPC_FLAGS_MMU_32B: error_code = 0x40000000; + break; +#if defined(TARGET_PPC64) + case PPC_FLAGS_MMU_64B: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; + case PPC_FLAGS_MMU_64BRIDGE: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; +#endif + case PPC_FLAGS_MMU_601: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; + case PPC_FLAGS_MMU_BOOKE: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; + case PPC_FLAGS_MMU_BOOKE_FSL: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; + default: + cpu_abort(env, "Unknown or invalid MMU model\n"); + return -1; } break; case -2: diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 590b31e725..e994486cf5 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -2537,39 +2537,72 @@ void do_4xx_tlbsx_ (void) env->crf[0] = tmp; } -void do_4xx_tlbwe_lo (void) +void do_4xx_tlbwe_hi (void) { ppcemb_tlb_t *tlb; target_ulong page, end; +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel) { + fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); + } +#endif T0 &= 0x3F; tlb = &env->tlb[T0].tlbe; /* Invalidate previous TLB (if it's valid) */ if (tlb->prot & PAGE_VALID) { end = tlb->EPN + tlb->size; +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel) { + fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX + " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end); + } +#endif for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) tlb_flush_page(env, page); } tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7); tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1); - if (T1 & 0x400) + if (T1 & 0x40) tlb->prot |= PAGE_VALID; else tlb->prot &= ~PAGE_VALID; - tlb->PID = env->spr[SPR_BOOKE_PID]; /* PID */ + tlb->PID = env->spr[SPR_40x_PID]; /* PID */ tlb->attr = T1 & 0xFF; +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel) { + fprintf(logfile, "%s: set up TLB %d RPN " ADDRX " EPN " ADDRX + " size " ADDRX " prot %c%c%c%c PID %d\n", __func__, + (int)T0, tlb->RPN, tlb->EPN, tlb->size, + tlb->prot & PAGE_READ ? 'r' : '-', + tlb->prot & PAGE_WRITE ? 'w' : '-', + tlb->prot & PAGE_EXEC ? 'x' : '-', + tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); + } +#endif /* Invalidate new TLB (if valid) */ if (tlb->prot & PAGE_VALID) { end = tlb->EPN + tlb->size; +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel) { + fprintf(logfile, "%s: invalidate TLB %d start " ADDRX + " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end); + } +#endif for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) tlb_flush_page(env, page); } } -void do_4xx_tlbwe_hi (void) +void do_4xx_tlbwe_lo (void) { ppcemb_tlb_t *tlb; +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel) { + fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); + } +#endif T0 &= 0x3F; tlb = &env->tlb[T0].tlbe; tlb->RPN = T1 & 0xFFFFFC00; @@ -2578,5 +2611,16 @@ void do_4xx_tlbwe_hi (void) tlb->prot |= PAGE_EXEC; if (T1 & 0x100) tlb->prot |= PAGE_WRITE; +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel) { + fprintf(logfile, "%s: set up TLB %d RPN " ADDRX " EPN " ADDRX + " size " ADDRX " prot %c%c%c%c PID %d\n", __func__, + (int)T0, tlb->RPN, tlb->EPN, tlb->size, + tlb->prot & PAGE_READ ? 'r' : '-', + tlb->prot & PAGE_WRITE ? 'w' : '-', + tlb->prot & PAGE_EXEC ? 'x' : '-', + tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); + } +#endif } #endif /* !CONFIG_USER_ONLY */