Skip to content

Commit

Permalink
x86/hvm: don't expose XENFEAT_hvm_pirqs by default
Browse files Browse the repository at this point in the history
The HVM pirq feature allows routing interrupts from both physical and emulated
devices over event channels, this was done a performance improvement.  However
its usage is fully undocumented, and the only reference implementation is in
Linux.  It defeats the purpose of local APIC hardware virtualization, because
when using it interrupts avoid the usage of the local APIC altogether.

It has also been reported to not work properly with certain devices, at least
when using some AMD GPUs Linux attempts to route interrupts over event
channels, but Xen doesn't correctly detect such routing, which leads to the
hypervisor complaining with:

(XEN) d15v0: Unsupported MSI delivery mode 7 for Dom15

When MSIs are attempted to be routed over event channels the entry delivery
mode is set to ExtINT, but Xen doesn't detect such routing and attempts to
inject the interrupt following the native MSI path, and the ExtINT delivery
mode is not supported.

Disable HVM PIRQs by default and provide a per-domain option in xl.cfg to
enable such feature.  Also for backwards compatibility keep the feature enabled
for any resumed domains that don't have an explicit selection.

Note that the only user of the feature (Linux) is also able to handle native
interrupts fine, as the feature was already not used if Xen reported local APIC
hardware virtualization active.

Link: QubesOS/qubes-issues#7971
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
Changes since v1:
 - Fix libxl for PV guests.
  • Loading branch information
royger committed Jan 10, 2024
1 parent c27c892 commit 6008460
Show file tree
Hide file tree
Showing 8 changed files with 36 additions and 7 deletions.
7 changes: 7 additions & 0 deletions docs/man/xl.cfg.5.pod.in
Original file line number Diff line number Diff line change
Expand Up @@ -2460,6 +2460,13 @@ The viridian option can be specified as a boolean. A value of true (1)
is equivalent to the list [ "defaults" ], and a value of false (0) is
equivalent to an empty list.

=item B<hvm_pirq=BOOLEAN>

Select whether the guest is allowed to route interrupts from devices (either
emulated or passed through) over event channels.

This option is disabled by default.

=back

=head3 Emulated VGA Graphics Device
Expand Down
7 changes: 7 additions & 0 deletions tools/include/libxl.h
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,13 @@
* executable in order to not run it as the same user as libxl.
*/

/*
* LIBXL_HAVE_HVM_PIRQ indicates the presence of the u.hvm.pirq filed in
* libxl_domain_build_info that signals whether an HVM guest has accesses to
* the XENFEAT_hvm_pirqs feature.
*/
#define LIBXL_HAVE_HVM_PIRQ 1

/*
* libxl memory management
*
Expand Down
7 changes: 5 additions & 2 deletions tools/libs/light/libxl_create.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ int libxl__domain_build_info_setdefault(libxl__gc *gc,
libxl_defbool_setdefault(&b_info->u.hvm.usb, false);
libxl_defbool_setdefault(&b_info->u.hvm.vkb_device, true);
libxl_defbool_setdefault(&b_info->u.hvm.xen_platform_pci, true);
libxl_defbool_setdefault(&b_info->u.hvm.pirq, false);

libxl_defbool_setdefault(&b_info->u.hvm.spice.enable, false);
if (!libxl_defbool_val(b_info->u.hvm.spice.enable) &&
Expand Down Expand Up @@ -2375,10 +2376,12 @@ int libxl_domain_create_restore(libxl_ctx *ctx, libxl_domain_config *d_config,

/*
* When restoring (either from a save file or for a migration domain) set
* the MSR relaxed mode for compatibility with older Xen versions if the
* option is not set as part of the original configuration.
* the MSR relaxed mode and HVM PIRQs for compatibility with older Xen
* versions if the options are not set as part of the original
* configuration.
*/
libxl_defbool_setdefault(&d_config->b_info.arch_x86.msr_relaxed, true);
libxl_defbool_setdefault(&d_config->b_info.u.hvm.pirq, true);

