Skip to content

Commit

Permalink
x86/msr: introduce an option for compatible MSR behavior selection
Browse files Browse the repository at this point in the history
Introduce an option to allow selecting a behavior similar to the pre
Xen 4.15 one for accesses to MSRs not explicitly handled. Since commit
84e848f and 322ec7c accesses to MSRs not explicitly
handled by Xen result in the injection of a #GP to the guest. This
is a behavior change since previously a #GP was only injected if
accessing the MSR on the real hardware would also trigger a #GP, or if
the attempted to be set bits wouldn't match the hardware values (for
PV). The reasons for not leaking hardware MSR values and injecting a
#GP are fully valid, so the solution proposed here should be
considered a temporary workaround until all the required MSRs are
properly handled.

This seems to be problematic for some guests, so introduce an option
to fallback to this kind of legacy behavior without leaking the
underlying MSR values to the guest.

When the option is set, for both PV and HVM don't inject a #GP to the
guest on MSR read if reading the underlying MSR doesn't result in a
#GP, do the same for writes and simply discard the value to be written
on that case.

Note that for guests restored or migrated from previous Xen versions
the option is enabled by default, in order to keep a compatible
MSR behavior. Such compatibility is done at the libxl layer, to avoid
higher-level toolstacks from having to know the details about this flag.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Acked-by: Christian Lindig <christian.lindig@citrix.com>
Reviewed-by: Ian Jackson <iwj@xenproject.org>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Tested-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Release-Acked-by: Ian Jackson <iwj@xenproject.org>
  • Loading branch information
royger authored and jbeulich committed Mar 12, 2021
1 parent 9e23f10 commit 0570d7f
Show file tree
Hide file tree
Showing 22 changed files with 158 additions and 1 deletion.
14 changes: 14 additions & 0 deletions docs/man/xl.cfg.5.pod.in
Original file line number Diff line number Diff line change
Expand Up @@ -2861,6 +2861,20 @@ No MCA capabilities in above list are enabled.

=back

=item B<msr_relaxed=BOOLEAN>

The "msr_relaxed" boolean is an interim option, and defaults to false.

In Xen 4.15, the default behaviour for unhandled MSRs has been changed,
to avoid leaking host data into guests, and to avoid breaking guest
logic which uses #GP probing to identify the availability of MSRs.

However, this new stricter behaviour has the possibility to break
guests, and a more 4.14-like behaviour can be selected by setting this
option.

If using this option is necessary to fix an issue, please report a bug.

=back

=head1 SEE ALSO
Expand Down
14 changes: 13 additions & 1 deletion docs/misc/xen-command-line.pandoc
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ Specify the bit width of the DMA heap.

### dom0
= List of [ pv | pvh, shadow=<bool>, verbose=<bool>,
cpuid-faulting=<bool> ]
cpuid-faulting=<bool>, msr-relaxed=<bool> ]

Applicability: x86

Expand Down Expand Up @@ -789,6 +789,18 @@ Controls for how dom0 is constructed on x86 systems.
restore the pre-4.13 behaviour. If specifying `no-cpuid-faulting` fixes
an issue in dom0, please report a bug.

* The `msr-relaxed` boolean is an interim option, and defaults to false.

In Xen 4.15, the default behaviour for unhandled MSRs has been changed,
to avoid leaking host data into guests, and to avoid breaking guest
logic which uses \#GP probing to identify the availability of MSRs.

However, this new stricter behaviour has the possibility to break
guests, and a more 4.14-like behaviour can be selected by specifying
`dom0=msr-relaxed`.

If using this option is necessary to fix an issue, please report a bug.

### dom0-iommu
= List of [ passthrough=<bool>, strict=<bool>, map-inclusive=<bool>,
map-reserved=<bool>, none ]
Expand Down
7 changes: 7 additions & 0 deletions tools/include/libxl.h
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,13 @@
*/
#define LIBXL_HAVE_VMTRACE_BUF_KB 1

/*
* LIBXL_HAVE_X86_MSR_RELAXED indicates the toolstack has support for switching
* the MSR access handling in the hypervisor to relaxed mode. This is done by
* setting the libxl_domain_build_info arch_x86.msr_relaxed field.
*/
#define LIBXL_HAVE_X86_MSR_RELAXED 1

