diff --git a/target-microblaze/mmu.c b/target-microblaze/mmu.c index adf11c839d..d868ac56e9 100644 --- a/target-microblaze/mmu.c +++ b/target-microblaze/mmu.c @@ -127,6 +127,16 @@ unsigned int mmu_translate(struct microblaze_mmu *mmu, tlb_zsel = (d >> 4) & 0xf; t0 = mmu->regs[MMU_R_ZPR] >> (30 - (tlb_zsel * 2)); t0 &= 0x3; + + if (tlb_zsel > mmu->c_mmu_zones) { + qemu_log("tlb zone select out of range! %d\n", tlb_zsel); + t0 = 1; /* Ignore. */ + } + + if (mmu->c_mmu == 1) { + t0 = 1; /* Zones are disabled. */ + } + switch (t0) { case 0: if (mmu_idx == MMU_USER_IDX) @@ -142,9 +152,9 @@ unsigned int mmu_translate(struct microblaze_mmu *mmu, tlb_ex = 1; tlb_wr = 1; break; + default: break; } - lu->err = ERR_PROT; lu->prot = PAGE_READ; if (tlb_wr) @@ -180,15 +190,33 @@ uint32_t mmu_read(CPUState *env, uint32_t rn) unsigned int i; uint32_t r; + if (env->mmu.c_mmu < 2 || !env->mmu.c_mmu_tlb_access) { + qemu_log("MMU access on MMU-less system\n"); + return 0; + } + switch (rn) { /* Reads to HI/LO trig reads from the mmu rams. */ case MMU_R_TLBLO: case MMU_R_TLBHI: + if (!(env->mmu.c_mmu_tlb_access & 1)) { + qemu_log("Invalid access to MMU reg %d\n", rn); + return 0; + } + i = env->mmu.regs[MMU_R_TLBX] & 0xff; r = env->mmu.rams[rn & 1][i]; if (rn == MMU_R_TLBHI) env->mmu.regs[MMU_R_PID] = env->mmu.tids[i]; break; + case MMU_R_PID: + case MMU_R_ZPR: + if (!(env->mmu.c_mmu_tlb_access & 1)) { + qemu_log("Invalid access to MMU reg %d\n", rn); + return 0; + } + r = env->mmu.regs[rn]; + break; default: r = env->mmu.regs[rn]; break; @@ -202,6 +230,11 @@ void mmu_write(CPUState *env, uint32_t rn, uint32_t v) unsigned int i; D(qemu_log("%s rn=%d=%x old=%x\n", __func__, rn, v, env->mmu.regs[rn])); + if (env->mmu.c_mmu < 2 || !env->mmu.c_mmu_tlb_access) { + qemu_log("MMU access on MMU-less system\n"); + return; + } + switch (rn) { /* Writes to HI/LO trig writes to the mmu rams. */ case MMU_R_TLBLO: @@ -219,6 +252,11 @@ void mmu_write(CPUState *env, uint32_t rn, uint32_t v) D(qemu_log("%s ram[%d][%d]=%x\n", __func__, rn & 1, i, v)); break; case MMU_R_ZPR: + if (env->mmu.c_mmu_tlb_access <= 1) { + qemu_log("Invalid access to MMU reg %d\n", rn); + return; + } + /* Changes to the zone protection reg flush the QEMU TLB. Fortunately, these are very uncommon. */ if (v != env->mmu.regs[rn]) { @@ -227,6 +265,11 @@ void mmu_write(CPUState *env, uint32_t rn, uint32_t v) env->mmu.regs[rn] = v; break; case MMU_R_PID: + if (env->mmu.c_mmu_tlb_access <= 1) { + qemu_log("Invalid access to MMU reg %d\n", rn); + return; + } + if (v != env->mmu.regs[rn]) { mmu_change_pid(env, v); env->mmu.regs[rn] = v; @@ -236,6 +279,12 @@ void mmu_write(CPUState *env, uint32_t rn, uint32_t v) { struct microblaze_mmu_lookup lu; int hit; + + if (env->mmu.c_mmu_tlb_access <= 1) { + qemu_log("Invalid access to MMU reg %d\n", rn); + return; + } + hit = mmu_translate(&env->mmu, &lu, v & TLB_EPN_MASK, 0, cpu_mmu_index(env)); if (hit) { @@ -252,5 +301,8 @@ void mmu_write(CPUState *env, uint32_t rn, uint32_t v) void mmu_init(struct microblaze_mmu *mmu) { - memset(mmu, 0, sizeof *mmu); + int i; + for (i = 0; i < ARRAY_SIZE(mmu->regs); i++) { + mmu->regs[i] = 0; + } } diff --git a/target-microblaze/mmu.h b/target-microblaze/mmu.h index 814c33cc7b..56149a54fd 100644 --- a/target-microblaze/mmu.h +++ b/target-microblaze/mmu.h @@ -63,7 +63,11 @@ struct microblaze_mmu /* We keep a separate ram for the tids to avoid the 48 bit tag width. */ uint8_t tids[TLB_ENTRIES]; /* Control flops. */ - uint32_t regs[8];; + uint32_t regs[8]; + + int c_mmu; + int c_mmu_tlb_access; + int c_mmu_zones; }; struct microblaze_mmu_lookup diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index b863eb0a16..3c69160135 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -1442,7 +1442,7 @@ CPUState *cpu_mb_init (const char *cpu_model) | PVR0_USE_DCACHE_MASK \ | PVR0_USE_MMU \ | (0xb << 8); - env->pvr.regs[2] = PVR2_D_OPB_MASK \ + env->pvr.regs[2] = PVR2_D_OPB_MASK \ | PVR2_D_LMB_MASK \ | PVR2_I_OPB_MASK \ | PVR2_I_LMB_MASK \ @@ -1453,8 +1453,13 @@ CPUState *cpu_mb_init (const char *cpu_model) | PVR2_USE_HW_MUL_MASK \ | PVR2_USE_MUL64_MASK \ | 0; - env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family. */ - env->pvr.regs[11] = PVR11_USE_MMU; + env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family. */ + env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17); +#if !defined(CONFIG_USER_ONLY) + env->mmu.c_mmu = 3; + env->mmu.c_mmu_tlb_access = 3; + env->mmu.c_mmu_zones = 16; +#endif if (tcg_initialized) return env;