@ -29,6 +29,69 @@ static const MemoryListener xen_memory_listener = {
. priority = MEMORY_LISTENER_PRIORITY_ACCEL ,
} ;
/*
* Map foreign RAM in bounded chunks so we don ' t build a PFN array for the
* entire guest size ( which can be huge for large guests ) . We reserve a VA
* range once and then MAP_FIXED each chunk into place .
*/
# define XEN_PVH_MAP_CHUNK_PAGES 65535
static void * xen_map_guest_ram ( XenPVHMachineState * s ,
uint64_t addr , uint64_t size )
{
size_t total_pages = size > > XC_PAGE_SHIFT ;
size_t chunk_pages = MIN ( XEN_PVH_MAP_CHUNK_PAGES , total_pages ) ;
g_autofree xen_pfn_t * pfns = NULL ;
void * base = NULL ;
size_t offset ;
if ( ! total_pages ) {
goto done ;
}
base = mmap ( NULL , size , PROT_NONE , MAP_PRIVATE | MAP_ANONYMOUS , - 1 , 0 ) ;
if ( base = = MAP_FAILED ) {
base = NULL ;
goto done ;
}
pfns = g_new0 ( xen_pfn_t , chunk_pages ) ;
if ( ! pfns ) {
munmap ( base , size ) ;
base = NULL ;
goto done ;
}
for ( offset = 0 ; offset < total_pages ; offset + = chunk_pages ) {
size_t num_pages = MIN ( chunk_pages , total_pages - offset ) ;
void * mapped ;
size_t i ;
for ( i = 0 ; i < num_pages ; i + + ) {
pfns [ i ] = ( addr > > XC_PAGE_SHIFT ) + offset + i ;
}
mapped = xenforeignmemory_map2 (
xen_fmem , xen_domid ,
( uint8_t * ) base + ( offset < < XC_PAGE_SHIFT ) ,
PROT_READ | PROT_WRITE , MAP_FIXED ,
num_pages , pfns , NULL ) ;
if ( ! mapped ) {
munmap ( base , size ) ;
base = NULL ;
goto done ;
}
}
done :
if ( ! base ) {
/* We can't recover from this. */
error_report ( " FATAL: Failed to foreign-map % " PRIx64 " - % " PRIx64 ,
addr , addr + size ) ;
exit ( EXIT_FAILURE ) ;
}
return base ;
}
static void xen_pvh_init_ram ( XenPVHMachineState * s ,
MemoryRegion * sysmem )
{
@ -45,22 +108,42 @@ static void xen_pvh_init_ram(XenPVHMachineState *s,
block_len = s - > cfg . ram_high . base + ram_size [ 1 ] ;
}
memory_region_init_ram ( & xen_memory , NULL , " xen.ram " , block_len ,
& error_fatal ) ;
if ( s - > cfg . mapcache ) {
memory_region_init_ram ( & xen_memory , NULL , " xen.ram " ,
block_len , & error_fatal ) ;
memory_region_init_alias ( & s - > ram . low , NULL , " xen.ram.lo " , & xen_memory ,
s - > cfg . ram_low . base , ram_size [ 0 ] ) ;
if ( ram_size [ 1 ] > 0 ) {
memory_region_init_alias ( & s - > ram . high , NULL , " xen.ram.hi " ,
& xen_memory ,
s - > cfg . ram_high . base , ram_size [ 1 ] ) ;
}
} else {
void * p ;
p = xen_map_guest_ram ( s , s - > cfg . ram_low . base , ram_size [ 0 ] ) ;
memory_region_init_ram_ptr ( & s - > ram . low , NULL , " xen.ram.lo " ,
ram_size [ 0 ] , p ) ;
if ( ram_size [ 1 ] > 0 ) {
p = xen_map_guest_ram ( s , s - > cfg . ram_high . base , ram_size [ 1 ] ) ;
memory_region_init_ram_ptr ( & s - > ram . high , NULL , " xen.ram.hi " ,
ram_size [ 1 ] , p ) ;
}
}
memory_region_init_alias ( & s - > ram . low , NULL , " xen.ram.lo " , & xen_memory ,
s - > cfg . ram_low . base , ram_size [ 0 ] ) ;
/* Map them onto QEMU's address-space. */
memory_region_add_subregion ( sysmem , s - > cfg . ram_low . base , & s - > ram . low ) ;
if ( ram_size [ 1 ] > 0 ) {
memory_region_init_alias ( & s - > ram . high , NULL , " xen.ram.hi " , & xen_memory ,
s - > cfg . ram_high . base , ram_size [ 1 ] ) ;
memory_region_add_subregion ( sysmem , s - > cfg . ram_high . base , & s - > ram . high ) ;
}
/* Setup support for grants. */
memory_region_init_ram ( & xen_grants , NULL , " xen.grants " , block_len ,
& error_fatal ) ;
memory_region_add_subregion ( sysmem , XEN_GRANT_ADDR_OFF , & xen_grants ) ;
/* Grants are only supported when the mapcache is on. */
if ( s - > cfg . mapcache ) {
/* Setup support for grants. */
memory_region_init_ram ( & xen_grants , NULL , " xen.grants " , block_len ,
& error_fatal ) ;
memory_region_add_subregion ( sysmem , XEN_GRANT_ADDR_OFF , & xen_grants ) ;
}
}
static void xen_set_irq ( void * opaque , int irq , int level )
@ -203,7 +286,7 @@ static void xen_pvh_init(MachineState *ms)
xen_register_ioreq ( & s - > ioreq , ms - > smp . max_cpus ,
xpc - > handle_bufioreq ,
& xen_memory_listener ,
tru e) ;
s - > cfg . mapcach e) ;
if ( s - > cfg . virtio_mmio_num ) {
xen_create_virtio_mmio_devices ( s ) ;
@ -285,6 +368,20 @@ XEN_PVH_PROP_MEMMAP(pci_ecam)
XEN_PVH_PROP_MEMMAP ( pci_mmio )
XEN_PVH_PROP_MEMMAP ( pci_mmio_high )
static void xen_pvh_set_mapcache ( Object * obj , bool value , Error * * errp )
{
XenPVHMachineState * xp = XEN_PVH_MACHINE ( obj ) ;
xp - > cfg . mapcache = value ;
}
static bool xen_pvh_get_mapcache ( Object * obj , Error * * errp )
{
XenPVHMachineState * xp = XEN_PVH_MACHINE ( obj ) ;
return xp - > cfg . mapcache ;
}
static void xen_pvh_set_pci_intx_irq_base ( Object * obj , Visitor * v ,
const char * name , void * opaque ,
Error * * errp )
@ -338,6 +435,12 @@ do { \
OC_MEMMAP_PROP_SIZE ( c , prop_name , name ) ; \
} while ( 0 )
object_class_property_add_bool ( oc , " mapcache " , xen_pvh_get_mapcache ,
xen_pvh_set_mapcache ) ;
object_class_property_set_description ( oc , " mapcache " ,
" Set on/off to enable/disable the "
" mapcache " ) ;
/*
* We provide memmap properties to allow Xen to move things to other
* addresses for example when users need to accomodate the memory - map
@ -377,6 +480,13 @@ do { \
# endif
}
static void xen_pvh_instance_init ( Object * obj )
{
XenPVHMachineState * xp = XEN_PVH_MACHINE ( obj ) ;
xp - > cfg . mapcache = true ;
}
static void xen_pvh_class_init ( ObjectClass * oc , const void * data )
{
MachineClass * mc = MACHINE_CLASS ( oc ) ;
@ -395,6 +505,7 @@ static const TypeInfo xen_pvh_info = {
. parent = TYPE_MACHINE ,
. abstract = true ,
. instance_size = sizeof ( XenPVHMachineState ) ,
. instance_init = xen_pvh_instance_init ,
. class_size = sizeof ( XenPVHMachineClass ) ,
. class_init = xen_pvh_class_init ,
} ;