Skip to content

Commit 0a9266b

Browse files
committed
Merge tag 'x86_bugs_zenbleed' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull Zen 2 errata fix from Borislav Petkov: "Fix an issue on AMD Zen2 processors called Zenbleed. The bug manifests itself as a data corruption issue when executing VZEROUPPER under certain microarchitectural conditions" * tag 'x86_bugs_zenbleed' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/cpu/amd: Add a Zenbleed fix x86/cpu/amd: Move the errata checking functionality up
2 parents 6eaae19 + 522b1d6 commit 0a9266b

File tree

5 files changed

+133
-72
lines changed

5 files changed

+133
-72
lines changed

arch/x86/include/asm/microcode.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <asm/cpu.h>
66
#include <linux/earlycpio.h>
77
#include <linux/initrd.h>
8+
#include <asm/microcode_amd.h>
89

910
struct ucode_patch {
1011
struct list_head plist;

arch/x86/include/asm/microcode_amd.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ extern void __init load_ucode_amd_bsp(unsigned int family);
4848
extern void load_ucode_amd_ap(unsigned int family);
4949
extern int __init save_microcode_in_initrd_amd(unsigned int family);
5050
void reload_ucode_amd(unsigned int cpu);
51+
extern void amd_check_microcode(void);
5152
#else
5253
static inline void __init load_ucode_amd_bsp(unsigned int family) {}
5354
static inline void load_ucode_amd_ap(unsigned int family) {}
5455
static inline int __init
5556
save_microcode_in_initrd_amd(unsigned int family) { return -EINVAL; }
5657
static inline void reload_ucode_amd(unsigned int cpu) {}
58+
static inline void amd_check_microcode(void) {}
5759
#endif
5860
#endif /* _ASM_X86_MICROCODE_AMD_H */

arch/x86/include/asm/msr-index.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,7 @@
545545
#define MSR_AMD64_DE_CFG 0xc0011029
546546
#define MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT 1
547547
#define MSR_AMD64_DE_CFG_LFENCE_SERIALIZE BIT_ULL(MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT)
548+
#define MSR_AMD64_DE_CFG_ZEN2_FP_BACKUP_FIX_BIT 9
548549

549550
#define MSR_AMD64_BU_CFG2 0xc001102a
550551
#define MSR_AMD64_IBSFETCHCTL 0xc0011030

arch/x86/kernel/cpu/amd.c

Lines changed: 127 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,85 @@
2727

2828
#include "cpu.h"
2929

30-
static const int amd_erratum_383[];
31-
static const int amd_erratum_400[];
32-
static const int amd_erratum_1054[];
33-
static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum);
34-
3530
/*
3631
* nodes_per_socket: Stores the number of nodes per socket.
3732
* Refer to Fam15h Models 00-0fh BKDG - CPUID Fn8000_001E_ECX
3833
* Node Identifiers[10:8]
3934
*/
4035
static u32 nodes_per_socket = 1;
4136

