diff options
author | David Gibson <david@gibson.dropbear.id.au> | 2013-03-12 00:31:16 +0000 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2013-03-22 15:28:48 +0100 |
commit | 9813279664162fa50d6124fe8c5ac4871fa59c13 (patch) | |
tree | ffebe29c7a4b2ee1b561e8818a04b2eee8390654 /target-ppc/mmu-hash32.c | |
parent | 59191721a16ae393c01280dc633937374cdf474e (diff) | |
download | hqemu-9813279664162fa50d6124fe8c5ac4871fa59c13.zip hqemu-9813279664162fa50d6124fe8c5ac4871fa59c13.tar.gz |
target-ppc: Disentangle BAT code for 32-bit hash MMUs
The functions for looking up BATs (Block Address Translation - essentially
a level 0 TLB) are shared between the classic 32-bit hash MMUs and the
6xx style software loaded TLB implementations.
This patch splits out a copy for the 32-bit hash MMUs, to facilitate
cleaning it up. The remaining version is left, but cleaned up slightly
to no longer deal with PowerPC 601 peculiarities (601 has a hash MMU).
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'target-ppc/mmu-hash32.c')
-rw-r--r-- | target-ppc/mmu-hash32.c | 140 |
1 files changed, 138 insertions, 2 deletions
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c index 0ccaf7c..f94b65d 100644 --- a/target-ppc/mmu-hash32.c +++ b/target-ppc/mmu-hash32.c @@ -25,6 +25,7 @@ #include "mmu-hash32.h" //#define DEBUG_MMU +//#define DEBUG_BAT #ifdef DEBUG_MMU # define LOG_MMU(...) qemu_log(__VA_ARGS__) @@ -34,6 +35,12 @@ # define LOG_MMU_STATE(...) do { } while (0) #endif +#ifdef DEBUG_BATS +# define LOG_BATS(...) qemu_log(__VA_ARGS__) +#else +# define LOG_BATS(...) do { } while (0) +#endif + #define PTE_PTEM_MASK 0x7FFFFFBF #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B) @@ -102,6 +109,136 @@ static int ppc_hash32_check_prot(int prot, int rw, int access_type) return ret; } +/* Perform BAT hit & translation */ +static void hash32_bat_size_prot(CPUPPCState *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 void hash32_bat_601_size_prot(CPUPPCState *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; + LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n", + (uint8_t)(*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 = ppc_hash32_pp_check(key, pp, 0); + } + *blp = bl; + *validp = valid; + *protp = prot; +} + +static int ppc_hash32_get_bat(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong virtual, int rw, int type) +{ + target_ulong *BATlt, *BATut, *BATu, *BATl; + target_ulong BEPIl, BEPIu, bl; + int i, valid, prot; + int ret = -1; + + LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__, + type == ACCESS_CODE ? 'I' : 'D', virtual); + switch (type) { + case ACCESS_CODE: + BATlt = env->IBAT[1]; + BATut = env->IBAT[0]; + break; + default: + BATlt = env->DBAT[1]; + BATut = env->DBAT[0]; + break; + } + for (i = 0; i < env->nb_BATs; i++) { + BATu = &BATut[i]; + BATl = &BATlt[i]; + BEPIu = *BATu & 0xF0000000; + BEPIl = *BATu & 0x0FFE0000; + if (unlikely(env->mmu_model == POWERPC_MMU_601)) { + hash32_bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl); + } else { + hash32_bat_size_prot(env, &bl, &valid, &prot, BATu, BATl); + } + LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx + " BATl " TARGET_FMT_lx "\n", __func__, + type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl); + if ((virtual & 0xF0000000) == BEPIu && + ((virtual & 0x0FFE0000) & ~bl) == BEPIl) { + /* BAT matches */ + if (valid != 0) { + /* Get physical address */ + ctx->raddr = (*BATl & 0xF0000000) | + ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | + (virtual & 0x0001F000); + /* Compute access rights */ + ctx->prot = prot; + ret = ppc_hash32_check_prot(ctx->prot, rw, type); + if (ret == 0) { + LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n", + i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-', + ctx->prot & PAGE_WRITE ? 'W' : '-'); + } + break; + } + } + } + if (ret < 0) { +#if defined(DEBUG_BATS) + if (qemu_log_enabled()) { + LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual); + for (i = 0; i < 4; i++) { + BATu = &BATut[i]; + BATl = &BATlt[i]; + BEPIu = *BATu & 0xF0000000; + BEPIl = *BATu & 0x0FFE0000; + bl = (*BATu & 0x00001FFC) << 15; + LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx + " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " " + TARGET_FMT_lx " " TARGET_FMT_lx "\n", + __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, + *BATu, *BATl, BEPIu, BEPIl, bl); + } + } +#endif + } + /* No hit */ + return ret; +} + + static inline int pte_is_valid_hash32(target_ulong pte0) { return pte0 & 0x80000000 ? 1 : 0; @@ -398,7 +535,6 @@ static int get_segment32(CPUPPCState *env, mmu_ctx_t *ctx, return ret; } - static int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw, int access_type) @@ -415,7 +551,7 @@ static int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, /* Try to find a BAT */ if (env->nb_BATs != 0) { - ret = get_bat(env, ctx, eaddr, rw, access_type); + ret = ppc_hash32_get_bat(env, ctx, eaddr, rw, access_type); } if (ret < 0) { /* We didn't match any BAT entry or don't have BATs */ |