diff options
author | j_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-11-19 11:41:10 +0000 |
---|---|---|
committer | j_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-11-19 11:41:10 +0000 |
commit | add78955b0451c6d14d325d66592a634b2e5d595 (patch) | |
tree | 7cf2b133679c9c26db7315e6895f7cd33863be62 | |
parent | 5b8105fa50b0dfde4ac49d7b1dd8044fb82caec6 (diff) |
PowerPC 620 MMU do not have the same exact behavior as standard
64 bits PowerPC ones.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3706 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r-- | target-ppc/cpu.h | 27 | ||||
-rw-r--r-- | target-ppc/helper.c | 41 | ||||
-rw-r--r-- | target-ppc/translate_init.c | 9 |
3 files changed, 53 insertions, 24 deletions
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index d2faf61e8e..6f3ff86a1c 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -93,30 +93,33 @@ typedef uint32_t ppc_gpr_t; /* MMU model */ typedef enum powerpc_mmu_t powerpc_mmu_t; enum powerpc_mmu_t { - POWERPC_MMU_UNKNOWN = 0, + POWERPC_MMU_UNKNOWN = 0x00000000, /* Standard 32 bits PowerPC MMU */ - POWERPC_MMU_32B, + POWERPC_MMU_32B = 0x00000001, /* PowerPC 6xx MMU with software TLB */ - POWERPC_MMU_SOFT_6xx, + POWERPC_MMU_SOFT_6xx = 0x00000002, /* PowerPC 74xx MMU with software TLB */ - POWERPC_MMU_SOFT_74xx, + POWERPC_MMU_SOFT_74xx = 0x00000003, /* PowerPC 4xx MMU with software TLB */ - POWERPC_MMU_SOFT_4xx, + POWERPC_MMU_SOFT_4xx = 0x00000004, /* PowerPC 4xx MMU with software TLB and zones protections */ - POWERPC_MMU_SOFT_4xx_Z, + POWERPC_MMU_SOFT_4xx_Z = 0x00000005, /* PowerPC MMU in real mode only */ - POWERPC_MMU_REAL, + POWERPC_MMU_REAL = 0x00000006, /* Freescale MPC8xx MMU model */ - POWERPC_MMU_MPC8xx, + POWERPC_MMU_MPC8xx = 0x00000007, /* BookE MMU model */ - POWERPC_MMU_BOOKE, + POWERPC_MMU_BOOKE = 0x00000008, /* BookE FSL MMU model */ - POWERPC_MMU_BOOKE_FSL, + POWERPC_MMU_BOOKE_FSL = 0x00000009, /* PowerPC 601 MMU model (specific BATs format) */ - POWERPC_MMU_601, + POWERPC_MMU_601 = 0x0000000A, #if defined(TARGET_PPC64) +#define POWERPC_MMU_64 0x00010000 /* 64 bits PowerPC MMU */ - POWERPC_MMU_64B, + POWERPC_MMU_64B = POWERPC_MMU_64 | 0x00000001, + /* 620 variant (no segment exceptions) */ + POWERPC_MMU_620 = POWERPC_MMU_64 | 0x00000002, #endif /* defined(TARGET_PPC64) */ }; diff --git a/target-ppc/helper.c b/target-ppc/helper.c index b4c38395f5..cb9b778cc7 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -706,7 +706,7 @@ static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx, int h, int rw, int type) { #if defined(TARGET_PPC64) - if (env->mmu_model == POWERPC_MMU_64B) + if (env->mmu_model & POWERPC_MMU_64) return find_pte64(ctx, h, rw, type); #endif @@ -916,7 +916,7 @@ static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx, pr = msr_pr; #if defined(TARGET_PPC64) - if (env->mmu_model == POWERPC_MMU_64B) { + if (env->mmu_model & POWERPC_MMU_64) { #if defined (DEBUG_MMU) if (loglevel != 0) { fprintf(logfile, "Check SLBs\n"); @@ -973,7 +973,7 @@ static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx, sdr = env->sdr1; pgidx = (eaddr & page_mask) >> TARGET_PAGE_BITS; #if defined(TARGET_PPC64) - if (env->mmu_model == POWERPC_MMU_64B) { + if (env->mmu_model & POWERPC_MMU_64) { htab_mask = 0x0FFFFFFF >> (28 - (sdr & 0x1F)); /* XXX: this is false for 1 TB segments */ hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask; @@ -1002,7 +1002,7 @@ static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx, #endif ctx->pg_addr[1] = get_pgaddr(sdr, sdr_sh, hash, mask); #if defined(TARGET_PPC64) - if (env->mmu_model == POWERPC_MMU_64B) { + if (env->mmu_model & POWERPC_MMU_64) { /* Only 5 bits of the page index are used in the AVPN */ ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80); } else @@ -1362,6 +1362,7 @@ static always_inline int check_physical (CPUState *env, mmu_ctx_t *ctx, ctx->prot |= PAGE_WRITE; break; #if defined(TARGET_PPC64) + case POWERPC_MMU_620: case POWERPC_MMU_64B: /* Real address are 60 bits long */ ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL; @@ -1430,6 +1431,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, case POWERPC_MMU_SOFT_6xx: case POWERPC_MMU_SOFT_74xx: #if defined(TARGET_PPC64) + case POWERPC_MMU_620: case POWERPC_MMU_64B: #endif /* Try to find a BAT */ @@ -1538,6 +1540,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, case POWERPC_MMU_32B: case POWERPC_MMU_601: #if defined(TARGET_PPC64) + case POWERPC_MMU_620: case POWERPC_MMU_64B: #endif env->exception_index = POWERPC_EXCP_ISI; @@ -1583,8 +1586,14 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, #if defined(TARGET_PPC64) case -5: /* No match in segment table */ - env->exception_index = POWERPC_EXCP_ISEG; - env->error_code = 0; + if (env->mmu_model == POWERPC_MMU_620) { + env->exception_index = POWERPC_EXCP_ISI; + /* XXX: this might be incorrect */ + env->error_code = 0x40000000; + } else { + env->exception_index = POWERPC_EXCP_ISEG; + env->error_code = 0; + } break; #endif } @@ -1634,6 +1643,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, case POWERPC_MMU_32B: case POWERPC_MMU_601: #if defined(TARGET_PPC64) + case POWERPC_MMU_620: case POWERPC_MMU_64B: #endif env->exception_index = POWERPC_EXCP_DSI; @@ -1716,9 +1726,20 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, #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; + if (env->mmu_model == POWERPC_MMU_620) { + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = address; + /* XXX: this might be incorrect */ + if (rw == 1) + env->spr[SPR_DSISR] = 0x42000000; + else + env->spr[SPR_DSISR] = 0x40000000; + } else { + env->exception_index = POWERPC_EXCP_DSEG; + env->error_code = 0; + env->spr[SPR_DAR] = address; + } break; #endif } @@ -1955,6 +1976,7 @@ void ppc_tlb_invalidate_all (CPUPPCState *env) case POWERPC_MMU_32B: case POWERPC_MMU_601: #if defined(TARGET_PPC64) + case POWERPC_MMU_620: case POWERPC_MMU_64B: #endif /* defined(TARGET_PPC64) */ tlb_flush(env, 1); @@ -2021,6 +2043,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) tlb_flush_page(env, addr | (0xF << 28)); break; #if defined(TARGET_PPC64) + case POWERPC_MMU_620: case POWERPC_MMU_64B: /* tlbie invalidate TLBs for all segments */ /* XXX: given the fact that there are too many segments to invalidate, diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index ce0027cc39..f3bc1f5f7f 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -5237,13 +5237,13 @@ static void init_proc_970MP (CPUPPCState *env) /* PowerPC 620 */ #define POWERPC_INSNS_620 (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT | \ PPC_64B | PPC_SLBI) -#define POWERPC_MSRM_620 (0x800000000005FF73ULL) -#define POWERPC_MMU_620 (POWERPC_MMU_64B) +#define POWERPC_MSRM_620 (0x800000000005FF77ULL) +//#define POWERPC_MMU_620 (POWERPC_MMU_620) #define POWERPC_EXCP_620 (POWERPC_EXCP_970) #define POWERPC_INPUT_620 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_620 (bfd_mach_ppc64) #define POWERPC_FLAG_620 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_BUS_CLK) + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) #define check_pow_620 check_pow_nocheck /* Check this */ __attribute__ (( unused )) @@ -8313,6 +8313,9 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) case POWERPC_MMU_64B: mmu_model = "PowerPC 64"; break; + case POWERPC_MMU_620: + mmu_model = "PowerPC 620"; + break; #endif default: mmu_model = "Unknown or invalid"; |