37+
/*
38+
* AMD errata checking
39+
*
40+
* Errata are defined as arrays of ints using the AMD_LEGACY_ERRATUM() or
41+
* AMD_OSVW_ERRATUM() macros. The latter is intended for newer errata that
42+
* have an OSVW id assigned, which it takes as first argument. Both take a
43+
* variable number of family-specific model-stepping ranges created by
44+
* AMD_MODEL_RANGE().
45+
*
46+
* Example:
47+
*
48+
* const int amd_erratum_319[] =
49+
* AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0x4, 0x2),
50+
* AMD_MODEL_RANGE(0x10, 0x8, 0x0, 0x8, 0x0),
51+
* AMD_MODEL_RANGE(0x10, 0x9, 0x0, 0x9, 0x0));
52+
*/
53+
54+
#define AMD_LEGACY_ERRATUM(...) { -1, __VA_ARGS__, 0 }
55+
#define AMD_OSVW_ERRATUM(osvw_id, ...) { osvw_id, __VA_ARGS__, 0 }
56+
#define AMD_MODEL_RANGE(f, m_start, s_start, m_end, s_end) \
57+
((f << 24) | (m_start << 16) | (s_start << 12) | (m_end << 4) | (s_end))
58+
#define AMD_MODEL_RANGE_FAMILY(range) (((range) >> 24) & 0xff)
59+
#define AMD_MODEL_RANGE_START(range) (((range) >> 12) & 0xfff)
60+
#define AMD_MODEL_RANGE_END(range) ((range) & 0xfff)
61+
62+
static const int amd_erratum_400[] =
63+
AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0xf, 0x41, 0x2, 0xff, 0xf),
64+
AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf));
65+
66+
static const int amd_erratum_383[] =
67+
AMD_OSVW_ERRATUM(3, AMD_MODEL_RANGE(0x10, 0, 0, 0xff, 0xf));
68+
69+
/* #1054: Instructions Retired Performance Counter May Be Inaccurate */
70+
static const int amd_erratum_1054[] =
71+
AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0, 0, 0x2f, 0xf));
72+
73+
static const int amd_zenbleed[] =
74+
AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0x30, 0x0, 0x4f, 0xf),
75+
AMD_MODEL_RANGE(0x17, 0x60, 0x0, 0x7f, 0xf),
76+
AMD_MODEL_RANGE(0x17, 0xa0, 0x0, 0xaf, 0xf));
77+
78+
static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)
79+
{
80+
int osvw_id = *erratum++;
81+
u32 range;
82+
u32 ms;
83+
84+
if (osvw_id >= 0 && osvw_id < 65536 &&
85+
cpu_has(cpu, X86_FEATURE_OSVW)) {
86+
u64 osvw_len;
87+
88+
rdmsrl(MSR_AMD64_OSVW_ID_LENGTH, osvw_len);
89+
if (osvw_id < osvw_len) {
90+
u64 osvw_bits;
91+
92+
rdmsrl(MSR_AMD64_OSVW_STATUS + (osvw_id >> 6),
93+
osvw_bits);
94+
return osvw_bits & (1ULL << (osvw_id & 0x3f));
95+
}
96+
}
97+
98+
/* OSVW unavailable or ID unknown, match family-model-stepping range */
99+
ms = (cpu->x86_model << 4) | cpu->x86_stepping;
100+
while ((range = *erratum++))
101+
if ((cpu->x86 == AMD_MODEL_RANGE_FAMILY(range)) &&
102+
(ms >= AMD_MODEL_RANGE_START(range)) &&
103+
(ms <= AMD_MODEL_RANGE_END(range)))
104+
return true;
105+
106+
return false;
107+
}
108+
42109
static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p)
43110
{
44111
u32 gprs[8] = { 0 };
@@ -916,6 +983,47 @@ static void init_amd_zn(struct cpuinfo_x86 *c)
916983
}
917984
}
918985

986+
static bool cpu_has_zenbleed_microcode(void)
987+
{
988+
u32 good_rev = 0;
989+
990+
switch (boot_cpu_data.x86_model) {
991+
case 0x30 ... 0x3f: good_rev = 0x0830107a; break;
992+
case 0x60 ... 0x67: good_rev = 0x0860010b; break;
993+
case 0x68 ... 0x6f: good_rev = 0x08608105; break;
994+
case 0x70 ... 0x7f: good_rev = 0x08701032; break;
995+
case 0xa0 ... 0xaf: good_rev = 0x08a00008; break;
996+
997+
default:
998+
return false;
999+
break;
1000+
}
1001+
1002+
if (boot_cpu_data.microcode < good_rev)
1003+
return false;
1004+
1005+
return true;
1006+
}
1007+
1008+
static void zenbleed_check(struct cpuinfo_x86 *c)
1009+
{
1010+
if (!cpu_has_amd_erratum(c, amd_zenbleed))
1011+
return;
1012+
1013+
if (cpu_has(c, X86_FEATURE_HYPERVISOR))
1014+
return;
1015+
1016+
if (!cpu_has(c, X86_FEATURE_AVX))
1017+
return;
1018+
1019+
if (!cpu_has_zenbleed_microcode()) {
1020+
pr_notice_once("Zenbleed: please update your microcode for the most optimal fix\n");
1021+
msr_set_bit(MSR_AMD64_DE_CFG, MSR_AMD64_DE_CFG_ZEN2_FP_BACKUP_FIX_BIT);
1022+
} else {
1023+
msr_clear_bit(MSR_AMD64_DE_CFG, MSR_AMD64_DE_CFG_ZEN2_FP_BACKUP_FIX_BIT);
1024+
}
1025+
}
1026+
9191027
static void init_amd(struct cpuinfo_x86 *c)
9201028
{
9211029
early_init_amd(c);
@@ -1020,6 +1128,8 @@ static void init_amd(struct cpuinfo_x86 *c)
10201128
if (spectre_v2_in_eibrs_mode(spectre_v2_enabled) &&
10211129
cpu_has(c, X86_FEATURE_AUTOIBRS))
10221130
WARN_ON_ONCE(msr_set_bit(MSR_EFER, _EFER_AUTOIBRS));
1131+
1132+
zenbleed_check(c);
10231133
}
10241134

