int cpu_ppc_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 = 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 */ switch (env->mmu_model) { case POWERPC_MMU_SOFT_6xx: env->exception_index = POWERPC_EXCP_IFTLB; env->error_code = 1 << 18; env->spr[SPR_IMISS] = address; env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem; goto tlb_miss; case POWERPC_MMU_SOFT_74xx: env->exception_index = POWERPC_EXCP_IFTLB; goto tlb_miss_74xx; case POWERPC_MMU_SOFT_4xx: case POWERPC_MMU_SOFT_4xx_Z: env->exception_index = POWERPC_EXCP_ITLB; env->error_code = 0; 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_620: case POWERPC_MMU_64B: case POWERPC_MMU_2_06: #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 */ case POWERPC_MMU_BOOKE: env->exception_index = POWERPC_EXCP_ITLB; env->error_code = 0; env->spr[SPR_BOOKE_DEAR] = address; return -1; case POWERPC_MMU_MPC8xx: /* XXX: TODO */ cpu_abort(env, "MPC8xx MMU model is not implemented\n"); break; case POWERPC_MMU_REAL: cpu_abort(env, "PowerPC in real mode should never raise " "any MMU exceptions\n"); return -1; default: cpu_abort(env, "Unknown or invalid MMU model\n"); return -1; } break; case -2: /* Access rights violation */ env->exception_index = POWERPC_EXCP_ISI; env->error_code = 0x08000000; break; case -3: /* No execute protection violation */ if ((env->mmu_model == POWERPC_MMU_BOOKE) || (env->mmu_model == POWERPC_MMU_BOOKE206)) { env->spr[SPR_BOOKE_ESR] = 0x00000000; } 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; #if defined(TARGET_PPC64) case -5: /* No match in segment table */ 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 } } else { switch (ret) { case -1: /* No matches in page tables or TLB */ switch (env->mmu_model) { case POWERPC_MMU_SOFT_6xx: if (rw == 1) { env->exception_index = POWERPC_EXCP_DSTLB; env->error_code = 1 << 16; } else { env->exception_index = POWERPC_EXCP_DLTLB; env->error_code = 0; } env->spr[SPR_DMISS] = address; env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem; tlb_miss: env->error_code |= ctx.key << 19; env->spr[SPR_HASH1] = env->htab_base + get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32); env->spr[SPR_HASH2] = env->htab_base + get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32); break; case POWERPC_MMU_SOFT_74xx: if (rw == 1) { env->exception_index = POWERPC_EXCP_DSTLB; } else { env->exception_index = POWERPC_EXCP_DLTLB; } tlb_miss_74xx: /* Implement LRU algorithm */ env->error_code = ctx.key << 19; env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) | ((env->last_way + 1) & (env->nb_ways - 1)); env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem; break; case POWERPC_MMU_SOFT_4xx: case POWERPC_MMU_SOFT_4xx_Z: env->exception_index = POWERPC_EXCP_DTLB; env->error_code = 0; env->spr[SPR_40x_DEAR] = address; if (rw) { env->spr[SPR_40x_ESR] = 0x00800000; } else { env->spr[SPR_40x_ESR] = 0x00000000; } break; case POWERPC_MMU_32B: case POWERPC_MMU_601: #if defined(TARGET_PPC64) case POWERPC_MMU_620: case POWERPC_MMU_64B: case POWERPC_MMU_2_06: #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"); break; case POWERPC_MMU_BOOKE206: booke206_update_mas_tlb_miss(env, address, rw); /* fall through */ case POWERPC_MMU_BOOKE: env->exception_index = POWERPC_EXCP_DTLB; env->error_code = 0; env->spr[SPR_BOOKE_DEAR] = address; env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0; return -1; case POWERPC_MMU_REAL: cpu_abort(env, "PowerPC in real mode should never raise " "any MMU exceptions\n"); return -1; default: cpu_abort(env, "Unknown or invalid MMU model\n"); return -1; } break; case -2: /* Access rights violation */ env->exception_index = POWERPC_EXCP_DSI; env->error_code = 0; if (env->mmu_model == POWERPC_MMU_SOFT_4xx || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) { env->spr[SPR_40x_DEAR] = address; if (rw) { env->spr[SPR_40x_ESR] |= 0x00800000; } } else if ((env->mmu_model == POWERPC_MMU_BOOKE) || (env->mmu_model == POWERPC_MMU_BOOKE206)) { env->spr[SPR_BOOKE_DEAR] = address; env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0; } else { 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 defined(TARGET_PPC64) case -5: /* No match in segment table */ 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 } } #if 0 printf("%s: set exception to %d %02x\n", __func__, env->exception, env->error_code); #endif ret = 1; } return ret; }