[PATCH 2/2] x86/cpu: Skip reading MSR_IA32_PLATFORM_ID in virtualized environment

Binbin Wu
2026-04-28T02:43:51Z

The Linux kernel now reads MSR_IA32_PLATFORM_ID during CPU init. When
running as a guest, if the underlying hypervisor does not emulate the
MSR, the RDMSR from 0x17 in intel_get_platform_id() can trigger an
unchecked MSR access during early boot.

unchecked MSR access error: RDMSR from 0x17 at rIP: 0xffffffffba38d6fc (intel_get_platform_id+0x7c/0xb0)
Call Trace:
<TASK>
? early_init_intel+0x28/0x2c0
? early_cpu_init+0x9b/0x930
? setup_arch+0xbf/0xbb0
? _printk+0x6b/0x90
? start_kernel+0x7f/0xaa0
? x86_64_start_reservations+0x24/0x30
? x86_64_start_kernel+0xda/0xe0
? common_startup_64+0x13e/0x141
</TASK>

Currently, KVM does not support guest reads of MSR_IA32_PLATFORM_ID for
TDX. This should be fixed in the hypervisor, but for compatibility with
newer guests running on older KVM hosts, skip reading MSR_IA32_PLATFORM_ID
and return 0. It's meaningless to read MSR_IA32_PLATFORM_ID since guests
are not allowed to do microcode update. cpu_has_old_microcode(), which
uses platform ID for CPU match, also skips checking whether the microcode
is old or not in a virtualized environment.

Since intel_get_platform_id() can be called early before cpuinfo_x86
is fully initialized, check whether it's running in a virtualized
environment from CPUID and opportunistically add a helper.

Fixes: d8630b67ca1ed ("x86/cpu: Add platform ID to CPU info structure")
Reported-by: Vishal Verma <vishal.l.verma@intel.com>
Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
---
arch/x86/kernel/cpu/microcode/core.c | 2 +-
arch/x86/kernel/cpu/microcode/intel.c | 4 ++++
arch/x86/kernel/cpu/microcode/internal.h | 5 +++++
3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index 651202e6fefb..ee204c8a90bf 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -135,7 +135,7 @@ bool __init microcode_loader_disabled(void)
* 3) Certain AMD patch levels are not allowed to be
* overwritten.
*/
- hypervisor_present = native_cpuid_ecx(1) & BIT(31);
+ hypervisor_present = x86_cpuid_has_hypervisor();

if ((hypervisor_present && !IS_ENABLED(CONFIG_MICROCODE_DBG)) ||
amd_check_current_patch_level())
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index 37ac4afe0972..cb93e4ea410e 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -147,6 +147,10 @@ u32 intel_get_platform_id(void)
if (intel_cpuid_vfm() <= INTEL_PENTIUM_II_KLAMATH)
return 0;

+ /* Don't try to read microcode bits when virtualized. */
+ if (x86_cpuid_has_hypervisor())
+ return 0;
+
/* get processor flags from MSR 0x17 */
native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);

diff --git a/arch/x86/kernel/cpu/microcode/internal.h b/arch/x86/kernel/cpu/microcode/internal.h
index 3b93c0676b4f..0233e074d76b 100644
--- a/arch/x86/kernel/cpu/microcode/internal.h
+++ b/arch/x86/kernel/cpu/microcode/internal.h
@@ -100,6 +100,11 @@ static inline unsigned int x86_cpuid_family(void)
return x86_family(eax);
}

+static inline bool x86_cpuid_has_hypervisor(void)
+{
+ return native_cpuid_ecx(1) & BIT(31);
+}
+
extern bool force_minrev;

#ifdef CONFIG_CPU_SUP_AMD
--
2.46.0