return do_domain_create(ctx, d_config, domid, restore_fd, send_back_fd,
params, ao_how, aop_console_how);
Expand Down
1 change: 1 addition & 0 deletions tools/libs/light/libxl_types.idl
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,7 @@ libxl_domain_build_info = Struct("domain_build_info",[
("rdm", libxl_rdm_reserve),
("rdm_mem_boundary_memkb", MemKB),
("mca_caps", uint64),
("pirq", libxl_defbool),
])),
("pv", Struct(None, [("kernel", string, {'deprecated_by': 'kernel'}),
("slack_memkb", MemKB),
Expand Down
12 changes: 9 additions & 3 deletions tools/libs/light/libxl_x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ int libxl__arch_domain_prepare_config(libxl__gc *gc,
switch(d_config->c_info.type) {
case LIBXL_DOMAIN_TYPE_HVM:
config->arch.emulation_flags = (XEN_X86_EMU_ALL & ~XEN_X86_EMU_VPCI);
if (!libxl_defbool_val(d_config->b_info.u.hvm.pirq))
config->arch.emulation_flags &= ~XEN_X86_EMU_USE_PIRQ;
break;
case LIBXL_DOMAIN_TYPE_PVH:
config->arch.emulation_flags = XEN_X86_EMU_LAPIC;
Expand Down Expand Up @@ -864,15 +866,19 @@ void libxl__arch_update_domain_config(libxl__gc *gc,
const libxl_domain_config *src)
{
/*
* Force MSR relaxed to be set (either to true or false) so it's part of
* the domain configuration when saving or performing a live-migration.
* Force MSR relaxed and HVM pirq to be set (either to true or false) so
* it's part of the domain configuration when saving or performing a
* live-migration.
*
* Doing so allows the recovery side to figure out whether the flag should
* Doing so allows the recovery side to figure out whether the flags should
* be set to true in order to keep backwards compatibility with already
* started domains.
*/
libxl_defbool_setdefault(&dst->b_info.arch_x86.msr_relaxed,
libxl_defbool_val(src->b_info.arch_x86.msr_relaxed));
if (src->c_info.type == LIBXL_DOMAIN_TYPE_HVM )
libxl_defbool_setdefault(&dst->b_info.u.hvm.pirq,
libxl_defbool_val(src->b_info.u.hvm.pirq));
}

/*
Expand Down
4 changes: 3 additions & 1 deletion tools/python/xen/lowlevel/xc/xc.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,9 @@ static PyObject *pyxc_domain_create(XcObject *self,

#if defined (__i386) || defined(__x86_64__)
if ( config.flags & XEN_DOMCTL_CDF_hvm )
config.arch.emulation_flags = (XEN_X86_EMU_ALL & ~XEN_X86_EMU_VPCI);
config.arch.emulation_flags = XEN_X86_EMU_ALL &
~(XEN_X86_EMU_VPCI |
XEN_X86_EMU_USE_PIRQ);
#elif defined (__arm__) || defined(__aarch64__)
config.arch.gic_version = XEN_DOMCTL_CONFIG_GIC_NATIVE;
#else
Expand Down
1 change: 1 addition & 0 deletions tools/xl/xl_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -1801,6 +1801,7 @@ void parse_config_data(const char *config_source,
xlu_cfg_get_defbool(config, "hpet", &b_info->u.hvm.hpet, 0);
xlu_cfg_get_defbool(config, "vpt_align", &b_info->u.hvm.vpt_align, 0);
xlu_cfg_get_defbool(config, "apic", &b_info->apic, 0);
xlu_cfg_get_defbool(config, "hvm_pirq", &b_info->u.hvm.pirq, 0);

switch (xlu_cfg_get_list(config, "viridian",
&viridian, &num_viridian, 1))
Expand Down
4 changes: 3 additions & 1 deletion xen/arch/x86/domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,9 @@ static bool emulation_flags_ok(const struct domain *d, uint32_t emflags)
emflags != (X86_EMU_VPCI | X86_EMU_LAPIC | X86_EMU_IOAPIC) )
return false;
if ( !is_hardware_domain(d) &&
emflags != (X86_EMU_ALL & ~X86_EMU_VPCI) &&
/* HVM PIRQ feature is user-selectable. */
(emflags & ~X86_EMU_USE_PIRQ) !=
(X86_EMU_ALL & ~(X86_EMU_VPCI | X86_EMU_USE_PIRQ)) &&
emflags != X86_EMU_LAPIC )
return false;
}
Expand Down

0 comments on commit 6008460

Please sign in to comment.