[RFC][PATCH 28/34] x86/cpu: Return sane defaults for early x86_config reads

From: Dave Hansen
Date: Thu Feb 22 2024 - 13:50:40 EST



From: Dave Hansen <dave.hansen@xxxxxxxxxxxxxxx>

*If* an unexpected user tries to read 'x86_config' before it is
C_FINALIZED and valid, it will likely get 0's or other garbage.
Those values often cause the user to crash before they can get
a nice message out to the console.

Provide some mostly random but unlikely-to-crash-the-caller
values.

Signed-off-by: Dave Hansen <dave.hansen@xxxxxxxxxxxxxxx>
---

b/arch/x86/include/asm/processor.h | 32 ++++++++++++++++++++++++++------
1 file changed, 26 insertions(+), 6 deletions(-)

diff -puN arch/x86/include/asm/processor.h~x86_config-defaults arch/x86/include/asm/processor.h
--- a/arch/x86/include/asm/processor.h~x86_config-defaults 2024-02-22 10:09:02.280995903 -0800
+++ b/arch/x86/include/asm/processor.h 2024-02-22 10:09:02.280995903 -0800
@@ -813,37 +813,57 @@ static inline void weak_wrmsr_fence(void
alternative("mfence; lfence", "", ALT_NOT(X86_FEATURE_APIC_MSRS_FENCE));
}

-static inline void read_x86_config(void)
+static inline int read_x86_config(void)
{
if (x86_config.conf_state == C_FINALIZED)
- return;
+ return 0;

/* Only record the first one: */
if (!x86_config.early_reader)
x86_config.early_reader = __builtin_return_address(0);
+
+ return -EINVAL;
}

+/*
+ * These _should_ not be called until x86_config is C_FINALIZED.
+ * In the case that they are, two things will happen:
+ * 1. The first caller will get the call site recorded in
+ * 'early_reader' which will trigger a warning later in
+ * boot.
+ * 2. A moderately sane hard-coded default value will be provided.
+ * The entire intent of this value is to let things limp along
+ * until the warning can spit out.
+ */
static inline u8 x86_phys_bits(void)
{
- read_x86_config();
+ if (read_x86_config())
+ return 52;
+
return x86_config.phys_bits;
}

static inline u8 x86_virt_bits(void)
{
- read_x86_config();
+ if (read_x86_config())
+ return IS_ENABLED(CONFIG_X86_64) ? 57 : 32;
+
return x86_config.virt_bits;
}

static inline u8 x86_cache_bits(void)
{
- read_x86_config();
+ if (read_x86_config())
+ return 52;
+
return x86_config.cache_bits;
}

static inline u8 x86_clflush_size(void)
{
- read_x86_config();
+ if (read_x86_config())
+ return 64;
+
return x86_config.clflush_size;
}

_