Skip to content

Commit

Permalink
x86/mm/mtrr: Generalize runtime disabling of MTRRs
Browse files Browse the repository at this point in the history
It is possible to enable CONFIG_MTRR and CONFIG_X86_PAT and end
up with a system with MTRR functionality disabled but PAT
functionality enabled. This can happen, for instance, when the
Xen hypervisor is used where MTRRs are not supported but PAT is.
This can happen on Linux as of commit

  47591df ("xen: Support Xen pv-domains using PAT")

by Juergen, introduced in v3.19.

Technically, we should assume the proper CPU bits would be set
to disable MTRRs but we can't always rely on this. At least on
the Xen Hypervisor, for instance, only X86_FEATURE_MTRR was
disabled as of Xen 4.4 through Xen commit 586ab6a [0], but not
X86_FEATURE_K6_MTRR, X86_FEATURE_CENTAUR_MCR, or
X86_FEATURE_CYRIX_ARR for instance.

Roger Pau Monné has clarified though that although this is
technically true we will never support PVH on these CPU types so
Xen has no need to disable these bits on those systems. As per
Roger, AMD K6, Centaur and VIA chips don't have the necessary
hardware extensions to allow running PVH guests [1].

As per Toshi it is also possible for the BIOS to disable MTRR
support, in such cases get_mtrr_state() would update the MTRR
state as per the BIOS, we need to propagate this information as
well.

x86 MTRR code relies on quite a bit of checks for mtrr_if being
set to check to see if MTRRs did get set up. Instead, lets
provide a generic getter for that. This also adds a few checks
where they were not before which could potentially safeguard
ourselves against incorrect usage of MTRR where this was not
desirable.

Where possible match error codes as if MTRRs were disabled on
arch/x86/include/asm/mtrr.h.

Lastly, since disabling MTRRs can happen at run time and we
could end up with PAT enabled, best record now in our logs when
MTRRs are disabled.

[0] ~/devel/xen (git::stable-4.5)$ git describe --contains 586ab6a 4.4.0-rc1~18
[1] http://lists.xenproject.org/archives/html/xen-devel/2015-03/msg03460.html

Signed-off-by: Luis R. Rodriguez <mcgrof@suse.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Antonino Daplas <adaplas@gmail.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Dave Airlie <airlied@redhat.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Davidlohr Bueso <dbueso@suse.de>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
Cc: Juergen Gross <jgross@suse.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roger Pau Monné <roger.pau@citrix.com>
Cc: Stefan Bader <stefan.bader@canonical.com>
Cc: Suresh Siddha <sbsiddha@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
Cc: Toshi Kani <toshi.kani@hp.com>
Cc: Ville Syrjälä <syrjala@sci.fi>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: bhelgaas@google.com
Cc: david.vrabel@citrix.com
Cc: jbeulich@suse.com
Cc: konrad.wilk@oracle.com
Cc: venkatesh.pallipadi@intel.com
Cc: ville.syrjala@linux.intel.com
Cc: xen-devel@lists.xensource.com
Link: http://lkml.kernel.org/r/1426893517-2511-3-git-send-email-mcgrof@do-not-panic.com
Link: http://lkml.kernel.org/r/1432628901-18044-12-git-send-email-bp@alien8.de
Signed-off-by: Ingo Molnar <mingo@kernel.org>
  • Loading branch information
Luis R. Rodriguez authored and Ingo Molnar committed May 27, 2015
1 parent 7d010fd commit f962610
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 10 deletions.
4 changes: 3 additions & 1 deletion arch/x86/kernel/cpu/mtrr/generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ static void __init print_mtrr_state(void)
}

/* Grab all of the MTRR state for this CPU into *state */
void __init get_mtrr_state(void)
bool __init get_mtrr_state(void)
{
struct mtrr_var_range *vrs;
unsigned long flags;
Expand Down Expand Up @@ -489,6 +489,8 @@ void __init get_mtrr_state(void)

post_set();
local_irq_restore(flags);

return !!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED);
}

/* Some BIOS's are messed up and don't set all MTRRs the same! */
Expand Down
39 changes: 31 additions & 8 deletions arch/x86/kernel/cpu/mtrr/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@
#define MTRR_TO_PHYS_WC_OFFSET 1000

