summaryrefslogtreecommitdiff
path: root/target-ppc/helper.c
diff options
context:
space:
mode:
authorj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>2007-11-03 13:37:12 +0000
committerj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>2007-11-03 13:37:12 +0000
commitfaadf50e2962dd54175647a80bd6fc4319c91973 (patch)
tree0eb974930ba5a40e54636c813c89a885ec9c2050 /target-ppc/helper.c
parentf10c315f8fa1b5ea06fdccee0001928af47d9147 (diff)
downloadqemu-faadf50e2962dd54175647a80bd6fc4319c91973.tar.gz
PowerPC MMU and exception fixes:
* PowerPC 601 (and probably POWER/POWER2) uses a different BAT format than later PowerPC implementation. * Bugfix in BATs check: must not stop after 4 BATs when more are provided. * Enable POWER 'rac' instruction. * Fix exception prefix for all supported PowerPC implementations. * Fix exceptions, MMU model and bus model for PowerPC 601 & 620. * Enable PowerPC 620 as it could mostly boot a PreP target. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3518 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-ppc/helper.c')
-rw-r--r--target-ppc/helper.c94
1 files changed, 74 insertions, 20 deletions
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index f68656d5d2..9d6f490b53 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -448,12 +448,65 @@ static always_inline int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx,
}
/* Perform BAT hit & translation */
+static always_inline void bat_size_prot (CPUState *env, target_ulong *blp,
+ int *validp, int *protp,
+ target_ulong *BATu, target_ulong *BATl)
+{
+ target_ulong bl;
+ int pp, valid, prot;
+
+ bl = (*BATu & 0x00001FFC) << 15;
+ valid = 0;
+ prot = 0;
+ if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
+ ((msr_pr != 0) && (*BATu & 0x00000001))) {
+ valid = 1;
+ pp = *BATl & 0x00000003;
+ if (pp != 0) {
+ prot = PAGE_READ | PAGE_EXEC;
+ if (pp == 0x2)
+ prot |= PAGE_WRITE;
+ }
+ }
+ *blp = bl;
+ *validp = valid;
+ *protp = prot;
+}
+
+static always_inline void bat_601_size_prot (CPUState *env,target_ulong *blp,
+ int *validp, int *protp,
+ target_ulong *BATu,
+ target_ulong *BATl)
+{
+ target_ulong bl;
+ int key, pp, valid, prot;
+
+ bl = (*BATl & 0x0000003F) << 17;
+ if (loglevel != 0) {
+ fprintf(logfile, "b %02x ==> bl %08x msk %08x\n",
+ *BATl & 0x0000003F, bl, ~bl);
+ }
+ prot = 0;
+ valid = (*BATl >> 6) & 1;
+ if (valid) {
+ pp = *BATu & 0x00000003;
+ if (msr_pr == 0)
+ key = (*BATu >> 3) & 1;
+ else
+ key = (*BATu >> 2) & 1;
+ prot = pp_check(key, pp, 0);
+ }
+ *blp = bl;
+ *validp = valid;
+ *protp = prot;
+}
+
static always_inline int get_bat (CPUState *env, mmu_ctx_t *ctx,
target_ulong virtual, int rw, int type)
{
target_ulong *BATlt, *BATut, *BATu, *BATl;
target_ulong base, BEPIl, BEPIu, bl;
- int i, pp, pr;
+ int i, valid, prot;
int ret = -1;
#if defined (DEBUG_BATS)
@@ -462,7 +515,6 @@ static always_inline int get_bat (CPUState *env, mmu_ctx_t *ctx,
type == ACCESS_CODE ? 'I' : 'D', virtual);
}
#endif
- pr = msr_pr;
switch (type) {
case ACCESS_CODE:
BATlt = env->IBAT[1];
@@ -480,12 +532,16 @@ static always_inline int get_bat (CPUState *env, mmu_ctx_t *ctx,
}
#endif
base = virtual & 0xFFFC0000;
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < env->nb_BATs; i++) {
BATu = &BATut[i];
BATl = &BATlt[i];
BEPIu = *BATu & 0xF0000000;
BEPIl = *BATu & 0x0FFE0000;
- bl = (*BATu & 0x00001FFC) << 15;
+ if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
+ bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
+ } else {
+ bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
+ }
#if defined (DEBUG_BATS)
if (loglevel != 0) {
fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX
@@ -497,20 +553,13 @@ static always_inline int get_bat (CPUState *env, mmu_ctx_t *ctx,
if ((virtual & 0xF0000000) == BEPIu &&
((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
/* BAT matches */
- if (((pr == 0) && (*BATu & 0x00000002)) ||
- ((pr != 0) && (*BATu & 0x00000001))) {
+ if (valid != 0) {
/* Get physical address */
ctx->raddr = (*BATl & 0xF0000000) |
((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
(virtual & 0x0001F000);
/* Compute access rights */
- pp = *BATl & 0x00000003;
- ctx->prot = 0;
- if (pp != 0) {
- ctx->prot = PAGE_READ | PAGE_EXEC;
- if (pp == 0x2)
- ctx->prot |= PAGE_WRITE;
- }
+ ctx->prot = prot;
ret = check_prot(ctx->prot, rw, type);
#if defined (DEBUG_BATS)
if (ret == 0 && loglevel != 0) {
@@ -1302,6 +1351,7 @@ static always_inline int check_physical (CPUState *env, mmu_ctx_t *ctx,
ret = 0;
switch (env->mmu_model) {
case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
case POWERPC_MMU_SOFT_4xx:
@@ -1353,7 +1403,7 @@ static always_inline int check_physical (CPUState *env, mmu_ctx_t *ctx,
}
int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
- int rw, int access_type, int check_BATs)
+ int rw, int access_type)
{
int ret;
@@ -1370,15 +1420,15 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
ret = -1;
switch (env->mmu_model) {
case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
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);
- /* No break here */
#if defined(TARGET_PPC64)
case POWERPC_MMU_64B:
#endif
+ /* Try to find a BAT */
+ if (env->nb_BATs != 0)
+ ret = get_bat(env, ctx, eaddr, rw, access_type);
if (ret < 0) {
/* We didn't match any BAT entry or don't have BATs */
ret = get_segment(env, ctx, eaddr, rw, access_type);
@@ -1419,7 +1469,7 @@ target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
{
mmu_ctx_t ctx;
- if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT, 1) != 0))
+ if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0))
return -1;
return ctx.raddr & TARGET_PAGE_MASK;
@@ -1444,7 +1494,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
access_type = ACCESS_INT;
// access_type = env->access_type;
}
- ret = get_physical_address(env, &ctx, address, rw, access_type, 1);
+ ret = get_physical_address(env, &ctx, address, rw, access_type);
if (ret == 0) {
ret = tlb_set_page_exec(env, address & TARGET_PAGE_MASK,
ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
@@ -1476,6 +1526,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *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:
#endif
@@ -1567,6 +1618,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *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:
#endif
@@ -1809,6 +1861,7 @@ void ppc_tlb_invalidate_all (CPUPPCState *env)
cpu_abort(env, "MMU model not implemented\n");
break;
case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
#if defined(TARGET_PPC64)
case POWERPC_MMU_64B:
#endif /* defined(TARGET_PPC64) */
@@ -1848,6 +1901,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
cpu_abort(env, "MMU model not implemented\n");
break;
case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
/* tlbie invalidate TLBs for all segments */
addr &= ~((target_ulong)-1 << 28);
/* XXX: this case should be optimized,