aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2013-03-12 00:31:12 +0000
committerAlexander Graf <agraf@suse.de>2013-03-22 15:28:47 +0100
commit25de24ab838be5801d5cc13b8a347922a3770fa5 (patch)
tree9a17bbc7aadc83308487299126400299c02ea61b
parent629bd516fda67c95ba1c7d1393bacb9e68ea0712 (diff)
target-ppc: Disentangle hash mmu paths for cpu_ppc_handle_mmu_fault
cpu_ppc_handle_mmu_fault() calls get_physical_address() (whose behaviour depends on MMU type) then, if that fails, issues an appropriate exception - which again has a number of dependencies on MMU type. This patch starts converting cpu_ppc_handle_mmu_fault() to have a single switch on MMU type, calling MMU specific fault handler functions which deal with both translation and exception delivery appropriately for the MMU type. We convert 32-bit and 64-bit hash MMUs to this new model, but the existing code is left in place for other MMU types for now. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Alexander Graf <agraf@suse.de>
-rw-r--r--target-ppc/mmu-hash32.c124
-rw-r--r--target-ppc/mmu-hash32.h2
-rw-r--r--target-ppc/mmu-hash64.c87
-rw-r--r--target-ppc/mmu-hash64.h2
-rw-r--r--target-ppc/mmu_helper.c57
5 files changed, 231 insertions, 41 deletions
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 3998d635f2..50f8c5495c 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -303,6 +303,7 @@ static int get_segment32(CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
+
int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
target_ulong eaddr, int rw, int access_type)
{
@@ -327,3 +328,126 @@ int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
}
+
+int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+ int mmu_idx)
+{
+ mmu_ctx_t ctx;
+ int access_type;
+ int ret = 0;
+
+ if (rw == 2) {
+ /* code access */
+ rw = 0;
+ access_type = ACCESS_CODE;
+ } else {
+ /* data access */
+ access_type = env->access_type;
+ }
+ ret = ppc_hash32_get_physical_address(env, &ctx, address, rw, access_type);
+ if (ret == 0) {
+ tlb_set_page(env, address & TARGET_PAGE_MASK,
+ ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
+ mmu_idx, TARGET_PAGE_SIZE);
+ ret = 0;
+ } else if (ret < 0) {
+ LOG_MMU_STATE(env);
+ if (access_type == ACCESS_CODE) {
+ switch (ret) {
+ case -1:
+ /* No matches in page tables or TLB */
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x40000000;
+ break;
+ case -2:
+ /* Access rights violation */
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x08000000;
+ break;
+ case -3:
+ /* No execute protection violation */
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x10000000;
+ break;
+ case -4:
+ /* Direct store exception */
+ /* No code fetch is allowed in direct-store areas */
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x10000000;
+ break;
+ }
+ } else {
+ switch (ret) {
+ case -1:
+ /* No matches in page tables or TLB */
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ if (rw == 1) {
+ env->spr[SPR_DSISR] = 0x42000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x40000000;
+ }
+ break;
+ case -2:
+ /* Access rights violation */
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ if (rw == 1) {
+ env->spr[SPR_DSISR] = 0x0A000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x08000000;
+ }
+ break;
+ case -4:
+ /* Direct store exception */
+ switch (access_type) {
+ case ACCESS_FLOAT:
+ /* Floating point load/store */
+ env->exception_index = POWERPC_EXCP_ALIGN;
+ env->error_code = POWERPC_EXCP_ALIGN_FP;
+ env->spr[SPR_DAR] = address;
+ break;
+ case ACCESS_RES:
+ /* lwarx, ldarx or stwcx. */
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ if (rw == 1) {
+ env->spr[SPR_DSISR] = 0x06000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x04000000;
+ }
+ break;
+ case ACCESS_EXT:
+ /* eciwx or ecowx */
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ if (rw == 1) {
+ env->spr[SPR_DSISR] = 0x06100000;
+ } else {
+ env->spr[SPR_DSISR] = 0x04100000;
+ }
+ break;
+ default:
+ printf("DSI: invalid exception (%d)\n", ret);
+ env->exception_index = POWERPC_EXCP_PROGRAM;
+ env->error_code =
+ POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
+ env->spr[SPR_DAR] = address;
+ break;
+ }
+ break;
+ }
+ }
+#if 0
+ printf("%s: set exception to %d %02x\n", __func__,
+ env->exception, env->error_code);
+#endif
+ ret = 1;
+ }
+
+ return ret;
+}
diff --git a/target-ppc/mmu-hash32.h b/target-ppc/mmu-hash32.h
index 1318562107..8f1f2a92a3 100644
--- a/target-ppc/mmu-hash32.h
+++ b/target-ppc/mmu-hash32.h
@@ -6,6 +6,8 @@
int pte32_is_valid(target_ulong pte0);
int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
target_ulong eaddr, int rw, int access_type);
+int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+ int mmu_idx);
#endif /* CONFIG_USER_ONLY */
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index c7272982b8..32825ff04e 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -450,3 +450,90 @@ int ppc_hash64_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
return get_segment64(env, ctx, eaddr, rw, access_type);
}
}
+
+int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+ int mmu_idx)
+{
+ mmu_ctx_t ctx;
+ int access_type;
+ int ret = 0;
+
+ if (rw == 2) {
+ /* code access */
+ rw = 0;
+ access_type = ACCESS_CODE;
+ } else {
+ /* data access */
+ access_type = env->access_type;
+ }
+ ret = ppc_hash64_get_physical_address(env, &ctx, address, rw, access_type);
+ if (ret == 0) {
+ tlb_set_page(env, address & TARGET_PAGE_MASK,
+ ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
+ mmu_idx, TARGET_PAGE_SIZE);
+ ret = 0;
+ } else if (ret < 0) {
+ LOG_MMU_STATE(env);
+ if (access_type == ACCESS_CODE) {
+ switch (ret) {
+ case -1:
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x40000000;
+ break;
+ case -2:
+ /* Access rights violation */
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x08000000;
+ break;
+ case -3:
+ /* No execute protection violation */
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x10000000;
+ break;
+ case -5:
+ /* No match in segment table */
+ env->exception_index = POWERPC_EXCP_ISEG;
+ env->error_code = 0;
+ break;
+ }
+ } else {
+ switch (ret) {
+ case -1:
+ /* No matches in page tables or TLB */
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ if (rw == 1) {
+ env->spr[SPR_DSISR] = 0x42000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x40000000;
+ }
+ break;
+ case -2:
+ /* Access rights violation */
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ if (rw == 1) {
+ env->spr[SPR_DSISR] = 0x0A000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x08000000;
+ }
+ break;
+ case -5:
+ /* No match in segment table */
+ env->exception_index = POWERPC_EXCP_DSEG;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ break;
+ }
+ }
+#if 0
+ printf("%s: set exception to %d %02x\n", __func__,
+ env->exception, env->error_code);
+#endif
+ ret = 1;
+ }
+
+ return ret;
+}
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
index d8eb8ded8a..3a53e61673 100644
--- a/target-ppc/mmu-hash64.h
+++ b/target-ppc/mmu-hash64.h
@@ -8,6 +8,8 @@ void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
int ppc_hash64_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
target_ulong eaddr, int rw, int access_type);
+int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+ int mmu_idx);
#endif
#endif /* CONFIG_USER_ONLY */
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index ce39f494c5..287334ffb9 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -1438,6 +1438,22 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
int access_type;
int ret = 0;
+ switch (env->mmu_model) {
+#if defined(TARGET_PPC64)
+ case POWERPC_MMU_64B:
+ case POWERPC_MMU_2_06:
+ case POWERPC_MMU_2_06d:
+ return ppc_hash64_handle_mmu_fault(env, address, rw, mmu_idx);
+#endif
+
+ case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
+ return ppc_hash32_handle_mmu_fault(env, address, rw, mmu_idx);
+
+ default:
+ ; /* Otherwise fall through to the general code below */
+ }
+
if (rw == 2) {
/* code access */
rw = 0;
@@ -1475,16 +1491,6 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
env->spr[SPR_40x_DEAR] = address;
env->spr[SPR_40x_ESR] = 0x00000000;
break;
- case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06d:
-#endif
- env->exception_index = POWERPC_EXCP_ISI;
- env->error_code = 0x40000000;
- break;
case POWERPC_MMU_BOOKE206:
booke206_update_mas_tlb_miss(env, address, rw);
/* fall through */
@@ -1526,13 +1532,6 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
env->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x10000000;
break;
-#if defined(TARGET_PPC64)
- case -5:
- /* No match in segment table */
- env->exception_index = POWERPC_EXCP_ISEG;
- env->error_code = 0;
- break;
-#endif
}
} else {
switch (ret) {
@@ -1580,22 +1579,6 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
env->spr[SPR_40x_ESR] = 0x00000000;
}
break;
- case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06d:
-#endif
- env->exception_index = POWERPC_EXCP_DSI;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- if (rw == 1) {
- env->spr[SPR_DSISR] = 0x42000000;
- } else {
- env->spr[SPR_DSISR] = 0x40000000;
- }
- break;
case POWERPC_MMU_MPC8xx:
/* XXX: TODO */
cpu_abort(env, "MPC8xx MMU model is not implemented\n");
@@ -1681,14 +1664,6 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
break;
}
break;
-#if defined(TARGET_PPC64)
- case -5:
- /* No match in segment table */
- env->exception_index = POWERPC_EXCP_DSEG;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- break;
-#endif
}
}
#if 0