/*
* libxl ABI compatibility
*
Expand Down
5 changes: 5 additions & 0 deletions tools/libs/light/libxl_arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ int libxl__arch_extra_memory(libxl__gc *gc,
const libxl_domain_build_info *info,
uint64_t *out);

_hidden
void libxl__arch_update_domain_config(libxl__gc *gc,
libxl_domain_config *dst,
const libxl_domain_config *src);

#if defined(__i386__) || defined(__x86_64__)

#define LAPIC_BASE_ADDRESS 0xfee00000
Expand Down
6 changes: 6 additions & 0 deletions tools/libs/light/libxl_arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1222,6 +1222,12 @@ int libxl__arch_passthrough_mode_setdefault(libxl__gc *gc,
return rc;
}

void libxl__arch_update_domain_config(libxl__gc *gc,
libxl_domain_config *dst,
const libxl_domain_config *src)
{
}

/*
* Local variables:
* mode: C
Expand Down
7 changes: 7 additions & 0 deletions tools/libs/light/libxl_create.c
Original file line number Diff line number Diff line change
Expand Up @@ -2287,6 +2287,13 @@ int libxl_domain_create_restore(libxl_ctx *ctx, libxl_domain_config *d_config,
unset_disk_colo_restore(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.
*/
libxl_defbool_setdefault(&d_config->b_info.arch_x86.msr_relaxed, true);

return do_domain_create(ctx, d_config, domid, restore_fd, send_back_fd,
params, ao_how, aop_console_how);
}
Expand Down
3 changes: 3 additions & 0 deletions tools/libs/light/libxl_internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "libxl_osdeps.h" /* must come before any other headers */

#include "libxl_internal.h"
#include "libxl_arch.h"

