From: Ian Campbell Date: Fri, 29 Jan 2016 13:11:51 +0000 (+0000) Subject: libxendevicemodel: add ioreq server interfaces X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=17ee78b5317c6e19b162a9d0cfc32938d44b2ffd;p=people%2Fliuw%2Flibxenctrl-split%2Fxen.git libxendevicemodel: add ioreq server interfaces These are taken wholesale pretty much directly from the libxc versions. Those libxc ones will be deleted later in the series in order to make the transition simpler for QEMU upstream. Changes compared with libxc are: - All functions take a xendevicemodel_handle instead of an xc_interface+domid, and are named xendevicemodel_* not xc_hvm_*. - ioservid_t becomes uint16_t (since hvm_op.h is not exposed to users of this library) - ioserv's which handle buffered ioreq must always use the ATOMIC variant, LEGACY is not exposed (since anything being ported to this library should be adjusted to be atomic at the same time) - a few integer params which were actually booleans converted to bool. - Internally use xencall_alloc_buffer directly. - All always log on failure. XXX underlying hypercall is not stable. Note this with the version of @@UNSTABLE. Also in order to build need to define __XEN_TOOLS__, use a separate source file to avoid accidentally poluting the stable bits of the library. TBD replace hypercall with a stable variant and move to ioreq.c + version as @@1.0 Signed-off-by: Ian Campbell Cc: Paul Durrant --- diff --git a/tools/libs/devicemodel/Makefile b/tools/libs/devicemodel/Makefile index 4293bc06c4..49599990f2 100644 --- a/tools/libs/devicemodel/Makefile +++ b/tools/libs/devicemodel/Makefile @@ -15,6 +15,7 @@ LDLIBS += $(LDLIBS_libxencall) SRCS-y += core.c SRCS-y += emuirq.c emuirq_unstable.c +SRCS-y += ioreqserv_unstable.c LIB_OBJS := $(patsubst %.c,%.o,$(SRCS-y)) PIC_OBJS := $(patsubst %.c,%.opic,$(SRCS-y)) @@ -26,6 +27,7 @@ endif # XXX These use unstable hypervisor interfaces emuirq_unstable.o emuirq_unstable.opic: CFLAGS += -D__XEN_TOOLS__ +ioreqserv_unstable.o ioreqserv_unstable.opic: CFLAGS += -D__XEN_TOOLS__ .PHONY: all all: build diff --git a/tools/libs/devicemodel/include/xendevicemodel.h b/tools/libs/devicemodel/include/xendevicemodel.h index c5626d3c2f..42058b752d 100644 --- a/tools/libs/devicemodel/include/xendevicemodel.h +++ b/tools/libs/devicemodel/include/xendevicemodel.h @@ -27,6 +27,7 @@ #include #include +#include /* Callers who don't care don't need to #include */ struct xentoollog_logger; @@ -143,6 +144,138 @@ int xendevicemodel_set_isa_irq_level(xendevicemodel_handle *dm, int xendevicemodel_inject_msi(xendevicemodel_handle *dm, uint64_t addr, uint32_t data); +/* + * IOREQ Servers + * ============= + * + * All functions log on failure. + */ + +/** + * This function instantiates an IOREQ Server. + * + * @dm a handle to an open xendevicemodel interface. + * @parm handle_bufioreq how should the IOREQ Server handle buffered requests + * If true then IOREQs must be handled atomically + * (i.e. as for HVM_IOREQSRV_BUFIOREQ_ATOMIC, not _LEGACY) + * @parm id pointer to an uint16_t to receive the IOREQ Server id. + * @return 0 on success, -1 on failure. + */ +int xendevicemodel_create_ioreq_server(xendevicemodel_handle *dm, + bool handle_bufioreq, + uint16_t *id); + +/** + * This function retrieves the necessary information to allow an + * emulator to use an IOREQ Server. + * + * @dm a handle to an open xendevicemodel interface. + * @parm id the IOREQ Server id. + * @parm ioreq_pfn pointer to a xen_pfn_t to receive the synchronous ioreq gmfn + * @parm bufioreq_pfn pointer to a xen_pfn_t to receive the buffered ioreq gmfn + * @parm bufioreq_port pointer to a evtchn_port_t to receive the buffered ioreq event channel + * @return 0 on success, -1 on failure. + */ +int xendevicemodel_get_ioreq_server_info(xendevicemodel_handle *dm, + uint16_t id, + xen_pfn_t *ioreq_pfn, + xen_pfn_t *bufioreq_pfn, + evtchn_port_t *bufioreq_port); + +/** + * This function sets IOREQ Server state. An IOREQ Server + * will not be passed emulation requests until it is in + * the enabled state. + * Note that the contents of the ioreq_pfn and bufioreq_pfn are + * not meaningful until the IOREQ Server is in the enabled state. + * + * @dm a handle to an open xendevicemodel interface. + * @parm id the IOREQ Server id. + * @parm enabled the state. + * @return 0 on success, -1 on failure. + */ +int xendevicemodel_set_ioreq_server_state(xendevicemodel_handle *dm, + uint16_t id, + bool enabled); + +/** + * This function registers a range of memory or I/O ports for emulation. + * + * @dm a handle to an open xendevicemodel interface. + * @parm id the IOREQ Server id. + * @parm is_mmio is this a range of ports or memory + * @parm start start of range + * @parm end end of range (inclusive). + * @return 0 on success, -1 on failure. + */ +int xendevicemodel_map_io_range_to_ioreq_server(xendevicemodel_handle *dm, + uint16_t id, + bool is_mmio, + uint64_t start, + uint64_t end); + +/** + * This function deregisters a range of memory or I/O ports for emulation. + * + * @dm a handle to an open xendevicemodel interface. + * @parm id the IOREQ Server id. + * @parm is_mmio is this a range of ports or memory + * @parm start start of range + * @parm end end of range (inclusive). + * @return 0 on success, -1 on failure. + */ +int xendevicemodel_unmap_io_range_from_ioreq_server(xendevicemodel_handle *dm, + uint16_t id, + bool is_mmio, + uint64_t start, + uint64_t end); + +/** + * This function registers a PCI device for config space emulation. + * + * @dm a handle to an open xendevicemodel interface. + * @parm id the IOREQ Server id. + * @parm segment the PCI segment of the device + * @parm bus the PCI bus of the device + * @parm device the 'slot' number of the device + * @parm function the function number of the device + * @return 0 on success, -1 on failure. + */ +int xendevicemodel_map_pcidev_to_ioreq_server(xendevicemodel_handle *dm, + uint16_t id, + uint16_t segment, + uint8_t bus, + uint8_t device, + uint8_t function); + +/** + * This function deregisters a PCI device for config space emulation. + * + * @dm a handle to an open xendevicemodel interface. + * @parm id the IOREQ Server id. + * @parm segment the PCI segment of the device + * @parm bus the PCI bus of the device + * @parm device the 'slot' number of the device + * @parm function the function number of the device + * @return 0 on success, -1 on failure. + */ +int xendevicemodel_unmap_pcidev_from_ioreq_server(xendevicemodel_handle *dm, + uint16_t id, + uint16_t segment, + uint8_t bus, + uint8_t device, + uint8_t function); + +/** + * This function destroys an IOREQ Server. + * + * @dm a handle to an open xendevicemodel interface. + * @parm id the IOREQ Server id. + * @return 0 on success, -1 on failure. + */ +int xendevicemodel_destroy_ioreq_server(xendevicemodel_handle *dm, + uint16_t id); + /* * Memory handling * =============== diff --git a/tools/libs/devicemodel/ioreqserv_unstable.c b/tools/libs/devicemodel/ioreqserv_unstable.c new file mode 100644 index 0000000000..187370cb72 --- /dev/null +++ b/tools/libs/devicemodel/ioreqserv_unstable.c @@ -0,0 +1,328 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see . + */ + +#include +#include +#include + +#include "private.h" + + +int xendevicemodel_create_ioreq_server(xendevicemodel_handle *dm, + bool handle_bufioreq, + uint16_t *id) +{ + xen_hvm_create_ioreq_server_t *arg; + int rc; + + arg = xencall_alloc_buffer(dm->call, sizeof(*arg)); + if ( arg == NULL ) + { + LOGE(ERROR, + "unable to allocate memory for create ioreqserv hypercall"); + return -1; + } + + arg->domid = dm->domid; + arg->handle_bufioreq = handle_bufioreq ? + HVM_IOREQSRV_BUFIOREQ_ATOMIC : + HVM_IOREQSRV_BUFIOREQ_OFF; + + rc = xencall2(dm->call, __HYPERVISOR_hvm_op, + HVMOP_create_ioreq_server, + (uintptr_t)arg); + + if ( rc ) + LOGE(ERROR, "create ioreqserv hypercall failed"); + + *id = arg->id; + + xencall_free_buffer(dm->call, arg); + return rc; +} + +int xendevicemodel_get_ioreq_server_info(xendevicemodel_handle *dm, + uint16_t id, + xen_pfn_t *ioreq_pfn, + xen_pfn_t *bufioreq_pfn, + evtchn_port_t *bufioreq_port) +{ + xen_hvm_get_ioreq_server_info_t *arg; + int rc; + + arg = xencall_alloc_buffer(dm->call, sizeof(*arg)); + if ( arg == NULL ) + { + LOGE(ERROR, + "unable to allocate memory for get ioreqserv info hypercall"); + return -1; + } + + + arg->domid = dm->domid; + arg->id = id; + + rc = xencall2(dm->call, __HYPERVISOR_hvm_op, + HVMOP_get_ioreq_server_info, + (uintptr_t)arg); + if ( rc != 0 ) + { + LOGE(ERROR, "create ioreqserv hypercall failed"); + goto done; + } + + if ( ioreq_pfn ) + *ioreq_pfn = arg->ioreq_pfn; + + if ( bufioreq_pfn ) + *bufioreq_pfn = arg->bufioreq_pfn; + + if ( bufioreq_port ) + *bufioreq_port = arg->bufioreq_port; + +done: + xencall_free_buffer(dm->call, arg); + return rc; +} + +int xendevicemodel_map_io_range_to_ioreq_server(xendevicemodel_handle *dm, + uint16_t id, + bool is_mmio, + uint64_t start, + uint64_t end) +{ + xen_hvm_io_range_t *arg; + int rc; + + arg = xencall_alloc_buffer(dm->call, sizeof(*arg)); + if ( arg == NULL ) + { + LOGE(ERROR, + "unable to allocate memory for map io range to ioreqserv hypercall"); + return -1; + } + + + arg->domid = dm->domid; + arg->id = id; + arg->type = is_mmio ? HVMOP_IO_RANGE_MEMORY : HVMOP_IO_RANGE_PORT; + arg->start = start; + arg->end = end; + + rc = xencall2(dm->call, __HYPERVISOR_hvm_op, + HVMOP_map_io_range_to_ioreq_server, + (uintptr_t)arg); + + if ( rc ) + LOGE(ERROR, "map io range to ioreqserv hypercall failed"); + + xencall_free_buffer(dm->call, arg); + return rc; +} + +int xendevicemodel_unmap_io_range_from_ioreq_server(xendevicemodel_handle *dm, + uint16_t id, + bool is_mmio, + uint64_t start, + uint64_t end) +{ + xen_hvm_io_range_t *arg; + int rc; + + arg = xencall_alloc_buffer(dm->call, sizeof(*arg)); + if ( arg == NULL ) + { + LOGE(ERROR, + "unable to allocate memory for umap io range from ioreq hypercall"); + return -1; + } + + + arg->domid = dm->domid; + arg->id = id; + arg->type = is_mmio ? HVMOP_IO_RANGE_MEMORY : HVMOP_IO_RANGE_PORT; + arg->start = start; + arg->end = end; + + rc = xencall2(dm->call, __HYPERVISOR_hvm_op, + HVMOP_unmap_io_range_from_ioreq_server, + (uintptr_t)arg); + + if ( rc ) + LOGE(ERROR, "unmap io range from ioreqserv hypercall failed"); + + xencall_free_buffer(dm->call, arg); + return rc; +} + +int xendevicemodel_map_pcidev_to_ioreq_server(xendevicemodel_handle *dm, + uint16_t id, + uint16_t segment, + uint8_t bus, + uint8_t device, + uint8_t function) +{ + xen_hvm_io_range_t *arg; + int rc; + + if (device > 0x1f || function > 0x7) { + errno = EINVAL; + return -1; + } + + arg = xencall_alloc_buffer(dm->call, sizeof(*arg)); + if ( arg == NULL ) + { + LOGE(ERROR, + "unable to allocate memory for map pcidev to ioreqserv hypercall"); + return -1; + } + + + arg->domid = dm->domid; + arg->id = id; + arg->type = HVMOP_IO_RANGE_PCI; + + /* + * The underlying hypercall will deal with ranges of PCI SBDF + * but, for simplicity, the API only uses singletons. + */ + arg->start = arg->end = HVMOP_PCI_SBDF((uint64_t)segment, + (uint64_t)bus, + (uint64_t)device, + (uint64_t)function); + + rc = xencall2(dm->call, __HYPERVISOR_hvm_op, + HVMOP_map_io_range_to_ioreq_server, + (uintptr_t)arg); + + if ( rc ) + LOGE(ERROR, "map pcidev to ioreqserv hypercall failed"); + + xencall_free_buffer(dm->call, arg); + return rc; +} + +int xendevicemodel_unmap_pcidev_from_ioreq_server(xendevicemodel_handle *dm, + uint16_t id, + uint16_t segment, + uint8_t bus, + uint8_t device, + uint8_t function) +{ + xen_hvm_io_range_t *arg; + int rc; + + if (device > 0x1f || function > 0x7) { + errno = EINVAL; + return -1; + } + + arg = xencall_alloc_buffer(dm->call, sizeof(*arg)); + if ( arg == NULL ) + { + LOGE(ERROR, + "unable to allocate memory for unmap pcidev from ioreqserv hypercall"); + return -1; + } + + + arg->domid = dm->domid; + arg->id = id; + arg->type = HVMOP_IO_RANGE_PCI; + arg->start = arg->end = HVMOP_PCI_SBDF((uint64_t)segment, + (uint64_t)bus, + (uint64_t)device, + (uint64_t)function); + + rc = xencall2(dm->call, __HYPERVISOR_hvm_op, + HVMOP_unmap_io_range_from_ioreq_server, + (uintptr_t)arg); + + if ( rc ) + LOGE(ERROR, "unmap pcidev from ioreqserv hypercall failed"); + + xencall_free_buffer(dm->call, arg); + return rc; +} + +int xendevicemodel_destroy_ioreq_server(xendevicemodel_handle *dm, + uint16_t id) +{ + xen_hvm_destroy_ioreq_server_t *arg; + int rc; + + arg = xencall_alloc_buffer(dm->call, sizeof(*arg)); + if ( arg == NULL ) + { + LOGE(ERROR, + "unable to allocate memory for destroy ioreqserv hypercall"); + return -1; + } + + + arg->domid = dm->domid; + arg->id = id; + + rc = xencall2(dm->call, __HYPERVISOR_hvm_op, + HVMOP_destroy_ioreq_server, + (uintptr_t)arg); + + if ( rc ) + LOGE(ERROR, "destroy ioreqserv hypercall failed"); + + xencall_free_buffer(dm->call, arg); + return rc; +} + +int xendevicemodel_set_ioreq_server_state(xendevicemodel_handle *dm, + uint16_t id, + bool enabled) +{ + xen_hvm_set_ioreq_server_state_t *arg; + int rc; + + arg = xencall_alloc_buffer(dm->call, sizeof(*arg)); + if ( arg == NULL ) + { + LOGE(ERROR, + "unable to allocate memory for set ioreqserv state hypercall"); + return -1; + } + + arg->domid = dm->domid; + arg->id = id; + arg->enabled = !!enabled; + + rc = xencall2(dm->call, __HYPERVISOR_hvm_op, + HVMOP_set_ioreq_server_state, + (uintptr_t)arg); + + if ( rc ) + LOGE(ERROR, "set ioreqserv state hypercall failed"); + + xencall_free_buffer(dm->call, arg); + return rc; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/tools/libs/devicemodel/libxendevicemodel.map b/tools/libs/devicemodel/libxendevicemodel.map index 366363cabb..f544eadbad 100644 --- a/tools/libs/devicemodel/libxendevicemodel.map +++ b/tools/libs/devicemodel/libxendevicemodel.map @@ -1,6 +1,15 @@ /* While this section exists this library is not stable */ UNSTABLE { global: + xendevicemodel_create_ioreq_server; + xendevicemodel_get_ioreq_server_info; + xendevicemodel_set_ioreq_server_state; + xendevicemodel_map_io_range_to_ioreq_server; + xendevicemodel_unmap_io_range_from_ioreq_server; + xendevicemodel_map_pcidev_to_ioreq_server; + xendevicemodel_unmap_pcidev_from_ioreq_server; + xendevicemodel_destroy_ioreq_server; + xendevicemodel_inject_msi; };