10251135
#ifdef CONFIG_X86_32
@@ -1115,73 +1225,6 @@ static const struct cpu_dev amd_cpu_dev = {
11151225

11161226
cpu_dev_register(amd_cpu_dev);
11171227

1118-
/*
1119-
* AMD errata checking
1120-
*
1121-
* Errata are defined as arrays of ints using the AMD_LEGACY_ERRATUM() or
1122-
* AMD_OSVW_ERRATUM() macros. The latter is intended for newer errata that
1123-
* have an OSVW id assigned, which it takes as first argument. Both take a
1124-
* variable number of family-specific model-stepping ranges created by
1125-
* AMD_MODEL_RANGE().
1126-
*
1127-
* Example:
1128-
*
1129-
* const int amd_erratum_319[] =
1130-
* AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0x4, 0x2),
1131-
* AMD_MODEL_RANGE(0x10, 0x8, 0x0, 0x8, 0x0),
1132-
* AMD_MODEL_RANGE(0x10, 0x9, 0x0, 0x9, 0x0));
1133-
*/
1134-
1135-
#define AMD_LEGACY_ERRATUM(...) { -1, __VA_ARGS__, 0 }
1136-
#define AMD_OSVW_ERRATUM(osvw_id, ...) { osvw_id, __VA_ARGS__, 0 }
1137-
#define AMD_MODEL_RANGE(f, m_start, s_start, m_end, s_end) \
1138-
((f << 24) | (m_start << 16) | (s_start << 12) | (m_end << 4) | (s_end))
1139-
#define AMD_MODEL_RANGE_FAMILY(range) (((range) >> 24) & 0xff)
1140-
#define AMD_MODEL_RANGE_START(range) (((range) >> 12) & 0xfff)
1141-
#define AMD_MODEL_RANGE_END(range) ((range) & 0xfff)
1142-
1143-
static const int amd_erratum_400[] =
1144-
AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0xf, 0x41, 0x2, 0xff, 0xf),
1145-
AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf));
1146-
1147-
static const int amd_erratum_383[] =
1148-
AMD_OSVW_ERRATUM(3, AMD_MODEL_RANGE(0x10, 0, 0, 0xff, 0xf));
1149-
1150-
/* #1054: Instructions Retired Performance Counter May Be Inaccurate */
1151-
static const int amd_erratum_1054[] =
1152-
AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0, 0, 0x2f, 0xf));
1153-
1154-
static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)
1155-
{
1156-
int osvw_id = *erratum++;
1157-
u32 range;
1158-
u32 ms;
1159-
1160-
if (osvw_id >= 0 && osvw_id < 65536 &&
1161-
cpu_has(cpu, X86_FEATURE_OSVW)) {
1162-
u64 osvw_len;
1163-
1164-
rdmsrl(MSR_AMD64_OSVW_ID_LENGTH, osvw_len);
1165-
if (osvw_id < osvw_len) {
1166-
u64 osvw_bits;
1167-
1168-
rdmsrl(MSR_AMD64_OSVW_STATUS + (osvw_id >> 6),
1169-
osvw_bits);
1170-
return osvw_bits & (1ULL << (osvw_id & 0x3f));
1171-
}
1172-
}
1173-
1174-
/* OSVW unavailable or ID unknown, match family-model-stepping range */
1175-
ms = (cpu->x86_model << 4) | cpu->x86_stepping;
1176-
while ((range = *erratum++))
1177-
if ((cpu->x86 == AMD_MODEL_RANGE_FAMILY(range)) &&
1178-
(ms >= AMD_MODEL_RANGE_START(range)) &&
1179-
(ms <= AMD_MODEL_RANGE_END(range)))
1180-
return true;
1181-
1182-
return false;
1183-
}
1184-
11851228
static DEFINE_PER_CPU_READ_MOSTLY(unsigned long[4], amd_dr_addr_mask);
11861229

11871230
static unsigned int amd_msr_dr_addr_masks[] = {
@@ -1235,3 +1278,15 @@ u32 amd_get_highest_perf(void)
12351278
return 255;
12361279
}
12371280
EXPORT_SYMBOL_GPL(amd_get_highest_perf);
1281+
1282+
static void zenbleed_check_cpu(void *unused)
1283+
{
1284+
struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
1285+
1286+
zenbleed_check(c);
1287+
}
1288+
1289+
void amd_check_microcode(void)
1290+
{
1291+
on_each_cpu(zenbleed_check_cpu, NULL, 1);
1292+
}

arch/x86/kernel/cpu/common.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2287,6 +2287,8 @@ void microcode_check(struct cpuinfo_x86 *prev_info)
22872287

22882288
perf_check_microcode();
22892289

2290+
amd_check_microcode();
2291+
22902292
store_cpu_caps(&curr_info);
22912293

22922294
if (!memcmp(&prev_info->x86_capability, &curr_info.x86_capability,

0 commit comments

Comments
 (0)