@ -24,6 +24,7 @@
# include <signal.h>
# include "cpu.h"
# include "sysemu/kvm.h"
enum {
TLBRET_DIRTY = - 4 ,
@ -100,7 +101,7 @@ int r4k_map_address (CPUMIPSState *env, hwaddr *physical, int *prot,
}
static int get_physical_address ( CPUMIPSState * env , hwaddr * physical ,
int * prot , target_ulong address ,
int * prot , target_ulong real_ address,
int rw , int access_type )
{
/* User mode can only access useg/xuseg */
@ -113,6 +114,8 @@ static int get_physical_address (CPUMIPSState *env, hwaddr *physical,
int KX = ( env - > CP0_Status & ( 1 < < CP0St_KX ) ) ! = 0 ;
# endif
int ret = TLBRET_MATCH ;
/* effective address (modified for KVM T&E kernel segments) */
target_ulong address = real_address ;
#if 0
qemu_log ( " user mode %d h %08x \n " , user_mode , env - > hflags ) ;
@ -124,19 +127,35 @@ static int get_physical_address (CPUMIPSState *env, hwaddr *physical,
# define KSEG2_BASE 0xC0000000UL
# define KSEG3_BASE 0xE0000000UL
# define KVM_KSEG0_BASE 0x40000000UL
# define KVM_KSEG2_BASE 0x60000000UL
if ( kvm_enabled ( ) ) {
/* KVM T&E adds guest kernel segments in useg */
if ( real_address > = KVM_KSEG0_BASE ) {
if ( real_address < KVM_KSEG2_BASE ) {
/* kseg0 */
address + = KSEG0_BASE - KVM_KSEG0_BASE ;
} else if ( real_address < = USEG_LIMIT ) {
/* kseg2/3 */
address + = KSEG2_BASE - KVM_KSEG2_BASE ;
}
}
}
if ( address < = USEG_LIMIT ) {
/* useg */
if ( env - > CP0_Status & ( 1 < < CP0St_ERL ) ) {
* physical = address & 0xFFFFFFFF ;
* prot = PAGE_READ | PAGE_WRITE ;
} else {
ret = env - > tlb - > map_address ( env , physical , prot , address , rw , access_type ) ;
ret = env - > tlb - > map_address ( env , physical , prot , real_ address, rw , access_type ) ;
}
# if defined(TARGET_MIPS64)
} else if ( address < 0x4000000000000000ULL ) {
/* xuseg */
if ( UX & & address < = ( 0x3FFFFFFFFFFFFFFFULL & env - > SEGMask ) ) {
ret = env - > tlb - > map_address ( env , physical , prot , address , rw , access_type ) ;
ret = env - > tlb - > map_address ( env , physical , prot , real_ address, rw , access_type ) ;
} else {
ret = TLBRET_BADADDR ;
}
@ -144,7 +163,7 @@ static int get_physical_address (CPUMIPSState *env, hwaddr *physical,
/* xsseg */
if ( ( supervisor_mode | | kernel_mode ) & &
SX & & address < = ( 0x7FFFFFFFFFFFFFFFULL & env - > SEGMask ) ) {
ret = env - > tlb - > map_address ( env , physical , prot , address , rw , access_type ) ;
ret = env - > tlb - > map_address ( env , physical , prot , real_ address, rw , access_type ) ;
} else {
ret = TLBRET_BADADDR ;
}
@ -161,7 +180,7 @@ static int get_physical_address (CPUMIPSState *env, hwaddr *physical,
/* xkseg */
if ( kernel_mode & & KX & &
address < = ( 0xFFFFFFFF7FFFFFFFULL & env - > SEGMask ) ) {
ret = env - > tlb - > map_address ( env , physical , prot , address , rw , access_type ) ;
ret = env - > tlb - > map_address ( env , physical , prot , real_ address, rw , access_type ) ;
} else {
ret = TLBRET_BADADDR ;
}
@ -185,7 +204,7 @@ static int get_physical_address (CPUMIPSState *env, hwaddr *physical,
} else if ( address < ( int32_t ) KSEG3_BASE ) {
/* sseg (kseg2) */
if ( supervisor_mode | | kernel_mode ) {
ret = env - > tlb - > map_address ( env , physical , prot , address , rw , access_type ) ;
ret = env - > tlb - > map_address ( env , physical , prot , real_ address, rw , access_type ) ;
} else {
ret = TLBRET_BADADDR ;
}
@ -193,7 +212,7 @@ static int get_physical_address (CPUMIPSState *env, hwaddr *physical,
/* kseg3 */
/* XXX: debug segment is not emulated */
if ( kernel_mode ) {
ret = env - > tlb - > map_address ( env , physical , prot , address , rw , access_type ) ;
ret = env - > tlb - > map_address ( env , physical , prot , real_ address, rw , access_type ) ;
} else {
ret = TLBRET_BADADDR ;
}