summaryrefslogtreecommitdiff
path: root/target-ppc/helper.c
diff options
context:
space:
mode:
authorj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>2007-10-01 05:16:57 +0000
committerj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>2007-10-01 05:16:57 +0000
commit7dbe11acd807b7a1566b2fe665333a49f8358de0 (patch)
treeb0c9681451bcb1d5631c564e8a5d6b9bd56bb725 /target-ppc/helper.c
parent578bb25230229307c0b6ff62ae03ac0fbda27b18 (diff)
downloadqemu-7dbe11acd807b7a1566b2fe665333a49f8358de0.tar.gz
Handle all MMU models in switches, even if it's just to abort because of lack
of supporting code. Implement 74xx software TLB model. Keep 74xx with software TLB disabled, as Linux is not able to handle TLB miss on those processors. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3307 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-ppc/helper.c')
-rw-r--r--target-ppc/helper.c107
1 files changed, 100 insertions, 7 deletions
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 66dc7b22a8..5b0fd09b9c 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -664,7 +664,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
int ret, ret2;
#if defined(TARGET_PPC64)
- if (env->mmu_model == POWERPC_MMU_64B) {
+ if (env->mmu_model == POWERPC_MMU_64B ||
+ env->mmu_model == POWERPC_MMU_64BRIDGE) {
ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr);
if (ret < 0)
return ret;
@@ -730,7 +731,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
}
/* Initialize real address with an invalid value */
ctx->raddr = (target_ulong)-1;
- if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx)) {
+ if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
+ env->mmu_model == POWERPC_MMU_SOFT_74xx)) {
/* Software TLB search */
ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
} else {
@@ -1092,9 +1094,11 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx,
switch (env->mmu_model) {
case POWERPC_MMU_32B:
case POWERPC_MMU_SOFT_6xx:
+ case POWERPC_MMU_SOFT_74xx:
case POWERPC_MMU_601:
case POWERPC_MMU_SOFT_4xx:
case POWERPC_MMU_REAL_4xx:
+ case POWERPC_MMU_BOOKE:
ctx->prot |= PAGE_WRITE;
break;
#if defined(TARGET_PPC64)
@@ -1129,9 +1133,6 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx,
}
}
break;
- case POWERPC_MMU_BOOKE:
- ctx->prot |= PAGE_WRITE;
- break;
case POWERPC_MMU_BOOKE_FSL:
/* XXX: TODO */
cpu_abort(env, "BookE FSL MMU model not implemented\n");
@@ -1162,6 +1163,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
switch (env->mmu_model) {
case POWERPC_MMU_32B:
case POWERPC_MMU_SOFT_6xx:
+ case POWERPC_MMU_SOFT_74xx:
/* Try to find a BAT */
if (check_BATs)
ret = get_bat(env, ctx, eaddr, rw, access_type);
@@ -1262,6 +1264,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
error_code = 1 << 18;
goto tlb_miss;
+ case POWERPC_MMU_SOFT_74xx:
+ exception = POWERPC_EXCP_IFTLB;
+ goto tlb_miss_74xx;
case POWERPC_MMU_SOFT_4xx:
case POWERPC_MMU_SOFT_4xx_Z:
exception = POWERPC_EXCP_ITLB;
@@ -1346,6 +1351,19 @@ 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;
+ case POWERPC_MMU_SOFT_74xx:
+ if (rw == 1) {
+ exception = POWERPC_EXCP_DSTLB;
+ } else {
+ exception = POWERPC_EXCP_DLTLB;
+ }
+ tlb_miss_74xx:
+ /* Implement LRU algorithm */
+ env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
+ ((env->last_way + 1) & (env->nb_ways - 1));
+ env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
+ error_code = ctx.key << 19;
+ break;
case POWERPC_MMU_SOFT_4xx:
case POWERPC_MMU_SOFT_4xx_Z:
exception = POWERPC_EXCP_DTLB;
@@ -1571,13 +1589,31 @@ void ppc_tlb_invalidate_all (CPUPPCState *env)
{
switch (env->mmu_model) {
case POWERPC_MMU_SOFT_6xx:
+ case POWERPC_MMU_SOFT_74xx:
ppc6xx_tlb_invalidate_all(env);
break;
case POWERPC_MMU_SOFT_4xx:
case POWERPC_MMU_SOFT_4xx_Z:
ppc4xx_tlb_invalidate_all(env);
break;
- default:
+ case POWERPC_MMU_REAL_4xx:
+ cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
+ break;
+ case POWERPC_MMU_BOOKE:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ break;
+ case POWERPC_MMU_BOOKE_FSL:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ break;
+ case POWERPC_MMU_601:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ break;
+ case POWERPC_MMU_32B:
+ case POWERPC_MMU_64B:
+ case POWERPC_MMU_64BRIDGE:
tlb_flush(env, 1);
break;
}
@@ -1589,6 +1625,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
addr &= TARGET_PAGE_MASK;
switch (env->mmu_model) {
case POWERPC_MMU_SOFT_6xx:
+ case POWERPC_MMU_SOFT_74xx:
ppc6xx_tlb_invalidate_virt(env, addr, 0);
if (env->id_tlbs == 1)
ppc6xx_tlb_invalidate_virt(env, addr, 1);
@@ -1597,7 +1634,22 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
case POWERPC_MMU_SOFT_4xx_Z:
ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
break;
- default:
+ case POWERPC_MMU_REAL_4xx:
+ cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
+ break;
+ case POWERPC_MMU_BOOKE:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ break;
+ case POWERPC_MMU_BOOKE_FSL:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ break;
+ case POWERPC_MMU_601:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ break;
+ case POWERPC_MMU_32B:
/* tlbie invalidate TLBs for all segments */
addr &= ~((target_ulong)-1 << 28);
/* XXX: this case should be optimized,
@@ -1619,6 +1671,15 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
tlb_flush_page(env, addr | (0xD << 28));
tlb_flush_page(env, addr | (0xE << 28));
tlb_flush_page(env, addr | (0xF << 28));
+ break;
+ case POWERPC_MMU_64B:
+ case POWERPC_MMU_64BRIDGE:
+ /* tlbie invalidate TLBs for all segments */
+ /* XXX: given the fact that there are too many segments to invalidate,
+ * we just invalidate all TLBs
+ */
+ tlb_flush(env, 1);
+ break;
}
#else
ppc_tlb_invalidate_all(env);
@@ -2317,6 +2378,8 @@ static always_inline void powerpc_excp (CPUState *env,
goto tlb_miss_tgpr;
case POWERPC_EXCP_7x5:
goto tlb_miss;
+ case POWERPC_EXCP_74xx:
+ goto tlb_miss_74xx;
default:
cpu_abort(env, "Invalid instruction TLB miss exception\n");
break;
@@ -2336,6 +2399,8 @@ static always_inline void powerpc_excp (CPUState *env,
goto tlb_miss_tgpr;
case POWERPC_EXCP_7x5:
goto tlb_miss;
+ case POWERPC_EXCP_74xx:
+ goto tlb_miss_74xx;
default:
cpu_abort(env, "Invalid data load TLB miss exception\n");
break;
@@ -2390,6 +2455,34 @@ static always_inline void powerpc_excp (CPUState *env,
/* Set way using a LRU mechanism */
msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
break;
+ case POWERPC_EXCP_74xx:
+ tlb_miss_74xx:
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ const unsigned char *es;
+ target_ulong *miss, *cmp;
+ int en;
+ if (excp == POWERPC_EXCP_IFTLB) {
+ es = "I";
+ en = 'I';
+ miss = &env->spr[SPR_IMISS];
+ cmp = &env->spr[SPR_ICMP];
+ } else {
+ if (excp == POWERPC_EXCP_DLTLB)
+ es = "DL";
+ else
+ es = "DS";
+ en = 'D';
+ miss = &env->spr[SPR_TLBMISS];
+ cmp = &env->spr[SPR_PTEHI];
+ }
+ fprintf(logfile, "74xx %sTLB miss: %cM " ADDRX " %cC " ADDRX
+ " %08x\n",
+ es, en, *miss, en, *cmp, env->error_code);
+ }
+#endif
+ msr |= env->error_code; /* key bit */
+ break;
default:
cpu_abort(env, "Invalid data store TLB miss exception\n");
break;