x86/mm/mtrr: Generalize runtime disabling of MTRRs
authorLuis R. Rodriguez <mcgrof@suse.com>
Tue, 26 May 2015 08:28:14 +0000 (10:28 +0200)
committerIngo Molnar <mingo@kernel.org>
Wed, 27 May 2015 12:41:01 +0000 (14:41 +0200)
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

  47591df50512 ("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>
arch/x86/kernel/cpu/mtrr/generic.c
arch/x86/kernel/cpu/mtrr/main.c
arch/x86/kernel/cpu/mtrr/mtrr.h

index f782d9b62cb3e0c1125cd1f0ceae45cb8ccb8510..3b533cf37c745c9ecfc81fc5fde94bc46f84e1b5 100644 (file)
@@ -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;
@@ -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! */
index 81baf5fee0e17417286c9de4c9dabf9117842091..383efb26e5162b54f1a65db90ff554a7939caaf1 100644 (file)
 #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);
@@ -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);
@@ -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,
@@ -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 */
@@ -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);
@@ -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);
@@ -737,10 +747,12 @@ 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;
@@ -748,10 +760,16 @@ void __init mtrr_bp_init(void)
                        }
                }
        }
+
+       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;
        /*
@@ -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);
@@ -785,6 +806,8 @@ void mtrr_save_state(void)
 
 void set_mtrr_aps_delayed_init(void)
 {
+       if (!mtrr_enabled())
+               return;
        if (!use_intel())
                return;
 
@@ -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;
 
        /*
@@ -813,7 +836,7 @@ void mtrr_aps_init(void)
 
 void mtrr_bp_restore(void)
 {
-       if (!use_intel())
+       if (!use_intel() || !mtrr_enabled())
                return;
 
        mtrr_if->set_all();
@@ -821,7 +844,7 @@ void mtrr_bp_restore(void)
 
 static int __init mtrr_init_finialize(void)
 {
-       if (!mtrr_if)
+       if (!mtrr_enabled())
                return 0;
 
        if (use_intel()) {
index df5e41f31a27e71cd44aadd35cf43f311b437008..951884dcc43354573c2bd234aed3fd3adb067a84 100644 (file)
@@ -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);