mirror of https://github.com/xemu-project/xemu.git
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:
parent
59191721a1
commit
9813279664
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue