Commit 0eeacaff authored by Borislav Petkov (AMD)'s avatar Borislav Petkov (AMD) Committed by Wang ShaoBo
Browse files

x86/cpu/amd: Add a Zenbleed fix

stable inclusion
from stable-v4.19.289
commit cfef7bbf0dca27209ea5d82d7060d4fc2c0d72ea
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I7RC8S
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=cfef7bbf0dca27209ea5d82d7060d4fc2c0d72ea



--------------------------------

Upstream commit: 522b1d69

Add a fix for the Zen2 VZEROUPPER data corruption bug where under
certain circumstances executing VZEROUPPER can cause register
corruption or leak data.

The optimal fix is through microcode but in the case the proper
microcode revision has not been applied, enable a fallback fix using
a chicken bit.

Signed-off-by: default avatarBorislav Petkov (AMD) <bp@alien8.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Conflicts:
    arch/x86/include/asm/microcode_amd.h
    arch/x86/include/asm/msr-index.h
    arch/x86/kernel/cpu/amd.c
Signed-off-by: default avatarWang ShaoBo <bobo.shaobowang@huawei.com>
parent 3019c879
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
#include <asm/cpu.h>
#include <linux/earlycpio.h>
#include <linux/initrd.h>
#include <asm/microcode_amd.h>

struct ucode_patch {
	struct list_head plist;
+2 −0
Original line number Diff line number Diff line
@@ -48,11 +48,13 @@ extern void __init load_ucode_amd_bsp(unsigned int family);
extern void load_ucode_amd_ap(unsigned int family);
extern int __init save_microcode_in_initrd_amd(unsigned int family);
void reload_ucode_amd(void);
extern void amd_check_microcode(void);
#else
static inline void __init load_ucode_amd_bsp(unsigned int family) {}
static inline void load_ucode_amd_ap(unsigned int family) {}
static inline int __init
save_microcode_in_initrd_amd(unsigned int family) { return -EINVAL; }
void reload_ucode_amd(void) {}
static inline void amd_check_microcode(void) {}
#endif
#endif /* _ASM_X86_MICROCODE_AMD_H */
+1 −0
Original line number Diff line number Diff line
@@ -404,6 +404,7 @@
#define MSR_AMD64_OSVW_STATUS		0xc0010141
#define MSR_AMD64_LS_CFG		0xc0011020
#define MSR_AMD64_DC_CFG		0xc0011022
#define MSR_AMD64_DE_CFG_ZEN2_FP_BACKUP_FIX_BIT 9
#define MSR_AMD64_BU_CFG2		0xc001102a
#define MSR_AMD64_IBSFETCHCTL		0xc0011030
#define MSR_AMD64_IBSFETCHLINAD		0xc0011031
+60 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@

static const int amd_erratum_383[];
static const int amd_erratum_400[];
static const int amd_zenbleed[];
static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum);

/*
@@ -901,6 +902,47 @@ static void init_amd_zn(struct cpuinfo_x86 *c)
	}
}

static bool cpu_has_zenbleed_microcode(void)
{
	u32 good_rev = 0;

	switch (boot_cpu_data.x86_model) {
	case 0x30 ... 0x3f: good_rev = 0x0830107a; break;
	case 0x60 ... 0x67: good_rev = 0x0860010b; break;
	case 0x68 ... 0x6f: good_rev = 0x08608105; break;
	case 0x70 ... 0x7f: good_rev = 0x08701032; break;
	case 0xa0 ... 0xaf: good_rev = 0x08a00008; break;

	default:
		return false;
		break;
	}

	if (boot_cpu_data.microcode < good_rev)
		return false;

	return true;
}

static void zenbleed_check(struct cpuinfo_x86 *c)
{
	if (!cpu_has_amd_erratum(c, amd_zenbleed))
		return;

	if (cpu_has(c, X86_FEATURE_HYPERVISOR))
		return;

	if (!cpu_has(c, X86_FEATURE_AVX))
		return;

	if (!cpu_has_zenbleed_microcode()) {
		pr_notice_once("Zenbleed: please update your microcode for the most optimal fix\n");
		msr_set_bit(MSR_AMD64_DE_CFG, MSR_AMD64_DE_CFG_ZEN2_FP_BACKUP_FIX_BIT);
	} else {
		msr_clear_bit(MSR_AMD64_DE_CFG, MSR_AMD64_DE_CFG_ZEN2_FP_BACKUP_FIX_BIT);
	}
}

static void init_amd(struct cpuinfo_x86 *c)
{
	early_init_amd(c);
@@ -995,6 +1037,8 @@ static void init_amd(struct cpuinfo_x86 *c)
		set_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS);

	check_null_seg_clears_base(c);

	zenbleed_check(c);
}

#ifdef CONFIG_X86_32
@@ -1122,6 +1166,10 @@ static const int amd_erratum_400[] =
static const int amd_erratum_383[] =
	AMD_OSVW_ERRATUM(3, AMD_MODEL_RANGE(0x10, 0, 0, 0xff, 0xf));

static const int amd_zenbleed[] =
	AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0x30, 0x0, 0x4f, 0xf),
			   AMD_MODEL_RANGE(0x17, 0x60, 0x0, 0x7f, 0xf),
			   AMD_MODEL_RANGE(0x17, 0xa0, 0x0, 0xaf, 0xf));

static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)
{
@@ -1172,3 +1220,15 @@ void set_dr_addr_mask(unsigned long mask, int dr)
		break;
	}
}

static void zenbleed_check_cpu(void *unused)
{
	struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());

	zenbleed_check(c);
}

void amd_check_microcode(void)
{
	on_each_cpu(zenbleed_check_cpu, NULL, 1);
}
+2 −0
Original line number Diff line number Diff line
@@ -2152,6 +2152,8 @@ void microcode_check(void)

	perf_check_microcode();

	amd_check_microcode();

	/* Reload CPUID max function as it might've changed. */
	info.cpuid_level = cpuid_eax(0);