mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
xen/x86: support per-domain flag for xpti
Instead of switching XPTI globally on or off add a per-domain flag for that purpose. This allows to modify the xpti boot parameter to support running dom0 without Meltdown mitigations. Using "xpti=no-dom0" as boot parameter will achieve that. Move the xpti boot parameter handling to xen/arch/x86/pv/domain.c as it is pv-domain specific. Signed-off-by: Juergen Gross <jgross@suse.com> Reviewed-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
1 parent
cda05dcae6
commit
0d3e7f0b6b
11 files changed
+119
-29
No files matched your search
@@ -1955,14 +1955,24 @@ minimum of 32M, subject to a suitably aligned and sized contiguous
|
||||
region of memory being available.
|
||||
|
||||
### xpti
|
||||
> `= <boolean>`
|
||||
> `= List of [ default | <boolean> | dom0=<bool> | domu=<bool> ]`
|
||||
|
||||
> Default: `false` on AMD hardware
|
||||
> Default: `false` on hardware not to be vulnerable to Meltdown (e.g. AMD)
|
||||
> Default: `true` everywhere else
|
||||
|
||||
Override default selection of whether to isolate 64-bit PV guest page
|
||||
tables.
|
||||
|
||||
`true` activates page table isolation even on hardware not vulnerable by
|
||||
Meltdown for all domains.
|
||||
|
||||
`false` deactivates page table isolation on all systems for all domains.
|
||||
|
||||
`default` sets the default behaviour.
|
||||
|
||||
With `dom0` and `domu` it is possible to control page table isolation
|
||||
for dom0 or guest domains only.
|
||||
|
||||
### xsave
|
||||
> `= <boolean>`
|
||||
|
||||
|
||||
+15
-2
@@ -502,8 +502,21 @@ void make_cr3(struct vcpu *v, mfn_t mfn)
|
||||
|
||||
void write_ptbase(struct vcpu *v)
|
||||
{
|
||||
get_cpu_info()->root_pgt_changed = true;
|
||||
switch_cr3(v->arch.cr3);
|
||||
struct cpu_info *cpu_info = get_cpu_info();
|
||||
|
||||
if ( is_pv_vcpu(v) && v->domain->arch.pv_domain.xpti )
|
||||
{
|
||||
cpu_info->root_pgt_changed = true;
|
||||
cpu_info->pv_cr3 = __pa(this_cpu(root_pgt));
|
||||
switch_cr3(v->arch.cr3);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Make sure to clear xen_cr3 before pv_cr3; switch_cr3() serializes. */
|
||||
cpu_info->xen_cr3 = 0;
|
||||
switch_cr3(v->arch.cr3);
|
||||
cpu_info->pv_cr3 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -387,6 +387,7 @@ int __init dom0_construct_pv(struct domain *d,
|
||||
if ( compat32 )
|
||||
{
|
||||
d->arch.is_32bit_pv = d->arch.has_32bit_shinfo = 1;
|
||||
d->arch.pv_domain.xpti = false;
|
||||
v->vcpu_info = (void *)&d->shared_info->compat.vcpu_info[0];
|
||||
if ( setup_compat_arg_xlat(v) != 0 )
|
||||
BUG();
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <xen/lib.h>
|
||||
#include <xen/sched.h>
|
||||
|
||||
#include <asm/spec_ctrl.h>
|
||||
#include <asm/pv/domain.h>
|
||||
|
||||
static void noreturn continue_nonidle_domain(struct vcpu *v)
|
||||
@@ -75,6 +76,8 @@ int switch_compat(struct domain *d)
|
||||
|
||||
d->arch.x87_fip_width = 4;
|
||||
|
||||
d->arch.pv_domain.xpti = false;
|
||||
|
||||
return 0;
|
||||
|
||||
undo_and_fail:
|
||||
@@ -205,6 +208,9 @@ int pv_domain_initialise(struct domain *d)
|
||||
/* 64-bit PV guest by default. */
|
||||
d->arch.is_32bit_pv = d->arch.has_32bit_shinfo = 0;
|
||||
|
||||
d->arch.pv_domain.xpti = opt_xpti & (is_hardware_domain(d)
|
||||
? OPT_XPTI_DOM0 : OPT_XPTI_DOMU);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
||||
@@ -169,9 +169,6 @@ static int __init parse_smap_param(const char *s)
|
||||
}
|
||||
custom_param("smap", parse_smap_param);
|
||||
|
||||
static int8_t __initdata opt_xpti = -1;
|
||||
boolean_param("xpti", opt_xpti);
|
||||
|
||||
bool __read_mostly acpi_disabled;
|
||||
bool __initdata acpi_force;
|
||||
static char __initdata acpi_param[10] = "";
|
||||
@@ -1546,22 +1543,6 @@ void __init noreturn __start_xen(unsigned long mbi_p)
|
||||
|
||||
cr4_pv32_mask = mmu_cr4_features & XEN_CR4_PV32_BITS;
|
||||
|
||||
if ( opt_xpti < 0 )
|
||||
{
|
||||
uint64_t caps = 0;
|
||||
|
||||
if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
|
||||
caps = ARCH_CAPABILITIES_RDCL_NO;
|
||||
else if ( boot_cpu_has(X86_FEATURE_ARCH_CAPS) )
|
||||
rdmsrl(MSR_ARCH_CAPABILITIES, caps);
|
||||
|
||||
opt_xpti = !(caps & ARCH_CAPABILITIES_RDCL_NO);
|
||||
}
|
||||
if ( opt_xpti )
|
||||
setup_clear_cpu_cap(X86_FEATURE_NO_XPTI);
|
||||
else
|
||||
setup_force_cpu_cap(X86_FEATURE_NO_XPTI);
|
||||
|
||||
if ( cpu_has_fsgsbase )
|
||||
set_in_cr4(X86_CR4_FSGSBASE);
|
||||
|
||||
|
||||
@@ -337,7 +337,7 @@ void start_secondary(void *unused)
|
||||
spin_debug_disable();
|
||||
|
||||
get_cpu_info()->xen_cr3 = 0;
|
||||
get_cpu_info()->pv_cr3 = this_cpu(root_pgt) ? __pa(this_cpu(root_pgt)) : 0;
|
||||
get_cpu_info()->pv_cr3 = 0;
|
||||
|
||||
load_system_tables();
|
||||
|
||||
@@ -1056,7 +1056,7 @@ void __init smp_prepare_cpus(void)
|
||||
panic("Error %d setting up PV root page table\n", rc);
|
||||
if ( per_cpu(root_pgt, 0) )
|
||||
{
|
||||
get_cpu_info()->pv_cr3 = __pa(per_cpu(root_pgt, 0));
|
||||
get_cpu_info()->pv_cr3 = 0;
|
||||
|
||||
/*
|
||||
* All entry points which may need to switch page tables have to start
|
||||
|
||||
@@ -136,8 +136,9 @@ static void __init print_details(enum ind_thunk thunk)
|
||||
boot_cpu_has(X86_FEATURE_RSB_NATIVE) ? " RSB_NATIVE" : "",
|
||||
boot_cpu_has(X86_FEATURE_RSB_VMEXIT) ? " RSB_VMEXIT" : "");
|
||||
|
||||
printk("XPTI: %s\n",
|
||||
boot_cpu_has(X86_FEATURE_NO_XPTI) ? "disabled" : "enabled");
|
||||
printk("XPTI (64-bit PV only): Dom0 %s, DomU %s\n",
|
||||
opt_xpti & OPT_XPTI_DOM0 ? "enabled" : "disabled",
|
||||
opt_xpti & OPT_XPTI_DOMU ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
/* Calculate whether Retpoline is known-safe on this CPU. */
|
||||
@@ -230,6 +231,70 @@ static bool __init retpoline_safe(void)
|
||||
}
|
||||
}
|
||||
|
||||
#define OPT_XPTI_DEFAULT 0xff
|
||||
uint8_t __read_mostly opt_xpti = OPT_XPTI_DEFAULT;
|
||||
|
||||
static __init void xpti_init_default(bool force)
|
||||
{
|
||||
uint64_t caps = 0;
|
||||
|
||||
if ( !force && (opt_xpti != OPT_XPTI_DEFAULT) )
|
||||
return;
|
||||
|
||||
if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
|
||||
caps = ARCH_CAPABILITIES_RDCL_NO;
|
||||
else if ( boot_cpu_has(X86_FEATURE_ARCH_CAPS) )
|
||||
rdmsrl(MSR_ARCH_CAPABILITIES, caps);
|
||||
|
||||
if ( caps & ARCH_CAPABILITIES_RDCL_NO )
|
||||
opt_xpti = 0;
|
||||
else
|
||||
opt_xpti = OPT_XPTI_DOM0 | OPT_XPTI_DOMU;
|
||||
}
|
||||
|
||||
static __init int parse_xpti(const char *s)
|
||||
{
|
||||
const char *ss;
|
||||
int val, rc = 0;
|
||||
|
||||
xpti_init_default(false);
|
||||
|
||||
do {
|
||||
ss = strchr(s, ',');
|
||||
if ( !ss )
|
||||
ss = strchr(s, '\0');
|
||||
|
||||
switch ( parse_bool(s, ss) )
|
||||
{
|
||||
case 0:
|
||||
opt_xpti = 0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
opt_xpti = OPT_XPTI_DOM0 | OPT_XPTI_DOMU;
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( !strcmp(s, "default") )
|
||||
xpti_init_default(true);
|
||||
else if ( (val = parse_boolean("dom0", s, ss)) >= 0 )
|
||||
opt_xpti = (opt_xpti & ~OPT_XPTI_DOM0) |
|
||||
(val ? OPT_XPTI_DOM0 : 0);
|
||||
else if ( (val = parse_boolean("domu", s, ss)) >= 0 )
|
||||
opt_xpti = (opt_xpti & ~OPT_XPTI_DOMU) |
|
||||
(val ? OPT_XPTI_DOMU : 0);
|
||||
else
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
s = ss + 1;
|
||||
} while ( *ss );
|
||||
|
||||
return rc;
|
||||
}
|
||||
custom_param("xpti", parse_xpti);
|
||||
|
||||
void __init init_speculation_mitigations(void)
|
||||
{
|
||||
enum ind_thunk thunk = THUNK_DEFAULT;
|
||||
@@ -347,6 +412,12 @@ void __init init_speculation_mitigations(void)
|
||||
/* (Re)init BSP state now that default_bti_ist_info has been calculated. */
|
||||
init_shadow_spec_ctrl_state();
|
||||
|
||||
xpti_init_default(false);
|
||||
if ( opt_xpti == 0 )
|
||||
setup_force_cpu_cap(X86_FEATURE_NO_XPTI);
|
||||
else
|
||||
setup_clear_cpu_cap(X86_FEATURE_NO_XPTI);
|
||||
|
||||
print_details(thunk);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,8 @@ struct cpu_info {
|
||||
/*
|
||||
* Of the two following fields the latter is being set to the CR3 value
|
||||
* to be used on the given pCPU for loading whenever 64-bit PV guest
|
||||
* context is being entered. The value never changes once set.
|
||||
* context is being entered. A value of zero indicates no setting of CR3
|
||||
* is to be performed.
|
||||
* The former is the value to restore when re-entering Xen, if any. IOW
|
||||
* its value being zero means there's nothing to restore. However, its
|
||||
* value can also be negative, indicating to the exit-to-Xen code that
|
||||
|
||||
@@ -253,6 +253,9 @@ struct pv_domain
|
||||
|
||||
atomic_t nr_l4_pages;
|
||||
|
||||
/* XPTI active? */
|
||||
bool xpti;
|
||||
|
||||
/* map_domain_page() mapping cache. */
|
||||
struct mapcache_domain mapcache;
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ void flush_area_mask(const cpumask_t *, const void *va, unsigned int flags);
|
||||
|
||||
#define flush_root_pgtbl_domain(d) \
|
||||
{ \
|
||||
if ( !cpu_has_no_xpti && is_pv_domain(d) && !is_pv_32bit_domain(d) ) \
|
||||
if ( is_pv_domain(d) && (d)->arch.pv_domain.xpti ) \
|
||||
flush_mask((d)->dirty_cpumask, FLUSH_ROOT_PGTBL); \
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,10 @@ void init_speculation_mitigations(void);
|
||||
extern bool opt_ibpb;
|
||||
extern uint8_t default_bti_ist_info;
|
||||
|
||||
extern uint8_t opt_xpti;
|
||||
#define OPT_XPTI_DOM0 0x01
|
||||
#define OPT_XPTI_DOMU 0x02
|
||||
|
||||
static inline void init_shadow_spec_ctrl_state(void)
|
||||
{
|
||||
struct cpu_info *info = get_cpu_info();
|
||||
|
||||