diff options
Diffstat (limited to 'arch/x86/kernel/cpu/common.c')
| -rw-r--r-- | arch/x86/kernel/cpu/common.c | 171 |
1 files changed, 107 insertions, 64 deletions
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 1c3261cae40c..c7352827f491 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -71,6 +71,7 @@ #include <asm/traps.h> #include <asm/sev.h> #include <asm/tdx.h> +#include <asm/virt.h> #include <asm/posted_intr.h> #include <asm/runtime-const.h> @@ -95,6 +96,9 @@ EXPORT_SYMBOL(__max_dies_per_package); unsigned int __max_logical_packages __ro_after_init = 1; EXPORT_SYMBOL(__max_logical_packages); +unsigned int __num_nodes_per_package __ro_after_init = 1; +EXPORT_SYMBOL(__num_nodes_per_package); + unsigned int __num_cores_per_package __ro_after_init = 1; EXPORT_SYMBOL(__num_cores_per_package); @@ -335,16 +339,16 @@ bool cpuid_feature(void) static void squash_the_stupid_serial_number(struct cpuinfo_x86 *c) { - unsigned long lo, hi; + struct msr val; if (!cpu_has(c, X86_FEATURE_PN) || !disable_x86_serial_nr) return; /* Disable processor serial number: */ - rdmsr(MSR_IA32_BBL_CR_CTL, lo, hi); - lo |= 0x200000; - wrmsr(MSR_IA32_BBL_CR_CTL, lo, hi); + rdmsrq(MSR_IA32_BBL_CR_CTL, val.q); + val.l |= 0x200000; + wrmsrq(MSR_IA32_BBL_CR_CTL, val.q); pr_notice("CPU serial number disabled.\n"); clear_cpu_cap(c, X86_FEATURE_PN); @@ -406,31 +410,46 @@ out: cr4_clear_bits(X86_CR4_UMIP); } -static __always_inline void setup_lass(struct cpuinfo_x86 *c) +static int enable_lass(unsigned int cpu) +{ + cr4_set_bits(X86_CR4_LASS); + + return 0; +} + +/* + * Finalize features that need to be enabled just before entering + * userspace. Note that this only runs on a single CPU. Use appropriate + * callbacks if all the CPUs need to reflect the same change. + */ +static int cpu_finalize_pre_userspace(void) { if (!cpu_feature_enabled(X86_FEATURE_LASS)) - return; + return 0; - /* - * Legacy vsyscall page access causes a #GP when LASS is active. - * Disable LASS because the #GP handler doesn't support vsyscall - * emulation. - * - * Also disable LASS when running under EFI, as some runtime and - * boot services rely on 1:1 mappings in the lower half. - */ - if (IS_ENABLED(CONFIG_X86_VSYSCALL_EMULATION) || - IS_ENABLED(CONFIG_EFI)) { - setup_clear_cpu_cap(X86_FEATURE_LASS); - return; - } + /* Runs on all online CPUs and future CPUs that come online. */ + cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/lass:enable", enable_lass, NULL); - cr4_set_bits(X86_CR4_LASS); + return 0; } +late_initcall(cpu_finalize_pre_userspace); /* These bits should not change their value after CPU init is finished. */ static const unsigned long cr4_pinned_mask = X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_UMIP | - X86_CR4_FSGSBASE | X86_CR4_CET | X86_CR4_FRED; + X86_CR4_FSGSBASE | X86_CR4_CET; + +/* + * The CR pinning protects against ROP on the 'mov %reg, %CRn' instruction(s). + * Since you can ROP directly to these instructions (barring shadow stack), + * any protection must follow immediately and unconditionally after that. + * + * Specifically, the CR[04] write functions below will have the value + * validation controlled by the @cr_pinning static_branch which is + * __ro_after_init, just like the cr4_pinned_bits value. + * + * Once set, an attacker will have to defeat page-tables to get around these + * restrictions. Which is a much bigger ask than 'simple' ROP. + */ static DEFINE_STATIC_KEY_FALSE_RO(cr_pinning); static unsigned long cr4_pinned_bits __ro_after_init; @@ -923,26 +942,27 @@ void get_cpu_vendor(struct cpuinfo_x86 *c) void cpu_detect(struct cpuinfo_x86 *c) { - /* Get vendor name */ - cpuid(0x00000000, (unsigned int *)&c->cpuid_level, - (unsigned int *)&c->x86_vendor_id[0], - (unsigned int *)&c->x86_vendor_id[8], - (unsigned int *)&c->x86_vendor_id[4]); + const struct leaf_0x0_0 *l0 = cpuid_leaf(c, 0x0); + const struct leaf_0x1_0 *l1; + + c->cpuid_level = l0->max_std_leaf; + *(u32 *)&c->x86_vendor_id[0] = l0->cpu_vendorid_0; + *(u32 *)&c->x86_vendor_id[4] = l0->cpu_vendorid_1; + *(u32 *)&c->x86_vendor_id[8] = l0->cpu_vendorid_2; c->x86 = 4; - /* Intel-defined flags: level 0x00000001 */ - if (c->cpuid_level >= 0x00000001) { - u32 junk, tfms, cap0, misc; - cpuid(0x00000001, &tfms, &misc, &junk, &cap0); - c->x86 = x86_family(tfms); - c->x86_model = x86_model(tfms); - c->x86_stepping = x86_stepping(tfms); + l1 = cpuid_leaf(c, 0x1); + if (!l1) + return; - if (cap0 & (1<<19)) { - c->x86_clflush_size = ((misc >> 8) & 0xff) * 8; - c->x86_cache_alignment = c->x86_clflush_size; - } + c->x86 = cpuid_family(l1); + c->x86_model = cpuid_model(l1); + c->x86_stepping = l1->stepping; + + if (l1->clflush) { + c->x86_clflush_size = l1->clflush_size * 8; + c->x86_cache_alignment = c->x86_clflush_size; } } @@ -1232,9 +1252,6 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = { #define VULNBL_INTEL_STEPS(vfm, max_stepping, issues) \ X86_MATCH_VFM_STEPS(vfm, X86_STEP_MIN, max_stepping, issues) -#define VULNBL_INTEL_TYPE(vfm, cpu_type, issues) \ - X86_MATCH_VFM_CPU_TYPE(vfm, INTEL_CPU_TYPE_##cpu_type, issues) - #define VULNBL_AMD(family, blacklist) \ VULNBL(AMD, family, X86_MODEL_ANY, blacklist) @@ -1297,11 +1314,9 @@ static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = { VULNBL_INTEL_STEPS(INTEL_TIGERLAKE, X86_STEP_MAX, GDS | ITS | ITS_NATIVE_ONLY), VULNBL_INTEL_STEPS(INTEL_LAKEFIELD, X86_STEP_MAX, MMIO | MMIO_SBDS | RETBLEED), VULNBL_INTEL_STEPS(INTEL_ROCKETLAKE, X86_STEP_MAX, MMIO | RETBLEED | GDS | ITS | ITS_NATIVE_ONLY), - VULNBL_INTEL_TYPE(INTEL_ALDERLAKE, ATOM, RFDS | VMSCAPE), - VULNBL_INTEL_STEPS(INTEL_ALDERLAKE, X86_STEP_MAX, VMSCAPE), + VULNBL_INTEL_STEPS(INTEL_ALDERLAKE, X86_STEP_MAX, RFDS | VMSCAPE), VULNBL_INTEL_STEPS(INTEL_ALDERLAKE_L, X86_STEP_MAX, RFDS | VMSCAPE), - VULNBL_INTEL_TYPE(INTEL_RAPTORLAKE, ATOM, RFDS | VMSCAPE), - VULNBL_INTEL_STEPS(INTEL_RAPTORLAKE, X86_STEP_MAX, VMSCAPE), + VULNBL_INTEL_STEPS(INTEL_RAPTORLAKE, X86_STEP_MAX, RFDS | VMSCAPE), VULNBL_INTEL_STEPS(INTEL_RAPTORLAKE_P, X86_STEP_MAX, RFDS | VMSCAPE), VULNBL_INTEL_STEPS(INTEL_RAPTORLAKE_S, X86_STEP_MAX, RFDS | VMSCAPE), VULNBL_INTEL_STEPS(INTEL_METEORLAKE_L, X86_STEP_MAX, VMSCAPE), @@ -1369,7 +1384,21 @@ static bool __init vulnerable_to_rfds(u64 x86_arch_cap_msr) return true; /* Only consult the blacklist when there is no enumeration: */ - return cpu_matches(cpu_vuln_blacklist, RFDS); + if (!cpu_matches(cpu_vuln_blacklist, RFDS)) + return false; + + /* + * ADL and RPL are affected only if they have Atom CPUs. Hybrids have + * both Core and Atom CPUs. Mark unaffected when Atom CPUs are not + * present. + */ + if ((boot_cpu_data.x86_model == 0x97 || + boot_cpu_data.x86_model == 0xB7) && + boot_cpu_data.topo.intel_type != INTEL_CPU_TYPE_ATOM && + !boot_cpu_has(X86_FEATURE_HYBRID_CPU)) + return false; + + return true; } static bool __init vulnerable_to_its(u64 x86_arch_cap_msr) @@ -1632,7 +1661,7 @@ static inline bool parse_set_clear_cpuid(char *arg, bool set) int taint = 0; while (arg) { - bool found __maybe_unused = false; + bool found = false; unsigned int bit; opt = strsep(&arg, ","); @@ -1718,13 +1747,6 @@ static void __init cpu_parse_early_param(void) int arglen; #ifdef CONFIG_X86_32 - if (cmdline_find_option_bool(boot_command_line, "no387")) -#ifdef CONFIG_MATH_EMULATION - setup_clear_cpu_cap(X86_FEATURE_FPU); -#else - pr_err("Option 'no387' required CONFIG_MATH_EMULATION enabled.\n"); -#endif - if (cmdline_find_option_bool(boot_command_line, "nofxsr")) setup_clear_cpu_cap(X86_FEATURE_FXSR); #endif @@ -1743,7 +1765,7 @@ static void __init cpu_parse_early_param(void) /* Minimize the gap between FRED is available and available but disabled. */ arglen = cmdline_find_option(boot_command_line, "fred", arg, sizeof(arg)); - if (arglen != 2 || strncmp(arg, "on", 2)) + if (arglen == 3 && !strncmp(arg, "off", 3)) setup_clear_cpu_cap(X86_FEATURE_FRED); arglen = cmdline_find_option(boot_command_line, "clearcpuid", arg, sizeof(arg)); @@ -1772,6 +1794,7 @@ static void __init cpu_parse_early_param(void) 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; if (!cpuid_feature()) @@ -1779,6 +1802,7 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) /* cyrix could have cpuid enabled via c_identify()*/ if (cpuid_feature()) { + cpuid_scan_cpu(c); cpu_detect(c); get_cpu_vendor(c); intel_unlock_cpuid_leafs(c); @@ -1951,8 +1975,8 @@ static void generic_identify(struct cpuinfo_x86 *c) if (!cpuid_feature()) return; + cpuid_scan_cpu(c); cpu_detect(c); - get_cpu_vendor(c); intel_unlock_cpuid_leafs(c); get_cpu_cap(c); @@ -2004,6 +2028,7 @@ static void identify_cpu(struct cpuinfo_x86 *c) #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 @@ -2045,13 +2070,6 @@ static void identify_cpu(struct cpuinfo_x86 *c) setup_smep(c); setup_smap(c); setup_umip(c); - setup_lass(c); - - /* Enable FSGSBASE instructions if available. */ - if (cpu_has(c, X86_FEATURE_FSGSBASE)) { - cr4_set_bits(X86_CR4_FSGSBASE); - elf_hwcap2 |= HWCAP2_FSGSBASE; - } /* * The vendor-specific functions might have changed features. @@ -2151,6 +2169,7 @@ static __init void identify_boot_cpu(void) cpu_detect_tlb(&boot_cpu_data); setup_cr_pinning(); + x86_virt_init(); tsx_init(); tdx_init(); lkgs_init(); @@ -2227,7 +2246,7 @@ DEFINE_PER_CPU_CACHE_HOT(struct task_struct *, current_task) = &init_task; EXPORT_PER_CPU_SYMBOL(current_task); EXPORT_PER_CPU_SYMBOL(const_current_task); -DEFINE_PER_CPU_CACHE_HOT(int, __preempt_count) = INIT_PREEMPT_COUNT; +DEFINE_PER_CPU_CACHE_HOT(unsigned long, __preempt_count) = INIT_PREEMPT_COUNT; EXPORT_PER_CPU_SYMBOL(__preempt_count); DEFINE_PER_CPU_CACHE_HOT(unsigned long, cpu_current_top_of_stack) = TOP_OF_INIT_STACK; @@ -2290,8 +2309,10 @@ static inline void idt_syscall_init(void) /* May not be marked __init: used by software suspend */ void syscall_init(void) { + struct msr val = { .h = (__USER32_CS << 16) | __KERNEL_CS }; + /* The default user and kernel segments */ - wrmsr(MSR_STAR, 0, (__USER32_CS << 16) | __KERNEL_CS); + wrmsrq(MSR_STAR, val.q); /* * Except the IA32_STAR MSR, there is NO need to setup SYSCALL and @@ -2413,6 +2434,18 @@ void cpu_init_exception_handling(bool boot_cpu) /* GHCB needs to be setup to handle #VC. */ setup_ghcb(); + /* + * On CPUs with FSGSBASE support, paranoid_entry() uses + * ALTERNATIVE-patched RDGSBASE/WRGSBASE instructions. Secondary CPUs + * boot after alternatives are patched globally, so early exceptions + * execute patched code that depends on FSGSBASE. Enable the feature + * before any exceptions occur. + */ + if (cpu_feature_enabled(X86_FEATURE_FSGSBASE)) { + cr4_set_bits(X86_CR4_FSGSBASE); + elf_hwcap2 |= HWCAP2_FSGSBASE; + } + if (cpu_feature_enabled(X86_FEATURE_FRED)) { /* The boot CPU has enabled FRED during early boot */ if (!boot_cpu) @@ -2643,3 +2676,13 @@ void __init arch_cpu_finalize_init(void) */ mem_encrypt_init(); } + +/* Control TLB flushing methods */ +static int __init tlbi_setup(char *str) +{ + if (!strcmp(str, "ipi")) + setup_clear_cpu_cap(X86_FEATURE_INVLPGB); + + return 1; +} +__setup("tlbi=", tlbi_setup); |
