|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v5 08/11] x86/hvm: Decode extended MSI / IO-APIC destination IDs when opted in
Add the plumbing to allow for 15-bit destination IDs:
- struct hvm_domain gains a tri-state ext_dest_id (UNSET / DISABLED /
ENABLED). hvm_ext_dest_id_active() is the single point to guard every
extended decode.
- The vIO-APIC RTE save record grows an ext_dest_id:7 field (the top 7
bits of a 15-bit APIC ID) and VIOAPIC_RTE_DEST() combines it with
dest_id.
- vmsi_deliver() / hvm_girq_dest_2_vcpu_id() take a uint32_t dest.
- hvm_inject_msi(), vioapic_deliver(), vmsi_deliver_pirq(),
pt_irq_bind_msi() and _hvm_dpci_msi_eoi() fold in the extended bits
only when hvm_ext_dest_id_active(), otherwise an unaware guest that
left non-zero values in those bits would have its interrupts
misrouted.
Since ext_dest_id is never ENABLED yet, there is no functional change.
Signed-off-by: Julian Vetter <julian.vetter@xxxxxxxxxx>
---
Changes in v5:
- Rewritten to use a tri-state d->arch.hvm.ext_dest_id (UNSET / DISABLED
/ ENABLED).
- Addressed Jan's comment about "wrong way round": every decode site
folds in the extended bits only when active and ignores them
otherwise, rather than rejecting a guest that left values there.
- VIOAPIC_RTE_DEST() takes a union vioapic_redir_entry and uses .dest_id
/ .ext_dest_id.
- Replaced comments and added one central explanation.
Signed-off-by: Julian Vetter <julian.vetter@xxxxxxxxxx>
---
xen/arch/x86/hvm/irq.c | 6 ++++--
xen/arch/x86/hvm/vioapic.c | 5 ++++-
xen/arch/x86/hvm/vmsi.c | 8 +++++---
xen/arch/x86/include/asm/hvm/domain.h | 13 +++++++++++++
xen/arch/x86/include/asm/hvm/hvm.h | 12 ++++++++++--
xen/arch/x86/include/asm/hvm/vioapic.h | 10 ++++++++++
xen/drivers/passthrough/x86/hvm.c | 8 ++++++--
xen/include/public/arch-x86/hvm/save.h | 4 +++-
8 files changed, 55 insertions(+), 11 deletions(-)
diff --git a/xen/arch/x86/hvm/irq.c b/xen/arch/x86/hvm/irq.c
index 5f64361113..aa5926529a 100644
--- a/xen/arch/x86/hvm/irq.c
+++ b/xen/arch/x86/hvm/irq.c
@@ -374,7 +374,8 @@ int hvm_set_pci_link_route(struct domain *d, u8 link, u8
isa_irq)
int hvm_inject_msi(struct domain *d, uint64_t addr, uint32_t data)
{
uint32_t tmp = (uint32_t) addr;
- uint8_t dest = (tmp & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
+ uint8_t dest = MASK_EXTR(tmp, MSI_ADDR_DEST_ID_MASK);
+ uint32_t full_dest = hvm_ext_dest_id_active(d) ? MSI_ADDR_DEST(tmp) : dest;
uint8_t dest_mode = !!(tmp & MSI_ADDR_DESTMODE_MASK);
uint8_t delivery_mode = (data & MSI_DATA_DELIVERY_MODE_MASK)
>> MSI_DATA_DELIVERY_MODE_SHIFT;
@@ -412,7 +413,8 @@ int hvm_inject_msi(struct domain *d, uint64_t addr,
uint32_t data)
return -ERANGE;
}
- return vmsi_deliver(d, vector, dest, dest_mode, delivery_mode, trig_mode);
+ return vmsi_deliver(d, vector, full_dest, dest_mode, delivery_mode,
+ trig_mode);
}
void hvm_set_callback_via(struct domain *d, uint64_t via)
diff --git a/xen/arch/x86/hvm/vioapic.c b/xen/arch/x86/hvm/vioapic.c
index 80dc9148a9..ca9b34d3ea 100644
--- a/xen/arch/x86/hvm/vioapic.c
+++ b/xen/arch/x86/hvm/vioapic.c
@@ -39,6 +39,7 @@
#include <asm/event.h>
#include <asm/io_apic.h>
#include <asm/x86_emulate.h>
+#include <asm/msi.h>
/* HACK: Route IRQ0 only to VCPU0 to prevent time jumps. */
#define IRQ0_SPECIAL_ROUTING 1
@@ -413,7 +414,9 @@ static void ioapic_inj_irq(
static void vioapic_deliver(struct hvm_vioapic *vioapic, unsigned int pin)
{
- uint16_t dest = vioapic->redirtbl[pin].fields.dest_id;
+ union vioapic_redir_entry rte = vioapic->redirtbl[pin];
+ uint32_t dest = hvm_ext_dest_id_active(vioapic_domain(vioapic))
+ ? VIOAPIC_RTE_DEST(rte) : rte.fields.dest_id;
uint8_t dest_mode = vioapic->redirtbl[pin].fields.dest_mode;
uint8_t delivery_mode = vioapic->redirtbl[pin].fields.delivery_mode;
uint8_t vector = vioapic->redirtbl[pin].fields.vector;
diff --git a/xen/arch/x86/hvm/vmsi.c b/xen/arch/x86/hvm/vmsi.c
index 6966cabfa7..eede42a202 100644
--- a/xen/arch/x86/hvm/vmsi.c
+++ b/xen/arch/x86/hvm/vmsi.c
@@ -67,7 +67,7 @@ static void vmsi_inj_irq(
int vmsi_deliver(
struct domain *d, int vector,
- uint8_t dest, uint8_t dest_mode,
+ uint32_t dest, uint8_t dest_mode,
uint8_t delivery_mode, uint8_t trig_mode)
{
struct vlapic *target;
@@ -111,7 +111,9 @@ void vmsi_deliver_pirq(struct domain *d, const struct
hvm_pirq_dpci *pirq_dpci)
uint64_t addr = pirq_dpci->gmsi.addr;
uint32_t data = pirq_dpci->gmsi.data;
unsigned int vector = MASK_EXTR(data, MSI_DATA_VECTOR_MASK);
- uint32_t dest = MSI_ADDR_DEST(addr);
+ uint32_t dest = hvm_ext_dest_id_active(d)
+ ? MSI_ADDR_DEST(addr)
+ : MASK_EXTR(addr, MSI_ADDR_DEST_ID_MASK);
bool dest_mode = addr & MSI_ADDR_DESTMODE_MASK;
unsigned int delivery_mode = MASK_EXTR(data, MSI_DATA_DELIVERY_MODE_MASK);
bool trig_mode = data & MSI_DATA_TRIGGER_MASK;
@@ -127,7 +129,7 @@ void vmsi_deliver_pirq(struct domain *d, const struct
hvm_pirq_dpci *pirq_dpci)
}
/* Return value, -1 : multi-dests, non-negative value: dest_vcpu_id */
-int hvm_girq_dest_2_vcpu_id(struct domain *d, uint8_t dest, uint8_t dest_mode)
+int hvm_girq_dest_2_vcpu_id(struct domain *d, uint32_t dest, uint8_t dest_mode)
{
int dest_vcpu_id = -1, w = 0;
struct vcpu *v;
diff --git a/xen/arch/x86/include/asm/hvm/domain.h
b/xen/arch/x86/include/asm/hvm/domain.h
index dd7fa96aad..16f0586907 100644
--- a/xen/arch/x86/include/asm/hvm/domain.h
+++ b/xen/arch/x86/include/asm/hvm/domain.h
@@ -102,6 +102,19 @@ struct hvm_domain {
bool is_s3_suspended;
+ /*
+ * Whether extended (15-bit) MSI / IO-APIC destination IDs are honoured for
+ * this domain. Tri-state: EXT_DEST_ID_UNSET until the value is locked (at
+ * creation_finished, or restored from a migration stream). Afterwards it
+ * is a stable, guest-visible property advertised through
+ * XEN_HVM_CPUID_EXT_DEST_ID.
+ */
+ enum {
+ EXT_DEST_ID_UNSET = 0,
+ EXT_DEST_ID_DISABLED,
+ EXT_DEST_ID_ENABLED,
+ } ext_dest_id;
+
/* Compatibility setting for a bug in x2APIC LDR */
bool bug_x2apic_ldr_vcpu_id;
diff --git a/xen/arch/x86/include/asm/hvm/hvm.h
b/xen/arch/x86/include/asm/hvm/hvm.h
index 16383e1084..cedaa28820 100644
--- a/xen/arch/x86/include/asm/hvm/hvm.h
+++ b/xen/arch/x86/include/asm/hvm/hvm.h
@@ -296,11 +296,19 @@ uint64_t hvm_get_guest_time_fixed(const struct vcpu *v,
uint64_t at_tsc);
int vmsi_deliver(
struct domain *d, int vector,
- uint8_t dest, uint8_t dest_mode,
+ uint32_t dest, uint8_t dest_mode,
uint8_t delivery_mode, uint8_t trig_mode);
struct hvm_pirq_dpci;
void vmsi_deliver_pirq(struct domain *d, const struct hvm_pirq_dpci
*pirq_dpci);
-int hvm_girq_dest_2_vcpu_id(struct domain *d, uint8_t dest, uint8_t dest_mode);
+int hvm_girq_dest_2_vcpu_id(struct domain *d, uint32_t dest, uint8_t
dest_mode);
+
+/*
+ * True when this domain has extended (15-bit) MSI / IO-APIC destination IDs
+ * enabled. Only then may address[11:5] / RTE[55:49] be folded into the
+ * destination ID.
+ */
+#define hvm_ext_dest_id_active(d) \
+ ((d)->arch.hvm.ext_dest_id == EXT_DEST_ID_ENABLED)
enum hvm_intblk
hvm_interrupt_blocked(struct vcpu *v, struct hvm_intack intack);
diff --git a/xen/arch/x86/include/asm/hvm/vioapic.h
b/xen/arch/x86/include/asm/hvm/vioapic.h
index 68af6dce79..3df2aa7fe5 100644
--- a/xen/arch/x86/include/asm/hvm/vioapic.h
+++ b/xen/arch/x86/include/asm/hvm/vioapic.h
@@ -32,6 +32,16 @@
#define VIOAPIC_EDGE_TRIG 0
#define VIOAPIC_LEVEL_TRIG 1
+/*
+ * Combined 15-bit destination ID of an IO-APIC redirection table entry: the
+ * architectural dest_id byte plus the 7 "Extended Destination ID" bits. The
+ * caller is responsible for only using the extended part when the guest has
+ * opted in (hvm_ext_dest_id_active()).
+ */
+#define VIOAPIC_RTE_DEST(rte) \
+ ((rte).fields.dest_id | \
+ ((uint32_t)(rte).fields.ext_dest_id << MSI_ADDR_DEST_ID_WIDTH))
+
#define VIOAPIC_DEFAULT_BASE_ADDRESS 0xfec00000U
#define VIOAPIC_MEM_LENGTH 0x100
diff --git a/xen/drivers/passthrough/x86/hvm.c
b/xen/drivers/passthrough/x86/hvm.c
index bdab065eb7..a13dd86610 100644
--- a/xen/drivers/passthrough/x86/hvm.c
+++ b/xen/drivers/passthrough/x86/hvm.c
@@ -380,7 +380,8 @@ int pt_irq_bind_msi(struct domain *d, unsigned int
machine_irq,
/* Calculate dest_vcpu_id for MSI-type pirq migration. */
gvec = MASK_EXTR(msi_data, MSI_DATA_VECTOR_MASK);
- dest = MSI_ADDR_DEST(msi_addr);
+ dest = hvm_ext_dest_id_active(d) ? MSI_ADDR_DEST(msi_addr)
+ : MASK_EXTR(msi_addr,
MSI_ADDR_DEST_ID_MASK);
dest_mode = msi_addr & MSI_ADDR_DESTMODE_MASK;
delivery_mode = MASK_EXTR(msi_data, MSI_DATA_DELIVERY_MODE_MASK);
@@ -883,7 +884,10 @@ static int cf_check _hvm_dpci_msi_eoi(
if ( (pirq_dpci->flags & HVM_IRQ_DPCI_MACH_MSI) &&
MASK_EXTR(pirq_dpci->gmsi.data, MSI_DATA_VECTOR_MASK) == vector )
{
- unsigned int dest = MSI_ADDR_DEST(pirq_dpci->gmsi.addr);
+ unsigned int dest = hvm_ext_dest_id_active(d)
+ ? MSI_ADDR_DEST(pirq_dpci->gmsi.addr)
+ : MASK_EXTR(pirq_dpci->gmsi.addr,
+ MSI_ADDR_DEST_ID_MASK);
bool dest_mode = pirq_dpci->gmsi.addr & MSI_ADDR_DESTMODE_MASK;
if ( vlapic_match_dest(vcpu_vlapic(current), NULL, 0, dest,
diff --git a/xen/include/public/arch-x86/hvm/save.h
b/xen/include/public/arch-x86/hvm/save.h
index 44d7924777..ff73b83d65 100644
--- a/xen/include/public/arch-x86/hvm/save.h
+++ b/xen/include/public/arch-x86/hvm/save.h
@@ -359,7 +359,9 @@ union vioapic_redir_entry
uint8_t trig_mode:1;
uint8_t mask:1;
uint8_t reserve:7;
- uint8_t reserved[4];
+ uint8_t reserved[3];
+ uint8_t reserved2:1;
+ uint8_t ext_dest_id:7;
uint8_t dest_id;
} fields;
};
--
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 |