diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index e713b5818c25..116a34908519 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -486,6 +486,8 @@ #define X86_FEATURE_AUTOIBRS (20*32+ 8) /* Automatic IBRS */ #define X86_FEATURE_NO_SMM_CTL_MSR (20*32+ 9) /* SMM_CTL MSR is not present */ +#define X86_FEATURE_L2_TLB_SIZE_X32 (20*32+14) /* L2 TLB sizes are encoded as multiples of 32 */ + #define X86_FEATURE_GP_ON_USER_CPUID (20*32+17) /* User CPUID faulting */ #define X86_FEATURE_PREFETCHI (20*32+20) /* Prefetch Data/Instruction to Cache Level */ diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 40463bad1078..3972966cb023 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -1196,7 +1196,7 @@ static unsigned int amd_size_cache(struct cpuinfo_x86 *c, unsigned int size) static void cpu_detect_tlb_amd(struct cpuinfo_x86 *c) { - u32 ebx, eax, ecx, edx; + u32 ebx, eax, ecx, edx, shift, tmp; u16 mask = 0xfff; if (c->x86 < 0xf) @@ -1205,10 +1205,12 @@ static void cpu_detect_tlb_amd(struct cpuinfo_x86 *c) if (c->extended_cpuid_level < 0x80000006) return; + shift = !!cpu_has(c, X86_FEATURE_L2_TLB_SIZE_X32) * 5; + cpuid(0x80000006, &eax, &ebx, &ecx, &edx); - tlb_lld_4k = (ebx >> 16) & mask; - tlb_lli_4k = ebx & mask; + tlb_lld_4k = ((ebx >> 16) & mask) << shift; + tlb_lli_4k = (ebx & mask) << shift; /* * K8 doesn't have 2M/4M entries in the L2 TLB so read out the L1 TLB @@ -1220,16 +1222,18 @@ static void cpu_detect_tlb_amd(struct cpuinfo_x86 *c) } /* Handle DTLB 2M and 4M sizes, fall back to L1 if L2 is disabled */ - if (!((eax >> 16) & mask)) + tmp = ((eax >> 16) & mask) << shift; + if (!tmp) tlb_lld_2m = (cpuid_eax(0x80000005) >> 16) & 0xff; else - tlb_lld_2m = (eax >> 16) & mask; + tlb_lld_2m = tmp; /* a 4M entry uses two 2M entries */ tlb_lld_4m = tlb_lld_2m >> 1; /* Handle ITLB 2M and 4M sizes, fall back to L1 if L2 is disabled */ - if (!(eax & mask)) { + tmp = (eax & mask) << shift; + if (!tmp) { /* Erratum 658 */ if (c->x86 == 0x15 && c->x86_model <= 0x1f) { tlb_lli_2m = 1024; @@ -1237,8 +1241,9 @@ static void cpu_detect_tlb_amd(struct cpuinfo_x86 *c) cpuid(0x80000005, &eax, &ebx, &ecx, &edx); tlb_lli_2m = eax & 0xff; } - } else - tlb_lli_2m = eax & mask; + } else { + tlb_lli_2m = tmp; + } tlb_lli_4m = tlb_lli_2m >> 1; diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 593ca8ce3894..7d0b9bdc64cc 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -857,7 +857,7 @@ static void get_model_name(struct cpuinfo_x86 *c) void cpu_detect_cache_sizes(struct cpuinfo_x86 *c) { - unsigned int n, dummy, ebx, ecx, edx, l2size; + unsigned int n, dummy, ebx, ecx, edx, l2size, shift __maybe_unused; n = c->extended_cpuid_level; @@ -877,7 +877,9 @@ void cpu_detect_cache_sizes(struct cpuinfo_x86 *c) l2size = ecx >> 16; #ifdef CONFIG_X86_64 + shift = !!cpu_has(c, X86_FEATURE_L2_TLB_SIZE_X32) * 5; c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff); + c->x86_tlbsize <<= shift; #else /* do processor-specific cache resizing */ if (this_cpu->legacy_cache_size) @@ -1782,25 +1784,50 @@ static void __init cpu_parse_early_param(void) } } +static void init_cpu_info(struct cpuinfo_x86 *c) +{ + c->x86_cache_size = 0; + c->x86_vendor = X86_VENDOR_UNKNOWN; + c->x86_model = c->x86_stepping = 0; /* So far unknown... */ + c->x86_vendor_id[0] = '\0'; /* Unset */ + c->x86_model_id[0] = '\0'; /* Unset */ +#ifdef CONFIG_X86_64 + c->x86_clflush_size = 64; + c->x86_phys_bits = 36; + c->x86_virt_bits = 48; +#else + c->cpuid_level = -1; /* CPUID not detected */ + c->x86_clflush_size = 32; + c->x86_phys_bits = 32; + c->x86_virt_bits = 32; +#endif + c->x86_cache_alignment = c->x86_clflush_size; + memset(&c->x86_capability, 0, sizeof(c->x86_capability)); + memset(&c->cpuid, 0, sizeof(c->cpuid)); +#ifdef CONFIG_X86_VMX_FEATURE_NAMES + memset(&c->vmx_capability, 0, sizeof(c->vmx_capability)); +#endif + c->extended_cpuid_level = 0; +} + /* * Do minimum CPU detection early. * Fields really needed: vendor, cpuid_level, family, model, mask, * cache alignment. - * The others are not touched to avoid unwanted side effects. + * The others are reset to their defaults here and only filled in later, + * by identify_cpu(). * * WARNING: this function is only called on the boot CPU. Don't add code * here that is supposed to run on all CPUs. */ static void __init early_identify_cpu(struct cpuinfo_x86 *c) { - memset(&c->x86_capability, 0, sizeof(c->x86_capability)); - memset(&c->cpuid, 0, sizeof(c->cpuid)); - c->extended_cpuid_level = 0; + init_cpu_info(c); if (!cpuid_feature()) identify_cpu_without_cpuid(c); - /* cyrix could have cpuid enabled via c_identify()*/ + /* Cyrix could have CPUID enabled via c_identify(). */ if (cpuid_feature()) { cpuid_scan_cpu(c); cpu_detect(c); @@ -1964,16 +1991,21 @@ void check_null_seg_clears_base(struct cpuinfo_x86 *c) set_cpu_bug(c, X86_BUG_NULL_SEG); } -static void generic_identify(struct cpuinfo_x86 *c) +/* + * This does the hard work of actually picking apart the CPU stuff... + */ +static void identify_cpu(struct cpuinfo_x86 *c) { - c->extended_cpuid_level = 0; + int i; + + c->loops_per_jiffy = loops_per_jiffy; if (!cpuid_feature()) identify_cpu_without_cpuid(c); - /* cyrix could have cpuid enabled via c_identify()*/ + /* Cyrix could have CPUID enabled via c_identify(). */ if (!cpuid_feature()) - return; + goto no_cpuid; cpuid_scan_cpu(c); cpu_detect(c); @@ -2001,40 +2033,8 @@ static void generic_identify(struct cpuinfo_x86 *c) #ifdef CONFIG_X86_32 set_cpu_bug(c, X86_BUG_ESPFIX); #endif -} - -/* - * This does the hard work of actually picking apart the CPU stuff... - */ -static void identify_cpu(struct cpuinfo_x86 *c) -{ - int i; - - c->loops_per_jiffy = loops_per_jiffy; - c->x86_cache_size = 0; - c->x86_vendor = X86_VENDOR_UNKNOWN; - c->x86_model = c->x86_stepping = 0; /* So far unknown... */ - c->x86_vendor_id[0] = '\0'; /* Unset */ - c->x86_model_id[0] = '\0'; /* Unset */ -#ifdef CONFIG_X86_64 - c->x86_clflush_size = 64; - c->x86_phys_bits = 36; - c->x86_virt_bits = 48; -#else - c->cpuid_level = -1; /* CPUID not detected */ - c->x86_clflush_size = 32; - c->x86_phys_bits = 32; - c->x86_virt_bits = 32; -#endif - c->x86_cache_alignment = c->x86_clflush_size; - memset(&c->x86_capability, 0, sizeof(c->x86_capability)); - memset(&c->cpuid, 0, sizeof(c->cpuid)); -#ifdef CONFIG_X86_VMX_FEATURE_NAMES - memset(&c->vmx_capability, 0, sizeof(c->vmx_capability)); -#endif - - generic_identify(c); +no_cpuid: cpu_parse_topology(c); if (this_cpu->c_identify) @@ -2126,6 +2126,9 @@ static void identify_cpu(struct cpuinfo_x86 *c) mcheck_cpu_init(c); numa_add_cpu(smp_processor_id()); + + if (IS_ENABLED(CONFIG_X86_32)) + enable_sep_cpu(); } /* @@ -2163,9 +2166,6 @@ static __init void identify_boot_cpu(void) identify_cpu(&boot_cpu_data); if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT)) pr_info("CET detected: Indirect Branch Tracking enabled\n"); -#ifdef CONFIG_X86_32 - enable_sep_cpu(); -#endif cpu_detect_tlb(&boot_cpu_data); setup_cr_pinning(); @@ -2184,10 +2184,8 @@ void identify_secondary_cpu(unsigned int cpu) *c = boot_cpu_data; c->cpu_index = cpu; + init_cpu_info(c); identify_cpu(c); -#ifdef CONFIG_X86_32 - enable_sep_cpu(); -#endif x86_spec_ctrl_setup_ap(); update_srbds_msr(); if (boot_cpu_has_bug(X86_BUG_GDS)) diff --git a/arch/x86/kernel/shstk.c b/arch/x86/kernel/shstk.c index 0ca64900192f..eb690ba90180 100644 --- a/arch/x86/kernel/shstk.c +++ b/arch/x86/kernel/shstk.c @@ -490,7 +490,7 @@ static int wrss_control(bool enable) * when disabling. */ if (!features_enabled(ARCH_SHSTK_SHSTK)) - return -EPERM; + return -EINVAL; /* Already enabled/disabled? */ if (features_enabled(ARCH_SHSTK_WRSS) == enable)