mirror of
https://github.com/torvalds/linux.git
synced 2026-10-23 23:51:02 +02:00
- Rework early CPU features detection code to handle a case where recorded
CPU capabilities are temporarily cleared in an interruptible region. The practical implication of this lead to, for example, KASAN complaining due to 5-level pagetable support disappearing intermittently; by Ihor Solodrai - AMD Zen5 started reporting TLB sizes as multiples of 32 so adjust the TLB sizes reporting code to consider that - Return the proper retval when trying to enable user shadow stacks -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEzv7L6UO9uDPlPSfHEsHwGGHeVUoFAmrW4dsACgkQEsHwGGHe VUqz6g//Rq7VGkkJDJi/mJayrTOaaC9relkWPENz52uY2L9WMO+JEbMCMZZy1qaZ E62uAJgE1KJC+CBQma/ZqkzPUSUFMEdqyY6rlOAxbr1FBeQoo/r44u0Sg2m8apbd pXqJs1vVZeT6/QWr54f4bcIcPhKdAjk6n4JmMFsTUiRFQ/9QhzjI31fshE0Ay3OM 2RrHTwUIZFtnKCiKg8BH5L8rv9gIupHwRBeF9gu8H7sXkVbzjlm+90hypmaKN0hB A/pExvfN+7t/8aLZFSJbjMzdih0OZfkNGeLr5BZAOMO9UmvSBbZD9QfedbqGcb5t VcKAK4ulKwdKH2anI69ddzMwMFsca6EzuorNRXjtpT7TFC62hBiVJ6/9AX9gcNQ9 2G09wfcb6Pf4UndHJMYtb/BeWJ7b6Ar75jGktlm64LTwkdnLPELcJH4DUHCsWk4i /rvstNOinhTDr2dZ3P4TcwaoTcUwYCmfP0l6m1Eg7j5d4g1JDyiIN1wqfZlH735c 1zlP/Kt7A52qOdms/9fCKvMYt+S20qxZuUgZJM/aBtXPNVd89iVwDmC303Xx6Ko3 bKGi50SbrTxakKb1APLOK+NtUEboUz4Lgm3R7dAjoRopiJtr5qWX3PdCXSekix82 tuW/x5EHTidrtZhr55Cwk9/lJ9wrsnzlP6nwEwc9iruT99ph33c= =jQ60 -----END PGP SIGNATURE----- Merge tag 'x86_cpu_for_v7.4_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull x86 cpu feature updates from Borislav Petkov: - Rework early CPU features detection code to handle a case where recorded CPU capabilities are temporarily cleared in an interruptible region. The practical implication of this lead to, for example, KASAN complaining due to 5-level pagetable support disappearing intermittently (Ihor Solodrai) - AMD Zen5 started reporting TLB sizes as multiples of 32 so adjust the TLB sizes reporting code to consider that - Return the proper retval when trying to enable user shadow stacks * tag 'x86_cpu_for_v7.4_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/cpu: Don't transiently clear the boot CPU's capabilities x86/cpu: Move 32-bit SEP setup into identify_cpu() x86/cpu: Inline generic_identify() into identify_cpu() x86/cpu: Initialize boot CPU cpuinfo defaults early x86/cpu: Factor init_cpu_info() out of identify_cpu() x86/CPU/AMD: Fix Zen5 TLB sizes reporting x86/shstk: Return the correct error value when user shadow stacks are disabled
This commit is contained in:
commit
42e6e6a6ff
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user