@ -85,9 +85,6 @@ static inline ioreq_t *xen_vcpu_ioreq(shared_iopage_t *shared_page, int vcpu)
}
# define FMT_ioreq_size "u"
# endif
# ifndef HVM_PARAM_BUFIOREQ_EVTCHN
# define HVM_PARAM_BUFIOREQ_EVTCHN 26
# endif
# define BUFFER_IO_MAX_DELAY 100
/* Leave some slack so that hvmloader does not complain about lack of
@ -107,6 +104,7 @@ typedef struct XenPhysmap {
} XenPhysmap ;
typedef struct XenIOState {
ioservid_t ioservid ;
shared_iopage_t * shared_page ;
shared_vmport_iopage_t * shared_vmport_page ;
buffered_iopage_t * buffered_io_page ;
@ -123,6 +121,8 @@ typedef struct XenIOState {
struct xs_handle * xenstore ;
MemoryListener memory_listener ;
MemoryListener io_listener ;
DeviceListener device_listener ;
QLIST_HEAD ( , XenPhysmap ) physmap ;
hwaddr free_phys_offset ;
const XenPhysmap * log_for_dirtybit ;
@ -491,12 +491,23 @@ static void xen_set_memory(struct MemoryListener *listener,
bool log_dirty = memory_region_is_logging ( section - > mr ) ;
hvmmem_type_t mem_type ;
if ( section - > mr = = & ram_memory ) {
return ;
} else {
if ( add ) {
xen_map_memory_section ( xen_xc , xen_domid , state - > ioservid ,
section ) ;
} else {
xen_unmap_memory_section ( xen_xc , xen_domid , state - > ioservid ,
section ) ;
}
}
if ( ! memory_region_is_ram ( section - > mr ) ) {
return ;
}
if ( ! ( section - > mr ! = & ram_memory
& & ( ( log_dirty & & add ) | | ( ! log_dirty & & ! add ) ) ) ) {
if ( log_dirty ! = add ) {
return ;
}
@ -539,6 +550,50 @@ static void xen_region_del(MemoryListener *listener,
memory_region_unref ( section - > mr ) ;
}
static void xen_io_add ( MemoryListener * listener ,
MemoryRegionSection * section )
{
XenIOState * state = container_of ( listener , XenIOState , io_listener ) ;
memory_region_ref ( section - > mr ) ;
xen_map_io_section ( xen_xc , xen_domid , state - > ioservid , section ) ;
}
static void xen_io_del ( MemoryListener * listener ,
MemoryRegionSection * section )
{
XenIOState * state = container_of ( listener , XenIOState , io_listener ) ;
xen_unmap_io_section ( xen_xc , xen_domid , state - > ioservid , section ) ;
memory_region_unref ( section - > mr ) ;
}
static void xen_device_realize ( DeviceListener * listener ,
DeviceState * dev )
{
XenIOState * state = container_of ( listener , XenIOState , device_listener ) ;
if ( object_dynamic_cast ( OBJECT ( dev ) , TYPE_PCI_DEVICE ) ) {
PCIDevice * pci_dev = PCI_DEVICE ( dev ) ;
xen_map_pcidev ( xen_xc , xen_domid , state - > ioservid , pci_dev ) ;
}
}
static void xen_device_unrealize ( DeviceListener * listener ,
DeviceState * dev )
{
XenIOState * state = container_of ( listener , XenIOState , device_listener ) ;
if ( object_dynamic_cast ( OBJECT ( dev ) , TYPE_PCI_DEVICE ) ) {
PCIDevice * pci_dev = PCI_DEVICE ( dev ) ;
xen_unmap_pcidev ( xen_xc , xen_domid , state - > ioservid , pci_dev ) ;
}
}
static void xen_sync_dirty_bitmap ( XenIOState * state ,
hwaddr start_addr ,
ram_addr_t size )
@ -639,6 +694,17 @@ static MemoryListener xen_memory_listener = {
. priority = 10 ,
} ;
static MemoryListener xen_io_listener = {
. region_add = xen_io_add ,
. region_del = xen_io_del ,
. priority = 10 ,
} ;
static DeviceListener xen_device_listener = {
. realize = xen_device_realize ,
. unrealize = xen_device_unrealize ,
} ;
/* get the ioreq packets from share mem */
static ioreq_t * cpu_get_ioreq_from_shared_memory ( XenIOState * state , int vcpu )
{
@ -887,6 +953,27 @@ static void handle_ioreq(XenIOState *state, ioreq_t *req)
case IOREQ_TYPE_INVALIDATE :
xen_invalidate_map_cache ( ) ;
break ;
case IOREQ_TYPE_PCI_CONFIG : {
uint32_t sbdf = req - > addr > > 32 ;
uint32_t val ;
/* Fake a write to port 0xCF8 so that
* the config space access will target the
* correct device model .
*/
val = ( 1u < < 31 ) |
( ( req - > addr & 0x0f00 ) < < 16 ) |
( ( sbdf & 0xffff ) < < 8 ) |
( req - > addr & 0xfc ) ;
do_outp ( 0xcf8 , 4 , val ) ;
/* Now issue the config space access via
* port 0xCFC
*/
req - > addr = 0xcfc | ( req - > addr & 0x03 ) ;
cpu_ioreq_pio ( req ) ;
break ;
}
default :
hw_error ( " Invalid ioreq type 0x%x \n " , req - > type ) ;
}
@ -1017,9 +1104,15 @@ static void xen_main_loop_prepare(XenIOState *state)
static void xen_hvm_change_state_handler ( void * opaque , int running ,
RunState rstate )
{
XenIOState * state = opaque ;
if ( running ) {
xen_main_loop_prepare ( ( XenIOState * ) opaque ) ;
xen_main_loop_prepare ( stat e) ;
}
xen_set_ioreq_server_state ( xen_xc , xen_domid ,
state - > ioservid ,
( rstate = = RUN_STATE_RUNNING ) ) ;
}
static void xen_exit_notifier ( Notifier * n , void * data )
@ -1088,8 +1181,9 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size,
MemoryRegion * * ram_memory )
{
int i , rc ;
unsigned long ioreq_pfn ;
unsigned long bufioreq_evtchn ;
xen_pfn_t ioreq_pfn ;
xen_pfn_t bufioreq_pfn ;
evtchn_port_t bufioreq_evtchn ;
XenIOState * state ;
state = g_malloc0 ( sizeof ( XenIOState ) ) ;
@ -1106,6 +1200,12 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size,
return - 1 ;
}
rc = xen_create_ioreq_server ( xen_xc , xen_domid , & state - > ioservid ) ;
if ( rc < 0 ) {
perror ( " xen: ioreq server create " ) ;
return - 1 ;
}
state - > exit . notify = xen_exit_notifier ;
qemu_add_exit_notifier ( & state - > exit ) ;
@ -1115,8 +1215,18 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size,
state - > wakeup . notify = xen_wakeup_notifier ;
qemu_register_wakeup_notifier ( & state - > wakeup ) ;
xc_get_hvm_param ( xen_xc , xen_domid , HVM_PARAM_IOREQ_PFN , & ioreq_pfn ) ;
rc = xen_get_ioreq_server_info ( xen_xc , xen_domid , state - > ioservid ,
& ioreq_pfn , & bufioreq_pfn ,
& bufioreq_evtchn ) ;
if ( rc < 0 ) {
hw_error ( " failed to get ioreq server info: error %d handle= " XC_INTERFACE_FMT ,
errno , xen_xc ) ;
}
DPRINTF ( " shared page at pfn %lx \n " , ioreq_pfn ) ;
DPRINTF ( " buffered io page at pfn %lx \n " , bufioreq_pfn ) ;
DPRINTF ( " buffered io evtchn is %x \n " , bufioreq_evtchn ) ;
state - > shared_page = xc_map_foreign_range ( xen_xc , xen_domid , XC_PAGE_SIZE ,
PROT_READ | PROT_WRITE , ioreq_pfn ) ;
if ( state - > shared_page = = NULL ) {
@ -1138,10 +1248,10 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size,
hw_error ( " get vmport regs pfn returned error %d, rc=%d " , errno , rc ) ;
}
xc_get_hvm_param ( xen_xc , xen_domid , HVM_PARAM_BUFIOREQ_PFN , & ioreq_pfn ) ;
DPRINTF ( " buffered io page at pfn %lx \n " , ioreq_pfn ) ;
state - > buffered_io_page = xc_map_foreign_range ( xen_xc , xen_domid , XC_PAGE_SIZ E,
PROT_READ | PROT_WRITE , ioreq_pfn ) ;
state - > buffered_io_page = xc_map_foreign_range ( xen_xc , xen_domid ,
XC_PAGE_SIZE ,
PROT_READ | PROT_WRIT E ,
buf ioreq_pfn) ;
if ( state - > buffered_io_page = = NULL ) {
hw_error ( " map buffered IO page returned error %d " , errno ) ;
}
@ -1149,6 +1259,12 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size,
/* Note: cpus is empty at this point in init */
state - > cpu_by_vcpu_id = g_malloc0 ( max_cpus * sizeof ( CPUState * ) ) ;
rc = xen_set_ioreq_server_state ( xen_xc , xen_domid , state - > ioservid , true ) ;
if ( rc < 0 ) {
hw_error ( " failed to enable ioreq server info: error %d handle= " XC_INTERFACE_FMT ,
errno , xen_xc ) ;
}
state - > ioreq_local_port = g_malloc0 ( max_cpus * sizeof ( evtchn_port_t ) ) ;
/* FIXME: how about if we overflow the page here? */
@ -1156,22 +1272,16 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size,
rc = xc_evtchn_bind_interdomain ( state - > xce_handle , xen_domid ,
xen_vcpu_eport ( state - > shared_page , i ) ) ;
if ( rc = = - 1 ) {
fprintf ( stderr , " bind interdomain ioctl error %d\n " , errno ) ;
fprintf ( stderr , " shared evtchn %d bind error %d\n " , i , errno ) ;
return - 1 ;
}
state - > ioreq_local_port [ i ] = rc ;
}
rc = xc_get_hvm_param ( xen_xc , xen_domid , HVM_PARAM_BUFIOREQ_EVTCHN ,
& bufioreq_evtchn ) ;
if ( rc < 0 ) {
fprintf ( stderr , " failed to get HVM_PARAM_BUFIOREQ_EVTCHN \n " ) ;
return - 1 ;
}
rc = xc_evtchn_bind_interdomain ( state - > xce_handle , xen_domid ,
( uint32_t ) bufioreq_evtchn ) ;
bufioreq_evtchn ) ;
if ( rc = = - 1 ) {
fprintf ( stderr , " bind interdomain ioctl error %d \n " , errno ) ;
fprintf ( stderr , " buffered evtchn bind error %d \n " , errno ) ;
return - 1 ;
}
state - > bufioreq_local_port = rc ;
@ -1187,6 +1297,12 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size,
memory_listener_register ( & state - > memory_listener , & address_space_memory ) ;
state - > log_for_dirtybit = NULL ;
state - > io_listener = xen_io_listener ;
memory_listener_register ( & state - > io_listener , & address_space_io ) ;
state - > device_listener = xen_device_listener ;
device_listener_register ( & state - > device_listener ) ;
/* Initialize backend core & drivers */
if ( xen_be_init ( ) ! = 0 ) {
fprintf ( stderr , " %s: xen backend core setup failed \n " , __FUNCTION__ ) ;