|
[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 |