| From c809b0d0e52d01c30066367b2952c4c4186b1047 Mon Sep 17 00:00:00 2001 |
| From: "Borislav Petkov (AMD)" <bp@alien8.de> |
| Date: Tue, 19 Nov 2024 12:21:33 +0100 |
| Subject: x86/microcode/AMD: Flush patch buffer mapping after application |
| |
| From: Borislav Petkov (AMD) <bp@alien8.de> |
| |
| commit c809b0d0e52d01c30066367b2952c4c4186b1047 upstream. |
| |
| Due to specific requirements while applying microcode patches on Zen1 |
| and 2, the patch buffer mapping needs to be flushed from the TLB after |
| application. Do so. |
| |
| If not, unnecessary and unnatural delays happen in the boot process. |
| |
| Reported-by: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com> |
| Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> |
| Tested-by: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com> |
| Cc: <stable@kernel.org> # f1d84b59cbb9 ("x86/mm: Carve out INVLPG inline asm for use by others") |
| Link: https://lore.kernel.org/r/ZyulbYuvrkshfsd2@antipodes |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/x86/kernel/cpu/microcode/amd.c | 25 ++++++++++++++++++++----- |
| 1 file changed, 20 insertions(+), 5 deletions(-) |
| |
| --- a/arch/x86/kernel/cpu/microcode/amd.c |
| +++ b/arch/x86/kernel/cpu/microcode/amd.c |
| @@ -34,6 +34,7 @@ |
| #include <asm/setup.h> |
| #include <asm/cpu.h> |
| #include <asm/msr.h> |
| +#include <asm/tlb.h> |
| |
| #include "internal.h" |
| |
| @@ -483,11 +484,25 @@ static void scan_containers(u8 *ucode, s |
| } |
| } |
| |
| -static int __apply_microcode_amd(struct microcode_amd *mc) |
| +static int __apply_microcode_amd(struct microcode_amd *mc, unsigned int psize) |
| { |
| + unsigned long p_addr = (unsigned long)&mc->hdr.data_code; |
| u32 rev, dummy; |
| |
| - native_wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc->hdr.data_code); |
| + native_wrmsrl(MSR_AMD64_PATCH_LOADER, p_addr); |
| + |
| + if (x86_family(bsp_cpuid_1_eax) == 0x17) { |
| + unsigned long p_addr_end = p_addr + psize - 1; |
| + |
| + invlpg(p_addr); |
| + |
| + /* |
| + * Flush next page too if patch image is crossing a page |
| + * boundary. |
| + */ |
| + if (p_addr >> PAGE_SHIFT != p_addr_end >> PAGE_SHIFT) |
| + invlpg(p_addr_end); |
| + } |
| |
| /* verify patch application was successful */ |
| native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); |
| @@ -529,7 +544,7 @@ static bool early_apply_microcode(u32 ol |
| if (old_rev > mc->hdr.patch_id) |
| return ret; |
| |
| - return !__apply_microcode_amd(mc); |
| + return !__apply_microcode_amd(mc, desc.psize); |
| } |
| |
| static bool get_builtin_microcode(struct cpio_data *cp) |
| @@ -745,7 +760,7 @@ void reload_ucode_amd(unsigned int cpu) |
| rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); |
| |
| if (rev < mc->hdr.patch_id) { |
| - if (!__apply_microcode_amd(mc)) |
| + if (!__apply_microcode_amd(mc, p->size)) |
| pr_info_once("reload revision: 0x%08x\n", mc->hdr.patch_id); |
| } |
| } |
| @@ -798,7 +813,7 @@ static enum ucode_state apply_microcode_ |
| goto out; |
| } |
| |
| - if (__apply_microcode_amd(mc_amd)) { |
| + if (__apply_microcode_amd(mc_amd, p->size)) { |
| pr_err("CPU%d: update failed for patch_level=0x%08x\n", |
| cpu, mc_amd->hdr.patch_id); |
| return UCODE_ERROR; |