x86/mtrr: Replace vendor tests in MTRR code
authorJuergen Gross <jgross@suse.com>
Tue, 2 May 2023 12:09:21 +0000 (14:09 +0200)
committerBorislav Petkov (AMD) <bp@alien8.de>
Thu, 1 Jun 2023 13:04:32 +0000 (15:04 +0200)
Modern CPUs all share the same MTRR interface implemented via
generic_mtrr_ops.

At several places in MTRR code this generic interface is deduced via
is_cpu(INTEL) tests, which is only working due to X86_VENDOR_INTEL
being 0 (the is_cpu() macro is testing mtrr_if->vendor, which isn't
explicitly set in generic_mtrr_ops).

Test the generic CPU feature X86_FEATURE_MTRR instead.

The only other place where the .vendor member of struct mtrr_ops is
being used is in set_num_var_ranges(), where depending on the vendor
the number of MTRR registers is determined. This can easily be changed
by replacing .vendor with the static number of MTRR registers.

It should be noted that the test "is_cpu(HYGON)" wasn't ever returning
true, as there is no struct mtrr_ops with that vendor information.

[ bp: Use mtrr_enabled() before doing mtrr_if-> accesses, esp. in
  mtrr_trim_uncached_memory() which gets called independently from
  whether mtrr_if is set or not. ]

Signed-off-by: Juergen Gross <jgross@suse.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/r/20230502120931.20719-7-jgross@suse.com
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
arch/x86/kernel/cpu/mtrr/amd.c
arch/x86/kernel/cpu/mtrr/centaur.c
arch/x86/kernel/cpu/mtrr/cleanup.c
arch/x86/kernel/cpu/mtrr/cyrix.c
arch/x86/kernel/cpu/mtrr/generic.c
arch/x86/kernel/cpu/mtrr/mtrr.c
arch/x86/kernel/cpu/mtrr/mtrr.h

