Skip to content

Commit be8b47e

Browse files
zhangjunopsiff
authored andcommitted
x86/hw-vuln:Support hardware-based mitigation for Retbleed and SRSO via Hygon IBRS to avoid performance degradation caused by software-based mitigation.
hygon inclusion category:feature ------------------ Hygon IBRS is different from AMD's Auto IBRS. It mitigates vulnerabilities based on the predicted branch type rather than the actual branch type; therefore, it can mitigate both Retbleed and SRSO by preventing predicted branch types from being used in the kernel. We leverage Hygon IBRS for Retbleed and SRSO mitigation, which avoids the performance degradation caused by software-based mitigation methods. Signed-off-by: zhangjun <zhangjun@hygon.cn>
1 parent f332e44 commit be8b47e

3 files changed

Lines changed: 142 additions & 4 deletions

File tree

arch/x86/kernel/cpu/bugs.c

Lines changed: 116 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,19 @@ static void __init retbleed_select_mitigation(void)
11181118
break;
11191119
}
11201120

1121+
/* Enhanced IBRS (eIBRS) is preferred on HYGON processors. */
1122+
if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
1123+
switch (spectre_v2_enabled) {
1124+
case SPECTRE_V2_EIBRS:
1125+
case SPECTRE_V2_EIBRS_RETPOLINE:
1126+
case SPECTRE_V2_EIBRS_LFENCE:
1127+
retbleed_mitigation = RETBLEED_MITIGATION_EIBRS;
1128+
break;
1129+
default:
1130+
break;
1131+
}
1132+
}
1133+
11211134
switch (retbleed_mitigation) {
11221135
case RETBLEED_MITIGATION_UNRET:
11231136
setup_force_cpu_cap(X86_FEATURE_RETHUNK);
@@ -2561,13 +2574,62 @@ int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
25612574
}
25622575
}
25632576

