mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-17 23:22:12 -06:00
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>
This commit is contained in:
parent
629bd516fd
commit
25de24ab83
5 changed files with 231 additions and 41 deletions
|
@ -303,6 +303,7 @@ static int get_segment32(CPUPPCState *env, mmu_ctx_t *ctx,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
|
int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
|
||||||
target_ulong eaddr, int rw, int access_type)
|
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;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
int pte32_is_valid(target_ulong pte0);
|
int pte32_is_valid(target_ulong pte0);
|
||||||
int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
|
int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
|
||||||
target_ulong eaddr, int rw, int access_type);
|
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 */
|
#endif /* CONFIG_USER_ONLY */
|
||||||
|
|
||||||
|
|
|
@ -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);
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -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_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
|
||||||
int ppc_hash64_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
|
int ppc_hash64_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
|
||||||
target_ulong eaddr, int rw, int access_type);
|
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
|
||||||
|
|
||||||
#endif /* CONFIG_USER_ONLY */
|
#endif /* CONFIG_USER_ONLY */
|
||||||
|
|
|
@ -1438,6 +1438,22 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
|
||||||
int access_type;
|
int access_type;
|
||||||
int ret = 0;
|
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) {
|
if (rw == 2) {
|
||||||
/* code access */
|
/* code access */
|
||||||
rw = 0;
|
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_DEAR] = address;
|
||||||
env->spr[SPR_40x_ESR] = 0x00000000;
|
env->spr[SPR_40x_ESR] = 0x00000000;
|
||||||
break;
|
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:
|
case POWERPC_MMU_BOOKE206:
|
||||||
booke206_update_mas_tlb_miss(env, address, rw);
|
booke206_update_mas_tlb_miss(env, address, rw);
|
||||||
/* fall through */
|
/* 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->exception_index = POWERPC_EXCP_ISI;
|
||||||
env->error_code = 0x10000000;
|
env->error_code = 0x10000000;
|
||||||
break;
|
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 {
|
} else {
|
||||||
switch (ret) {
|
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;
|
env->spr[SPR_40x_ESR] = 0x00000000;
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case POWERPC_MMU_MPC8xx:
|
||||||
/* XXX: TODO */
|
/* XXX: TODO */
|
||||||
cpu_abort(env, "MPC8xx MMU model is not implemented\n");
|
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;
|
||||||
}
|
}
|
||||||
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
|
#if 0
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue