|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v5 09/11] x86/dmop: Add XEN_DMOP_{,un}bind_pt_msi_irq
Add two device-model ops that bind / unbind a passthrough interrupt to a
guest MSI from the raw MSI message (address + data) the guest
programmed. Xen decodes the message itself via pt_irq_bind_msi(), so the
emulator needs no knowledge of the MSI layout and, in particular,
extended (15-bit) destination IDs are handled without emulator changes.
The MSI-X table base is passed as a guest-physical address. Fields are
named msg_addr / msg_data / pirq, and the flag is
XEN_DMOP_MSI_BIND_UNMASKED. The unbind op only requires a valid pirq
mapping, not current IRQ permission, so an emulator can remove a binding
even after the device has been deassigned.
With this in place, PT_IRQ_TYPE_MSI is removed from
XEN_DOMCTL_{,un}bind_pt_irq (returns -EINVAL) and from
pt_irq_create_bind(). libxc's xc_domain_{update,unbind}_msi_irq() and
vPCI already funnel through pt_irq_bind_msi(). This is an incompatible
change for device models still using the domctl sub-case (noted in
CHANGELOG.md and public/domctl.h).
libxendevicemodel gains xendevicemodel_{,un}bind_pt_msi_irq() (map
version VERS_1.5).
Signed-off-by: Julian Vetter <julian.vetter@xxxxxxxxxx>
---
Changes in v5:
- Retitled to "{,un}bind_pt_msi_irq".
- Struct/flag renamed: pirq (was machine_irq), msg_addr / msg_data (was
addr / data), XEN_DMOP_MSI_BIND_UNMASKED (was
XEN_DMOP_MSI_FLAG_UNMASKED).
- Documented gtable as a guest-physical address.
- Diagnostics shortened to "%pd: fn() failed: %ld".
- The unbind op drops the current-domain IRQ-permission check, so an
emulator can unbind after the device has been deassigned.
- Comment added noting access is gated by xsm_dm_op().
- This patch now also removes PT_IRQ_TYPE_MSI: a hard -EINVAL from
XEN_DOMCTL_{,un}bind_pt_irq (not -EOPNOTSUPP) and deletion of the
now-dead case from pt_irq_create_bind()
- Incompatible changes are recorded in CHANGELOG.md and public/domctl.h.
- Added the missing libxendevicemodel.map VERS_1.5 entry and Makefile
MINOR bump. v4 never exported the new symbols.
- Stale XEN_DMOP_enable_ext_dest_id #define and a stray blank line
before a typedef removed.
Signed-off-by: Julian Vetter <julian.vetter@xxxxxxxxxx>
---
CHANGELOG.md | 6 ++
tools/include/xendevicemodel.h | 30 +++++++++
tools/libs/ctrl/xc_domain.c | 51 +++++++--------
tools/libs/devicemodel/Makefile | 2 +-
tools/libs/devicemodel/core.c | 38 +++++++++++
tools/libs/devicemodel/libxendevicemodel.map | 6 ++
xen/arch/x86/domctl.c | 11 +++-
xen/arch/x86/hvm/dm.c | 66 ++++++++++++++++++++
xen/drivers/passthrough/x86/hvm.c | 35 +----------
xen/include/public/hvm/dm_op.h | 38 +++++++++++
xen/include/xlat.lst | 2 +
11 files changed, 221 insertions(+), 64 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aa1a777dd4..76f5d06c91 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -34,6 +34,9 @@ The format is based on [Keep a
Changelog](https://keepachangelog.com/en/1.0.0/)
- On x86:
- Enable pf-fixup option by default for PVH dom0.
- The libxenguest bzImage loader now uses the system liblz4 library.
+ - XEN_DOMCTL_{,un}bind_pt_irq no longer accept PT_IRQ_TYPE_MSI, device
+ models must bind passthrough MSIs via the new
+ XEN_DMOP_{,un}bind_pt_msi_irq, which carry the raw MSI message.
### Added
- Support for per-domain Xenstore quota in C xenstored (includes
@@ -47,6 +50,9 @@ The format is based on [Keep a
Changelog](https://keepachangelog.com/en/1.0.0/)
- Support for CPIO microcode in discrete multiboot modules.
- Introduce get-core-temp command to xenpm to query CPU temperatures on
Intel platforms.
+ - XEN_DMOP_{,un}bind_pt_msi_irq for binding passthrough MSIs from the raw
+ guest MSI message, enabling extended (15-bit) destination IDs for HVM
+ guests whose device models opt in.
- On Arm:
- Support for guest suspend and resume to/from RAM via vPSCI.
diff --git a/tools/include/xendevicemodel.h b/tools/include/xendevicemodel.h
index 227e7fd810..698d719119 100644
--- a/tools/include/xendevicemodel.h
+++ b/tools/include/xendevicemodel.h
@@ -375,6 +375,36 @@ int xendevicemodel_nr_vcpus(
*/
int xendevicemodel_restrict(xendevicemodel_handle *dmod, domid_t domid);
+/**
+ * This function binds a passthrough interrupt to a guest MSI, described by the
+ * raw MSI message (address and data) the guest programmed. Xen decodes the
+ * message itself, so the caller does not need to interpret it.
+ *
+ * @parm dmod a handle to an open devicemodel interface.
+ * @parm domid the domain id to be serviced.
+ * @parm pirq the pass-through IRQ (pirq).
+ * @parm msg_addr the MSI message address, as programmed by the guest.
+ * @parm msg_data the MSI message data, as programmed by the guest.
+ * @parm gtable the MSI-X table base guest-physical address, or 0 for plain
MSI.
+ * @parm unmasked if non-zero, leave the IRQ unmasked after binding.
+ * @return 0 on success, -1 on failure.
+ */
+int xendevicemodel_bind_pt_msi_irq(
+ xendevicemodel_handle *dmod, domid_t domid, uint32_t pirq,
+ uint64_t msg_addr, uint32_t msg_data, uint64_t gtable, int unmasked);
+
+/**
+ * This function unbinds a passthrough interrupt previously bound with
+ * xendevicemodel_bind_pt_msi_irq.
+ *
+ * @parm dmod a handle to an open devicemodel interface.
+ * @parm domid the domain id to be serviced.
+ * @parm pirq the pass-through IRQ (pirq).
+ * @return 0 on success, -1 on failure.
+ */
+int xendevicemodel_unbind_pt_msi_irq(
+ xendevicemodel_handle *dmod, domid_t domid, uint32_t pirq);
+
#endif /* XENDEVICEMODEL_H */
/*
diff --git a/tools/libs/ctrl/xc_domain.c b/tools/libs/ctrl/xc_domain.c
index 94cfab0fa1..b4eed42f97 100644
--- a/tools/libs/ctrl/xc_domain.c
+++ b/tools/libs/ctrl/xc_domain.c
@@ -1677,6 +1677,21 @@ int xc_deassign_dt_device(
+static void xc_msi_gflags_to_addr_data(uint32_t gvec, uint32_t gflags,
+ uint64_t *msi_addr, uint32_t *msi_data)
+{
+ *msi_addr = 0xfee00000U |
+ ((uint64_t)((gflags & XEN_DOMCTL_VMSI_X86_DEST_ID_MASK) << 12)) |
+ (gflags & XEN_DOMCTL_VMSI_X86_RH_MASK ? (1U << 3) : 0) |
+ (gflags & XEN_DOMCTL_VMSI_X86_DM_MASK ? (1U << 2) : 0);
+
+ *msi_data = (gvec & 0xff) |
+ (uint32_t)(((gflags & XEN_DOMCTL_VMSI_X86_DELIV_MASK) >>
+ (/* shift of XEN_DOMCTL_VMSI_X86_DELIV_MASK */ 12 -
+ /* MSI data delivery shift */ 8))) |
+ (gflags & XEN_DOMCTL_VMSI_X86_TRIG_MASK ? (1U << 15) : 0);
+}
+
int xc_domain_update_msi_irq(
xc_interface *xch,
uint32_t domid,
@@ -1685,22 +1700,14 @@ int xc_domain_update_msi_irq(
uint32_t gflags,
uint64_t gtable)
{
- int rc;
- struct xen_domctl_bind_pt_irq *bind;
- struct xen_domctl domctl = {};
-
- domctl.cmd = XEN_DOMCTL_bind_pt_irq;
- domctl.domain = domid;
+ uint64_t msi_addr;
+ uint32_t msi_data;
- bind = &(domctl.u.bind_pt_irq);
- bind->irq_type = PT_IRQ_TYPE_MSI;
- bind->machine_irq = pirq;
- bind->u.msi.gvec = gvec;
- bind->u.msi.gflags = gflags;
- bind->u.msi.gtable = gtable;
+ xc_msi_gflags_to_addr_data(gvec, gflags, &msi_addr, &msi_data);
- rc = do_domctl(xch, &domctl);
- return rc;
+ return xendevicemodel_bind_pt_msi_irq(xch->dmod, domid, pirq,
+ msi_addr, msi_data, gtable,
+ gflags &
XEN_DOMCTL_VMSI_X86_UNMASKED);
}
int xc_domain_unbind_msi_irq(
@@ -1710,21 +1717,7 @@ int xc_domain_unbind_msi_irq(
uint32_t pirq,
uint32_t gflags)
{
- int rc;
- struct xen_domctl_bind_pt_irq *bind;
- struct xen_domctl domctl = {};
-
- domctl.cmd = XEN_DOMCTL_unbind_pt_irq;
- domctl.domain = domid;
-
- bind = &(domctl.u.bind_pt_irq);
- bind->irq_type = PT_IRQ_TYPE_MSI;
- bind->machine_irq = pirq;
- bind->u.msi.gvec = gvec;
- bind->u.msi.gflags = gflags;
-
- rc = do_domctl(xch, &domctl);
- return rc;
+ return xendevicemodel_unbind_pt_msi_irq(xch->dmod, domid, pirq);
}
/* Pass-through: binds machine irq to guests irq */
diff --git a/tools/libs/devicemodel/Makefile b/tools/libs/devicemodel/Makefile
index 20d1d112e7..270bb6c89f 100644
--- a/tools/libs/devicemodel/Makefile
+++ b/tools/libs/devicemodel/Makefile
@@ -2,7 +2,7 @@ XEN_ROOT = $(CURDIR)/../../..
include $(XEN_ROOT)/tools/Rules.mk
MAJOR = 1
-MINOR = 4
+MINOR = 5
version-script := libxendevicemodel.map
include Makefile.common
diff --git a/tools/libs/devicemodel/core.c b/tools/libs/devicemodel/core.c
index 8e619eeb0a..274a8eb28b 100644
--- a/tools/libs/devicemodel/core.c
+++ b/tools/libs/devicemodel/core.c
@@ -645,6 +645,44 @@ int xendevicemodel_nr_vcpus(
return 0;
}
+int xendevicemodel_bind_pt_msi_irq(
+ xendevicemodel_handle *dmod, domid_t domid, uint32_t pirq,
+ uint64_t msg_addr, uint32_t msg_data, uint64_t gtable, int unmasked)
+{
+ struct xen_dm_op op;
+ struct xen_dm_op_bind_pt_msi_irq *data;
+
+ memset(&op, 0, sizeof(op));
+
+ op.op = XEN_DMOP_bind_pt_msi_irq;
+ data = &op.u.bind_pt_msi_irq;
+
+ data->pirq = pirq;
+ data->msg_data = msg_data;
+ data->msg_addr = msg_addr;
+ data->gtable = gtable;
+ if ( unmasked )
+ data->flags |= XEN_DMOP_MSI_BIND_UNMASKED;
+
+ return xendevicemodel_op(dmod, domid, 1, &op, sizeof(op));
+}
+
+int xendevicemodel_unbind_pt_msi_irq(
+ xendevicemodel_handle *dmod, domid_t domid, uint32_t pirq)
+{
+ struct xen_dm_op op;
+ struct xen_dm_op_unbind_pt_msi_irq *data;
+
+ memset(&op, 0, sizeof(op));
+
+ op.op = XEN_DMOP_unbind_pt_msi_irq;
+ data = &op.u.unbind_pt_msi_irq;
+
+ data->pirq = pirq;
+
+ return xendevicemodel_op(dmod, domid, 1, &op, sizeof(op));
+}
+
int xendevicemodel_restrict(xendevicemodel_handle *dmod, domid_t domid)
{
return osdep_xendevicemodel_restrict(dmod, domid);
diff --git a/tools/libs/devicemodel/libxendevicemodel.map
b/tools/libs/devicemodel/libxendevicemodel.map
index f7f9e3d932..c34b66004e 100644
--- a/tools/libs/devicemodel/libxendevicemodel.map
+++ b/tools/libs/devicemodel/libxendevicemodel.map
@@ -44,3 +44,9 @@ VERS_1.4 {
xendevicemodel_set_irq_level;
xendevicemodel_nr_vcpus;
} VERS_1.3;
+
+VERS_1.5 {
+ global:
+ xendevicemodel_bind_pt_msi_irq;
+ xendevicemodel_unbind_pt_msi_irq;
+} VERS_1.4;
diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index 51d62617bb..9846df4f88 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -622,6 +622,15 @@ long arch_do_domctl(
if ( !is_hvm_domain(d) )
break;
+ /*
+ * PT_IRQ_TYPE_MSI is no longer supported here: it can only convey an
+ * 8-bit destination ID. Emulators must use XEN_DMOP_bind_pt_msi_irq,
+ * which passes the raw MSI message so Xen can decode it (extended
+ * destination IDs included).
+ */
+ if ( bind->irq_type == PT_IRQ_TYPE_MSI )
+ break;
+
ret = xsm_bind_pt_irq(XSM_DM_PRIV, d, bind);
if ( ret )
break;
@@ -657,7 +666,7 @@ long arch_do_domctl(
int irq = domain_pirq_to_irq(d, bind->machine_irq);
ret = -EINVAL;
- if ( !is_hvm_domain(d) )
+ if ( !is_hvm_domain(d) || bind->irq_type == PT_IRQ_TYPE_MSI )
break;
ret = xsm_unbind_pt_irq(XSM_DM_PRIV, d, bind);
diff --git a/xen/arch/x86/hvm/dm.c b/xen/arch/x86/hvm/dm.c
index 91f6ca669b..9a6347e873 100644
--- a/xen/arch/x86/hvm/dm.c
+++ b/xen/arch/x86/hvm/dm.c
@@ -7,6 +7,8 @@
#include <xen/guest_access.h>
#include <xen/dm.h>
#include <xen/hypercall.h>
+#include <xen/iocap.h>
+#include <xen/iommu.h>
#include <xen/ioreq.h>
#include <xen/nospec.h>
#include <xen/sched.h>
@@ -350,6 +352,8 @@ int dm_op(const struct dmop_args *op_args)
[XEN_DMOP_relocate_memory] = sizeof(struct
xen_dm_op_relocate_memory),
[XEN_DMOP_pin_memory_cacheattr] = sizeof(struct
xen_dm_op_pin_memory_cacheattr),
[XEN_DMOP_nr_vcpus] = sizeof(struct
xen_dm_op_nr_vcpus),
+ [XEN_DMOP_bind_pt_msi_irq] = sizeof(struct
xen_dm_op_bind_pt_msi_irq),
+ [XEN_DMOP_unbind_pt_msi_irq] = sizeof(struct
xen_dm_op_unbind_pt_msi_irq),
};
rc = rcu_lock_remote_domain_by_id(op_args->domid, &d);
@@ -617,6 +621,66 @@ int dm_op(const struct dmop_args *op_args)
break;
}
+ case XEN_DMOP_bind_pt_msi_irq:
+ {
+ const struct xen_dm_op_bind_pt_msi_irq *data = &op.u.bind_pt_msi_irq;
+ int irq = domain_pirq_to_irq(d, data->pirq);
+
+ rc = -EINVAL;
+ if ( data->pad || (data->flags & ~XEN_DMOP_MSI_BIND_UNMASKED) )
+ break;
+
+ /* Access is otherwise gated by xsm_dm_op() at the top of dm_op(). */
+ rc = -EPERM;
+ if ( irq <= 0 || !irq_access_permitted(current->domain, irq) )
+ break;
+
+ rc = -ESRCH;
+ if ( is_iommu_enabled(d) )
+ {
+ read_lock(&d->pci_lock);
+ rc = pt_irq_bind_msi(d, data->pirq, data->msg_addr, data->msg_data,
+ data->gtable,
+ data->flags & XEN_DMOP_MSI_BIND_UNMASKED);
+ read_unlock(&d->pci_lock);
+ }
+ if ( rc < 0 )
+ printk(XENLOG_G_ERR "%pd: pt_irq_bind_msi() failed: %ld\n", d, rc);
+ break;
+ }
+
+ case XEN_DMOP_unbind_pt_msi_irq:
+ {
+ const struct xen_dm_op_unbind_pt_msi_irq *data =
+ &op.u.unbind_pt_msi_irq;
+ struct xen_domctl_bind_pt_irq bind = {
+ .machine_irq = data->pirq,
+ .irq_type = PT_IRQ_TYPE_MSI,
+ };
+ int irq = domain_pirq_to_irq(d, data->pirq);
+
+ /*
+ * Only require a valid pirq mapping, not current permission over it:
+ * the emulator must be able to tear the binding down even after the
+ * device (and its IRQ) has been deassigned.
+ */
+ rc = -EPERM;
+ if ( irq <= 0 )
+ break;
+
+ rc = -ESRCH;
+ if ( is_iommu_enabled(d) )
+ {
+ read_lock(&d->pci_lock);
+ rc = pt_irq_destroy_bind(d, &bind);
+ read_unlock(&d->pci_lock);
+ }
+ if ( rc < 0 )
+ printk(XENLOG_G_ERR "%pd: pt_irq_destroy_bind() failed: %ld\n",
+ d, rc);
+ break;
+ }
+
default:
rc = ioreq_server_dm_op(&op, d, &const_op);
break;
@@ -653,6 +717,8 @@ CHECK_dm_op_remote_shutdown;
CHECK_dm_op_relocate_memory;
CHECK_dm_op_pin_memory_cacheattr;
CHECK_dm_op_nr_vcpus;
+CHECK_dm_op_bind_pt_msi_irq;
+CHECK_dm_op_unbind_pt_msi_irq;
int compat_dm_op(
domid_t domid, unsigned int nr_bufs, XEN_GUEST_HANDLE_PARAM(void) bufs)
diff --git a/xen/drivers/passthrough/x86/hvm.c
b/xen/drivers/passthrough/x86/hvm.c
index a13dd86610..c5d74fcebf 100644
--- a/xen/drivers/passthrough/x86/hvm.c
+++ b/xen/drivers/passthrough/x86/hvm.c
@@ -449,37 +449,6 @@ int pt_irq_create_bind(
switch ( pt_irq_bind->irq_type )
{
- case PT_IRQ_TYPE_MSI:
- {
- unsigned int gflags = pt_irq_bind->u.msi.gflags;
- uint64_t msi_addr;
- uint32_t msi_data;
-
- /*
- * Rebuild a raw MSI message from the pre-decoded domctl gflags so the
- * canonical bind path can decode it uniformly. This legacy path never
- * carries extended destination ID bits.
- */
- msi_addr = MSI_ADDR_HEADER |
- MASK_INSR(MASK_EXTR(gflags,
XEN_DOMCTL_VMSI_X86_DEST_ID_MASK),
- MSI_ADDR_DEST_ID_MASK) |
- (gflags & XEN_DOMCTL_VMSI_X86_RH_MASK
- ? MSI_ADDR_REDIRECTION_LOWPRI
- : MSI_ADDR_REDIRECTION_CPU) |
- (gflags & XEN_DOMCTL_VMSI_X86_DM_MASK
- ? MSI_ADDR_DESTMODE_LOGIC
- : MSI_ADDR_DESTMODE_PHYS);
- msi_data = MASK_INSR(pt_irq_bind->u.msi.gvec, MSI_DATA_VECTOR_MASK) |
- MASK_INSR(MASK_EXTR(gflags, XEN_DOMCTL_VMSI_X86_DELIV_MASK),
- MSI_DATA_DELIVERY_MODE_MASK) |
- (gflags & XEN_DOMCTL_VMSI_X86_TRIG_MASK
- ? MSI_DATA_TRIGGER_LEVEL : 0);
-
- return pt_irq_bind_msi(d, pt_irq_bind->machine_irq, msi_addr, msi_data,
- pt_irq_bind->u.msi.gtable,
- gflags & XEN_DOMCTL_VMSI_X86_UNMASKED);
- }
-
case PT_IRQ_TYPE_PCI:
case PT_IRQ_TYPE_MSI_TRANSLATE:
{
@@ -767,8 +736,8 @@ int pt_irq_destroy_bind(
msixtbl_pt_unregister(d, pirq);
pirq_dpci->flags = 0;
/*
- * See comment in pt_irq_create_bind's PT_IRQ_TYPE_MSI before the
- * call to pt_pirq_softirq_reset.
+ * See the comment in pt_irq_bind_msi() before its call to
+ * pt_pirq_softirq_reset.
*/
pt_pirq_softirq_reset(pirq_dpci);
diff --git a/xen/include/public/hvm/dm_op.h b/xen/include/public/hvm/dm_op.h
index 2bf0fdc1ae..d76777f71f 100644
--- a/xen/include/public/hvm/dm_op.h
+++ b/xen/include/public/hvm/dm_op.h
@@ -444,6 +444,42 @@ struct xen_dm_op_nr_vcpus {
};
typedef struct xen_dm_op_nr_vcpus xen_dm_op_nr_vcpus_t;
+/*
+ * XEN_DMOP_bind_pt_msi_irq: bind a passthrough interrupt to a guest MSI,
+ * described by the raw MSI message (address and data) the guest programmed.
+ * Xen decodes the message itself, so the emulator does not need to know the
+ * MSI layout and, in particular, extended destination IDs are handled
+ * transparently.
+ */
+#define XEN_DMOP_bind_pt_msi_irq 21
+
+struct xen_dm_op_bind_pt_msi_irq {
+ /* IN - pirq */
+ uint32_t pirq;
+ /* IN - MSI message data word */
+ uint32_t msg_data;
+ /* IN - bind flags */
+ uint32_t flags;
+#define XEN_DMOP_MSI_BIND_UNMASKED (1u << 0)
+ uint32_t pad;
+ /* IN - MSI message address */
+ uint64_aligned_t msg_addr;
+ /* IN - MSI-X table base address (guest physical), 0 for plain MSI */
+ uint64_aligned_t gtable;
+};
+typedef struct xen_dm_op_bind_pt_msi_irq xen_dm_op_bind_pt_msi_irq_t;
+
+/*
+ * XEN_DMOP_unbind_pt_msi_irq: undo a previous XEN_DMOP_bind_pt_msi_irq.
+ */
+#define XEN_DMOP_unbind_pt_msi_irq 22
+
+struct xen_dm_op_unbind_pt_msi_irq {
+ /* IN - pirq */
+ uint32_t pirq;
+};
+typedef struct xen_dm_op_unbind_pt_msi_irq xen_dm_op_unbind_pt_msi_irq_t;
+
struct xen_dm_op {
uint32_t op;
uint32_t pad;
@@ -468,6 +504,8 @@ struct xen_dm_op {
xen_dm_op_relocate_memory_t relocate_memory;
xen_dm_op_pin_memory_cacheattr_t pin_memory_cacheattr;
xen_dm_op_nr_vcpus_t nr_vcpus;
+ xen_dm_op_bind_pt_msi_irq_t bind_pt_msi_irq;
+ xen_dm_op_unbind_pt_msi_irq_t unbind_pt_msi_irq;
} u;
};
diff --git a/xen/include/xlat.lst b/xen/include/xlat.lst
index 33dc8e2b2a..7255f4c65d 100644
--- a/xen/include/xlat.lst
+++ b/xen/include/xlat.lst
@@ -98,6 +98,7 @@
? grant_entry_v2 grant_table.h
! dm_op_buf hvm/dm_op.h
+? dm_op_bind_pt_msi_irq hvm/dm_op.h
? dm_op_create_ioreq_server hvm/dm_op.h
? dm_op_destroy_ioreq_server hvm/dm_op.h
? dm_op_get_ioreq_server_info hvm/dm_op.h
@@ -116,6 +117,7 @@
? dm_op_set_pci_intx_level hvm/dm_op.h
? dm_op_set_pci_link_route hvm/dm_op.h
? dm_op_track_dirty_vram hvm/dm_op.h
+? dm_op_unbind_pt_msi_irq hvm/dm_op.h
! hvm_altp2m_set_mem_access_multi hvm/hvm_op.h
--
2.53.0
--
Julian Vetter | Vates Hypervisor & Kernel Developer
XCP-ng & Xen Orchestra - Vates solutions
web: https://vates.tech
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |