- 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:
Linus Torvalds 2026-10-20 10:38:57 -10:00
commit 42e6e6a6ff
4 changed files with 63 additions and 58 deletions

View File

@ -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 */

View File

@ -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;

View File

@ -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))

View File

@ -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)