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