[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v2 5/6] ioreq-server: add support for multiple servers
On 04/03/14 11:40, Paul Durrant wrote: > The legacy 'catch-all' server is always created with id 0. Secondary > servers will have an id ranging from 1 to a limit set by the toolstack > via the 'max_emulators' build info field. This defaults to 1 so ordinarily > no extra special pages are reserved for secondary emulators. It may be > increased using the secondary_device_emulators parameter in xl.cfg(5). > There's no clear limit to apply to the number of emulators so I've not > applied one. > > Because of the re-arrangement of the special pages in a previous patch we > only need the addition of parameter HVM_PARAM_NR_IOREQ_SERVERS to determine > the layout of the shared pages for multiple emulators. Guests migrated in > from hosts without this patch will be lacking the save record which stores > the new parameter and so the guest is assumed to only have had a single > emulator. > > Added some more emacs boilerplate to xenctrl.h and xenguest.h > > Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx> How does the build param interact with the hvmparam? It appears not to. On migrate, the receiving side will have to know, out-of-band, what to set max_emulators to when building the domain. The setparam code needs to validate the hvmparam against the build param and return -EINVAL/-E2BIG in the case that the hvmparam is too large. xc_domain_restore() needs to detect this and abort the migration if the guest can't be restored with the expected number of emulators. ~Andrew > --- > docs/man/xl.cfg.pod.5 | 7 + > tools/libxc/xc_domain.c | 175 +++++++ > tools/libxc/xc_domain_restore.c | 20 + > tools/libxc/xc_domain_save.c | 12 + > tools/libxc/xc_hvm_build_x86.c | 24 +- > tools/libxc/xenctrl.h | 51 ++ > tools/libxc/xenguest.h | 12 + > tools/libxc/xg_save_restore.h | 1 + > tools/libxl/libxl.h | 8 + > tools/libxl/libxl_create.c | 3 + > tools/libxl/libxl_dom.c | 1 + > tools/libxl/libxl_types.idl | 1 + > tools/libxl/xl_cmdimpl.c | 3 + > xen/arch/x86/hvm/hvm.c | 951 > +++++++++++++++++++++++++++++++++++--- > xen/arch/x86/hvm/io.c | 2 +- > xen/include/asm-x86/hvm/domain.h | 23 +- > xen/include/asm-x86/hvm/hvm.h | 1 + > xen/include/public/hvm/hvm_op.h | 70 +++ > xen/include/public/hvm/ioreq.h | 1 + > xen/include/public/hvm/params.h | 4 +- > 20 files changed, 1300 insertions(+), 70 deletions(-) > > diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5 > index e15a49f..0226c55 100644 > --- a/docs/man/xl.cfg.pod.5 > +++ b/docs/man/xl.cfg.pod.5 > @@ -1281,6 +1281,13 @@ specified, enabling the use of XenServer PV drivers in > the guest. > This parameter only takes effect when device_model_version=qemu-xen. > See F<docs/misc/pci-device-reservations.txt> for more information. > > +=item B<secondary_device_emulators=NUMBER> > + > +If a number of secondary device emulators (i.e. in addition to > +qemu-xen or qemu-xen-traditional) are to be invoked to support the > +guest then this parameter can be set with the count of how many are > +to be used. The default value is zero. > + > =back > > =head2 Device-Model Options > diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c > index 369c3f3..dfa905b 100644 > --- a/tools/libxc/xc_domain.c > +++ b/tools/libxc/xc_domain.c > @@ -1284,6 +1284,181 @@ int xc_get_hvm_param(xc_interface *handle, domid_t > dom, int param, unsigned long > return rc; > } > > +int xc_hvm_create_ioreq_server(xc_interface *xch, > + domid_t domid, > + ioservid_t *id) > +{ > + DECLARE_HYPERCALL; > + DECLARE_HYPERCALL_BUFFER(xen_hvm_create_ioreq_server_t, arg); > + int rc; > + > + arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg)); > + if ( arg == NULL ) > + return -1; > + > + hypercall.op = __HYPERVISOR_hvm_op; > + hypercall.arg[0] = HVMOP_create_ioreq_server; > + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg); > + arg->domid = domid; > + rc = do_xen_hypercall(xch, &hypercall); > + *id = arg->id; > + xc_hypercall_buffer_free(xch, arg); > + return rc; > +} > + > +int xc_hvm_get_ioreq_server_info(xc_interface *xch, > + domid_t domid, > + ioservid_t id, > + xen_pfn_t *pfn, > + xen_pfn_t *buf_pfn, > + evtchn_port_t *buf_port) > +{ > + DECLARE_HYPERCALL; > + DECLARE_HYPERCALL_BUFFER(xen_hvm_get_ioreq_server_info_t, arg); > + int rc; > + > + arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg)); > + if ( arg == NULL ) > + return -1; > + > + hypercall.op = __HYPERVISOR_hvm_op; > + hypercall.arg[0] = HVMOP_get_ioreq_server_info; > + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg); > + arg->domid = domid; > + arg->id = id; > + rc = do_xen_hypercall(xch, &hypercall); > + if ( rc != 0 ) > + goto done; > + > + if ( pfn ) > + *pfn = arg->pfn; > + > + if ( buf_pfn ) > + *buf_pfn = arg->buf_pfn; > + > + if ( buf_port ) > + *buf_port = arg->buf_port; > + > +done: > + xc_hypercall_buffer_free(xch, arg); > + return rc; > +} > + > +int xc_hvm_map_io_range_to_ioreq_server(xc_interface *xch, domid_t domid, > + ioservid_t id, int is_mmio, > + uint64_t start, uint64_t end) > +{ > + DECLARE_HYPERCALL; > + DECLARE_HYPERCALL_BUFFER(xen_hvm_map_io_range_to_ioreq_server_t, arg); > + int rc; > + > + arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg)); > + if ( arg == NULL ) > + return -1; > + > + hypercall.op = __HYPERVISOR_hvm_op; > + hypercall.arg[0] = HVMOP_map_io_range_to_ioreq_server; > + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg); > + arg->domid = domid; > + arg->id = id; > + arg->is_mmio = is_mmio; > + arg->start = start; > + arg->end = end; > + rc = do_xen_hypercall(xch, &hypercall); > + xc_hypercall_buffer_free(xch, arg); > + return rc; > +} > + > +int xc_hvm_unmap_io_range_from_ioreq_server(xc_interface *xch, domid_t domid, > + ioservid_t id, int is_mmio, > + uint64_t start) > +{ > + DECLARE_HYPERCALL; > + DECLARE_HYPERCALL_BUFFER(xen_hvm_unmap_io_range_from_ioreq_server_t, > arg); > + int rc; > + > + arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg)); > + if ( arg == NULL ) > + return -1; > + > + hypercall.op = __HYPERVISOR_hvm_op; > + hypercall.arg[0] = HVMOP_unmap_io_range_from_ioreq_server; > + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg); > + arg->domid = domid; > + arg->id = id; > + arg->is_mmio = is_mmio; > + arg->start = start; > + rc = do_xen_hypercall(xch, &hypercall); > + xc_hypercall_buffer_free(xch, arg); > + return rc; > +} > + > +int xc_hvm_map_pcidev_to_ioreq_server(xc_interface *xch, domid_t domid, > + ioservid_t id, uint16_t bdf) > +{ > + DECLARE_HYPERCALL; > + DECLARE_HYPERCALL_BUFFER(xen_hvm_map_pcidev_to_ioreq_server_t, arg); > + int rc; > + > + arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg)); > + if ( arg == NULL ) > + return -1; > + > + hypercall.op = __HYPERVISOR_hvm_op; > + hypercall.arg[0] = HVMOP_map_pcidev_to_ioreq_server; > + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg); > + arg->domid = domid; > + arg->id = id; > + arg->bdf = bdf; > + rc = do_xen_hypercall(xch, &hypercall); > + xc_hypercall_buffer_free(xch, arg); > + return rc; > +} > + > +int xc_hvm_unmap_pcidev_from_ioreq_server(xc_interface *xch, domid_t domid, > + ioservid_t id, uint16_t bdf) > +{ > + DECLARE_HYPERCALL; > + DECLARE_HYPERCALL_BUFFER(xen_hvm_unmap_pcidev_from_ioreq_server_t, arg); > + int rc; > + > + arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg)); > + if ( arg == NULL ) > + return -1; > + > + hypercall.op = __HYPERVISOR_hvm_op; > + hypercall.arg[0] = HVMOP_unmap_pcidev_from_ioreq_server; > + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg); > + arg->domid = domid; > + arg->id = id; > + arg->bdf = bdf; > + rc = do_xen_hypercall(xch, &hypercall); > + xc_hypercall_buffer_free(xch, arg); > + return rc; > +} > + > +int xc_hvm_destroy_ioreq_server(xc_interface *xch, > + domid_t domid, > + ioservid_t id) > +{ > + DECLARE_HYPERCALL; > + DECLARE_HYPERCALL_BUFFER(xen_hvm_destroy_ioreq_server_t, arg); > + int rc; > + > + arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg)); > + if ( arg == NULL ) > + return -1; > + > + hypercall.op = __HYPERVISOR_hvm_op; > + hypercall.arg[0] = HVMOP_destroy_ioreq_server; > + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg); > + arg->domid = domid; > + arg->id = id; > + rc = do_xen_hypercall(xch, &hypercall); > + xc_hypercall_buffer_free(xch, arg); > + return rc; > +} > + > int xc_domain_setdebugging(xc_interface *xch, > uint32_t domid, > unsigned int enable) > diff --git a/tools/libxc/xc_domain_restore.c b/tools/libxc/xc_domain_restore.c > index 1f6ce50..3116653 100644 > --- a/tools/libxc/xc_domain_restore.c > +++ b/tools/libxc/xc_domain_restore.c > @@ -746,6 +746,7 @@ typedef struct { > uint64_t acpi_ioport_location; > uint64_t viridian; > uint64_t vm_generationid_addr; > + uint64_t nr_ioreq_servers; > > struct toolstack_data_t tdata; > } pagebuf_t; > @@ -996,6 +997,16 @@ static int pagebuf_get_one(xc_interface *xch, struct > restore_ctx *ctx, > DPRINTF("read generation id buffer address"); > return pagebuf_get_one(xch, ctx, buf, fd, dom); > > + case XC_SAVE_ID_HVM_NR_IOREQ_SERVERS: > + /* Skip padding 4 bytes then read the acpi ioport location. */ > + if ( RDEXACT(fd, &buf->nr_ioreq_servers, sizeof(uint32_t)) || > + RDEXACT(fd, &buf->nr_ioreq_servers, sizeof(uint64_t)) ) > + { > + PERROR("error reading the number of IOREQ servers"); > + return -1; > + } > + return pagebuf_get_one(xch, ctx, buf, fd, dom); > + > default: > if ( (count > MAX_BATCH_SIZE) || (count < 0) ) { > ERROR("Max batch size exceeded (%d). Giving up.", count); > @@ -1755,6 +1766,15 @@ int xc_domain_restore(xc_interface *xch, int io_fd, > uint32_t dom, > if (pagebuf.viridian != 0) > xc_set_hvm_param(xch, dom, HVM_PARAM_VIRIDIAN, 1); > > + if ( hvm ) { > + int nr_ioreq_servers = pagebuf.nr_ioreq_servers; > + > + if ( nr_ioreq_servers == 0 ) > + nr_ioreq_servers = 1; > + > + xc_set_hvm_param(xch, dom, HVM_PARAM_NR_IOREQ_SERVERS, > nr_ioreq_servers); > + } > + > if (pagebuf.acpi_ioport_location == 1) { > DBGPRINTF("Use new firmware ioport from the checkpoint\n"); > xc_set_hvm_param(xch, dom, HVM_PARAM_ACPI_IOPORTS_LOCATION, 1); > diff --git a/tools/libxc/xc_domain_save.c b/tools/libxc/xc_domain_save.c > index 42c4752..3293e29 100644 > --- a/tools/libxc/xc_domain_save.c > +++ b/tools/libxc/xc_domain_save.c > @@ -1731,6 +1731,18 @@ int xc_domain_save(xc_interface *xch, int io_fd, > uint32_t dom, uint32_t max_iter > PERROR("Error when writing the viridian flag"); > goto out; > } > + > + chunk.id = XC_SAVE_ID_HVM_NR_IOREQ_SERVERS; > + chunk.data = 0; > + xc_get_hvm_param(xch, dom, HVM_PARAM_NR_IOREQ_SERVERS, > + (unsigned long *)&chunk.data); > + > + if ( (chunk.data != 0) && > + wrexact(io_fd, &chunk, sizeof(chunk)) ) > + { > + PERROR("Error when writing the number of IOREQ servers"); > + goto out; > + } > } > > if ( callbacks != NULL && callbacks->toolstack_save != NULL ) > diff --git a/tools/libxc/xc_hvm_build_x86.c b/tools/libxc/xc_hvm_build_x86.c > index b65e702..6d6328a 100644 > --- a/tools/libxc/xc_hvm_build_x86.c > +++ b/tools/libxc/xc_hvm_build_x86.c > @@ -45,7 +45,7 @@ > #define SPECIALPAGE_IDENT_PT 4 > #define SPECIALPAGE_CONSOLE 5 > #define SPECIALPAGE_IOREQ 6 > -#define NR_SPECIAL_PAGES SPECIALPAGE_IOREQ + 2 /* ioreq server needs 2 > pages */ > +#define NR_SPECIAL_PAGES(n) SPECIALPAGE_IOREQ + (2 * n) /* ioreq server > needs 2 pages */ > #define special_pfn(x) (0xff000u - 1 - (x)) > > #define VGA_HOLE_SIZE (0x20) > @@ -85,7 +85,8 @@ static int modules_init(struct xc_hvm_build_args *args, > } > > static void build_hvm_info(void *hvm_info_page, uint64_t mem_size, > - uint64_t mmio_start, uint64_t mmio_size) > + uint64_t mmio_start, uint64_t mmio_size, > + int max_emulators) > { > struct hvm_info_table *hvm_info = (struct hvm_info_table *) > (((unsigned char *)hvm_info_page) + HVM_INFO_OFFSET); > @@ -113,7 +114,7 @@ static void build_hvm_info(void *hvm_info_page, uint64_t > mem_size, > /* Memory parameters. */ > hvm_info->low_mem_pgend = lowmem_end >> PAGE_SHIFT; > hvm_info->high_mem_pgend = highmem_end >> PAGE_SHIFT; > - hvm_info->reserved_mem_pgstart = special_pfn(0) - NR_SPECIAL_PAGES; > + hvm_info->reserved_mem_pgstart = special_pfn(0) - > NR_SPECIAL_PAGES(max_emulators); > > /* Finish with the checksum. */ > for ( i = 0, sum = 0; i < hvm_info->length; i++ ) > @@ -256,6 +257,10 @@ static int setup_guest(xc_interface *xch, > stat_1gb_pages = 0; > int pod_mode = 0; > int claim_enabled = args->claim_enabled; > + int max_emulators = args->max_emulators; > + > + if ( max_emulators < 1 ) > + goto error_out; > > if ( nr_pages > target_pages ) > pod_mode = XENMEMF_populate_on_demand; > @@ -468,12 +473,13 @@ static int setup_guest(xc_interface *xch, > xch, dom, PAGE_SIZE, PROT_READ | PROT_WRITE, > HVM_INFO_PFN)) == NULL ) > goto error_out; > - build_hvm_info(hvm_info_page, v_end, mmio_start, mmio_size); > + build_hvm_info(hvm_info_page, v_end, mmio_start, mmio_size, > + max_emulators); > munmap(hvm_info_page, PAGE_SIZE); > > /* Allocate and clear special pages. */ > > - DPRINTF("%d SPECIAL PAGES:\n", NR_SPECIAL_PAGES); > + DPRINTF("%d SPECIAL PAGES:\n", NR_SPECIAL_PAGES(max_emulators)); > DPRINTF(" PAGING: %"PRI_xen_pfn"\n", > (xen_pfn_t)special_pfn(SPECIALPAGE_PAGING)); > DPRINTF(" ACCESS: %"PRI_xen_pfn"\n", > @@ -486,10 +492,10 @@ static int setup_guest(xc_interface *xch, > (xen_pfn_t)special_pfn(SPECIALPAGE_IDENT_PT)); > DPRINTF(" CONSOLE: %"PRI_xen_pfn"\n", > (xen_pfn_t)special_pfn(SPECIALPAGE_CONSOLE)); > - DPRINTF(" IOREQ: %"PRI_xen_pfn"\n", > + DPRINTF(" IOREQ(%02d): %"PRI_xen_pfn"\n", max_emulators * 2, > (xen_pfn_t)special_pfn(SPECIALPAGE_IOREQ)); > > - for ( i = 0; i < NR_SPECIAL_PAGES; i++ ) > + for ( i = 0; i < NR_SPECIAL_PAGES(max_emulators); i++ ) > { > xen_pfn_t pfn = special_pfn(i); > rc = xc_domain_populate_physmap_exact(xch, dom, 1, 0, 0, &pfn); > @@ -515,7 +521,9 @@ static int setup_guest(xc_interface *xch, > xc_set_hvm_param(xch, dom, HVM_PARAM_IOREQ_PFN, > special_pfn(SPECIALPAGE_IOREQ)); > xc_set_hvm_param(xch, dom, HVM_PARAM_BUFIOREQ_PFN, > - special_pfn(SPECIALPAGE_IOREQ) - 1); > + special_pfn(SPECIALPAGE_IOREQ) - max_emulators); > + xc_set_hvm_param(xch, dom, HVM_PARAM_NR_IOREQ_SERVERS, > + max_emulators); > > /* > * Identity-map page table is required for running with CR0.PG=0 when > diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h > index 13f816b..84cab13 100644 > --- a/tools/libxc/xenctrl.h > +++ b/tools/libxc/xenctrl.h > @@ -1801,6 +1801,47 @@ void xc_clear_last_error(xc_interface *xch); > int xc_set_hvm_param(xc_interface *handle, domid_t dom, int param, unsigned > long value); > int xc_get_hvm_param(xc_interface *handle, domid_t dom, int param, unsigned > long *value); > > +/* > + * IOREQ server API > + */ > +int xc_hvm_create_ioreq_server(xc_interface *xch, > + domid_t domid, > + ioservid_t *id); > + > +int xc_hvm_get_ioreq_server_info(xc_interface *xch, > + domid_t domid, > + ioservid_t id, > + xen_pfn_t *pfn, > + xen_pfn_t *buf_pfn, > + evtchn_port_t *buf_port); > + > +int xc_hvm_map_io_range_to_ioreq_server(xc_interface *xch, > + domid_t domid, > + ioservid_t id, > + int is_mmio, > + uint64_t start, > + uint64_t end); > + > +int xc_hvm_unmap_io_range_from_ioreq_server(xc_interface *xch, > + domid_t domid, > + ioservid_t id, > + int is_mmio, > + uint64_t start); > + > +int xc_hvm_map_pcidev_to_ioreq_server(xc_interface *xch, > + domid_t domid, > + ioservid_t id, > + uint16_t bdf); > + > +int xc_hvm_unmap_pcidev_from_ioreq_server(xc_interface *xch, > + domid_t domid, > + ioservid_t id, > + uint16_t bdf); > + > +int xc_hvm_destroy_ioreq_server(xc_interface *xch, > + domid_t domid, > + ioservid_t id); > + > /* HVM guest pass-through */ > int xc_assign_device(xc_interface *xch, > uint32_t domid, > @@ -2428,3 +2469,13 @@ int xc_kexec_load(xc_interface *xch, uint8_t type, > uint16_t arch, > int xc_kexec_unload(xc_interface *xch, int type); > > #endif /* XENCTRL_H */ > + > +/* > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 4 > + * tab-width: 4 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/tools/libxc/xenguest.h b/tools/libxc/xenguest.h > index a0e30e1..1300933 100644 > --- a/tools/libxc/xenguest.h > +++ b/tools/libxc/xenguest.h > @@ -234,6 +234,8 @@ struct xc_hvm_build_args { > struct xc_hvm_firmware_module smbios_module; > /* Whether to use claim hypercall (1 - enable, 0 - disable). */ > int claim_enabled; > + /* Maximum number of emulators for VM */ > + int max_emulators; > }; > > /** > @@ -306,3 +308,13 @@ xen_pfn_t *xc_map_m2p(xc_interface *xch, > int prot, > unsigned long *mfn0); > #endif /* XENGUEST_H */ > + > +/* > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 4 > + * tab-width: 4 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/tools/libxc/xg_save_restore.h b/tools/libxc/xg_save_restore.h > index f859621..5170b7f 100644 > --- a/tools/libxc/xg_save_restore.h > +++ b/tools/libxc/xg_save_restore.h > @@ -259,6 +259,7 @@ > #define XC_SAVE_ID_HVM_ACCESS_RING_PFN -16 > #define XC_SAVE_ID_HVM_SHARING_RING_PFN -17 > #define XC_SAVE_ID_TOOLSTACK -18 /* Optional toolstack specific > info */ > +#define XC_SAVE_ID_HVM_NR_IOREQ_SERVERS -19 > > /* > ** We process save/restore/migrate in batches of pages; the below > diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h > index 06bbca6..5a70b76 100644 > --- a/tools/libxl/libxl.h > +++ b/tools/libxl/libxl.h > @@ -95,6 +95,14 @@ > #define LIBXL_HAVE_BUILDINFO_EVENT_CHANNELS 1 > > /* > + * LIBXL_HAVE_BUILDINFO_HVM_MAX_EMULATORS indicates that the > + * max_emulators field is present in the hvm sections of > + * libxl_domain_build_info. This field can be used to reserve > + * extra special pages for secondary device emulators. > + */ > +#define LIBXL_HAVE_BUILDINFO_HVM_MAX_EMULATORS 1 > + > +/* > * libxl ABI compatibility > * > * The only guarantee which libxl makes regarding ABI compatibility > diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c > index a604cd8..cce93d9 100644 > --- a/tools/libxl/libxl_create.c > +++ b/tools/libxl/libxl_create.c > @@ -330,6 +330,9 @@ int libxl__domain_build_info_setdefault(libxl__gc *gc, > > libxl_defbool_setdefault(&b_info->u.hvm.gfx_passthru, false); > > + if (b_info->u.hvm.max_emulators < 1) > + b_info->u.hvm.max_emulators = 1; > + > break; > case LIBXL_DOMAIN_TYPE_PV: > libxl_defbool_setdefault(&b_info->u.pv.e820_host, false); > diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c > index 55f74b2..9de06f9 100644 > --- a/tools/libxl/libxl_dom.c > +++ b/tools/libxl/libxl_dom.c > @@ -637,6 +637,7 @@ int libxl__build_hvm(libxl__gc *gc, uint32_t domid, > args.mem_size = (uint64_t)(info->max_memkb - info->video_memkb) << 10; > args.mem_target = (uint64_t)(info->target_memkb - info->video_memkb) << > 10; > args.claim_enabled = libxl_defbool_val(info->claim_mode); > + args.max_emulators = info->u.hvm.max_emulators; > if (libxl__domain_firmware(gc, info, &args)) { > LOG(ERROR, "initializing domain firmware failed"); > goto out; > diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl > index 649ce50..b707159 100644 > --- a/tools/libxl/libxl_types.idl > +++ b/tools/libxl/libxl_types.idl > @@ -372,6 +372,7 @@ libxl_domain_build_info = Struct("domain_build_info",[ > ("xen_platform_pci", libxl_defbool), > ("usbdevice_list", > libxl_string_list), > ("vendor_device", > libxl_vendor_device), > + ("max_emulators", integer), > ])), > ("pv", Struct(None, [("kernel", string), > ("slack_memkb", MemKB), > diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c > index 4fc46eb..cf9b67d 100644 > --- a/tools/libxl/xl_cmdimpl.c > +++ b/tools/libxl/xl_cmdimpl.c > @@ -1750,6 +1750,9 @@ skip_vfb: > > b_info->u.hvm.vendor_device = d; > } > + > + if (!xlu_cfg_get_long (config, "secondary_device_emulators", &l, 0)) > + b_info->u.hvm.max_emulators = l + 1; > } > > xlu_cfg_destroy(config); > diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c > index fb2dd73..e8b73fa 100644 > --- a/xen/arch/x86/hvm/hvm.c > +++ b/xen/arch/x86/hvm/hvm.c > @@ -357,14 +357,21 @@ static ioreq_t *get_ioreq(struct hvm_ioreq_server *s, > int id) > bool_t hvm_io_pending(struct vcpu *v) > { > struct domain *d = v->domain; > - struct hvm_ioreq_server *s = d->arch.hvm_domain.ioreq_server; > - ioreq_t *p; > + struct list_head *entry; > > - if ( !s ) > - return 0; > + list_for_each ( entry, &d->arch.hvm_domain.ioreq_server_list ) > + { > + struct hvm_ioreq_server *s = list_entry(entry, > + struct hvm_ioreq_server, > + list_entry); > + ioreq_t *p = get_ioreq(s, v->vcpu_id); > > - p = get_ioreq(s, v->vcpu_id); > - return ( p->state != STATE_IOREQ_NONE ); > + p = get_ioreq(s, v->vcpu_id); > + if ( p->state != STATE_IOREQ_NONE ) > + return 1; > + } > + > + return 0; > } > > static void hvm_wait_on_io(struct domain *d, ioreq_t *p) > @@ -394,18 +401,20 @@ static void hvm_wait_on_io(struct domain *d, ioreq_t *p) > void hvm_do_resume(struct vcpu *v) > { > struct domain *d = v->domain; > - struct hvm_ioreq_server *s = d->arch.hvm_domain.ioreq_server; > + struct list_head *entry; > > check_wakeup_from_wait(); > > if ( is_hvm_vcpu(v) ) > pt_restore_timer(v); > > - if ( s ) > + list_for_each ( entry, &d->arch.hvm_domain.ioreq_server_list ) > { > - ioreq_t *p = get_ioreq(s, v->vcpu_id); > + struct hvm_ioreq_server *s = list_entry(entry, > + struct hvm_ioreq_server, > + list_entry); > > - hvm_wait_on_io(d, p); > + hvm_wait_on_io(d, get_ioreq(s, v->vcpu_id)); > } > > /* Inject pending hw/sw trap */ > @@ -543,6 +552,83 @@ static int hvm_print_line( > return X86EMUL_OKAY; > } > > +static int hvm_access_cf8( > + int dir, uint32_t port, uint32_t bytes, uint32_t *val) > +{ > + struct vcpu *curr = current; > + struct hvm_domain *hd = &curr->domain->arch.hvm_domain; > + int rc; > + > + BUG_ON(port < 0xcf8); > + port -= 0xcf8; > + > + spin_lock(&hd->pci_lock); > + > + if ( dir == IOREQ_WRITE ) > + { > + switch ( bytes ) > + { > + case 4: > + hd->pci_cf8 = *val; > + break; > + > + case 2: > + { > + uint32_t mask = 0xffff << (port * 8); > + uint32_t subval = *val << (port * 8); > + > + hd->pci_cf8 = (hd->pci_cf8 & ~mask) | > + (subval & mask); > + break; > + } > + > + case 1: > + { > + uint32_t mask = 0xff << (port * 8); > + uint32_t subval = *val << (port * 8); > + > + hd->pci_cf8 = (hd->pci_cf8 & ~mask) | > + (subval & mask); > + break; > + } > + > + default: > + break; > + } > + > + /* We always need to fall through to the catch all emulator */ > + rc = X86EMUL_UNHANDLEABLE; > + } > + else > + { > + switch ( bytes ) > + { > + case 4: > + *val = hd->pci_cf8; > + rc = X86EMUL_OKAY; > + break; > + > + case 2: > + *val = (hd->pci_cf8 >> (port * 8)) & 0xffff; > + rc = X86EMUL_OKAY; > + break; > + > + case 1: > + *val = (hd->pci_cf8 >> (port * 8)) & 0xff; > + rc = X86EMUL_OKAY; > + break; > + > + default: > + rc = X86EMUL_UNHANDLEABLE; > + break; > + } > + } > + > + spin_unlock(&hd->pci_lock); > + > + return rc; > +} > + > static int handle_pvh_io( > int dir, uint32_t port, uint32_t bytes, uint32_t *val) > { > @@ -618,39 +704,53 @@ static void hvm_ioreq_server_remove_vcpu(struct > hvm_ioreq_server *s, struct vcpu > } > } > > -static int hvm_create_ioreq_server(struct domain *d, domid_t domid) > +static int hvm_create_ioreq_server(struct domain *d, ioservid_t id, domid_t > domid) > { > struct hvm_ioreq_server *s; > unsigned long pfn; > struct vcpu *v; > int i, rc; > > + if ( id >= d->arch.hvm_domain.params[HVM_PARAM_NR_IOREQ_SERVERS] ) > + return -EINVAL; > + > + spin_lock(&d->arch.hvm_domain.ioreq_server_lock); > + > rc = -EEXIST; > - if ( d->arch.hvm_domain.ioreq_server != NULL ) > - goto fail_exist; > + list_for_each_entry ( s, > + &d->arch.hvm_domain.ioreq_server_list, > + list_entry ) > + { > + if ( s->id == id ) > + goto fail_exist; > + } > > - gdprintk(XENLOG_INFO, "%s: %d\n", __func__, d->domain_id); > + gdprintk(XENLOG_INFO, "%s: %d:%d\n", __func__, d->domain_id, id); > > rc = -ENOMEM; > s = xzalloc(struct hvm_ioreq_server); > if ( !s ) > goto fail_alloc; > > + s->id = id; > s->domain = d; > s->domid = domid; > + INIT_LIST_HEAD(&s->mmio_range_list); > + INIT_LIST_HEAD(&s->portio_range_list); > + INIT_LIST_HEAD(&s->pcidev_list); > > for ( i = 0; i < MAX_HVM_VCPUS; i++ ) > s->ioreq_evtchn[i] = -1; > s->buf_ioreq_evtchn = -1; > > /* Initialize shared pages */ > - pfn = d->arch.hvm_domain.params[HVM_PARAM_IOREQ_PFN]; > + pfn = d->arch.hvm_domain.params[HVM_PARAM_IOREQ_PFN] - s->id; > > hvm_init_ioreq_page(s, 0); > if ( (rc = hvm_set_ioreq_page(s, 0, pfn)) < 0 ) > goto fail_set_ioreq; > > - pfn = d->arch.hvm_domain.params[HVM_PARAM_BUFIOREQ_PFN]; > + pfn = d->arch.hvm_domain.params[HVM_PARAM_BUFIOREQ_PFN] - s->id; > > hvm_init_ioreq_page(s, 1); > if ( (rc = hvm_set_ioreq_page(s, 1, pfn)) < 0 ) > @@ -664,10 +764,12 @@ static int hvm_create_ioreq_server(struct domain *d, > domid_t domid) > goto fail_add_vcpu; > } > > - d->arch.hvm_domain.ioreq_server = s; > + list_add(&s->list_entry, > + &d->arch.hvm_domain.ioreq_server_list); > > domain_unpause(d); > > + spin_unlock(&d->arch.hvm_domain.ioreq_server_lock); > return 0; > > fail_add_vcpu: > @@ -681,23 +783,33 @@ fail_set_ioreq: > xfree(s); > fail_alloc: > fail_exist: > + spin_unlock(&d->arch.hvm_domain.ioreq_server_lock); > return rc; > } > > -static void hvm_destroy_ioreq_server(struct domain *d) > +static void hvm_destroy_ioreq_server(struct domain *d, ioservid_t id) > { > struct hvm_ioreq_server *s; > struct vcpu *v; > > - gdprintk(XENLOG_INFO, "%s: %d\n", __func__, d->domain_id); > + spin_lock(&d->arch.hvm_domain.ioreq_server_lock); > > - s = d->arch.hvm_domain.ioreq_server; > - if ( !s ) > - return; > + list_for_each_entry ( s, > + &d->arch.hvm_domain.ioreq_server_list, > + list_entry) > + { > + if ( s->id == id ) > + goto found; > + } > + > + goto done; > + > +found: > + gdprintk(XENLOG_INFO, "%s: %d:%d\n", __func__, d->domain_id, id); > > domain_pause(d); > > - d->arch.hvm_domain.ioreq_server = NULL; > + list_del_init(&s->list_entry); > > for_each_vcpu ( d, v ) > hvm_ioreq_server_remove_vcpu(s, v); > @@ -708,31 +820,373 @@ static void hvm_destroy_ioreq_server(struct domain *d) > hvm_destroy_ioreq_page(s, 0); > > xfree(s); > + > +done: > + spin_unlock(&d->arch.hvm_domain.ioreq_server_lock); > } > > -static int hvm_get_ioreq_server_buf_port(struct domain *d, evtchn_port_t > *port) > +static int hvm_get_ioreq_server_buf_port(struct domain *d, ioservid_t id, > + evtchn_port_t *port) > { > - struct hvm_ioreq_server *s = d->arch.hvm_domain.ioreq_server; > + struct list_head *entry; > + int rc; > > - if ( !s ) > - return -ENOENT; > + if ( id >= d->arch.hvm_domain.params[HVM_PARAM_NR_IOREQ_SERVERS] ) > + return -EINVAL; > + > + spin_lock(&d->arch.hvm_domain.ioreq_server_lock); > + > + rc = -ENOENT; > + list_for_each ( entry, > + &d->arch.hvm_domain.ioreq_server_list ) > + { > + struct hvm_ioreq_server *s = list_entry(entry, > + struct hvm_ioreq_server, > + list_entry); > + > + if ( s->id == id ) > + { > + *port = s->buf_ioreq_evtchn; > + rc = 0; > + break; > + } > + } > + > + spin_unlock(&d->arch.hvm_domain.ioreq_server_lock); > + > + return rc; > +} > + > +static int hvm_get_ioreq_server_pfn(struct domain *d, ioservid_t id, int buf, > + xen_pfn_t *pfn) > +{ > + struct list_head *entry; > + int rc; > + > + if ( id >= d->arch.hvm_domain.params[HVM_PARAM_NR_IOREQ_SERVERS] ) > + return -EINVAL; > + > + spin_lock(&d->arch.hvm_domain.ioreq_server_lock); > + > + rc = -ENOENT; > + list_for_each ( entry, > + &d->arch.hvm_domain.ioreq_server_list ) > + { > + struct hvm_ioreq_server *s = list_entry(entry, > + struct hvm_ioreq_server, > + list_entry); > + > + if ( s->id == id ) > + { > + int i = ( buf ) ? HVM_PARAM_BUFIOREQ_PFN : HVM_PARAM_IOREQ_PFN; > + > + *pfn = d->arch.hvm_domain.params[i] - s->id; > + rc = 0; > + break; > + } > + } > + > + spin_unlock(&d->arch.hvm_domain.ioreq_server_lock); > + > + return rc; > +} > + > +static int hvm_map_io_range_to_ioreq_server(struct domain *d, ioservid_t id, > + int is_mmio, uint64_t start, > uint64_t end) > +{ > + struct hvm_ioreq_server *s; > + struct hvm_io_range *x; > + struct list_head *list; > + int rc; > + > + if ( id >= d->arch.hvm_domain.params[HVM_PARAM_NR_IOREQ_SERVERS] ) > + return -EINVAL; > + > + x = xmalloc(struct hvm_io_range); > + if ( x == NULL ) > + return -ENOMEM; > + > + spin_lock(&d->arch.hvm_domain.ioreq_server_lock); > + > + rc = -ENOENT; > + list_for_each_entry ( s, > + &d->arch.hvm_domain.ioreq_server_list, > + list_entry ) > + { > + if ( s->id == id ) > + goto found; > + } > + > + goto fail; > + > +found: > + INIT_RCU_HEAD(&x->rcu); > + x->start = start; > + x->end = end; > + > + list = ( is_mmio ) ? &s->mmio_range_list : &s->portio_range_list; > + list_add_rcu(&x->list_entry, list); > + > + gdprintk(XENLOG_DEBUG, "%d:%d: +%s %"PRIX64" - %"PRIX64"\n", > + d->domain_id, > + s->id, > + ( is_mmio ) ? "MMIO" : "PORTIO", > + x->start, > + x->end); > + > + spin_unlock(&d->arch.hvm_domain.ioreq_server_lock); > > - *port = s->buf_ioreq_evtchn; > return 0; > + > +fail: > + xfree(x); > + > + spin_unlock(&d->arch.hvm_domain.ioreq_server_lock); > + > + return rc; > } > > -static int hvm_get_ioreq_server_pfn(struct domain *d, int buf, xen_pfn_t > *pfn) > +static void free_io_range(struct rcu_head *rcu) > { > - struct hvm_ioreq_server *s = d->arch.hvm_domain.ioreq_server; > - int i; > + struct hvm_io_range *x; > > - if ( !s ) > - return -ENOENT; > + x = container_of (rcu, struct hvm_io_range, rcu); > + > + xfree(x); > +} > + > +static int hvm_unmap_io_range_from_ioreq_server(struct domain *d, ioservid_t > id, > + int is_mmio, uint64_t start) > +{ > + struct hvm_ioreq_server *s; > + struct list_head *list, *entry; > + int rc; > + > + if ( id >= d->arch.hvm_domain.params[HVM_PARAM_NR_IOREQ_SERVERS] ) > + return -EINVAL; > + > + spin_lock(&d->arch.hvm_domain.ioreq_server_lock); > + > + rc = -ENOENT; > + list_for_each_entry ( s, > + &d->arch.hvm_domain.ioreq_server_list, > + list_entry ) > + { > + if ( s->id == id ) > + goto found; > + } > + > + goto done; > + > +found: > + list = ( is_mmio ) ? &s->mmio_range_list : &s->portio_range_list; > + > + list_for_each ( entry, > + list ) > + { > + struct hvm_io_range *x = list_entry(entry, > + struct hvm_io_range, > + list_entry); > + > + if ( start == x->start ) > + { > + gdprintk(XENLOG_DEBUG, "%d:%d: -%s %"PRIX64" - %"PRIX64"\n", > + d->domain_id, > + s->id, > + ( is_mmio ) ? "MMIO" : "PORTIO", > + x->start, > + x->end); > + > + list_del_rcu(&x->list_entry); > + call_rcu(&x->rcu, free_io_range); > > - i = ( buf ) ? HVM_PARAM_BUFIOREQ_PFN : HVM_PARAM_IOREQ_PFN; > - *pfn = d->arch.hvm_domain.params[i]; > + rc = 0; > + break; > + } > + } > + > +done: > + spin_unlock(&d->arch.hvm_domain.ioreq_server_lock); > + > + return rc; > +} > + > +static int hvm_map_pcidev_to_ioreq_server(struct domain *d, ioservid_t id, > + uint16_t bdf) > +{ > + struct hvm_ioreq_server *s; > + struct hvm_pcidev *x; > + int rc; > + > + if ( id >= d->arch.hvm_domain.params[HVM_PARAM_NR_IOREQ_SERVERS] ) > + return -EINVAL; > + > + x = xmalloc(struct hvm_pcidev); > + if ( x == NULL ) > + return -ENOMEM; > + > + spin_lock(&d->arch.hvm_domain.ioreq_server_lock); > + > + rc = -ENOENT; > + list_for_each_entry ( s, > + &d->arch.hvm_domain.ioreq_server_list, > + list_entry ) > + { > + if ( s->id == id ) > + goto found; > + } > + > + goto fail; > + > +found: > + INIT_RCU_HEAD(&x->rcu); > + x->bdf = bdf; > + > + list_add_rcu(&x->list_entry, &s->pcidev_list); > + > + gdprintk(XENLOG_DEBUG, "%d:%d: +PCIDEV %04X\n", > + d->domain_id, > + s->id, > + x->bdf); > + > + spin_unlock(&d->arch.hvm_domain.ioreq_server_lock); > > return 0; > + > +fail: > + xfree(x); > + > + spin_unlock(&d->arch.hvm_domain.ioreq_server_lock); > + > + return rc; > +} > + > +static void free_pcidev(struct rcu_head *rcu) > +{ > + struct hvm_pcidev *x; > + > + x = container_of (rcu, struct hvm_pcidev, rcu); > + > + xfree(x); > +} > + > +static int hvm_unmap_pcidev_from_ioreq_server(struct domain *d, ioservid_t > id, > + uint16_t bdf) > +{ > + struct hvm_ioreq_server *s; > + struct list_head *entry; > + int rc; > + > + if ( id >= d->arch.hvm_domain.params[HVM_PARAM_NR_IOREQ_SERVERS] ) > + return -EINVAL; > + > + spin_lock(&d->arch.hvm_domain.ioreq_server_lock); > + > + rc = -ENOENT; > + list_for_each_entry ( s, > + &d->arch.hvm_domain.ioreq_server_list, > + list_entry ) > + { > + if ( s->id == id ) > + goto found; > + } > + > + goto done; > + > +found: > + list_for_each ( entry, > + &s->pcidev_list ) > + { > + struct hvm_pcidev *x = list_entry(entry, > + struct hvm_pcidev, > + list_entry); > + > + if ( bdf == x->bdf ) > + { > + gdprintk(XENLOG_DEBUG, "%d:%d: -PCIDEV %04X\n", > + d->domain_id, > + s->id, > + x->bdf); > + > + list_del_rcu(&x->list_entry); > + call_rcu(&x->rcu, free_pcidev); > + > + rc = 0; > + break; > + } > + } > + > +done: > + spin_unlock(&d->arch.hvm_domain.ioreq_server_lock); > + > + return rc; > +} > + > +static int hvm_all_ioreq_servers_add_vcpu(struct domain *d, struct vcpu *v) > +{ > + struct list_head *entry; > + int rc; > + > + spin_lock(&d->arch.hvm_domain.ioreq_server_lock); > + > + list_for_each ( entry, > + &d->arch.hvm_domain.ioreq_server_list ) > + { > + struct hvm_ioreq_server *s = list_entry(entry, > + struct hvm_ioreq_server, > + list_entry); > + > + if ( (rc = hvm_ioreq_server_add_vcpu(s, v)) < 0 ) > + goto fail; > + } > + > + spin_unlock(&d->arch.hvm_domain.ioreq_server_lock); > + > + return 0; > + > +fail: > + list_for_each ( entry, > + &d->arch.hvm_domain.ioreq_server_list ) > + { > + struct hvm_ioreq_server *s = list_entry(entry, > + struct hvm_ioreq_server, > + list_entry); > + > + hvm_ioreq_server_remove_vcpu(s, v); > + } > + > + spin_unlock(&d->arch.hvm_domain.ioreq_server_lock); > + > + return rc; > +} > + > +static void hvm_all_ioreq_servers_remove_vcpu(struct domain *d, struct vcpu > *v) > +{ > + struct list_head *entry; > + > + spin_lock(&d->arch.hvm_domain.ioreq_server_lock); > + > + list_for_each ( entry, > + &d->arch.hvm_domain.ioreq_server_list ) > + { > + struct hvm_ioreq_server *s = list_entry(entry, > + struct hvm_ioreq_server, > + list_entry); > + > + hvm_ioreq_server_remove_vcpu(s, v); > + } > + > + spin_unlock(&d->arch.hvm_domain.ioreq_server_lock); > +} > + > +static void hvm_destroy_all_ioreq_servers(struct domain *d) > +{ > + ioservid_t id; > + > + for ( id = 0; > + id < d->arch.hvm_domain.params[HVM_PARAM_NR_IOREQ_SERVERS]; > + id++ ) > + hvm_destroy_ioreq_server(d, id); > } > > static int hvm_replace_event_channel(struct vcpu *v, domid_t remote_domid, > @@ -750,18 +1204,31 @@ static int hvm_replace_event_channel(struct vcpu *v, > domid_t remote_domid, > return 0; > } > > -static int hvm_set_ioreq_server_domid(struct domain *d, domid_t domid) > +static int hvm_set_ioreq_server_domid(struct domain *d, ioservid_t id, > domid_t domid) > { > - struct hvm_ioreq_server *s = d->arch.hvm_domain.ioreq_server; > + struct hvm_ioreq_server *s; > struct vcpu *v; > int rc = 0; > > + if ( id >= d->arch.hvm_domain.params[HVM_PARAM_NR_IOREQ_SERVERS] ) > + return -EINVAL; > + > + spin_lock(&d->arch.hvm_domain.ioreq_server_lock); > + > domain_pause(d); > > + list_for_each_entry ( s, > + &d->arch.hvm_domain.ioreq_server_list, > + list_entry ) > + { > + if ( s->id == id ) > + goto found; > + } > + > rc = -ENOENT; > - if ( !s ) > - goto done; > + goto done; > > +found: > rc = 0; > if ( s->domid == domid ) > goto done; > @@ -787,6 +1254,8 @@ static int hvm_set_ioreq_server_domid(struct domain *d, > domid_t domid) > done: > domain_unpause(d); > > + spin_unlock(&d->arch.hvm_domain.ioreq_server_lock); > + > return rc; > } > > @@ -817,6 +1286,9 @@ int hvm_domain_initialise(struct domain *d) > > } > > + spin_lock_init(&d->arch.hvm_domain.ioreq_server_lock); > + INIT_LIST_HEAD(&d->arch.hvm_domain.ioreq_server_list); > + spin_lock_init(&d->arch.hvm_domain.pci_lock); > spin_lock_init(&d->arch.hvm_domain.irq_lock); > spin_lock_init(&d->arch.hvm_domain.uc_lock); > > @@ -858,6 +1330,7 @@ int hvm_domain_initialise(struct domain *d) > rtc_init(d); > > register_portio_handler(d, 0xe9, 1, hvm_print_line); > + register_portio_handler(d, 0xcf8, 4, hvm_access_cf8); > > rc = hvm_funcs.domain_initialise(d); > if ( rc != 0 ) > @@ -888,7 +1361,7 @@ void hvm_domain_relinquish_resources(struct domain *d) > if ( hvm_funcs.nhvm_domain_relinquish_resources ) > hvm_funcs.nhvm_domain_relinquish_resources(d); > > - hvm_destroy_ioreq_server(d); > + hvm_destroy_all_ioreq_servers(d); > > msixtbl_pt_cleanup(d); > > @@ -1520,7 +1993,6 @@ int hvm_vcpu_initialise(struct vcpu *v) > { > int rc; > struct domain *d = v->domain; > - struct hvm_ioreq_server *s = d->arch.hvm_domain.ioreq_server; > > hvm_asid_flush_vcpu(v); > > @@ -1563,12 +2035,9 @@ int hvm_vcpu_initialise(struct vcpu *v) > && (rc = nestedhvm_vcpu_initialise(v)) < 0 ) /* teardown: > nestedhvm_vcpu_destroy */ > goto fail5; > > - if ( s ) > - { > - rc = hvm_ioreq_server_add_vcpu(s, v); > - if ( rc < 0 ) > - goto fail6; > - } > + rc = hvm_all_ioreq_servers_add_vcpu(d, v); > + if ( rc < 0 ) > + goto fail6; > > if ( v->vcpu_id == 0 ) > { > @@ -1604,10 +2073,8 @@ int hvm_vcpu_initialise(struct vcpu *v) > void hvm_vcpu_destroy(struct vcpu *v) > { > struct domain *d = v->domain; > - struct hvm_ioreq_server *s = d->arch.hvm_domain.ioreq_server; > > - if ( s ) > - hvm_ioreq_server_remove_vcpu(s, v); > + hvm_all_ioreq_servers_remove_vcpu(d, v); > > nestedhvm_vcpu_destroy(v); > > @@ -1646,11 +2113,112 @@ void hvm_vcpu_down(struct vcpu *v) > } > } > > +static DEFINE_RCU_READ_LOCK(ioreq_server_rcu_lock); > + > +static struct hvm_ioreq_server *hvm_select_ioreq_server(struct vcpu *v, > ioreq_t *p) > +{ > +#define BDF(cf8) (((cf8) & 0x00ffff00) >> 8) > + > + struct domain *d = v->domain; > + struct hvm_ioreq_server *s; > + uint8_t type; > + uint64_t addr; > + > + if ( p->type == IOREQ_TYPE_PIO && > + (p->addr & ~3) == 0xcfc ) > + { > + /* PCI config data cycle */ > + type = IOREQ_TYPE_PCI_CONFIG; > + > + spin_lock(&d->arch.hvm_domain.pci_lock); > + addr = d->arch.hvm_domain.pci_cf8 + (p->addr & 3); > + spin_unlock(&d->arch.hvm_domain.pci_lock); > + } > + else > + { > + type = p->type; > + addr = p->addr; > + } > + > + rcu_read_lock(&ioreq_server_rcu_lock); > + > + switch ( type ) > + { > + case IOREQ_TYPE_COPY: > + case IOREQ_TYPE_PIO: > + case IOREQ_TYPE_PCI_CONFIG: > + break; > + default: > + goto done; > + } > + > + list_for_each_entry ( s, > + &d->arch.hvm_domain.ioreq_server_list, > + list_entry ) > + { > + switch ( type ) > + { > + case IOREQ_TYPE_COPY: > + case IOREQ_TYPE_PIO: { > + struct list_head *list; > + struct hvm_io_range *x; > + > + list = ( type == IOREQ_TYPE_COPY ) ? > + &s->mmio_range_list : > + &s->portio_range_list; > + > + list_for_each_entry ( x, > + list, > + list_entry ) > + { > + if ( (addr >= x->start) && (addr <= x->end) ) > + goto found; > + } > + break; > + } > + case IOREQ_TYPE_PCI_CONFIG: { > + struct hvm_pcidev *x; > + > + list_for_each_entry ( x, > + &s->pcidev_list, > + list_entry ) > + { > + if ( BDF(addr) == x->bdf ) { > + p->type = type; > + p->addr = addr; > + goto found; > + } > + } > + break; > + } > + } > + } > + > +done: > + /* The catch-all server has id 0 */ > + list_for_each_entry ( s, > + &d->arch.hvm_domain.ioreq_server_list, > + list_entry ) > + { > + if ( s->id == 0 ) > + goto found; > + } > + > + s = NULL; > + > +found: > + rcu_read_unlock(&ioreq_server_rcu_lock); > + > + return s; > + > +#undef BDF > +} > + > int hvm_buffered_io_send(ioreq_t *p) > { > struct vcpu *v = current; > struct domain *d = v->domain; > - struct hvm_ioreq_server *s = d->arch.hvm_domain.ioreq_server; > + struct hvm_ioreq_server *s; > struct hvm_ioreq_page *iorp; > buffered_iopage_t *pg; > buf_ioreq_t bp; > @@ -1660,6 +2228,7 @@ int hvm_buffered_io_send(ioreq_t *p) > /* Ensure buffered_iopage fits in a page */ > BUILD_BUG_ON(sizeof(buffered_iopage_t) > PAGE_SIZE); > > + s = hvm_select_ioreq_server(v, p); > if ( !s ) > return 0; > > @@ -1770,18 +2339,34 @@ static bool_t hvm_send_assist_req_to_server(struct > hvm_ioreq_server *s, > > bool_t hvm_send_assist_req(struct vcpu *v, ioreq_t *p) > { > - struct domain *d = v->domain; > - struct hvm_ioreq_server *s = d->arch.hvm_domain.ioreq_server; > + struct hvm_ioreq_server *s; > > if ( unlikely(!vcpu_start_shutdown_deferral(v)) ) > return 0; > > + s = hvm_select_ioreq_server(v, p); > if ( !s ) > return 0; > > return hvm_send_assist_req_to_server(s, v, p); > } > > +void hvm_broadcast_assist_req(struct vcpu *v, ioreq_t *p) > +{ > + struct domain *d = v->domain; > + struct list_head *entry; > + > + list_for_each ( entry, > + &d->arch.hvm_domain.ioreq_server_list ) > + { > + struct hvm_ioreq_server *s = list_entry(entry, > + struct hvm_ioreq_server, > + list_entry); > + > + (void) hvm_send_assist_req_to_server(s, v, p); > + } > +} > + > void hvm_hlt(unsigned long rflags) > { > struct vcpu *curr = current; > @@ -4370,6 +4955,215 @@ static int hvmop_flush_tlb_all(void) > return 0; > } > > +static int hvmop_create_ioreq_server( > + XEN_GUEST_HANDLE_PARAM(xen_hvm_create_ioreq_server_t) uop) > +{ > + struct domain *curr_d = current->domain; > + xen_hvm_create_ioreq_server_t op; > + struct domain *d; > + ioservid_t id; > + int rc; > + > + if ( copy_from_guest(&op, uop, 1) ) > + return -EFAULT; > + > + rc = rcu_lock_remote_domain_by_id(op.domid, &d); > + if ( rc != 0 ) > + return rc; > + > + rc = -EINVAL; > + if ( !is_hvm_domain(d) ) > + goto out; > + > + rc = -ENOSPC; > + for ( id = 1; > + id < d->arch.hvm_domain.params[HVM_PARAM_NR_IOREQ_SERVERS]; > + id++ ) > + { > + rc = hvm_create_ioreq_server(d, id, curr_d->domain_id); > + if ( rc == -EEXIST ) > + continue; > + > + break; > + } > + > + if ( rc == -EEXIST ) > + rc = -ENOSPC; > + > + if ( rc < 0 ) > + goto out; > + > + op.id = id; > + > + rc = copy_to_guest(uop, &op, 1) ? -EFAULT : 0; > + > +out: > + rcu_unlock_domain(d); > + return rc; > +} > + > +static int hvmop_get_ioreq_server_info( > + XEN_GUEST_HANDLE_PARAM(xen_hvm_get_ioreq_server_info_t) uop) > +{ > + xen_hvm_get_ioreq_server_info_t op; > + struct domain *d; > + int rc; > + > + if ( copy_from_guest(&op, uop, 1) ) > + return -EFAULT; > + > + rc = rcu_lock_remote_domain_by_id(op.domid, &d); > + if ( rc != 0 ) > + return rc; > + > + rc = -EINVAL; > + if ( !is_hvm_domain(d) ) > + goto out; > + > + if ( (rc = hvm_get_ioreq_server_pfn(d, op.id, 0, &op.pfn)) < 0 ) > + goto out; > + > + if ( (rc = hvm_get_ioreq_server_pfn(d, op.id, 1, &op.buf_pfn)) < 0 ) > + goto out; > + > + if ( (rc = hvm_get_ioreq_server_buf_port(d, op.id, &op.buf_port)) < 0 ) > + goto out; > + > + rc = copy_to_guest(uop, &op, 1) ? -EFAULT : 0; > + > +out: > + rcu_unlock_domain(d); > + return rc; > +} > + > +static int hvmop_map_io_range_to_ioreq_server( > + XEN_GUEST_HANDLE_PARAM(xen_hvm_map_io_range_to_ioreq_server_t) uop) > +{ > + xen_hvm_map_io_range_to_ioreq_server_t op; > + struct domain *d; > + int rc; > + > + if ( copy_from_guest(&op, uop, 1) ) > + return -EFAULT; > + > + rc = rcu_lock_remote_domain_by_id(op.domid, &d); > + if ( rc != 0 ) > + return rc; > + > + rc = -EINVAL; > + if ( !is_hvm_domain(d) ) > + goto out; > + > + rc = hvm_map_io_range_to_ioreq_server(d, op.id, op.is_mmio, > + op.start, op.end); > + > +out: > + rcu_unlock_domain(d); > + return rc; > +} > + > +static int hvmop_unmap_io_range_from_ioreq_server( > + XEN_GUEST_HANDLE_PARAM(xen_hvm_unmap_io_range_from_ioreq_server_t) uop) > +{ > + xen_hvm_unmap_io_range_from_ioreq_server_t op; > + struct domain *d; > + int rc; > + > + if ( copy_from_guest(&op, uop, 1) ) > + return -EFAULT; > + > + rc = rcu_lock_remote_domain_by_id(op.domid, &d); > + if ( rc != 0 ) > + return rc; > + > + rc = -EINVAL; > + if ( !is_hvm_domain(d) ) > + goto out; > + > + rc = hvm_unmap_io_range_from_ioreq_server(d, op.id, op.is_mmio, > + op.start); > + > +out: > + rcu_unlock_domain(d); > + return rc; > +} > + > +static int hvmop_map_pcidev_to_ioreq_server( > + XEN_GUEST_HANDLE_PARAM(xen_hvm_map_pcidev_to_ioreq_server_t) uop) > +{ > + xen_hvm_map_pcidev_to_ioreq_server_t op; > + struct domain *d; > + int rc; > + > + if ( copy_from_guest(&op, uop, 1) ) > + return -EFAULT; > + > + rc = rcu_lock_remote_domain_by_id(op.domid, &d); > + if ( rc != 0 ) > + return rc; > + > + rc = -EINVAL; > + if ( !is_hvm_domain(d) ) > + goto out; > + > + rc = hvm_map_pcidev_to_ioreq_server(d, op.id, op.bdf); > + > +out: > + rcu_unlock_domain(d); > + return rc; > +} > + > +static int hvmop_unmap_pcidev_from_ioreq_server( > + XEN_GUEST_HANDLE_PARAM(xen_hvm_unmap_pcidev_from_ioreq_server_t) uop) > +{ > + xen_hvm_unmap_pcidev_from_ioreq_server_t op; > + struct domain *d; > + int rc; > + > + if ( copy_from_guest(&op, uop, 1) ) > + return -EFAULT; > + > + rc = rcu_lock_remote_domain_by_id(op.domid, &d); > + if ( rc != 0 ) > + return rc; > + > + rc = -EINVAL; > + if ( !is_hvm_domain(d) ) > + goto out; > + > + rc = hvm_unmap_pcidev_from_ioreq_server(d, op.id, op.bdf); > + > +out: > + rcu_unlock_domain(d); > + return rc; > +} > + > +static int hvmop_destroy_ioreq_server( > + XEN_GUEST_HANDLE_PARAM(xen_hvm_destroy_ioreq_server_t) uop) > +{ > + xen_hvm_destroy_ioreq_server_t op; > + struct domain *d; > + int rc; > + > + if ( copy_from_guest(&op, uop, 1) ) > + return -EFAULT; > + > + rc = rcu_lock_remote_domain_by_id(op.domid, &d); > + if ( rc != 0 ) > + return rc; > + > + rc = -EINVAL; > + if ( !is_hvm_domain(d) ) > + goto out; > + > + hvm_destroy_ioreq_server(d, op.id); > + rc = 0; > + > +out: > + rcu_unlock_domain(d); > + return rc; > +} > + > long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) > > { > @@ -4378,6 +5172,41 @@ long do_hvm_op(unsigned long op, > XEN_GUEST_HANDLE_PARAM(void) arg) > > switch ( op ) > { > + case HVMOP_create_ioreq_server: > + rc = hvmop_create_ioreq_server( > + guest_handle_cast(arg, xen_hvm_create_ioreq_server_t)); > + break; > + > + case HVMOP_get_ioreq_server_info: > + rc = hvmop_get_ioreq_server_info( > + guest_handle_cast(arg, xen_hvm_get_ioreq_server_info_t)); > + break; > + > + case HVMOP_map_io_range_to_ioreq_server: > + rc = hvmop_map_io_range_to_ioreq_server( > + guest_handle_cast(arg, xen_hvm_map_io_range_to_ioreq_server_t)); > + break; > + > + case HVMOP_unmap_io_range_from_ioreq_server: > + rc = hvmop_unmap_io_range_from_ioreq_server( > + guest_handle_cast(arg, > xen_hvm_unmap_io_range_from_ioreq_server_t)); > + break; > + > + case HVMOP_map_pcidev_to_ioreq_server: > + rc = hvmop_map_pcidev_to_ioreq_server( > + guest_handle_cast(arg, xen_hvm_map_pcidev_to_ioreq_server_t)); > + break; > + > + case HVMOP_unmap_pcidev_from_ioreq_server: > + rc = hvmop_unmap_pcidev_from_ioreq_server( > + guest_handle_cast(arg, > xen_hvm_unmap_pcidev_from_ioreq_server_t)); > + break; > + > + case HVMOP_destroy_ioreq_server: > + rc = hvmop_destroy_ioreq_server( > + guest_handle_cast(arg, xen_hvm_destroy_ioreq_server_t)); > + break; > + > case HVMOP_set_param: > case HVMOP_get_param: > { > @@ -4466,9 +5295,9 @@ long do_hvm_op(unsigned long op, > XEN_GUEST_HANDLE_PARAM(void) arg) > if ( a.value == DOMID_SELF ) > a.value = curr_d->domain_id; > > - rc = hvm_create_ioreq_server(d, a.value); > + rc = hvm_create_ioreq_server(d, 0, a.value); > if ( rc == -EEXIST ) > - rc = hvm_set_ioreq_server_domid(d, a.value); > + rc = hvm_set_ioreq_server_domid(d, 0, a.value); > break; > case HVM_PARAM_ACPI_S_STATE: > /* Not reflexive, as we must domain_pause(). */ > @@ -4533,6 +5362,10 @@ long do_hvm_op(unsigned long op, > XEN_GUEST_HANDLE_PARAM(void) arg) > if ( a.value > SHUTDOWN_MAX ) > rc = -EINVAL; > break; > + case HVM_PARAM_NR_IOREQ_SERVERS: > + if ( d == current->domain ) > + rc = -EPERM; > + break; > } > > if ( rc == 0 ) > @@ -4567,7 +5400,7 @@ long do_hvm_op(unsigned long op, > XEN_GUEST_HANDLE_PARAM(void) arg) > case HVM_PARAM_BUFIOREQ_PFN: > case HVM_PARAM_BUFIOREQ_EVTCHN: > /* May need to create server */ > - rc = hvm_create_ioreq_server(d, curr_d->domain_id); > + rc = hvm_create_ioreq_server(d, 0, curr_d->domain_id); > if ( rc != 0 && rc != -EEXIST ) > goto param_fail; > > @@ -4576,7 +5409,7 @@ long do_hvm_op(unsigned long op, > XEN_GUEST_HANDLE_PARAM(void) arg) > case HVM_PARAM_IOREQ_PFN: { > xen_pfn_t pfn; > > - if ( (rc = hvm_get_ioreq_server_pfn(d, 0, &pfn)) < 0 ) > + if ( (rc = hvm_get_ioreq_server_pfn(d, 0, 0, &pfn)) < 0 ) > goto param_fail; > > a.value = pfn; > @@ -4585,7 +5418,7 @@ long do_hvm_op(unsigned long op, > XEN_GUEST_HANDLE_PARAM(void) arg) > case HVM_PARAM_BUFIOREQ_PFN: { > xen_pfn_t pfn; > > - if ( (rc = hvm_get_ioreq_server_pfn(d, 1, &pfn)) < 0 ) > + if ( (rc = hvm_get_ioreq_server_pfn(d, 0, 1, &pfn)) < 0 ) > goto param_fail; > > a.value = pfn; > @@ -4594,7 +5427,7 @@ long do_hvm_op(unsigned long op, > XEN_GUEST_HANDLE_PARAM(void) arg) > case HVM_PARAM_BUFIOREQ_EVTCHN: { > evtchn_port_t port; > > - if ( (rc = hvm_get_ioreq_server_buf_port(d, &port)) < 0 ) > + if ( (rc = hvm_get_ioreq_server_buf_port(d, 0, &port)) < > 0 ) > goto param_fail; > > a.value = port; > diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c > index c9adb94..ac0d867 100644 > --- a/xen/arch/x86/hvm/io.c > +++ b/xen/arch/x86/hvm/io.c > @@ -75,7 +75,7 @@ void send_invalidate_req(void) > .data = ~0UL, /* flush all */ > }; > > - (void)hvm_send_assist_req(v, &p); > + hvm_broadcast_assist_req(v, &p); > } > > int handle_mmio(void) > diff --git a/xen/include/asm-x86/hvm/domain.h > b/xen/include/asm-x86/hvm/domain.h > index a77b83d..e9da543 100644 > --- a/xen/include/asm-x86/hvm/domain.h > +++ b/xen/include/asm-x86/hvm/domain.h > @@ -41,17 +41,38 @@ struct hvm_ioreq_page { > void *va; > }; > > +struct hvm_io_range { > + struct list_head list_entry; > + uint64_t start, end; > + struct rcu_head rcu; > +}; > + > +struct hvm_pcidev { > + struct list_head list_entry; > + uint16_t bdf; > + struct rcu_head rcu; > +}; > + > struct hvm_ioreq_server { > + struct list_head list_entry; > + ioservid_t id; > struct domain *domain; > domid_t domid; > struct hvm_ioreq_page ioreq; > int ioreq_evtchn[MAX_HVM_VCPUS]; > struct hvm_ioreq_page buf_ioreq; > int buf_ioreq_evtchn; > + struct list_head mmio_range_list; > + struct list_head portio_range_list; > + struct list_head pcidev_list; > }; > > struct hvm_domain { > - struct hvm_ioreq_server *ioreq_server; > + struct list_head ioreq_server_list; > + spinlock_t ioreq_server_lock; > + uint32_t pci_cf8; > + spinlock_t pci_lock; > + > struct pl_time pl_time; > > struct hvm_io_handler *io_handler; > diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h > index 40aeddf..4118669 100644 > --- a/xen/include/asm-x86/hvm/hvm.h > +++ b/xen/include/asm-x86/hvm/hvm.h > @@ -229,6 +229,7 @@ int prepare_ring_for_helper(struct domain *d, unsigned > long gmfn, > void destroy_ring_for_helper(void **_va, struct page_info *page); > > bool_t hvm_send_assist_req(struct vcpu *v, ioreq_t *p); > +void hvm_broadcast_assist_req(struct vcpu *v, ioreq_t *p); > > void hvm_get_guest_pat(struct vcpu *v, u64 *guest_pat); > int hvm_set_guest_pat(struct vcpu *v, u64 guest_pat); > diff --git a/xen/include/public/hvm/hvm_op.h b/xen/include/public/hvm/hvm_op.h > index a9aab4b..6b31189 100644 > --- a/xen/include/public/hvm/hvm_op.h > +++ b/xen/include/public/hvm/hvm_op.h > @@ -23,6 +23,7 @@ > > #include "../xen.h" > #include "../trace.h" > +#include "../event_channel.h" > > /* Get/set subcommands: extra argument == pointer to xen_hvm_param struct. */ > #define HVMOP_set_param 0 > @@ -270,6 +271,75 @@ struct xen_hvm_inject_msi { > typedef struct xen_hvm_inject_msi xen_hvm_inject_msi_t; > DEFINE_XEN_GUEST_HANDLE(xen_hvm_inject_msi_t); > > +typedef uint32_t ioservid_t; > + > +DEFINE_XEN_GUEST_HANDLE(ioservid_t); > + > +#define HVMOP_create_ioreq_server 17 > +struct xen_hvm_create_ioreq_server { > + domid_t domid; /* IN - domain to be serviced */ > + ioservid_t id; /* OUT - server id */ > +}; > +typedef struct xen_hvm_create_ioreq_server xen_hvm_create_ioreq_server_t; > +DEFINE_XEN_GUEST_HANDLE(xen_hvm_create_ioreq_server_t); > + > +#define HVMOP_get_ioreq_server_info 18 > +struct xen_hvm_get_ioreq_server_info { > + domid_t domid; /* IN - domain to be serviced */ > + ioservid_t id; /* IN - server id */ > + xen_pfn_t pfn; /* OUT - ioreq pfn */ > + xen_pfn_t buf_pfn; /* OUT - buf ioreq pfn */ > + evtchn_port_t buf_port; /* OUT - buf ioreq port */ > +}; > +typedef struct xen_hvm_get_ioreq_server_info xen_hvm_get_ioreq_server_info_t; > +DEFINE_XEN_GUEST_HANDLE(xen_hvm_get_ioreq_server_info_t); > + > +#define HVMOP_map_io_range_to_ioreq_server 19 > +struct xen_hvm_map_io_range_to_ioreq_server { > + domid_t domid; /* IN - domain to be serviced */ > + ioservid_t id; /* IN - handle from > HVMOP_register_ioreq_server */ > + int is_mmio; /* IN - MMIO or port IO? */ > + uint64_aligned_t start, end; /* IN - inclusive start and end of range > */ > +}; > +typedef struct xen_hvm_map_io_range_to_ioreq_server > xen_hvm_map_io_range_to_ioreq_server_t; > +DEFINE_XEN_GUEST_HANDLE(xen_hvm_map_io_range_to_ioreq_server_t); > + > +#define HVMOP_unmap_io_range_from_ioreq_server 20 > +struct xen_hvm_unmap_io_range_from_ioreq_server { > + domid_t domid; /* IN - domain to be serviced */ > + ioservid_t id; /* IN - handle from HVMOP_register_ioreq_server > */ > + uint8_t is_mmio; /* IN - MMIO or port IO? */ > + uint64_aligned_t start; /* IN - start address of the range to remove */ > +}; > +typedef struct xen_hvm_unmap_io_range_from_ioreq_server > xen_hvm_unmap_io_range_from_ioreq_server_t; > +DEFINE_XEN_GUEST_HANDLE(xen_hvm_unmap_io_range_from_ioreq_server_t); > + > +#define HVMOP_map_pcidev_to_ioreq_server 21 > +struct xen_hvm_map_pcidev_to_ioreq_server { > + domid_t domid; /* IN - domain to be serviced */ > + ioservid_t id; /* IN - handle from HVMOP_register_ioreq_server */ > + uint16_t bdf; /* IN - PCI bus/dev/func */ > +}; > +typedef struct xen_hvm_map_pcidev_to_ioreq_server > xen_hvm_map_pcidev_to_ioreq_server_t; > +DEFINE_XEN_GUEST_HANDLE(xen_hvm_map_pcidev_to_ioreq_server_t); > + > +#define HVMOP_unmap_pcidev_from_ioreq_server 22 > +struct xen_hvm_unmap_pcidev_from_ioreq_server { > + domid_t domid; /* IN - domain to be serviced */ > + ioservid_t id; /* IN - handle from HVMOP_register_ioreq_server */ > + uint16_t bdf; /* IN - PCI bus/dev/func */ > +}; > +typedef struct xen_hvm_unmap_pcidev_from_ioreq_server > xen_hvm_unmap_pcidev_from_ioreq_server_t; > +DEFINE_XEN_GUEST_HANDLE(xen_hvm_unmap_pcidev_from_ioreq_server_t); > + > +#define HVMOP_destroy_ioreq_server 23 > +struct xen_hvm_destroy_ioreq_server { > + domid_t domid; /* IN - domain to be serviced */ > + ioservid_t id; /* IN - server id */ > +}; > +typedef struct xen_hvm_destroy_ioreq_server xen_hvm_destroy_ioreq_server_t; > +DEFINE_XEN_GUEST_HANDLE(xen_hvm_destroy_ioreq_server_t); > + > #endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */ > > #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */ > diff --git a/xen/include/public/hvm/ioreq.h b/xen/include/public/hvm/ioreq.h > index f05d130..e84fa75 100644 > --- a/xen/include/public/hvm/ioreq.h > +++ b/xen/include/public/hvm/ioreq.h > @@ -34,6 +34,7 @@ > > #define IOREQ_TYPE_PIO 0 /* pio */ > #define IOREQ_TYPE_COPY 1 /* mmio ops */ > +#define IOREQ_TYPE_PCI_CONFIG 2 /* pci config ops */ > #define IOREQ_TYPE_TIMEOFFSET 7 > #define IOREQ_TYPE_INVALIDATE 8 /* mapcache */ > > diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h > index 517a184..4109b11 100644 > --- a/xen/include/public/hvm/params.h > +++ b/xen/include/public/hvm/params.h > @@ -145,6 +145,8 @@ > /* SHUTDOWN_* action in case of a triple fault */ > #define HVM_PARAM_TRIPLE_FAULT_REASON 31 > > -#define HVM_NR_PARAMS 32 > +#define HVM_PARAM_NR_IOREQ_SERVERS 32 > + > +#define HVM_NR_PARAMS 33 > > #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */ _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |