|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v4 6/9] x86/hvm: Support extended destination IDs in virtual MSI and IO-APIC
Le 27/04/2026 à 15:57, Julian Vetter a écrit :
> 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))
> +
We can probably simplify that by using vioapic_redir_entry.dest_id and
vioapic_redir_entry.ext_dest_id directly instead of reparsing it from
vioapic_redir_entry.bits.
IOW, replace MASK_EXTR((rte), IO_APIC_REDIR_DEST_MASK) with
(rte).dest_id and MASK_EXTR((rte), IO_APIC_REDIR_EXT_DEST_MASK) with
(rte).ext_dest_id. So VIOAPIC_RTE_DEST() would now take
vioapic_redir_entry as parameter.
> #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;
> };
Teddy
--
Teddy Astie | Vates XCP-ng Developer
XCP-ng & Xen Orchestra - Vates solutions
web: https://vates.tech
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |