|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v4 6/9] x86/hvm: Support extended destination IDs in virtual MSI and IO-APIC
Add IO_APIC_REDIR_DEST_MASK and IO_APIC_REDIR_EXT_DEST_MASK for the
standard and extended destination fields of the IO-APIC RTE, and a
VIOAPIC_RTE_DEST() helper that extracts the combined 15-bit destination
ID. Extend the IO-APIC RTE save/restore struct with an ext_dest_id field
so migration preserves the extended bits.
Use the newly defined masks to extract the full 15-bit destination ID
from guest MSI addresses and IO-APIC RTEs. In hvm_inject_msi() combine
the standard bits [19:12] with the extended bits [11:5] of the MSI
address into a 15-bit destination ID for LAPIC delivery. Widen the dest
parameter of vmsi_deliver() and hvm_girq_dest_2_vcpu_id() from uint8_t
to uint32_t to accommodate the larger range. In vioapic_deliver() read
the combined 15-bit destination using the VIOAPIC_RTE_DEST() macro.
Extend ioapic_check() to check for extended destination bits set in a
domain that does not advertise XEN_HVM_CPUID_EXT_DEST_ID and refuse to
restore the IO-APIC state, preventing silent interrupt misrouting after
live migration.
Signed-off-by: Julian Vetter <julian.vetter@xxxxxxxxxx>
---
Changes in v4:
- Corresponds to v3 patch 3, but adapted for the new raw-addr/data
storage introduced in patch 5:
- In v3, vmsi_deliver_pirq() extracted the full destination from
gflags via XEN_DOMCTL_VMSI_X86_FULL_DEST(), and msi_gflags()
packed the extended address bits into gflags
- In v4 both helpers are gone. vmsi_deliver_pirq() reads
pirq_dpci->gmsi.addr and pirq_dpci->gmsi.data directly using the
standard MSI masks
- Moved the IO-APIC masks and VIOAPIC_RTE_DEST() helper (previously in
v3 patch 2) into this patch
- Added ioapic_check() ext destination safety check (refusing migration
with ext_dest_id bits set when XEN_HVM_CPUID_EXT_DEST_ID is not
advertised)
---
xen/arch/x86/hvm/irq.c | 9 ++++++++-
xen/arch/x86/hvm/vioapic.c | 2 +-
xen/arch/x86/hvm/vmsi.c | 4 ++--
xen/arch/x86/include/asm/hvm/hvm.h | 4 ++--
xen/arch/x86/include/asm/hvm/vioapic.h | 12 ++++++++++++
xen/include/public/arch-x86/hvm/save.h | 4 +++-
6 files changed, 28 insertions(+), 7 deletions(-)
diff --git a/xen/arch/x86/hvm/irq.c b/xen/arch/x86/hvm/irq.c
index 5f64361113..b43adf8b96 100644
--- a/xen/arch/x86/hvm/irq.c
+++ b/xen/arch/x86/hvm/irq.c
@@ -374,7 +374,14 @@ 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;
+ /*
+ * Standard MSI destination address bits 19:12 carry the 8-bit APIC ID.
+ * When XEN_HVM_CPUID_EXT_DEST_ID is enabled, bits 11:5 carry APIC ID bits
+ * [14:8], extending the addressable range to 15 bits. Guests that do not
+ * use extended IDs leave these bits at zero, so the combined extraction is
+ * safe regardless.
+ */
+ uint32_t dest = MSI_ADDR_DEST(tmp);
uint8_t dest_mode = !!(tmp & MSI_ADDR_DESTMODE_MASK);
uint8_t delivery_mode = (data & MSI_DATA_DELIVERY_MODE_MASK)
>> MSI_DATA_DELIVERY_MODE_SHIFT;
diff --git a/xen/arch/x86/hvm/vioapic.c b/xen/arch/x86/hvm/vioapic.c
index 43fb165f84..527cc770b7 100644
--- a/xen/arch/x86/hvm/vioapic.c
+++ b/xen/arch/x86/hvm/vioapic.c
@@ -411,7 +411,7 @@ 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;
+ uint32_t dest = VIOAPIC_RTE_DEST(vioapic->redirtbl[pin].bits);
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 2a4b97e2e1..7b338c4ddc 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;
@@ -126,7 +126,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/hvm.h
b/xen/arch/x86/include/asm/hvm/hvm.h
index e7c1364802..884dd44c81 100644
--- a/xen/arch/x86/include/asm/hvm/hvm.h
+++ b/xen/arch/x86/include/asm/hvm/hvm.h
@@ -294,11 +294,11 @@ 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);
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..4499208bad 100644
--- a/xen/arch/x86/include/asm/hvm/vioapic.h
+++ b/xen/arch/x86/include/asm/hvm/vioapic.h
@@ -32,6 +32,18 @@
#define VIOAPIC_EDGE_TRIG 0
#define VIOAPIC_LEVEL_TRIG 1
+/*
+ * Extract the destination ID from a 64-bit IO-APIC RTE, including the
+ * extended bits (55:49) used when XEN_HVM_CPUID_EXT_DEST_ID is advertised.
+ */
+#define IO_APIC_REDIR_DEST_MASK (0xffULL << 56)
+#define IO_APIC_REDIR_EXT_DEST_MASK (0x7fULL << 49)
+
+#define VIOAPIC_RTE_DEST(rte) \
+ (MASK_EXTR((rte), IO_APIC_REDIR_DEST_MASK) | \
+ (MASK_EXTR((rte), IO_APIC_REDIR_EXT_DEST_MASK) << \
+ MSI_ADDR_DEST_ID_UPPER_BITS))
+
#define VIOAPIC_DEFAULT_BASE_ADDRESS 0xfec00000U
#define VIOAPIC_MEM_LENGTH 0x100
diff --git a/xen/include/public/arch-x86/hvm/save.h
b/xen/include/public/arch-x86/hvm/save.h
index 9c4bfc7ebd..483097d940 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 |