u32 num_var_ranges;
static bool __mtrr_enabled;

static bool mtrr_enabled(void)
{
return __mtrr_enabled;
}

unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES];
static DEFINE_MUTEX(mtrr_mutex);
Expand Down Expand Up @@ -286,7 +292,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
int i, replace, error;
mtrr_type ltype;

if (!mtrr_if)
if (!mtrr_enabled())
return -ENXIO;

error = mtrr_if->validate_add_page(base, size, type);
Expand Down Expand Up @@ -435,6 +441,8 @@ static int mtrr_check(unsigned long base, unsigned long size)
int mtrr_add(unsigned long base, unsigned long size, unsigned int type,
bool increment)
{
if (!mtrr_enabled())
return -ENODEV;
if (mtrr_check(base, size))
return -EINVAL;
return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
Expand Down Expand Up @@ -463,8 +471,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
unsigned long lbase, lsize;
int error = -EINVAL;

if (!mtrr_if)
return -ENXIO;
if (!mtrr_enabled())
return -ENODEV;

max = num_var_ranges;
/* No CPU hotplug when we change MTRR entries */
Expand Down Expand Up @@ -523,6 +531,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
*/
int mtrr_del(int reg, unsigned long base, unsigned long size)
{
if (!mtrr_enabled())
return -ENODEV;
if (mtrr_check(base, size))
return -EINVAL;
return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
Expand All @@ -548,7 +558,7 @@ int arch_phys_wc_add(unsigned long base, unsigned long size)
{
int ret;

if (pat_enabled)
if (pat_enabled || !mtrr_enabled())
return 0; /* Success! (We don't need to do anything.) */

ret = mtrr_add(base, size, MTRR_TYPE_WRCOMB, true);
Expand Down Expand Up @@ -737,21 +747,29 @@ void __init mtrr_bp_init(void)
}

if (mtrr_if) {
__mtrr_enabled = true;
set_num_var_ranges();
init_table();
if (use_intel()) {
get_mtrr_state();
/* BIOS may override */
__mtrr_enabled = get_mtrr_state();

if (mtrr_cleanup(phys_addr)) {
changed_by_mtrr_cleanup = 1;
mtrr_if->set_all();
}
}
}

if (!mtrr_enabled())
pr_info("MTRR: Disabled\n");
}

void mtrr_ap_init(void)
{
if (!mtrr_enabled())
return;

if (!use_intel() || mtrr_aps_delayed_init)
return;
/*
Expand All @@ -777,6 +795,9 @@ void mtrr_save_state(void)
{
int first_cpu;

if (!mtrr_enabled())
return;

get_online_cpus();
first_cpu = cpumask_first(cpu_online_mask);
smp_call_function_single(first_cpu, mtrr_save_fixed_ranges, NULL, 1);
Expand All @@ -785,6 +806,8 @@ void mtrr_save_state(void)

void set_mtrr_aps_delayed_init(void)
{
if (!mtrr_enabled())
return;
if (!use_intel())
return;

Expand All @@ -796,7 +819,7 @@ void set_mtrr_aps_delayed_init(void)
*/
void mtrr_aps_init(void)
{
if (!use_intel())
if (!use_intel() || !mtrr_enabled())
return;

/*
Expand All @@ -813,15 +836,15 @@ void mtrr_aps_init(void)

void mtrr_bp_restore(void)
{
if (!use_intel())
if (!use_intel() || !mtrr_enabled())
return;

mtrr_if->set_all();
}

static int __init mtrr_init_finialize(void)
{
if (!mtrr_if)
if (!mtrr_enabled())
return 0;

if (use_intel()) {
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/kernel/cpu/mtrr/mtrr.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ void set_mtrr_prepare_save(struct set_mtrr_context *ctxt);

void fill_mtrr_var_range(unsigned int index,
u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi);
void get_mtrr_state(void);
bool get_mtrr_state(void);

extern void set_mtrr_ops(const struct mtrr_ops *ops);

Expand Down

0 comments on commit f962610

Please sign in to comment.