Xen cannot simply advertise XEN_HVM_CPUID_EXT_DEST_ID to the guest without knowing that the device model will handle extended destination IDs correctly for passthrough MSIs. A device model that still uses XEN_DOMCTL_bind_pt_irq would pass only the low 8 bits of the destination ID, misrouting interrupts to vCPUs with APIC IDs greater than 255. So, add a DM op XEN_DMOP_enable_ext_dest_id that the device model can call during domain setup (before vCPUs are started) to signal that it will use XEN_DMOP_bind_pt_msi_irq for all passthrough MSI bindings. When called, Xen sets ext_dest_id_enabled in struct hvm_domain, so it's visible to the guest via CPUID.
Signed-off-by: Julian Vetter <[email protected]> --- Changes in V3: - New patch addressing feedback from Roger --- tools/include/xendevicemodel.h | 14 ++++++++++++++ tools/libs/devicemodel/core.c | 10 ++++++++++ xen/arch/x86/hvm/dm.c | 5 +++++ xen/arch/x86/include/asm/hvm/domain.h | 7 +++++++ xen/include/public/hvm/dm_op.h | 9 +++++++++ 5 files changed, 45 insertions(+) diff --git a/tools/include/xendevicemodel.h b/tools/include/xendevicemodel.h index 0d5d7b0ff1..270d76fe9c 100644 --- a/tools/include/xendevicemodel.h +++ b/tools/include/xendevicemodel.h @@ -412,6 +412,20 @@ int xendevicemodel_unbind_pt_msi_irq( xendevicemodel_handle *dmod, domid_t domid, uint32_t machine_irq, uint8_t gvec, uint64_t msi_addr, uint32_t msi_data); +/** + * This function signals to Xen that this device model will use + * xendevicemodel_bind_pt_msi_irq() for all passthrough MSI bindings. + * After this call, Xen will advertise XEN_HVM_CPUID_EXT_DEST_ID to the + * guest, enabling 15-bit destination IDs. Must be called before the + * guest vCPUs are started! + * + * @parm dmod a handle to an open devicemodel interface. + * @parm domid the domain id to be serviced. + * @return 0 on success, -1 on failure. + */ +int xendevicemodel_enable_ext_dest_id( + xendevicemodel_handle *dmod, domid_t domid); + #endif /* XENDEVICEMODEL_H */ /* diff --git a/tools/libs/devicemodel/core.c b/tools/libs/devicemodel/core.c index 4a52fe4750..03838aa37b 100644 --- a/tools/libs/devicemodel/core.c +++ b/tools/libs/devicemodel/core.c @@ -689,6 +689,16 @@ int xendevicemodel_unbind_pt_msi_irq( return xendevicemodel_op(dmod, domid, 1, &op, sizeof(op)); } +int xendevicemodel_enable_ext_dest_id( + xendevicemodel_handle *dmod, domid_t domid) +{ + struct xen_dm_op op = { + .op = XEN_DMOP_enable_ext_dest_id, + }; + + 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/xen/arch/x86/hvm/dm.c b/xen/arch/x86/hvm/dm.c index 3d530d948f..7738400540 100644 --- a/xen/arch/x86/hvm/dm.c +++ b/xen/arch/x86/hvm/dm.c @@ -374,6 +374,7 @@ int dm_op(const struct dmop_args *op_args) [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_bind_pt_msi_irq), + [XEN_DMOP_enable_ext_dest_id] = 0, }; rc = rcu_lock_remote_domain_by_id(op_args->domid, &d); @@ -708,6 +709,10 @@ int dm_op(const struct dmop_args *op_args) break; } + case XEN_DMOP_enable_ext_dest_id: + d->arch.hvm.ext_dest_id_enabled = true; + break; + default: rc = ioreq_server_dm_op(&op, d, &const_op); break; diff --git a/xen/arch/x86/include/asm/hvm/domain.h b/xen/arch/x86/include/asm/hvm/domain.h index abf9bc448d..770bc96970 100644 --- a/xen/arch/x86/include/asm/hvm/domain.h +++ b/xen/arch/x86/include/asm/hvm/domain.h @@ -105,6 +105,13 @@ struct hvm_domain { /* Compatibility setting for a bug in x2APIC LDR */ bool bug_x2apic_ldr_vcpu_id; + /* + * Set by the device model via XEN_DMOP_enable_ext_dest_id to indicate + * it uses XEN_DMOP_bind_pt_msi_irq (raw MSI addr/data) for passthrough. + * Controls advertisement of XEN_HVM_CPUID_EXT_DEST_ID to the guest. + */ + bool ext_dest_id_enabled; + /* hypervisor intercepted msix table */ struct list_head msixtbl_list; diff --git a/xen/include/public/hvm/dm_op.h b/xen/include/public/hvm/dm_op.h index fd0f3a6a99..2814fe1c3d 100644 --- a/xen/include/public/hvm/dm_op.h +++ b/xen/include/public/hvm/dm_op.h @@ -447,6 +447,15 @@ typedef struct xen_dm_op_nr_vcpus xen_dm_op_nr_vcpus_t; #define XEN_DMOP_bind_pt_msi_irq 21 #define XEN_DMOP_unbind_pt_msi_irq 22 +/* + * XEN_DMOP_enable_ext_dest_id: Signal to Xen that this device model will use + * XEN_DMOP_bind_pt_msi_irq for all passthrough MSI bindings, passing raw MSI + * address/data fields. Once called, Xen will advertise + * XEN_HVM_CPUID_EXT_DEST_ID to the guest. Must be called before the guest + * starts. + */ +#define XEN_DMOP_enable_ext_dest_id 23 + struct xen_dm_op_bind_pt_msi_irq { /* IN - physical IRQ (pirq) */ uint32_t machine_irq; -- 2.51.0 -- Julian Vetter | Vates Hypervisor & Kernel Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