2577+
/**
2578+
* enum ibpb_brtype_cmd - IBPB action control flag
2579+
* @IBPB_FLUSH_IND:IBPB command only flushes indirect branches in branch target buffer
2580+
* @IBPB_FLUSH_ALL:IBPB command flushes all types of branches in branch target buffer
2581+
*/
2582+
enum ibpb_brtype_cmd {
2583+
IBPB_FLUSH_IND,
2584+
IBPB_FLUSH_ALL,
2585+
};
2586+
static enum ibpb_brtype_cmd ibpb_brtype __ro_after_init = IBPB_FLUSH_ALL;
2587+
/**
2588+
* The kernel parameter ibpb_brtype is used to control
2589+
* whether IBPB flushes all branches or indirect branches:
2590+
* ibpb_brtype= [X86, HYGON only]
2591+
* IBPB action control flag
2592+
* Format: { ibpb-all | ibpb-ind }
2593+
* ibpb-all -- IBPB flushes all types of branches,this is the default value.
2594+
* ibpb-ind -- IBPB flushes only indirect branches.
2595+
*/
2596+
static int __init ibpb_brtype_cmdline(char *str)
2597+
{
2598+
if (boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
2599+
return 0;
2600+
2601+
if (!str)
2602+
return -EINVAL;
2603+
2604+
if (!strcmp(str, "ibpb-all")) {
2605+
ibpb_brtype = IBPB_FLUSH_ALL;
2606+
pr_info("IBPB flushes all branches.\n");
2607+
} else if (!strcmp(str, "ibpb-ind")) {
2608+
ibpb_brtype = IBPB_FLUSH_IND;
2609+
pr_info("IBPB flushes only indirect branches.\n");
2610+
} else
2611+
pr_err("Ignoring unknown ibpb branch type option (%s).", str);
2612+
2613+
return 0;
2614+
}
2615+
early_param("ibpb_brtype", ibpb_brtype_cmdline);
2616+
2617+
#define IBPB_FLUSH_ALL_BIT 55
2618+
25642619
void x86_spec_ctrl_setup_ap(void)
25652620
{
25662621
if (boot_cpu_has(X86_FEATURE_MSR_SPEC_CTRL))
25672622
update_spec_ctrl(x86_spec_ctrl_base);
25682623

25692624
if (ssb_mode == SPEC_STORE_BYPASS_DISABLE)
25702625
x86_amd_ssb_disable();
2626+
2627+
if ((boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) &&
2628+
(boot_cpu_data.x86 == 0x18)) {
2629+
if ((boot_cpu_data.x86_model > 0x3) &&
2630+
(ibpb_brtype == IBPB_FLUSH_ALL))
2631+
msr_set_bit(MSR_ZEN4_BP_CFG, IBPB_FLUSH_ALL_BIT);
2632+
}
25712633
}
25722634

25732635
bool itlb_multihit_kvm_mitigation;
@@ -2706,6 +2768,7 @@ enum srso_mitigation {
27062768
SRSO_MITIGATION_SAFE_RET,
27072769
SRSO_MITIGATION_IBPB,
27082770
SRSO_MITIGATION_IBPB_ON_VMEXIT,
2771+
SRSO_MITIGATION_EIBRS,
27092772
};
27102773

27112774
enum srso_mitigation_cmd {
@@ -2723,7 +2786,8 @@ static const char * const srso_strings[] = {
27232786
[SRSO_MITIGATION_MICROCODE] = "Vulnerable: Microcode, no safe RET",
27242787
[SRSO_MITIGATION_SAFE_RET] = "Mitigation: Safe RET",
27252788
[SRSO_MITIGATION_IBPB] = "Mitigation: IBPB",
2726-
[SRSO_MITIGATION_IBPB_ON_VMEXIT] = "Mitigation: IBPB on VMEXIT only"
2789+
[SRSO_MITIGATION_IBPB_ON_VMEXIT] = "Mitigation: IBPB on VMEXIT only",
2790+
[SRSO_MITIGATION_EIBRS] = "Mitigation: Enhanced IBRS"
27272791
};
27282792

27292793
static enum srso_mitigation srso_mitigation __ro_after_init = SRSO_MITIGATION_NONE;
@@ -2753,10 +2817,36 @@ early_param("spec_rstack_overflow", srso_parse_cmdline);
27532817

27542818
#define SRSO_NOTICE "WARNING: See https://kernel.org/doc/html/latest/admin-guide/hw-vuln/srso.html for mitigation options."
27552819

2820+
/*
2821+
* ibpb_can_flush_all() - set IBPB flush type according to the cmdline param
2822+
* - and check whether IBPB can flush all branches
2823+
* @return: true when IBPB can flush all types of branches and
2824+
* false when IBPB can flush only indirect branches.
2825+
*/
2826+
bool ibpb_can_flush_all(void)
2827+
{
2828+
if ((boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) &&
2829+
(boot_cpu_data.x86 == 0x18)) {
2830+
if (boot_cpu_data.x86_model <= 0x3) {
2831+
return true;
2832+
} else if (ibpb_brtype == IBPB_FLUSH_ALL) {
2833+
msr_set_bit(MSR_ZEN4_BP_CFG, IBPB_FLUSH_ALL_BIT);
2834+
return true;
2835+
}
2836+
return false;
2837+
}
2838+
2839+
pr_err("WARNING: this ibpb check is only used for HYGON.\n");
2840+
return false;
2841+
}
2842+
27562843
static void __init srso_select_mitigation(void)
27572844
{
27582845
bool has_microcode = boot_cpu_has(X86_FEATURE_IBPB_BRTYPE);
27592846

2847+
if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
2848+
has_microcode = ibpb_can_flush_all();
2849+
27602850
if (!boot_cpu_has_bug(X86_BUG_SRSO) || cpu_mitigations_off())
27612851
goto pred_cmd;
27622852

@@ -2782,6 +2872,20 @@ static void __init srso_select_mitigation(void)
27822872
srso_mitigation = SRSO_MITIGATION_UCODE_NEEDED;
27832873
}
27842874

2875+
/* Enhanced IBRS (eIBRS) is preferred on HYGON processors. */
2876+
if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
2877+
switch (spectre_v2_enabled) {
2878+
case SPECTRE_V2_EIBRS:
2879+
case SPECTRE_V2_EIBRS_RETPOLINE:
2880+
case SPECTRE_V2_EIBRS_LFENCE:
2881+
srso_mitigation = SRSO_MITIGATION_EIBRS;
2882+
pr_info("%s%s\n", srso_strings[srso_mitigation],
2883+
(has_microcode ? "" : ", no microcode"));
2884+
goto pred_cmd;
2885+
default:
2886+
break;
2887+
}
2888+
}
27852889
switch (srso_cmd) {
27862890
case SRSO_CMD_OFF:
27872891
goto pred_cmd;
@@ -3254,11 +3358,21 @@ static ssize_t retbleed_show_state(char *buf)
32543358
boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
32553359
return sysfs_emit(buf, "Vulnerable: untrained return thunk / IBPB on non-AMD based uarch\n");
32563360

3257-
return sysfs_emit(buf, "%s; SMT %s\n", retbleed_strings[retbleed_mitigation],
3361+
if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
3362+
return sysfs_emit(buf, "%s; SMT %s\n",
3363+
retbleed_strings[retbleed_mitigation],
32583364
!sched_smt_active() ? "disabled" :
3365+
spectre_v2_in_eibrs_mode(spectre_v2_enabled) ||
32593366
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
32603367
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED ?
32613368
"enabled with STIBP protection" : "vulnerable");
3369+
}
3370+
3371+
return sysfs_emit(buf, "%s; SMT %s\n", retbleed_strings[retbleed_mitigation],
3372+
!sched_smt_active() ? "disabled" :
3373+
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
3374+
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED ?
3375+
"enabled with STIBP protection" : "vulnerable");
32623376
}
32633377

32643378
return sysfs_emit(buf, "%s\n", retbleed_strings[retbleed_mitigation]);

arch/x86/kernel/cpu/common.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,7 +1071,10 @@ static void init_speculation_control(struct cpuinfo_x86 *c)
10711071
* Intel CPUs, for finer-grained selection of what's available.
10721072
*/
10731073
if (cpu_has(c, X86_FEATURE_SPEC_CTRL)) {
1074-
set_cpu_cap(c, X86_FEATURE_IBRS);
1074+
if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
1075+
set_cpu_cap(c, X86_FEATURE_IBRS_ENHANCED);
1076+
else
1077+
set_cpu_cap(c, X86_FEATURE_IBRS);
10751078
set_cpu_cap(c, X86_FEATURE_IBPB);
10761079
set_cpu_cap(c, X86_FEATURE_MSR_SPEC_CTRL);
10771080
}
@@ -1084,7 +1087,10 @@ static void init_speculation_control(struct cpuinfo_x86 *c)
10841087
set_cpu_cap(c, X86_FEATURE_SSBD);
10851088

10861089
if (cpu_has(c, X86_FEATURE_AMD_IBRS)) {
1087-
set_cpu_cap(c, X86_FEATURE_IBRS);
1090+
if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
1091+
set_cpu_cap(c, X86_FEATURE_IBRS_ENHANCED);
1092+
else
1093+
set_cpu_cap(c, X86_FEATURE_IBRS);
10881094
set_cpu_cap(c, X86_FEATURE_MSR_SPEC_CTRL);
10891095
}
10901096

arch/x86/kernel/cpu/hygon.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include "cpu.h"
2424

25+
#define IBRS_FLUSH_RAS_BIT 56
2526
#define APICID_SOCKET_ID_BIT 6
2627

2728
/*
@@ -310,12 +311,29 @@ static void early_detect_mem_encrypt(struct cpuinfo_x86 *c)
310311
setup_clear_cpu_cap(X86_FEATURE_CSV3);
311312
}
312313

314+
/*
315+
* cpu_vul_mitigation() - set the basic configuration to mitigate CPU vulnerabilities
316+
*/
317+
static void cpu_vul_mitigation(void)
318+
{
319+
/*
320+
* Automatically flush RAS upon protection level changes from low to high.
321+
* it's used as rsb mitigation instead of RSB filling.
322+
*/
323+
if ((boot_cpu_data.x86 == 0x18) &&
324+
(boot_cpu_data.x86_model > 0x3)) {
325+
msr_set_bit(MSR_ZEN4_BP_CFG, IBRS_FLUSH_RAS_BIT);
326+
}
327+
}
328+
313329
static void early_init_hygon(struct cpuinfo_x86 *c)
314330
{
315331
u32 dummy;
316332

317333
early_init_hygon_mc(c);
318334

335+
cpu_vul_mitigation();
336+
319337
set_cpu_cap(c, X86_FEATURE_K8);
320338

321339
rdmsr_safe(MSR_AMD64_PATCH_LEVEL, &c->microcode, &dummy);

0 commit comments

Comments
 (0)