From: Maxim Levitsky <mlevitsk@redhat.com>
To: Dave Hansen <dave.hansen@intel.com>, linux-kernel@vger.kernel.org
Cc: "Chang S. Bae" <chang.seok.bae@intel.com>,
Jiri Olsa <jolsa@kernel.org>,
linux-perf-users@vger.kernel.org,
Peter Zijlstra <peterz@infradead.org>,
"H. Peter Anvin" <hpa@zytor.com>,
"David S. Miller" <davem@davemloft.net>,
Borislav Petkov <bp@alien8.de>, Kees Cook <keescook@chromium.org>,
Mark Rutland <mark.rutland@arm.com>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Namhyung Kim <namhyung@kernel.org>,
Tim Chen <tim.c.chen@linux.intel.com>,
Pawan Gupta <pawan.kumar.gupta@linux.intel.com>,
Herbert Xu <herbert@gondor.apana.org.au>,
Dave Hansen <dave.hansen@linux.intel.com>,
"maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT)"
<x86@kernel.org>, Jane Malalane <jane.malalane@citrix.com>,
Tony Luck <tony.luck@intel.com>, Ingo Molnar <mingo@redhat.com>,
Thomas Gleixner <tglx@linutronix.de>,
Arnaldo Carvalho de Melo <acme@kernel.org>,
"open list:CRYPTO API" <linux-crypto@vger.kernel.org>,
Paolo Bonzini <pbonzini@redhat.com>
Subject: Re: [PATCH 4/4] x86/cpuid: check for dependencies violations in CPUID and attempt to fix them
Date: Wed, 22 Jun 2022 20:09:20 +0300 [thread overview]
Message-ID: <70deac4c885b2bf41daecaed054f80f867ed19de.camel@redhat.com> (raw)
In-Reply-To: <c271cbf5-dfb5-c3dd-002b-9a358c90e984@intel.com>
On Wed, 2022-06-22 at 08:32 -0700, Dave Hansen wrote:
> On 6/22/22 07:48, Maxim Levitsky wrote:
> > Due to configuration bugs, sometimes a CPU feature is disabled in CPUID,
> > but not features that depend on it.
> >
> > While the above is not supported, the kernel should try to not crash,
> > and clearing the dependent cpu caps is the best way to do it.
>
> That's a rather paltry changelog.
>
> If I remember correctly, there's a crystal clear problem:
>
> If a CPU enumerates support for AVX2 but AVX via CPUID, the
> kernel crashes.
>
> There's also a follow-on problem. The kernel has all the data it needs
> to fix this, but just doesn't consult it:
>
> To make matters worse, the kernel _knows_ that this is an ill-
> advised situation: The kernel prevents itself from clearing the
> software representation of the AVX CPUID bit without also
> clearing AVX2.
>
> But, the kernel only consults this knowledge when it is clearing
> cpu_cap bits. It does not consult this information when it is
> populating those cpu_cap bits.
Yes, I agree. I'll update the changelog with something more in depth.
>
> > diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
> > index 4cc79971d2d847..c83a8f447d6aed 100644
> > --- a/arch/x86/kernel/cpu/common.c
> > +++ b/arch/x86/kernel/cpu/common.c
> > @@ -1469,7 +1469,7 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
> > this_cpu->c_early_init(c);
> >
> > c->cpu_index = 0;
> > - filter_cpuid_features(c, false);
> > + filter_cpuid_features(c, true);
> >
> > if (this_cpu->c_bsp_init)
> > this_cpu->c_bsp_init(c);
> > @@ -1757,7 +1757,7 @@ static void identify_cpu(struct cpuinfo_x86 *c)
> > */
> >
> > /* Filter out anything that depends on CPUID levels we don't have */
> > - filter_cpuid_features(c, true);
> > + filter_cpuid_features(c, false);
> >
> > /* If the model name is still unset, do table lookup. */
> > if (!c->x86_model_id[0]) {
>
> While we're at it, could we please rid ourselves of this unreadable
> mystery true/false gunk?
It is present if I understand the code correctly to avoid printing a warning twice.
It used to be 'warn' parameter, and I changed it to 'early' parameter,
inverting its boolean value, because I have seen that warning is not printed at all,
and I assumed that it is because the first early call already clears the cpuid cap
and the second call doesn't get the warning.
Now however, looking at that I think that the same will
happen with the cpuid level fitering as well, and thus we can just remove that
'warn' parameter.
>
> > diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c
> > index bcb091d02a754b..6d9c0e39851805 100644
> > --- a/arch/x86/kernel/cpu/cpuid-deps.c
> > +++ b/arch/x86/kernel/cpu/cpuid-deps.c
> > @@ -94,6 +94,11 @@ static inline void clear_feature(struct cpuinfo_x86 *c, unsigned int feature)
> > set_bit(feature, (unsigned long *)cpu_caps_cleared);
> > }
> >
> > +static inline bool test_feature(struct cpuinfo_x86 *c, unsigned int feature)
> > +{
> > + return test_bit(feature, (unsigned long *)c->x86_capability);
> > +}
> > +
> > /* Take the capabilities and the BUG bits into account */
> > #define MAX_FEATURE_BITS ((NCAPINTS + NBUGINTS) * sizeof(u32) * 8)
> >
> > @@ -127,6 +132,7 @@ void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature)
> > } while (changed);
> > }
> >
> > +
> > void setup_clear_cpu_cap(unsigned int feature)
>
> More superfluous whitespace.
Sorry about that, will check better next time.
>
> > {
> > clear_cpu_cap(&boot_cpu_data, feature);
> > @@ -137,6 +143,10 @@ void setup_clear_cpu_cap(unsigned int feature)
> > * Some CPU features depend on higher CPUID levels, which may not always
> > * be available due to CPUID level capping or broken virtualization
> > * software. Add those features to this table to auto-disable them.
> > + *
> > + * Also due to configuration bugs, some CPUID features might be present
> > + * while CPUID features that they depend on are not present,
> > + * e.g a AVX2 present but AVX is not present.
> > */
> > struct cpuid_dependent_feature {
> > u32 feature;
> > @@ -151,9 +161,10 @@ cpuid_dependent_features[] = {
> > { 0, 0 }
> > };
> >
> > -void filter_cpuid_features(struct cpuinfo_x86 *c, bool warn)
> > +void filter_cpuid_features(struct cpuinfo_x86 *c, bool early)
> > {
>
> I have at least an inkling what 'warn' could mean. But, 'early'? One
> man's 'early' is another one's 'late'.
I understand what you mean, as I said above, I will try to reproduce
the original issue of cpuid level mismatch and see if I can remove
the warn parameter at all.
>
> > const struct cpuid_dependent_feature *df;
> > + const struct cpuid_dep *d;
> >
> > for (df = cpuid_dependent_features; df->feature; df++) {
> >
> > @@ -172,10 +183,22 @@ void filter_cpuid_features(struct cpuinfo_x86 *c, bool warn)
> > continue;
> >
> > clear_cpu_cap(c, df->feature);
> > - if (!warn)
> > + if (early)
> > continue;
>
> Why is it that 'early' calls don't want warnings?
I don't know to be honest, except that I assumed that this
allows to not print the warning twice, but as I said above,
I might be able to just remove that code.
>
> > pr_warn("CPU: CPU feature " X86_CAP_FMT " disabled, no CPUID level 0x%x\n",
> > x86_cap_flag(df->feature), df->level);
> > }
> > +
> > + for (d = cpuid_deps; d->feature; d++) {
> > +
> > + if (!test_feature(c, d->feature) || test_feature(c, d->depends))
> > + continue;
> > +
> > + clear_feature(c, d->feature);
> > +
> > + pr_warn("CPU: CPU feature " X86_CAP_FMT " disabled, because it depends on "
> > + X86_CAP_FMT " which is not supported in CPUID\n",
> > + x86_cap_flag(d->feature), x86_cap_flag(d->depends));
> > + }
> > }
>
> The do_clear_cpu_cap() does this with a loop, presumably because a later
> (higher index in the array) feature in cpuid_deps[] could theoretically
> clear an earlier (lower index) feature.
Sorry this is my silly mistake. I intended to call clear_cpu_cap here,
which will if needed disable all the depedencies, so a loop doesn't
seem to be needed here.
It's not very efficient but this is only done once per vCPU so shouldn't matter.
>
> Also, is that message strictly correct? There might have been a
> clearcpuid= argument or even another dependency that ended up clearing a
> bit. It might have nothing to do with CPUID itself.
I think it should work, because clearcpuid= will end up calling clear_cpu_cap
which will disable both the requested feature and everything that depends on
it, thus filter_cpuid_features should not notice any inconsistencies.
Other way around, if the clear_cpu_cap is called before filter_cpuid_features,
it might 'fix' the inconsistency, and silence the warning but that isn't an
issue IMHO.
Thanks a lot for the review,
Best regards,
Maxim Levitsky
>
next prev parent reply other threads:[~2022-06-22 17:10 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-06-22 14:48 [PATCH 0/4] x86: cpuid: improve support for broken CPUID configurations Maxim Levitsky
2022-06-22 14:48 ` [PATCH 1/4] perf/x86/intel/lbr: use setup_clear_cpu_cap instead of clear_cpu_cap Maxim Levitsky
2022-06-22 14:58 ` Dave Hansen
2022-06-22 18:57 ` Liang, Kan
2022-06-22 19:32 ` Liang, Kan
2022-06-22 14:48 ` [PATCH 2/4] x86/cpuid: refactor setup_clear_cpu_cap/clear_feature Maxim Levitsky
2022-06-22 15:07 ` Dave Hansen
2022-06-22 15:59 ` Maxim Levitsky
2022-06-22 14:48 ` [PATCH 3/4] x86/cpuid: move filter_cpuid_features to cpuid-deps.c Maxim Levitsky
2022-06-22 15:07 ` Dave Hansen
2022-06-22 16:01 ` Maxim Levitsky
2022-06-22 14:48 ` [PATCH 4/4] x86/cpuid: check for dependencies violations in CPUID and attempt to fix them Maxim Levitsky
2022-06-22 15:32 ` Dave Hansen
2022-06-22 17:09 ` Maxim Levitsky [this message]
2022-06-22 17:18 ` Dave Hansen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=70deac4c885b2bf41daecaed054f80f867ed19de.camel@redhat.com \
--to=mlevitsk@redhat.com \
--cc=acme@kernel.org \
--cc=alexander.shishkin@linux.intel.com \
--cc=bp@alien8.de \
--cc=chang.seok.bae@intel.com \
--cc=dave.hansen@intel.com \
--cc=dave.hansen@linux.intel.com \
--cc=davem@davemloft.net \
--cc=herbert@gondor.apana.org.au \
--cc=hpa@zytor.com \
--cc=jane.malalane@citrix.com \
--cc=jolsa@kernel.org \
--cc=keescook@chromium.org \
--cc=linux-crypto@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mingo@redhat.com \
--cc=namhyung@kernel.org \
--cc=pawan.kumar.gupta@linux.intel.com \
--cc=pbonzini@redhat.com \
--cc=peterz@infradead.org \
--cc=tglx@linutronix.de \
--cc=tim.c.chen@linux.intel.com \
--cc=tony.luck@intel.com \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox