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>
This commit is contained in:
David Gibson 2013-03-12 00:31:16 +00:00 committed by Alexander Graf
parent 59191721a1
commit 9813279664
3 changed files with 142 additions and 38 deletions

View File

@ -1133,8 +1133,6 @@ void ppc_hw_interrupt (CPUPPCState *env);
#if !defined(CONFIG_USER_ONLY)
void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
target_ulong virtual, int rw, int type);
#endif /* !defined(CONFIG_USER_ONLY) */
void ppc_store_msr (CPUPPCState *env, target_ulong value);

View File

@ -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 */

View File

@ -397,34 +397,8 @@ static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
*protp = prot;
}
static inline void 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 = pp_check(key, pp, 0);
}
*blp = bl;
*validp = valid;
*protp = prot;
}
int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
target_ulong virtual, int rw, int type)
static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
target_ulong virtual, int rw, int type)
{
target_ulong *BATlt, *BATut, *BATu, *BATl;
target_ulong BEPIl, BEPIu, bl;
@ -448,11 +422,7 @@ int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
BATl = &BATlt[i];
BEPIu = *BATu & 0xF0000000;
BEPIl = *BATu & 0x0FFE0000;
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);
}
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);
@ -1309,7 +1279,7 @@ static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
} else {
/* Try to find a BAT */
if (env->nb_BATs != 0) {
ret = get_bat(env, ctx, eaddr, rw, access_type);
ret = get_bat_6xx_tlb(env, ctx, eaddr, rw, access_type);
}
if (ret < 0) {
/* We didn't match any BAT entry or don't have BATs */