void libxl__alloc_failed(libxl_ctx *ctx, const char *func,
size_t nmemb, size_t size) {
Expand Down Expand Up @@ -594,6 +595,8 @@ void libxl__update_domain_configuration(libxl__gc *gc,

/* video ram */
dst->b_info.video_memkb = src->b_info.video_memkb;

libxl__arch_update_domain_config(gc, dst, src);
}

static void ev_slowlock_init_internal(libxl__ev_slowlock *lock,
Expand Down
2 changes: 2 additions & 0 deletions tools/libs/light/libxl_types.idl
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,8 @@ libxl_domain_build_info = Struct("domain_build_info",[
("arch_arm", Struct(None, [("gic_version", libxl_gic_version),
("vuart", libxl_vuart_type),
])),
("arch_x86", Struct(None, [("msr_relaxed", libxl_defbool),
])),
# Alternate p2m is not bound to any architecture or guest type, as it is
# supported by x86 HVM and ARM support is planned.
("altp2m", libxl_altp2m_mode),
Expand Down
20 changes: 20 additions & 0 deletions tools/libs/light/libxl_x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ int libxl__arch_domain_prepare_config(libxl__gc *gc,
abort();
}

config->arch.misc_flags = 0;
if (libxl_defbool_val(d_config->b_info.arch_x86.msr_relaxed))
config->arch.misc_flags |= XEN_X86_MSR_RELAXED;

return 0;
}

Expand Down Expand Up @@ -809,6 +813,7 @@ void libxl__arch_domain_build_info_setdefault(libxl__gc *gc,
libxl_domain_build_info *b_info)
{
libxl_defbool_setdefault(&b_info->acpi, true);
libxl_defbool_setdefault(&b_info->arch_x86.msr_relaxed, false);
}

int libxl__arch_passthrough_mode_setdefault(libxl__gc *gc,
Expand Down Expand Up @@ -851,6 +856,21 @@ int libxl__arch_passthrough_mode_setdefault(libxl__gc *gc,
return rc;
}

void libxl__arch_update_domain_config(libxl__gc *gc,
libxl_domain_config *dst,
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.
*
* Doing so allows the recovery side to figure out whether the flag 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));
}

/*
* Local variables:
Expand Down
4 changes: 4 additions & 0 deletions tools/ocaml/libs/xc/xenctrl.ml
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,13 @@ type x86_arch_emulation_flags =
| X86_EMU_USE_PIRQ
| X86_EMU_VPCI

type x86_arch_misc_flags =
| X86_MSR_RELAXED

type xen_x86_arch_domainconfig =
{
emulation_flags: x86_arch_emulation_flags list;
misc_flags: x86_arch_misc_flags list;
}

type arch_domainconfig =
Expand Down
4 changes: 4 additions & 0 deletions tools/ocaml/libs/xc/xenctrl.mli
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,12 @@ type x86_arch_emulation_flags =
| X86_EMU_USE_PIRQ
| X86_EMU_VPCI

type x86_arch_misc_flags =
| X86_MSR_RELAXED

type xen_x86_arch_domainconfig = {
emulation_flags: x86_arch_emulation_flags list;
misc_flags: x86_arch_misc_flags list;
}

type arch_domainconfig =
Expand Down
9 changes: 9 additions & 0 deletions tools/ocaml/libs/xc/xenctrl_stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,15 @@ CAMLprim value stub_xc_domain_create(value xch, value wanted_domid, value config

#undef VAL_EMUL_FLAGS

#define VAL_MISC_FLAGS Field(arch_domconfig, 1)

cfg.arch.misc_flags = ocaml_list_to_c_bitmap
/* ! x86_arch_misc_flags X86_ none */
/* ! XEN_X86_ XEN_X86_MSR_RELAXED all */
(VAL_MISC_FLAGS);

#undef VAL_MISC_FLAGS

#else
caml_failwith("Unhandled: x86");
#endif
Expand Down
7 changes: 7 additions & 0 deletions tools/xl/xl_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -2741,6 +2741,13 @@ void parse_config_data(const char *config_source,
xlu_cfg_get_defbool(config, "xend_suspend_evtchn_compat",
&c_info->xend_suspend_evtchn_compat, 0);

if (!xlu_cfg_get_defbool(config, "msr_relaxed",
&b_info->arch_x86.msr_relaxed, 0))
fprintf(stderr,
"WARNING: msr_relaxed will be removed in future versions.\n"
"If it fixes an issue you are having please report to "
"xen-devel@lists.xenproject.org.\n");

xlu_cfg_destroy(config);
}

Expand Down
3 changes: 3 additions & 0 deletions xen/arch/x86/dom0_build.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ bool __initdata opt_dom0_shadow;
#endif
bool __initdata opt_dom0_pvh = !IS_ENABLED(CONFIG_PV);
bool __initdata opt_dom0_verbose = IS_ENABLED(CONFIG_VERBOSE_DEBUG);
bool __initdata opt_dom0_msr_relaxed;

static int __init parse_dom0_param(const char *s)
{
Expand All @@ -282,6 +283,8 @@ static int __init parse_dom0_param(const char *s)
else if ( IS_ENABLED(CONFIG_PV) &&
(val = parse_boolean("cpuid-faulting", s, ss)) >= 0 )
opt_dom0_cpuid_faulting = val;
else if ( (val = parse_boolean("msr-relaxed", s, ss)) >= 0 )
opt_dom0_msr_relaxed = val;
else
rc = -EINVAL;

Expand Down
9 changes: 9 additions & 0 deletions xen/arch/x86/domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,13 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
}
}

if ( config->arch.misc_flags & ~XEN_X86_MSR_RELAXED )
{
dprintk(XENLOG_INFO, "Invalid arch misc flags %#x\n",
config->arch.misc_flags);
return -EINVAL;
}

return 0;
}

