diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc index ee12b0f53f..e16bb90184 100644 --- a/docs/misc/xen-command-line.pandoc +++ b/docs/misc/xen-command-line.pandoc @@ -488,6 +488,10 @@ The Speculation Control hardware features `md-clear`, `ibrsb`, `stibp`, `ibpb`, be ignored, e.g. `no-ibrsb`, at which point Xen won't use them itself, and won't offer them to guests. +`rdrand` can be used to override the default disabling of the feature on certain +AMD systems. Its negative form can of course also be used to suppress use and +exposure of the feature. + ### cpuid_mask_cpu > `= fam_0f_rev_[cdefg] | fam_10_rev_[bc] | fam_11_rev_b` diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c index 05cbcbad73..0cc6853c42 100644 --- a/xen/arch/x86/cpu/amd.c +++ b/xen/arch/x86/cpu/amd.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -747,6 +748,26 @@ static void init_amd(struct cpuinfo_x86 *c) if (acpi_smi_cmd && (acpi_enable_value | acpi_disable_value)) amd_acpi_c1e_quirk = true; break; + + case 0x15: case 0x16: + /* + * There are some Fam15/Fam16 systems where upon resume from S3 + * firmware fails to re-setup properly functioning RDRAND. + * By the time we can spot the problem, it is too late to take + * action, and there is nothing Xen can do to repair the problem. + * Clear the feature unless force-enabled on the command line. + */ + if (c == &boot_cpu_data && + cpu_has(c, X86_FEATURE_RDRAND) && + !is_forced_cpu_cap(X86_FEATURE_RDRAND)) { + static const char __initconst text[] = + "RDRAND may cease to work on this hardware upon resume from S3.\n" + "Please choose an explicit cpuid={no-}rdrand setting.\n"; + + setup_clear_cpu_cap(X86_FEATURE_RDRAND); + warning_add(text); + } + break; } display_cacheinfo(c); diff --git a/xen/arch/x86/cpu/common.c b/xen/arch/x86/cpu/common.c index 3e0d9cbe98..c413188d00 100644 --- a/xen/arch/x86/cpu/common.c +++ b/xen/arch/x86/cpu/common.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include /* for XEN_INVALID_{SOCKET,CORE}_ID */ @@ -98,6 +99,11 @@ void __init setup_force_cpu_cap(unsigned int cap) __set_bit(cap, boot_cpu_data.x86_capability); } +bool __init is_forced_cpu_cap(unsigned int cap) +{ + return test_bit(cap, forced_caps); +} + static void default_init(struct cpuinfo_x86 * c) { /* Not much we can do here... */ @@ -497,6 +503,27 @@ void identify_cpu(struct cpuinfo_x86 *c) printk("\n"); #endif + /* + * If RDRAND is available, make an attempt to check that it actually + * (still) works. + */ + if (cpu_has(c, X86_FEATURE_RDRAND)) { + unsigned int prev = 0; + + for (i = 0; i < 5; ++i) + { + unsigned int cur = arch_get_random(); + + if (prev && cur != prev) + break; + prev = cur; + } + + if (i >= 5) + printk(XENLOG_WARNING "CPU%u: RDRAND appears to not work\n", + smp_processor_id()); + } + if (system_state == SYS_STATE_resume) return; diff --git a/xen/arch/x86/cpuid.c b/xen/arch/x86/cpuid.c index 4b734284a4..ee11087626 100644 --- a/xen/arch/x86/cpuid.c +++ b/xen/arch/x86/cpuid.c @@ -72,6 +72,9 @@ static int __init parse_xen_cpuid(const char *s) { if ( !val ) setup_clear_cpu_cap(mid->bit); + else if ( mid->bit == X86_FEATURE_RDRAND && + (cpuid_ecx(1) & cpufeat_mask(X86_FEATURE_RDRAND)) ) + setup_force_cpu_cap(X86_FEATURE_RDRAND); mid = NULL; } diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index 8f6f5a97dd..070691882b 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -165,6 +165,7 @@ extern const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id table[]); extern void identify_cpu(struct cpuinfo_x86 *); extern void setup_clear_cpu_cap(unsigned int); extern void setup_force_cpu_cap(unsigned int); +extern bool is_forced_cpu_cap(unsigned int); extern void print_cpu_info(unsigned int cpu); extern void init_intel_cacheinfo(struct cpuinfo_x86 *c);