]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/xen.git/commitdiff
libxendevicemodel: add ioreq server interfaces
authorIan Campbell <ian.campbell@citrix.com>
Fri, 29 Jan 2016 13:11:51 +0000 (13:11 +0000)
committerIan Campbell <ian.campbell@citrix.com>
Wed, 10 Feb 2016 17:09:53 +0000 (17:09 +0000)
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 <ian.campbell@citrix.com>
Cc: Paul Durrant <paul.durrant@citrix.com>
tools/libs/devicemodel/Makefile
tools/libs/devicemodel/include/xendevicemodel.h
tools/libs/devicemodel/ioreqserv_unstable.c [new file with mode: 0644]
tools/libs/devicemodel/libxendevicemodel.map

index 4293bc06c49d04d8d74051c1b73878aa3658dd22..49599990f2adcf9299c8ddac90a2ba3fd7946622 100644 (file)
@@ -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
index c5626d3c2f49f36fee75042be7e8bcdad2a8bf8b..42058b752d31259d42811ab120dca626a9c0536b 100644 (file)
@@ -27,6 +27,7 @@
 #include <stdbool.h>
 
 #include <xen/xen.h>
+#include <xen/event_channel.h>
 
 /* Callers who don't care don't need to #include <xentoollog.h> */
 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 (file)
index 0000000..187370c
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+
+#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:
+ */
index 366363cabbffde6cb85cbf592cbbc659ecd20d12..f544eadbada2b3379f31aaf18702e81dcbb730d4 100644 (file)
@@ -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;
 };