From nobody Sun Oct 5 03:35:08 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2F7D123D287 for ; Sat, 9 Aug 2025 09:42:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754732533; cv=none; b=KNJWvYES0sllJfdr2HPwY7rEEbUCrecKsaRSsx2nsRZF2RfdFylgGi9LbWwdvlEUf5if5DLuGJbHzKiIwKNUwCj4QN6Fl5hPLo1Kpwl9lq7Ef8bixefAOE6XDd5qoT1cdq9UWWvdTOgTNsiuuRzLN4FvnYvP8Xlh80Cabl4r1X8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754732533; c=relaxed/simple; bh=0+cTrLYGr14tJTy6mkahmdCjTBiuKiDWPh7CEnVxl1E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YpWjbiiCIUlSY9OqBeV1r8SNf9aOwzpIKufwwyrIBgx3PCIN+vf+1iDQAIjvI/p92whgqNCoOL6rz7OzDl9xAXWmfmBUIedrfl9ptuutSi5LF3p0s4Rve+wF7ukSxOtx62HusQZOkNNYsX7NiUcXfv3k/JtG1XzWeHAGOSXYgOI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=LuWGza8y; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="LuWGza8y" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 309CBC4CEF6; Sat, 9 Aug 2025 09:42:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1754732533; bh=0+cTrLYGr14tJTy6mkahmdCjTBiuKiDWPh7CEnVxl1E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LuWGza8ygyt+VSaeH9hKQbFJ3FBVM+yct6T0MUOl6SAme/pyc3GSPZZMso1M2r0De z0ybhf0FWQofS2uQ31TjDKd2Cb//MIMxl3oqYd2pfBaDcdbIkBH9Pfhmj651q22dEU +U02XepZF6tJFs5T5v+M4yAXTKfDruJ/5rmXdHxxTQvbjzZ7eKOJSm8UqusJk6ojZj 08VvHqPmujtda9Yuwv4nQDSqvVXDONGF8jbJEnIrvKGM9SXAYWNJdwXXX6NYWdjEbb rAEcAdPe4tBu9miKoWNIKrJHgsHOYpvDUX5hthzuQlW79BdQN1JaD6Qvns++iK4JiA eZdmZ94QfTj4g== From: Borislav Petkov To: X86 ML Cc: LKML , "Borislav Petkov (AMD)" Subject: [PATCH 1/2] x86/microcode: Add microcode= cmdline parsing Date: Sat, 9 Aug 2025 11:42:05 +0200 Message-ID: <20250809094206.28028-2-bp@kernel.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250809094206.28028-1-bp@kernel.org> References: <20250809094206.28028-1-bp@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Borislav Petkov (AMD)" Add a "microcode=3D" command line argument after which all options can be passed in a comma-separated list. Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Sohil Mehta --- .../admin-guide/kernel-parameters.txt | 8 +++-- arch/x86/kernel/cpu/microcode/core.c | 30 +++++++++++++++---- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentatio= n/admin-guide/kernel-parameters.txt index 747a55abf494..7c095177da85 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3767,10 +3767,12 @@ =20 mga=3D [HW,DRM] =20 - microcode.force_minrev=3D [X86] - Format: + microcode=3D [X86] Control the behavior of the microcode loader. + Available options, comma separated: + + force_minrev Enable or disable the microcode minimal revision - enforcement for the runtime microcode loader. + enforcement for the runtime microcode loader. =20 mini2440=3D [ARM,HW,KNL] Format:[0..2][b][c][t] diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/mic= rocode/core.c index b92e09a87c69..351a51861f00 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -43,10 +43,9 @@ #include "internal.h" =20 static struct microcode_ops *microcode_ops; -static bool dis_ucode_ldr =3D false; +static bool dis_ucode_ldr; =20 -bool force_minrev =3D IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV); -module_param(force_minrev, bool, S_IRUSR | S_IWUSR); +bool force_minrev =3D false; =20 /* * Synchronization. @@ -126,13 +125,34 @@ bool __init microcode_loader_disabled(void) return dis_ucode_ldr; } =20 +static void early_parse_cmdline(void) +{ + char cmd_buf[64] =3D {}; + char *s, *p =3D cmd_buf; + + if (cmdline_find_option(boot_command_line, "microcode", cmd_buf, 64) > 0)= { + while ((s =3D strsep(&p, ","))) { + if (IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV)) { + if (!strcmp("force_minrev", s)) + force_minrev =3D true; + } + + if (!strcmp(s, "dis_ucode_ldr")) + dis_ucode_ldr =3D true; + } + } + + /* old, compat option */ + if (cmdline_find_option_bool(boot_command_line, "dis_ucode_ldr") > 0) + dis_ucode_ldr =3D true; +} + void __init load_ucode_bsp(void) { unsigned int cpuid_1_eax; bool intel =3D true; =20 - if (cmdline_find_option_bool(boot_command_line, "dis_ucode_ldr") > 0) - dis_ucode_ldr =3D true; + early_parse_cmdline(); =20 if (microcode_loader_disabled()) return; --=20 2.43.0 From nobody Sun Oct 5 03:35:08 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B54AD254AE7 for ; Sat, 9 Aug 2025 09:42:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754732534; cv=none; b=TN4/Hsi32pao+wLk5A9Cim5iMv/Ok6v6SISuUkoQx6YiqPdNQZM9CXynGNCkwR2EWAACME7OjBX/0YIQGjvs0TQgVkUd1yygAXNxXbBWd5e7m96KUvyFxIHLVLgg5jnx4WEe1Re1R2CIgBjYMt2ARV25r6mTcRASHiA3+342S/U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754732534; c=relaxed/simple; bh=cnqONiHBoRrmTHioMp4RU6JIOiAF3SAi/ctEt+NRIvs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XfYm6ouAlQ35AYxCK+S7SnHhulIVf9Pye9Na0meM4rsu0b9mqYE6lz9SNF/CD1n4RTpeg2mZ+/towv2yAttPElWD6A1Ly1G6hO0tX/tia1603cQ7s6gSyPvsAw46XS22MkA8PQjCWFtb5N/8e2rUU5QIalS4nhCUmJ/W7p0zWYQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=paqOG+r0; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="paqOG+r0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 70F4AC4CEF7; Sat, 9 Aug 2025 09:42:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1754732534; bh=cnqONiHBoRrmTHioMp4RU6JIOiAF3SAi/ctEt+NRIvs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=paqOG+r0cnGf0WJTK7kaNkAzpkJiML80m0y0pvPvovPTvyvQQEHM1FhbvOVuzmneR D6dRbpiXOqKYKyKgyTcJILI5rZeW+GqORDR+VZF19HoX2C4Bw20Qo3+Lb3XB47Wakc JUnlobfjskkW1rPoBLpIZ0TN+JKH0ODY+7tCBE61qt2uhIj2uTimccz1QkGmUwIxac Tm9t0xR5oJLnriUQKSN/eAkOoqGmIWG8ExwA4CDLNLXmLaDCv3J1BqhnQXjIWOPFFk A6iK78eepeUDMnimB9b4VuDsSpkeUSvoIPunuMHGbRLjZhCP1Gbr/rjryja7JjJyT6 MZs4suMDDOIFw== From: Borislav Petkov To: X86 ML Cc: LKML , "Borislav Petkov (AMD)" Subject: [PATCH 2/2] x86/microcode: Add microcode loader debugging functionality Date: Sat, 9 Aug 2025 11:42:06 +0200 Message-ID: <20250809094206.28028-3-bp@kernel.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250809094206.28028-1-bp@kernel.org> References: <20250809094206.28028-1-bp@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Borislav Petkov (AMD)" Instead of adding ad-hoc debugging glue to the microcode loader each time I need it, add debugging functionality which is not built by default and when built-in, off by default so that it can only be enabled explicitly on the command line. Simulate all patch handling the loader does except the actual loading of the microcode patch into the hw. Signed-off-by: Borislav Petkov (AMD) --- .../admin-guide/kernel-parameters.txt | 7 ++ arch/x86/Kconfig | 12 +++ arch/x86/kernel/cpu/microcode/amd.c | 88 ++++++++++++++----- arch/x86/kernel/cpu/microcode/core.c | 25 +++++- arch/x86/kernel/cpu/microcode/internal.h | 10 +++ 5 files changed, 119 insertions(+), 23 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentatio= n/admin-guide/kernel-parameters.txt index 7c095177da85..fc002b1a9f57 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3770,6 +3770,13 @@ microcode=3D [X86] Control the behavior of the microcode loader. Available options, comma separated: =20 + dbg - Format: + enable debugging mode when run in a guest + + base_rev=3DX - with with format: + Set the base microcode revision of each thread when in + debug mode. + force_minrev Enable or disable the microcode minimal revision enforcement for the runtime microcode loader. diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 58d890fe2100..462bf03aeda5 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1360,6 +1360,18 @@ config MICROCODE_LATE_FORCE_MINREV =20 If unsure say Y. =20 +config MICROCODE_DBG + bool "Enable microcode loader debugging" + default n + depends on MICROCODE + help + Enable code which allows for debugging the microcode loader in + a guest. Meaning the patch loading is simulated but everything else + related to patch parsing and handling is done as on baremetal with + the purpose of debugging solely the software side of things. + + You almost certainly want to say n here. + config X86_MSR tristate "/dev/cpu/*/msr - Model-specific register support" help diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/micr= ocode/amd.c index 097e39327942..ced499789d64 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -249,15 +249,6 @@ static bool verify_sha256_digest(u32 patch_id, u32 cur= _rev, const u8 *data, unsi return true; } =20 -static u32 get_patch_level(void) -{ - u32 rev, dummy __always_unused; - - native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); - - return rev; -} - static union cpuid_1_eax ucode_rev_to_cpuid(unsigned int val) { union zen_patch_rev p; @@ -275,6 +266,45 @@ static union cpuid_1_eax ucode_rev_to_cpuid(unsigned i= nt val) return c; } =20 +static u32 cpuid_to_ucode_rev(unsigned int val) +{ + union zen_patch_rev p =3D {}; + union cpuid_1_eax c; + + c.full =3D val; + + p.stepping =3D c.stepping; + p.model =3D c.model; + p.ext_model =3D c.ext_model; + p.ext_fam =3D c.ext_fam; + + return p.ucode_rev; +} + +static u32 get_patch_level(void) +{ + u32 rev, dummy __always_unused; + + if (IS_ENABLED(CONFIG_MICROCODE_DBG)) { + int cpu =3D smp_processor_id(); + + if (!microcode_rev[cpu]) { + if (!base_rev) + base_rev =3D cpuid_to_ucode_rev(bsp_cpuid_1_eax); + + microcode_rev[cpu] =3D base_rev; + + ucode_dbg("CPU%d, base_rev: 0x%x\n", cpu, base_rev); + } + + return microcode_rev[cpu]; + } + + native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); + + return rev; +} + static u16 find_equiv_id(struct equiv_cpu_table *et, u32 sig) { unsigned int i; @@ -304,13 +334,13 @@ static bool verify_container(const u8 *buf, size_t bu= f_size) u32 cont_magic; =20 if (buf_size <=3D CONTAINER_HDR_SZ) { - pr_debug("Truncated microcode container header.\n"); + ucode_dbg("Truncated microcode container header.\n"); return false; } =20 cont_magic =3D *(const u32 *)buf; if (cont_magic !=3D UCODE_MAGIC) { - pr_debug("Invalid magic value (0x%08x).\n", cont_magic); + ucode_dbg("Invalid magic value (0x%08x).\n", cont_magic); return false; } =20 @@ -335,8 +365,8 @@ static bool verify_equivalence_table(const u8 *buf, siz= e_t buf_size) =20 cont_type =3D hdr[1]; if (cont_type !=3D UCODE_EQUIV_CPU_TABLE_TYPE) { - pr_debug("Wrong microcode container equivalence table type: %u.\n", - cont_type); + ucode_dbg("Wrong microcode container equivalence table type: %u.\n", + cont_type); return false; } =20 @@ -345,7 +375,7 @@ static bool verify_equivalence_table(const u8 *buf, siz= e_t buf_size) equiv_tbl_len =3D hdr[2]; if (equiv_tbl_len < sizeof(struct equiv_cpu_entry) || buf_size < equiv_tbl_len) { - pr_debug("Truncated equivalence table.\n"); + ucode_dbg("Truncated equivalence table.\n"); return false; } =20 @@ -365,7 +395,7 @@ static bool __verify_patch_section(const u8 *buf, size_= t buf_size, u32 *sh_psize const u32 *hdr; =20 if (buf_size < SECTION_HDR_SIZE) { - pr_debug("Truncated patch section.\n"); + ucode_dbg("Truncated patch section.\n"); return false; } =20 @@ -374,13 +404,13 @@ static bool __verify_patch_section(const u8 *buf, siz= e_t buf_size, u32 *sh_psize p_size =3D hdr[1]; =20 if (p_type !=3D UCODE_UCODE_TYPE) { - pr_debug("Invalid type field (0x%x) in container file section header.\n", - p_type); + ucode_dbg("Invalid type field (0x%x) in container file section header.\n= ", + p_type); return false; } =20 if (p_size < sizeof(struct microcode_header_amd)) { - pr_debug("Patch of size %u too short.\n", p_size); + ucode_dbg("Patch of size %u too short.\n", p_size); return false; } =20 @@ -457,12 +487,12 @@ static int verify_patch(const u8 *buf, size_t buf_siz= e, u32 *patch_size) * size sh_psize, as the section claims. */ if (buf_size < sh_psize) { - pr_debug("Patch of size %u truncated.\n", sh_psize); + ucode_dbg("Patch of size %u truncated.\n", sh_psize); return -1; } =20 if (!__verify_patch_size(sh_psize, buf_size)) { - pr_debug("Per-family patch size mismatch.\n"); + ucode_dbg("Per-family patch size mismatch.\n"); return -1; } =20 @@ -476,6 +506,9 @@ static int verify_patch(const u8 *buf, size_t buf_size,= u32 *patch_size) =20 proc_id =3D mc_hdr->processor_rev_id; patch_fam =3D 0xf + (proc_id >> 12); + + ucode_dbg("Patch-ID 0x%08x: family: 0x%x\n", mc_hdr->patch_id, patch_fam); + if (patch_fam !=3D family) return 1; =20 @@ -546,9 +579,14 @@ static size_t parse_container(u8 *ucode, size_t size, = struct cont_desc *desc) } =20 mc =3D (struct microcode_amd *)(buf + SECTION_HDR_SIZE); + + ucode_dbg("patch_id: 0x%x\n", mc->hdr.patch_id); + if (mc_patch_matches(mc, eq_id)) { desc->psize =3D patch_size; desc->mc =3D mc; + + ucode_dbg(" match: size: %d\n", patch_size); } =20 skip: @@ -619,8 +657,14 @@ static bool __apply_microcode_amd(struct microcode_amd= *mc, u32 *cur_rev, invlpg(p_addr_end); } =20 + if (IS_ENABLED(CONFIG_MICROCODE_DBG)) + microcode_rev[smp_processor_id()] =3D mc->hdr.patch_id; + /* verify patch application was successful */ *cur_rev =3D get_patch_level(); + + ucode_dbg("updated rev: 0x%x\n", *cur_rev); + if (*cur_rev !=3D mc->hdr.patch_id) return false; =20 @@ -1008,7 +1052,7 @@ static int verify_and_add_patch(u8 family, u8 *fw, un= signed int leftover, patch->patch_id =3D mc_hdr->patch_id; patch->equiv_cpu =3D proc_id; =20 - pr_debug("%s: Adding patch_id: 0x%08x, proc_id: 0x%04x\n", + ucode_dbg("%s: Adding patch_id: 0x%08x, proc_id: 0x%04x\n", __func__, patch->patch_id, proc_id); =20 /* ... and add to cache. */ @@ -1151,7 +1195,7 @@ static enum ucode_state request_microcode_amd(int cpu= , struct device *device) snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin= ", c->x86); =20 if (request_firmware_direct(&fw, (const char *)fw_name, device)) { - pr_debug("failed to load file %s\n", fw_name); + ucode_dbg("failed to load file %s\n", fw_name); goto out; } =20 diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/mic= rocode/core.c index 351a51861f00..3a4e210f6cf3 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -47,6 +47,18 @@ static bool dis_ucode_ldr; =20 bool force_minrev =3D false; =20 +/* + * Those below should be behind CONFIG_MICROCODE_DBG ifdeffery but in + * order to not uglify the code with ifdeffery and use IS_ENABLED() + * instead, leave them in. When microcode debugging is not enabled, + * those are meaningless anyway. + */ +/* enable loader debugging */ +bool dbg; +/* base microcode revision for debugging */ +u32 base_rev; +u32 microcode_rev[NR_CPUS] =3D {}; + /* * Synchronization. * @@ -118,7 +130,7 @@ bool __init microcode_loader_disabled(void) * overwritten. */ if (!cpuid_feature() || - native_cpuid_ecx(1) & BIT(31) || + ((native_cpuid_ecx(1) & BIT(31)) && !dbg) || amd_check_current_patch_level()) dis_ucode_ldr =3D true; =20 @@ -132,6 +144,17 @@ static void early_parse_cmdline(void) =20 if (cmdline_find_option(boot_command_line, "microcode", cmd_buf, 64) > 0)= { while ((s =3D strsep(&p, ","))) { + if (IS_ENABLED(CONFIG_MICROCODE_DBG)) { + if (!strcmp(s, "dbg")) + dbg =3D true; + + if (strstr(s, "base_rev=3D")) { + /* advance to the option arg */ + strsep(&s, "=3D"); + if (kstrtouint(s, 16, &base_rev)) { ; } + } + } + if (IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV)) { if (!strcmp("force_minrev", s)) force_minrev =3D true; diff --git a/arch/x86/kernel/cpu/microcode/internal.h b/arch/x86/kernel/cpu= /microcode/internal.h index 50a9702ae4e2..bca806dd1aac 100644 --- a/arch/x86/kernel/cpu/microcode/internal.h +++ b/arch/x86/kernel/cpu/microcode/internal.h @@ -44,6 +44,10 @@ struct early_load_data { =20 extern struct early_load_data early_data; extern struct ucode_cpu_info ucode_cpu_info[]; +extern u32 microcode_rev[NR_CPUS]; +extern u32 base_rev; +extern bool dbg; + struct cpio_data find_microcode_in_initrd(const char *path); =20 #define MAX_UCODE_COUNT 128 @@ -122,4 +126,10 @@ static inline void reload_ucode_intel(void) { } static inline struct microcode_ops *init_intel_microcode(void) { return NU= LL; } #endif /* !CONFIG_CPU_SUP_INTEL */ =20 +#define ucode_dbg(fmt, ...) \ +({ \ + if (dbg) \ + pr_info(fmt, ##__VA_ARGS__); \ +}) + #endif /* _X86_MICROCODE_INTERNAL_H */ --=20 2.43.0