index eff6ac62c0ff41586a7d36e30b09dfdf6d56ead1..ef3e8e42b7820ea5c7746f25b4bcec70f57e5f9d 100644 (file)
@@ -110,7 +110,7 @@ amd_validate_add_page(unsigned long base, unsigned long size, unsigned int type)
 }
 
 const struct mtrr_ops amd_mtrr_ops = {
-       .vendor            = X86_VENDOR_AMD,
+       .var_regs          = 2,
        .set               = amd_set_mtrr,
        .get               = amd_get_mtrr,
        .get_free_region   = generic_get_free_region,
index b8a74eddde83b0eda80f0ce090f75422dcb88f02..4466ddeb0125844bd26761f37b43e32fb2f81760 100644 (file)
@@ -112,7 +112,7 @@ centaur_validate_add_page(unsigned long base, unsigned long size, unsigned int t
 }
 
 const struct mtrr_ops centaur_mtrr_ops = {
-       .vendor            = X86_VENDOR_CENTAUR,
+       .var_regs          = 8,
        .set               = centaur_set_mcr,
        .get               = centaur_get_mcr,
        .get_free_region   = centaur_get_free_region,
index ca2d567e729e22b04fc23268019d973b3311f71a..ed5f84c20ac2d25057b1f86bff2d68c34d22f39e 100644 (file)
@@ -689,7 +689,10 @@ int __init mtrr_cleanup(void)
        int index_good;
        int i;
 
-       if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1)
+       if (!mtrr_enabled())
+               return 0;
+
+       if (!cpu_feature_enabled(X86_FEATURE_MTRR) || enable_mtrr_cleanup < 1)
                return 0;
 
        rdmsr(MSR_MTRRdefType, def, dummy);
@@ -882,11 +885,14 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
        /* extra one for all 0 */
        int num[MTRR_NUM_TYPES + 1];
 
+       if (!mtrr_enabled())
+               return 0;
+
        /*
         * Make sure we only trim uncachable memory on machines that
         * support the Intel MTRR architecture:
         */
-       if (!is_cpu(INTEL) || disable_mtrr_trim)
+       if (!cpu_feature_enabled(X86_FEATURE_MTRR) || disable_mtrr_trim)
                return 0;
 
        rdmsr(MSR_MTRRdefType, def, dummy);
index 173b9e01e6231da0831cfed0580fcbf2957e57b8..238dad57d4d6bc9f34184bbc16f950dd87a8f03e 100644 (file)
@@ -235,7 +235,7 @@ static void cyrix_set_arr(unsigned int reg, unsigned long base,
 }
 
 const struct mtrr_ops cyrix_mtrr_ops = {
-       .vendor            = X86_VENDOR_CYRIX,
+       .var_regs          = 8,
        .set               = cyrix_set_arr,
        .get               = cyrix_get_arr,
        .get_free_region   = cyrix_get_free_region,
index e81d832475a1fdbfa9963ea3146923284cc8ebf1..4d8ca6234bbf848be4e090263f77c2c536f52567 100644 (file)
@@ -843,7 +843,7 @@ int generic_validate_add_page(unsigned long base, unsigned long size,
         * For Intel PPro stepping <= 7
         * must be 4 MiB aligned and not touch 0x70000000 -> 0x7003FFFF
         */
-       if (is_cpu(INTEL) && boot_cpu_data.x86 == 6 &&
+       if (mtrr_if == &generic_mtrr_ops && boot_cpu_data.x86 == 6 &&
            boot_cpu_data.x86_model == 1 &&
            boot_cpu_data.x86_stepping <= 7) {
                if (base & ((1 << (22 - PAGE_SHIFT)) - 1)) {
index be35a0b09604d1549b73dad91b9e5d3dea070235..85113af353938107751b20ff7675bf81c1aeaf24 100644 (file)
 #define MTRR_TO_PHYS_WC_OFFSET 1000
 
 u32 num_var_ranges;
-static bool mtrr_enabled(void)
-{
-       return !!mtrr_if;
-}
 
 unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES];
 static DEFINE_MUTEX(mtrr_mutex);
@@ -103,21 +99,6 @@ static int have_wrcomb(void)
        return mtrr_if->have_wrcomb ? mtrr_if->have_wrcomb() : 0;
 }
 
-/*  This function returns the number of variable MTRRs  */
-static void __init set_num_var_ranges(bool use_generic)
-{
-       unsigned long config = 0, dummy;
-
-       if (use_generic)
-               rdmsr(MSR_MTRRcap, config, dummy);
-       else if (is_cpu(AMD) || is_cpu(HYGON))
-               config = 2;
-       else if (is_cpu(CYRIX) || is_cpu(CENTAUR))
-               config = 8;
-
-       num_var_ranges = config & MTRR_CAP_VCNT;
-}
-
 static void __init init_table(void)
 {
        int i, max;
@@ -627,6 +608,7 @@ void __init mtrr_bp_init(void)
 {
        bool generic_mtrrs = cpu_feature_enabled(X86_FEATURE_MTRR);
        const char *why = "(not available)";
+       unsigned long config, dummy;
 
        phys_hi_rsvd = GENMASK(31, boot_cpu_data.x86_phys_bits - 32);
 
@@ -664,7 +646,13 @@ void __init mtrr_bp_init(void)
        }
 
        if (mtrr_enabled()) {
-               set_num_var_ranges(mtrr_if == &generic_mtrr_ops);
+               /* Get the number of variable MTRR ranges. */
+               if (mtrr_if == &generic_mtrr_ops)
+                       rdmsr(MSR_MTRRcap, config, dummy);
+               else
+                       config = mtrr_if->var_regs;
+               num_var_ranges = config & MTRR_CAP_VCNT;
+
                init_table();
                if (mtrr_if == &generic_mtrr_ops) {
                        /* BIOS may override */
index 59e8fb26bf9dddbf80ef53b1552ebc8de348cb96..6f3312be4b277df2ebe1bc0cd533b4c8a5ee3926 100644 (file)
@@ -13,7 +13,7 @@
 extern unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES];
 
 struct mtrr_ops {
-       u32     vendor;
+       u32     var_regs;
        void    (*set)(unsigned int reg, unsigned long base,
                       unsigned long size, mtrr_type type);
        void    (*get)(unsigned int reg, unsigned long *base,
@@ -53,8 +53,6 @@ bool get_mtrr_state(void);
 
 extern const struct mtrr_ops *mtrr_if;
 
-#define is_cpu(vnd)    (mtrr_if && mtrr_if->vendor == X86_VENDOR_##vnd)
-
 extern unsigned int num_var_ranges;
 extern u64 mtrr_tom2;
 extern struct mtrr_state_type mtrr_state;
@@ -71,3 +69,13 @@ extern const struct mtrr_ops centaur_mtrr_ops;
 
 extern int changed_by_mtrr_cleanup;
 extern int mtrr_cleanup(void);
+void generic_rebuild_map(void);
+
+/*
+ * Must be used by code which uses mtrr_if to call platform-specific
+ * MTRR manipulation functions.
+ */
+static inline bool mtrr_enabled(void)
+{
+       return !!mtrr_if;
+}