aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuis R. Rodriguez <mcgrof@suse.com>2015-05-26 04:28:14 -0400
committerIngo Molnar <mingo@kernel.org>2015-05-27 08:41:01 -0400
commitf9626104a5b6815ec7d65789dfb900af5fa51e64 (patch)
treeafaf68aeaf593478bf2df8ef048b85819ee0b680
parent7d010fdf299929f9583ce5e17da629dcd83c36ef (diff)
x86/mm/mtrr: Generalize runtime disabling of MTRRs
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>
-rw-r--r--arch/x86/kernel/cpu/mtrr/generic.c4
-rw-r--r--arch/x86/kernel/cpu/mtrr/main.c39
-rw-r--r--arch/x86/kernel/cpu/mtrr/mtrr.h2
3 files changed, 35 insertions, 10 deletions
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c
index f782d9b62cb3..3b533cf37c74 100644
--- a/arch/x86/kernel/cpu/mtrr/generic.c
+++ b/arch/x86/kernel/cpu/mtrr/generic.c
@@ -445,7 +445,7 @@ static void __init print_mtrr_state(void)
445} 445}
446 446
447/* Grab all of the MTRR state for this CPU into *state */ 447/* Grab all of the MTRR state for this CPU into *state */
448void __init get_mtrr_state(void) 448bool __init get_mtrr_state(void)
449{ 449{
450 struct mtrr_var_range *vrs; 450 struct mtrr_var_range *vrs;
451 unsigned long flags; 451 unsigned long flags;
@@ -489,6 +489,8 @@ void __init get_mtrr_state(void)
489 489
490 post_set(); 490 post_set();
491 local_irq_restore(flags); 491 local_irq_restore(flags);
492
493 return !!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED);
492} 494}
493 495
494/* Some BIOS's are messed up and don't set all MTRRs the same! */ 496/* Some BIOS's are messed up and don't set all MTRRs the same! */
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
index 81baf5fee0e1..383efb26e516 100644
--- a/arch/x86/kernel/cpu/mtrr/main.c
+++ b/arch/x86/kernel/cpu/mtrr/main.c
@@ -59,6 +59,12 @@
59#define MTRR_TO_PHYS_WC_OFFSET 1000 59#define MTRR_TO_PHYS_WC_OFFSET 1000
60 60
61u32 num_var_ranges; 61u32 num_var_ranges;
62static bool __mtrr_enabled;
63
64static bool mtrr_enabled(void)
65{
66 return __mtrr_enabled;
67}
62 68
63unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES]; 69unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES];
64static DEFINE_MUTEX(mtrr_mutex); 70static DEFINE_MUTEX(mtrr_mutex);
@@ -286,7 +292,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
286 int i, replace, error; 292 int i, replace, error;
287 mtrr_type ltype; 293 mtrr_type ltype;
288 294
289 if (!mtrr_if) 295 if (!mtrr_enabled())
290 return -ENXIO; 296 return -ENXIO;
291 297
292 error = mtrr_if->validate_add_page(base, size, type); 298 error = mtrr_if->validate_add_page(base, size, type);
@@ -435,6 +441,8 @@ static int mtrr_check(unsigned long base, unsigned long size)
435int mtrr_add(unsigned long base, unsigned long size, unsigned int type, 441int mtrr_add(unsigned long base, unsigned long size, unsigned int type,
436 bool increment) 442 bool increment)
437{ 443{
444 if (!mtrr_enabled())
445 return -ENODEV;
438 if (mtrr_check(base, size)) 446 if (mtrr_check(base, size))
439 return -EINVAL; 447 return -EINVAL;
440 return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, 448 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)
463 unsigned long lbase, lsize; 471 unsigned long lbase, lsize;
464 int error = -EINVAL; 472 int error = -EINVAL;
465 473
466 if (!mtrr_if) 474 if (!mtrr_enabled())
467 return -ENXIO; 475 return -ENODEV;
468 476
469 max = num_var_ranges; 477 max = num_var_ranges;
470 /* No CPU hotplug when we change MTRR entries */ 478 /* No CPU hotplug when we change MTRR entries */
@@ -523,6 +531,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
523 */ 531 */
524int mtrr_del(int reg, unsigned long base, unsigned long size) 532int mtrr_del(int reg, unsigned long base, unsigned long size)
525{ 533{
534 if (!mtrr_enabled())
535 return -ENODEV;
526 if (mtrr_check(base, size)) 536 if (mtrr_check(base, size))
527 return -EINVAL; 537 return -EINVAL;
528 return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT); 538 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)
548{ 558{
549 int ret; 559 int ret;
550 560
551 if (pat_enabled) 561 if (pat_enabled || !mtrr_enabled())
552 return 0; /* Success! (We don't need to do anything.) */ 562 return 0; /* Success! (We don't need to do anything.) */
553 563
554 ret = mtrr_add(base, size, MTRR_TYPE_WRCOMB, true); 564 ret = mtrr_add(base, size, MTRR_TYPE_WRCOMB, true);
@@ -737,10 +747,12 @@ void __init mtrr_bp_init(void)
737 } 747 }
738 748
739 if (mtrr_if) { 749 if (mtrr_if) {
750 __mtrr_enabled = true;
740 set_num_var_ranges(); 751 set_num_var_ranges();
741 init_table(); 752 init_table();
742 if (use_intel()) { 753 if (use_intel()) {
743 get_mtrr_state(); 754 /* BIOS may override */
755 __mtrr_enabled = get_mtrr_state();
744 756
745 if (mtrr_cleanup(phys_addr)) { 757 if (mtrr_cleanup(phys_addr)) {
746 changed_by_mtrr_cleanup = 1; 758 changed_by_mtrr_cleanup = 1;
@@ -748,10 +760,16 @@ void __init mtrr_bp_init(void)
748 } 760 }
749 } 761 }
750 } 762 }
763
764 if (!mtrr_enabled())
765 pr_info("MTRR: Disabled\n");
751} 766}
752 767
753void mtrr_ap_init(void) 768void mtrr_ap_init(void)
754{ 769{
770 if (!mtrr_enabled())
771 return;
772
755 if (!use_intel() || mtrr_aps_delayed_init) 773 if (!use_intel() || mtrr_aps_delayed_init)
756 return; 774 return;
757 /* 775 /*
@@ -777,6 +795,9 @@ void mtrr_save_state(void)
777{ 795{
778 int first_cpu; 796 int first_cpu;
779 797
798 if (!mtrr_enabled())
799 return;
800
780 get_online_cpus(); 801 get_online_cpus();
781 first_cpu = cpumask_first(cpu_online_mask); 802 first_cpu = cpumask_first(cpu_online_mask);
782 smp_call_function_single(first_cpu, mtrr_save_fixed_ranges, NULL, 1); 803 smp_call_function_single(first_cpu, mtrr_save_fixed_ranges, NULL, 1);
@@ -785,6 +806,8 @@ void mtrr_save_state(void)
785 806
786void set_mtrr_aps_delayed_init(void) 807void set_mtrr_aps_delayed_init(void)
787{ 808{
809 if (!mtrr_enabled())
810 return;
788 if (!use_intel()) 811 if (!use_intel())
789 return; 812 return;
790 813
@@ -796,7 +819,7 @@ void set_mtrr_aps_delayed_init(void)
796 */ 819 */
797void mtrr_aps_init(void) 820void mtrr_aps_init(void)
798{ 821{
799 if (!use_intel()) 822 if (!use_intel() || !mtrr_enabled())
800 return; 823 return;
801 824
802 /* 825 /*
@@ -813,7 +836,7 @@ void mtrr_aps_init(void)
813 836
814void mtrr_bp_restore(void) 837void mtrr_bp_restore(void)
815{ 838{
816 if (!use_intel()) 839 if (!use_intel() || !mtrr_enabled())
817 return; 840 return;
818 841
819 mtrr_if->set_all(); 842 mtrr_if->set_all();
@@ -821,7 +844,7 @@ void mtrr_bp_restore(void)
821 844
822static int __init mtrr_init_finialize(void) 845static int __init mtrr_init_finialize(void)
823{ 846{
824 if (!mtrr_if) 847 if (!mtrr_enabled())
825 return 0; 848 return 0;
826 849
827 if (use_intel()) { 850 if (use_intel()) {
diff --git a/arch/x86/kernel/cpu/mtrr/mtrr.h b/arch/x86/kernel/cpu/mtrr/mtrr.h
index df5e41f31a27..951884dcc433 100644
--- a/arch/x86/kernel/cpu/mtrr/mtrr.h
+++ b/arch/x86/kernel/cpu/mtrr/mtrr.h
@@ -51,7 +51,7 @@ void set_mtrr_prepare_save(struct set_mtrr_context *ctxt);
51 51
52void fill_mtrr_var_range(unsigned int index, 52void fill_mtrr_var_range(unsigned int index,
53 u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi); 53 u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi);
54void get_mtrr_state(void); 54bool get_mtrr_state(void);
55 55
56extern void set_mtrr_ops(const struct mtrr_ops *ops); 56extern void set_mtrr_ops(const struct mtrr_ops *ops);
57 57