#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;
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
* ===============
--- /dev/null
+/*
+ * 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:
+ */