Expand Down Expand Up @@ -852,6 +859,8 @@ int arch_domain_create(struct domain *d,

domain_cpu_policy_changed(d);

d->arch.msr_relaxed = config->arch.misc_flags & XEN_X86_MSR_RELAXED;

return 0;

fail:
Expand Down
10 changes: 10 additions & 0 deletions xen/arch/x86/hvm/svm/svm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1795,6 +1795,7 @@ static int svm_msr_read_intercept(unsigned int msr, uint64_t *msr_content)
const struct domain *d = v->domain;
struct vmcb_struct *vmcb = v->arch.hvm.svm.vmcb;
const struct nestedsvm *nsvm = &vcpu_nestedsvm(v);
uint64_t tmp;

switch ( msr )
{
Expand Down Expand Up @@ -1965,6 +1966,12 @@ static int svm_msr_read_intercept(unsigned int msr, uint64_t *msr_content)
break;

default:
if ( d->arch.msr_relaxed && !rdmsr_safe(msr, tmp) )
{
*msr_content = 0;
break;
}

gdprintk(XENLOG_WARNING, "RDMSR 0x%08x unimplemented\n", msr);
goto gpf;
}
Expand Down Expand Up @@ -2151,6 +2158,9 @@ static int svm_msr_write_intercept(unsigned int msr, uint64_t msr_content)
break;

default:
if ( d->arch.msr_relaxed && !rdmsr_safe(msr, msr_content) )
break;

gdprintk(XENLOG_WARNING,
"WRMSR 0x%08x val 0x%016"PRIx64" unimplemented\n",
msr, msr_content);
Expand Down
10 changes: 10 additions & 0 deletions xen/arch/x86/hvm/vmx/vmx.c
Original file line number Diff line number Diff line change
Expand Up @@ -3123,6 +3123,7 @@ static int is_last_branch_msr(u32 ecx)
static int vmx_msr_read_intercept(unsigned int msr, uint64_t *msr_content)
{
struct vcpu *curr = current;
uint64_t tmp;

HVM_DBG_LOG(DBG_LEVEL_MSR, "ecx=%#x", msr);

Expand Down Expand Up @@ -3204,6 +3205,12 @@ static int vmx_msr_read_intercept(unsigned int msr, uint64_t *msr_content)
break;
}

if ( curr->domain->arch.msr_relaxed && !rdmsr_safe(msr, tmp) )
{
*msr_content = 0;
break;
}

gdprintk(XENLOG_WARNING, "RDMSR 0x%08x unimplemented\n", msr);
goto gp_fault;
}
Expand Down Expand Up @@ -3505,6 +3512,9 @@ static int vmx_msr_write_intercept(unsigned int msr, uint64_t msr_content)
is_last_branch_msr(msr) )
break;

if ( v->domain->arch.msr_relaxed && !rdmsr_safe(msr, msr_content) )
break;

gdprintk(XENLOG_WARNING,
"WRMSR 0x%08x val 0x%016"PRIx64" unimplemented\n",
msr, msr_content);
Expand Down
10 changes: 10 additions & 0 deletions xen/arch/x86/pv/emul-priv-op.c
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,7 @@ static int read_msr(unsigned int reg, uint64_t *val,
const struct domain *currd = curr->domain;
const struct cpuid_policy *cp = currd->arch.cpuid;
bool vpmu_msr = false;
uint64_t tmp;
int ret;

if ( (ret = guest_rdmsr(curr, reg, val)) != X86EMUL_UNHANDLEABLE )
Expand Down Expand Up @@ -986,6 +987,12 @@ static int read_msr(unsigned int reg, uint64_t *val,
}
/* fall through */
default:
if ( currd->arch.msr_relaxed && !rdmsr_safe(reg, tmp) )
{
*val = 0;
return X86EMUL_OKAY;
}

gdprintk(XENLOG_WARNING, "RDMSR 0x%08x unimplemented\n", reg);
break;

Expand Down Expand Up @@ -1148,6 +1155,9 @@ static int write_msr(unsigned int reg, uint64_t val,
}
/* fall through */
default:
if ( currd->arch.msr_relaxed && !rdmsr_safe(reg, val) )
return X86EMUL_OKAY;

gdprintk(XENLOG_WARNING,
"WRMSR 0x%08x val 0x%016"PRIx64" unimplemented\n",
reg, val);
Expand Down
3 changes: 3 additions & 0 deletions xen/arch/x86/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,9 @@ static struct domain *__init create_dom0(const module_t *image,
.max_grant_frames = -1,
.max_maptrack_frames = -1,
.max_vcpus = dom0_max_vcpus(),
.arch = {
.misc_flags = opt_dom0_msr_relaxed ? XEN_X86_MSR_RELAXED : 0,
},
};
struct domain *d;
char *cmdline;
Expand Down
3 changes: 3 additions & 0 deletions xen/include/asm-x86/domain.h
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,9 @@ struct arch_domain
/* Mem_access emulation control */
bool_t mem_access_emulate_each_rep;

/* Don't unconditionally inject #GP for unhandled MSRs. */
bool msr_relaxed;

/* Emulated devices enabled bitmap. */
uint32_t emulation_flags;
} __cacheline_aligned;
Expand Down
1 change: 1 addition & 0 deletions xen/include/asm-x86/setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ extern bool opt_dom0_shadow;
extern bool opt_dom0_pvh;
extern bool opt_dom0_verbose;
extern bool opt_dom0_cpuid_faulting;
extern bool opt_dom0_msr_relaxed;

#define max_init_domid (0)

Expand Down

0 comments on commit 0570d7f

Please sign in to comment.