diff options
Diffstat (limited to 'target-ppc/helper.c')
-rw-r--r-- | target-ppc/helper.c | 159 |
1 files changed, 142 insertions, 17 deletions
diff --git a/target-ppc/helper.c b/target-ppc/helper.c index c835b1efe8..c541e7128b 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -549,8 +549,6 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { /* Software TLB search */ ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type); - } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { - /* XXX: TODO */ } else { #if defined (DEBUG_MMU) if (loglevel > 0) { @@ -632,6 +630,115 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, return ret; } +int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, + uint32_t address, int rw, int access_type) +{ + ppcemb_tlb_t *tlb; + target_phys_addr_t raddr; + target_ulong mask; + int i, ret, zsel, zpr; + + ret = -6; + for (i = 0; i < env->nb_tlb; i++) { + tlb = &env->tlb[i].tlbe; + /* Check valid flag */ + if (!(tlb->prot & PAGE_VALID)) { + if (loglevel) + fprintf(logfile, "%s: TLB %d not valid\n", __func__, i); + continue; + } + mask = ~(tlb->size - 1); + if (loglevel) { + fprintf(logfile, "%s: TLB %d address %08x PID %04x <=> " + "%08x %08x %04x\n", + __func__, i, address, env->spr[SPR_40x_PID], + tlb->EPN, mask, tlb->PID); + } + /* Check PID */ + if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) + continue; + /* Check effective address */ + if ((address & mask) != tlb->EPN) + continue; + raddr = (tlb->RPN & mask) | (address & ~mask); + zsel = (tlb->attr >> 4) & 0xF; + zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3; + if (loglevel) { + fprintf(logfile, "%s: TLB %d zsel %d zpr %d rw %d attr %08x\n", + __func__, i, zsel, zpr, rw, tlb->attr); + } + if (access_type == ACCESS_CODE) { + /* Check execute enable bit */ + switch (zpr) { + case 0x0: + if (msr_pr) { + ret = -3; + ctx->prot = 0; + break; + } + /* No break here */ + case 0x1: + case 0x2: + /* Check from TLB entry */ + if (!(tlb->prot & PAGE_EXEC)) { + ret = -3; + } else { + if (tlb->prot & PAGE_WRITE) + ctx->prot = PAGE_READ | PAGE_WRITE; + else + ctx->prot = PAGE_READ; + ret = 0; + } + break; + case 0x3: + /* All accesses granted */ + ret = 0; + ctx->prot = PAGE_READ | PAGE_WRITE; + break; + } + } else { + switch (zpr) { + case 0x0: + if (msr_pr) { + ret = -2; + ctx->prot = 0; + break; + } + /* No break here */ + case 0x1: + case 0x2: + /* Check from TLB entry */ + /* Check write protection bit */ + if (rw && !(tlb->prot & PAGE_WRITE)) { + ret = -2; + } else { + ret = 2; + if (tlb->prot & PAGE_WRITE) + ctx->prot = PAGE_READ | PAGE_WRITE; + else + ctx->prot = PAGE_READ; + } + break; + case 0x3: + /* All accesses granted */ + ret = 2; + ctx->prot = PAGE_READ | PAGE_WRITE; + break; + } + } + if (ret >= 0) { + ctx->raddr = raddr; + if (loglevel) { + fprintf(logfile, "%s: access granted " ADDRX " => " REGX + " %d\n", __func__, address, ctx->raddr, ctx->prot); + } + return i; + } + } + + return ret; +} + static int check_physical (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw) { @@ -682,13 +789,26 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, /* No address translation */ ret = check_physical(env, ctx, eaddr, rw); } else { - /* Try to find a BAT */ - ret = -1; - if (check_BATs) - ret = get_bat(env, ctx, eaddr, rw, access_type); - if (ret < 0) { - /* We didn't match any BAT entry */ - ret = get_segment(env, ctx, eaddr, rw, access_type); + switch (PPC_MMU(env)) { + case PPC_FLAGS_MMU_32B: + case PPC_FLAGS_MMU_SOFT_6xx: + /* Try to find a BAT */ + ret = -1; + if (check_BATs) + ret = get_bat(env, ctx, eaddr, rw, access_type); + if (ret < 0) { + /* We didn't match any BAT entry */ + ret = get_segment(env, ctx, eaddr, rw, access_type); + } + break; + case PPC_FLAGS_MMU_SOFT_4xx: + ret = mmu4xx_get_physical_address(env, ctx, eaddr, + rw, access_type); + break; + default: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; } } #if 0 @@ -753,7 +873,10 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, error_code = 1 << 18; goto tlb_miss; } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { - /* XXX: TODO */ + exception = EXCP_40x_ITLBMISS; + error_code = 0; + env->spr[SPR_40x_DEAR] = address; + env->spr[SPR_40x_ESR] = 0x00000000; } else { error_code = 0x40000000; } @@ -799,7 +922,13 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, /* Do not alter DAR nor DSISR */ goto out; } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { - /* XXX: TODO */ + exception = EXCP_40x_DTLBMISS; + error_code = 0; + env->spr[SPR_40x_DEAR] = address; + if (rw) + env->spr[SPR_40x_ESR] = 0x00800000; + else + env->spr[SPR_40x_ESR] = 0x00000000; } else { error_code = 0x40000000; } @@ -1518,9 +1647,7 @@ void do_interrupt (CPUState *env) switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_40x: /* DTLBMISS on 4xx */ - /* XXX: TODO */ - cpu_abort(env, - "40x DTLBMISS exception is not implemented yet !\n"); + msr &= ~0xFFFF0000; goto store_next; case PPC_FLAGS_EXCP_602: case PPC_FLAGS_EXCP_603: @@ -1538,9 +1665,7 @@ void do_interrupt (CPUState *env) switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_40x: /* ITLBMISS on 4xx */ - /* XXX: TODO */ - cpu_abort(env, - "40x ITLBMISS exception is not implemented yet !\n"); + msr &= ~0xFFFF0000; goto store_next; case PPC_FLAGS_EXCP_602: case PPC_FLAGS_EXCP_603: |