@ -429,6 +429,160 @@ void helper_tlbie(CPUPPCState *env, target_ulong addr)
ppc_tlb_invalidate_one ( env , addr ) ;
}
# if defined(TARGET_PPC64)
/* Invalidation Selector */
# define TLBIE_IS_VA 0
# define TLBIE_IS_PID 1
# define TLBIE_IS_LPID 2
# define TLBIE_IS_ALL 3
/* Radix Invalidation Control */
# define TLBIE_RIC_TLB 0
# define TLBIE_RIC_PWC 1
# define TLBIE_RIC_ALL 2
# define TLBIE_RIC_GRP 3
/* Radix Actual Page sizes */
# define TLBIE_R_AP_4K 0
# define TLBIE_R_AP_64K 5
# define TLBIE_R_AP_2M 1
# define TLBIE_R_AP_1G 2
/* RB field masks */
# define TLBIE_RB_EPN_MASK PPC_BITMASK(0, 51)
# define TLBIE_RB_IS_MASK PPC_BITMASK(52, 53)
# define TLBIE_RB_AP_MASK PPC_BITMASK(56, 58)
void helper_tlbie_isa300 ( CPUPPCState * env , target_ulong rb , target_ulong rs ,
uint32_t flags )
{
unsigned ric = ( flags & TLBIE_F_RIC_MASK ) > > TLBIE_F_RIC_SHIFT ;
/*
* With the exception of the checks for invalid instruction forms ,
* PRS is currently ignored , because we don ' t know if a given TLB entry
* is process or partition scoped .
*/
bool prs = flags & TLBIE_F_PRS ;
bool r = flags & TLBIE_F_R ;
bool local = flags & TLBIE_F_LOCAL ;
bool effR ;
unsigned is = extract64 ( rb , PPC_BIT_NR ( 53 ) , 2 ) ;
unsigned ap ; /* actual page size */
target_ulong addr , pgoffs_mask ;
qemu_log_mask ( CPU_LOG_MMU ,
" %s: local=%d addr= " TARGET_FMT_lx " ric=%u prs=%d r=%d is=%u \n " ,
__func__ , local , rb & TARGET_PAGE_MASK , ric , prs , r , is ) ;
effR = FIELD_EX64 ( env - > msr , MSR , HV ) ? r : env - > spr [ SPR_LPCR ] & LPCR_HR ;
/* Partial TLB invalidation is supported for Radix only for now. */
if ( ! effR ) {
goto inval_all ;
}
/* Check for invalid instruction forms (effR=1). */
if ( unlikely ( ric = = TLBIE_RIC_GRP | |
( ( ric = = TLBIE_RIC_PWC | | ric = = TLBIE_RIC_ALL ) & &
is = = TLBIE_IS_VA ) | |
( ! prs & & is = = TLBIE_IS_PID ) ) ) {
qemu_log_mask ( LOG_GUEST_ERROR ,
" %s: invalid instruction form: ric=%u prs=%d r=%d is=%u \n " ,
__func__ , ric , prs , r , is ) ;
goto invalid ;
}
/* We don't cache Page Walks. */
if ( ric = = TLBIE_RIC_PWC ) {
if ( local ) {
unsigned set = extract64 ( rb , PPC_BIT_NR ( 51 ) , 12 ) ;
if ( set ! = 0 ) {
qemu_log_mask ( LOG_GUEST_ERROR , " %s: invalid set: %d \n " ,
__func__ , set ) ;
goto invalid ;
}
}
return ;
}
/*
* Invalidation by LPID or PID is not supported , so fallback
* to full TLB flush in these cases .
*/
if ( is ! = TLBIE_IS_VA ) {
goto inval_all ;
}
/*
* The results of an attempt to invalidate a translation outside of
* quadrant 0 for Radix Tree translation ( effR = 1 , RIC = 0 , PRS = 1 , IS = 0 ,
* and EA 0 : 1 ! = 0 b00 ) are boundedly undefined .
*/
if ( unlikely ( ric = = TLBIE_RIC_TLB & & prs & & is = = TLBIE_IS_VA & &
( rb & R_EADDR_QUADRANT ) ! = R_EADDR_QUADRANT0 ) ) {
qemu_log_mask ( LOG_GUEST_ERROR ,
" %s: attempt to invalidate a translation outside of quadrant 0 \n " ,
__func__ ) ;
goto inval_all ;
}
assert ( is = = TLBIE_IS_VA ) ;
assert ( ric = = TLBIE_RIC_TLB | | ric = = TLBIE_RIC_ALL ) ;
ap = extract64 ( rb , PPC_BIT_NR ( 58 ) , 3 ) ;
switch ( ap ) {
case TLBIE_R_AP_4K :
pgoffs_mask = 0xfffull ;
break ;
case TLBIE_R_AP_64K :
pgoffs_mask = 0xffffull ;
break ;
case TLBIE_R_AP_2M :
pgoffs_mask = 0x1fffffull ;
break ;
case TLBIE_R_AP_1G :
pgoffs_mask = 0x3fffffffull ;
break ;
default :
/*
* If the value specified in RS 0 : 31 , RS 32 : 63 , RB 54 : 55 , RB 56 : 58 ,
* RB 44 : 51 , or RB 56 : 63 , when it is needed to perform the specified
* operation , is not supported by the implementation , the instruction
* is treated as if the instruction form were invalid .
*/
qemu_log_mask ( LOG_GUEST_ERROR , " %s: invalid AP: %d \n " , __func__ , ap ) ;
goto invalid ;
}
addr = rb & TLBIE_RB_EPN_MASK & ~ pgoffs_mask ;
if ( local ) {
tlb_flush_page ( env_cpu ( env ) , addr ) ;
} else {
tlb_flush_page_all_cpus ( env_cpu ( env ) , addr ) ;
}
return ;
inval_all :
env - > tlb_need_flush | = TLB_NEED_LOCAL_FLUSH ;
if ( ! local ) {
env - > tlb_need_flush | = TLB_NEED_GLOBAL_FLUSH ;
}
return ;
invalid :
raise_exception_err_ra ( env , POWERPC_EXCP_PROGRAM ,
POWERPC_EXCP_INVAL |
POWERPC_EXCP_INVAL_INVAL , GETPC ( ) ) ;
}
# endif
void helper_tlbiva ( CPUPPCState * env , target_ulong addr )
{
/* tlbiva instruction only exists on BookE */