diff options
Diffstat (limited to 'arch/x86/kernel/cpu/amd.c')
-rw-r--r-- | arch/x86/kernel/cpu/amd.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 8d4e50428b68..68c363c341bf 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c | |||
@@ -804,6 +804,64 @@ static void init_amd_ln(struct cpuinfo_x86 *c) | |||
804 | msr_set_bit(MSR_AMD64_DE_CFG, 31); | 804 | msr_set_bit(MSR_AMD64_DE_CFG, 31); |
805 | } | 805 | } |
806 | 806 | ||
807 | static bool rdrand_force; | ||
808 | |||
809 | static int __init rdrand_cmdline(char *str) | ||
810 | { | ||
811 | if (!str) | ||
812 | return -EINVAL; | ||
813 | |||
814 | if (!strcmp(str, "force")) | ||
815 | rdrand_force = true; | ||
816 | else | ||
817 | return -EINVAL; | ||
818 | |||
819 | return 0; | ||
820 | } | ||
821 | early_param("rdrand", rdrand_cmdline); | ||
822 | |||
823 | static void clear_rdrand_cpuid_bit(struct cpuinfo_x86 *c) | ||
824 | { | ||
825 | /* | ||
826 | * Saving of the MSR used to hide the RDRAND support during | ||
827 | * suspend/resume is done by arch/x86/power/cpu.c, which is | ||
828 | * dependent on CONFIG_PM_SLEEP. | ||
829 | */ | ||
830 | if (!IS_ENABLED(CONFIG_PM_SLEEP)) | ||
831 | return; | ||
832 | |||
833 | /* | ||
834 | * The nordrand option can clear X86_FEATURE_RDRAND, so check for | ||
835 | * RDRAND support using the CPUID function directly. | ||
836 | */ | ||
837 | if (!(cpuid_ecx(1) & BIT(30)) || rdrand_force) | ||
838 | return; | ||
839 | |||
840 | msr_clear_bit(MSR_AMD64_CPUID_FN_1, 62); | ||
841 | |||
842 | /* | ||
843 | * Verify that the CPUID change has occurred in case the kernel is | ||
844 | * running virtualized and the hypervisor doesn't support the MSR. | ||
845 | */ | ||
846 | if (cpuid_ecx(1) & BIT(30)) { | ||
847 | pr_info_once("BIOS may not properly restore RDRAND after suspend, but hypervisor does not support hiding RDRAND via CPUID.\n"); | ||
848 | return; | ||
849 | } | ||
850 | |||
851 | clear_cpu_cap(c, X86_FEATURE_RDRAND); | ||
852 | pr_info_once("BIOS may not properly restore RDRAND after suspend, hiding RDRAND via CPUID. Use rdrand=force to reenable.\n"); | ||
853 | } | ||
854 | |||
855 | static void init_amd_jg(struct cpuinfo_x86 *c) | ||
856 | { | ||
857 | /* | ||
858 | * Some BIOS implementations do not restore proper RDRAND support | ||
859 | * across suspend and resume. Check on whether to hide the RDRAND | ||
860 | * instruction support via CPUID. | ||
861 | */ | ||
862 | clear_rdrand_cpuid_bit(c); | ||
863 | } | ||
864 | |||
807 | static void init_amd_bd(struct cpuinfo_x86 *c) | 865 | static void init_amd_bd(struct cpuinfo_x86 *c) |
808 | { | 866 | { |
809 | u64 value; | 867 | u64 value; |
@@ -818,6 +876,13 @@ static void init_amd_bd(struct cpuinfo_x86 *c) | |||
818 | wrmsrl_safe(MSR_F15H_IC_CFG, value); | 876 | wrmsrl_safe(MSR_F15H_IC_CFG, value); |
819 | } | 877 | } |
820 | } | 878 | } |
879 | |||
880 | /* | ||
881 | * Some BIOS implementations do not restore proper RDRAND support | ||
882 | * across suspend and resume. Check on whether to hide the RDRAND | ||
883 | * instruction support via CPUID. | ||
884 | */ | ||
885 | clear_rdrand_cpuid_bit(c); | ||
821 | } | 886 | } |
822 | 887 | ||
823 | static void init_amd_zn(struct cpuinfo_x86 *c) | 888 | static void init_amd_zn(struct cpuinfo_x86 *c) |
@@ -860,6 +925,7 @@ static void init_amd(struct cpuinfo_x86 *c) | |||
860 | case 0x10: init_amd_gh(c); break; | 925 | case 0x10: init_amd_gh(c); break; |
861 | case 0x12: init_amd_ln(c); break; | 926 | case 0x12: init_amd_ln(c); break; |
862 | case 0x15: init_amd_bd(c); break; | 927 | case 0x15: init_amd_bd(c); break; |
928 | case 0x16: init_amd_jg(c); break; | ||
863 | case 0x17: init_amd_zn(c); break; | 929 | case 0x17: init_amd_zn(c); break; |
864 | } | 930 | } |
865 | 931 | ||