@@ -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+
25642619void 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
25732635bool 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
27112774enum 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
27292793static 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+
27562843static 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 ]);
0 commit comments