@ -1231,131 +1231,134 @@ static void notdirty_write(CPUState *cpu, vaddr mem_vaddr, unsigned size,
}
}
/*
* Probe for whether the specified guest access is permitted . If it is not
* permitted then an exception will be taken in the same way as if this
* were a real access ( and we will not return ) .
* If the size is 0 or the page requires I / O access , returns NULL ; otherwise ,
* returns the address of the host page similar to tlb_vaddr_to_host ( ) .
*/
void * probe_access ( CPUArchState * env , target_ulong addr , int size ,
MMUAccessType access_type , int mmu_idx , uintptr_t retaddr )
static int probe_access_internal ( CPUArchState * env , target_ulong addr ,
int fault_size , MMUAccessType access_type ,
int mmu_idx , bool nonfault ,
void * * phost , uintptr_t retaddr )
{
uintptr_t index = tlb_index ( env , mmu_idx , addr ) ;
CPUTLBEntry * entry = tlb_entry ( env , mmu_idx , addr ) ;
target_ulong tlb_addr ;
target_ulong tlb_addr , page_addr ;
size_t elt_ofs ;
int wp_access ;
g_assert ( - ( addr | TARGET_PAGE_MASK ) > = size ) ;
int flags ;
switch ( access_type ) {
case MMU_DATA_LOAD :
elt_ofs = offsetof ( CPUTLBEntry , addr_read ) ;
wp_access = BP_MEM_READ ;
break ;
case MMU_DATA_STORE :
elt_ofs = offsetof ( CPUTLBEntry , addr_write ) ;
wp_access = BP_MEM_WRITE ;
break ;
case MMU_INST_FETCH :
elt_ofs = offsetof ( CPUTLBEntry , addr_code ) ;
wp_access = BP_MEM_READ ;
break ;
default :
g_assert_not_reached ( ) ;
}
tlb_addr = tlb_read_ofs ( entry , elt_ofs ) ;
if ( unlikely ( ! tlb_hit ( tlb_addr , addr ) ) ) {
if ( ! victim_tlb_hit ( env , mmu_idx , index , elt_ofs ,
addr & TARGET_PAGE_MASK ) ) {
tlb_fill ( env_cpu ( env ) , addr , size , access_type , mmu_idx , retaddr ) ;
/* TLB resize via tlb_fill may have moved the entry. */
index = tlb_index ( env , mmu_idx , addr ) ;
page_addr = addr & TARGET_PAGE_MASK ;
if ( ! tlb_hit_page ( tlb_addr , page_addr ) ) {
if ( ! victim_tlb_hit ( env , mmu_idx , index , elt_ofs , page_addr ) ) {
CPUState * cs = env_cpu ( env ) ;
CPUClass * cc = CPU_GET_CLASS ( cs ) ;
if ( ! cc - > tlb_fill ( cs , addr , fault_size , access_type ,
mmu_idx , nonfault , retaddr ) ) {
/* Non-faulting page table read failed. */
* phost = NULL ;
return TLB_INVALID_MASK ;
}
/* TLB resize via tlb_fill may have moved the entry. */
entry = tlb_entry ( env , mmu_idx , addr ) ;
}
tlb_addr = tlb_read_ofs ( entry , elt_ofs ) ;
}
flags = tlb_addr & TLB_FLAGS_MASK ;
if ( ! size ) {
return NULL ;
/* Fold all "mmio-like" bits into TLB_MMIO. This is not RAM. */
if ( unlikely ( flags & ~ ( TLB_WATCHPOINT | TLB_NOTDIRTY ) ) ) {
* phost = NULL ;
return TLB_MMIO ;
}
if ( unlikely ( tlb_addr & TLB_FLAGS_MASK ) ) {
/* Everything else is RAM. */
* phost = ( void * ) ( ( uintptr_t ) addr + entry - > addend ) ;
return flags ;
}
int probe_access_flags ( CPUArchState * env , target_ulong addr ,
MMUAccessType access_type , int mmu_idx ,
bool nonfault , void * * phost , uintptr_t retaddr )
{
int flags ;
flags = probe_access_internal ( env , addr , 0 , access_type , mmu_idx ,
nonfault , phost , retaddr ) ;
/* Handle clean RAM pages. */
if ( unlikely ( flags & TLB_NOTDIRTY ) ) {
uintptr_t index = tlb_index ( env , mmu_idx , addr ) ;
CPUIOTLBEntry * iotlbentry = & env_tlb ( env ) - > d [ mmu_idx ] . iotlb [ index ] ;
/* Reject I/O access, or other required slow-path. */
if ( tlb_addr & ( TLB_MMIO | TLB_BSWAP | TLB_DISCARD_WRITE ) ) {
return NULL ;
}
notdirty_write ( env_cpu ( env ) , addr , 1 , iotlbentry , retaddr ) ;
flags & = ~ TLB_NOTDIRTY ;
}
return flags ;
}
void * probe_access ( CPUArchState * env , target_ulong addr , int size ,
MMUAccessType access_type , int mmu_idx , uintptr_t retaddr )
{
void * host ;
int flags ;
g_assert ( - ( addr | TARGET_PAGE_MASK ) > = size ) ;
flags = probe_access_internal ( env , addr , size , access_type , mmu_idx ,
false , & host , retaddr ) ;
/* Per the interface, size == 0 merely faults the access. */
if ( size = = 0 ) {
return NULL ;
}
if ( unlikely ( flags & ( TLB_NOTDIRTY | TLB_WATCHPOINT ) ) ) {
uintptr_t index = tlb_index ( env , mmu_idx , addr ) ;
CPUIOTLBEntry * iotlbentry = & env_tlb ( env ) - > d [ mmu_idx ] . iotlb [ index ] ;
/* Handle watchpoints. */
if ( tlb_addr & TLB_WATCHPOINT ) {
if ( flags & TLB_WATCHPOINT ) {
int wp_access = ( access_type = = MMU_DATA_STORE
? BP_MEM_WRITE : BP_MEM_READ ) ;
cpu_check_watchpoint ( env_cpu ( env ) , addr , size ,
iotlbentry - > attrs , wp_access , retaddr ) ;
}
/* Handle clean RAM pages. */
if ( tlb_addr & TLB_NOTDIRTY ) {
notdirty_write ( env_cpu ( env ) , addr , size , iotlbentry , retaddr ) ;
if ( flags & TLB_NOTDIRTY ) {
notdirty_write ( env_cpu ( env ) , addr , 1 , iotlbentry , retaddr ) ;
}
}
return ( void * ) ( ( uintptr_t ) addr + entry - > addend ) ;
return host ;
}
void * tlb_vaddr_to_host ( CPUArchState * env , abi_ptr addr ,
MMUAccessType access_type , int mmu_idx )
{
CPUTLBEntry * entry = tlb_entry ( env , mmu_idx , addr ) ;
target_ulong tlb_addr , page ;
size_t elt_ofs ;
switch ( access_type ) {
case MMU_DATA_LOAD :
elt_ofs = offsetof ( CPUTLBEntry , addr_read ) ;
break ;
case MMU_DATA_STORE :
elt_ofs = offsetof ( CPUTLBEntry , addr_write ) ;
break ;
case MMU_INST_FETCH :
elt_ofs = offsetof ( CPUTLBEntry , addr_code ) ;
break ;
default :
g_assert_not_reached ( ) ;
}
void * host ;
int flags ;
page = addr & TARGET_PAGE_MASK ;
tlb_addr = tlb_read_ofs ( entry , elt_ofs ) ;
if ( ! tlb_hit_page ( tlb_addr , page ) ) {
uintptr_t index = tlb_index ( env , mmu_idx , addr ) ;
if ( ! victim_tlb_hit ( env , mmu_idx , index , elt_ofs , page ) ) {
CPUState * cs = env_cpu ( env ) ;
CPUClass * cc = CPU_GET_CLASS ( cs ) ;
flags = probe_access_internal ( env , addr , 0 , access_type ,
mmu_idx , true , & host , 0 ) ;
if ( ! cc - > tlb_fill ( cs , addr , 0 , access_type , mmu_idx , true , 0 ) ) {
/* Non-faulting page table read failed. */
return NULL ;
}
/* TLB resize via tlb_fill may have moved the entry. */
entry = tlb_entry ( env , mmu_idx , addr ) ;
}
tlb_addr = tlb_read_ofs ( entry , elt_ofs ) ;
}
if ( tlb_addr & ~ TARGET_PAGE_MASK ) {
/* IO access */
return NULL ;
}
return ( void * ) ( ( uintptr_t ) addr + entry - > addend ) ;
/* No combination of flags are expected by the caller. */
return flags ? NULL : host ;
}
# ifdef CONFIG_PLUGIN
/*
* Perform a TLB lookup and populate the qemu_plugin_hwaddr structure .