@@ -593,6 +593,7 @@ config KVM_GUEST
bool "KVM Guest support (including kvmclock)"
depends on PARAVIRT
select PARAVIRT_CLOCK
+ select ARCH_SLOW_RNG
default y
---help---
This option enables various optimizations for running under the KVM
@@ -627,6 +628,9 @@ config PARAVIRT_TIME_ACCOUNTING
config PARAVIRT_CLOCK
bool
+config ARCH_SLOW_RNG
+ bool
+
endif #HYPERVISOR_GUEST
config NO_BOOTMEM
new file mode 100644
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the Linux kernel.
+ *
+ * Copyright (c) 2014 Andy Lutomirski
+ * Authors: Andy Lutomirski <luto@amacapital.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef ASM_X86_ARCHSLOWRANDOM_H
+#define ASM_X86_ARCHSLOWRANDOM_H
+
+#ifndef CONFIG_ARCH_SLOW_RNG
+# error archslowrng.h should not be included if !CONFIG_ARCH_SLOW_RNG
+#endif
+
+/*
+ * Performance is irrelevant here, so there's no point in using the
+ * paravirt ops mechanism. Instead just use a function pointer.
+ */
+extern int (*arch_get_slow_rng_u64)(u64 *v);
+
+#endif /* ASM_X86_ARCHSLOWRANDOM_H */
@@ -416,6 +416,25 @@ void kvm_disable_steal_time(void)
wrmsr(MSR_KVM_STEAL_TIME, 0, 0);
}
+static int nop_get_slow_rng_u64(u64 *v)
+{
+ return 0;
+}
+
+static int kvm_get_slow_rng_u64(u64 *v)
+{
+ /*
+ * Allow migration from a hypervisor with the GET_RNG_SEED
+ * feature to a hypervisor without it.
+ */
+ if (rdmsrl_safe(MSR_KVM_GET_RNG_SEED, v) == 0)
+ return 1;
+ else
+ return 0;
+}
+
+int (*arch_get_slow_rng_u64)(u64 *v) = nop_get_slow_rng_u64;
+
#ifdef CONFIG_SMP
static void __init kvm_smp_prepare_boot_cpu(void)
{
@@ -493,6 +512,9 @@ void __init kvm_guest_init(void)
if (kvmclock_vsyscall)
kvm_setup_vsyscall_timeinfo();
+ if (kvm_para_has_feature(KVM_FEATURE_GET_RNG_SEED))
+ arch_get_slow_rng_u64 = kvm_get_slow_rng_u64;
+
#ifdef CONFIG_SMP
smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu;
register_cpu_notifier(&kvm_cpu_notifier);
@@ -106,6 +106,15 @@ static inline int arch_has_random_seed(void)
}
#endif
+#ifdef CONFIG_ARCH_SLOW_RNG
+# include <asm/archslowrng.h>
+#else
+static inline int arch_get_slow_rng_u64(u64 *v)
+{
+ return 0;
+}
+#endif
+
/* Pseudo random number generator from numerical recipes. */
static inline u32 next_pseudo_random32(u32 seed)
{
arch_get_slow_rng_u64 tries to get 64 bits of RNG seed data. Unlike arch_get_random_{bytes,seed}, etc., it makes no claims about entropy content. It's also likely to be much slower and should not be used frequently. That being said, it should be fast enough to call several times during boot without any noticeable slowdown. This initial implementation backs it with MSR_KVM_GET_RNG_SEED if available. The intent is for other hypervisor guest implementations to implement this interface. Signed-off-by: Andy Lutomirski <luto@amacapital.net> --- arch/x86/Kconfig | 4 ++++ arch/x86/include/asm/archslowrng.h | 30 ++++++++++++++++++++++++++++++ arch/x86/kernel/kvm.c | 22 ++++++++++++++++++++++ include/linux/random.h | 9 +++++++++ 4 files changed, 65 insertions(+) create mode 100644 arch/x86/include/asm/archslowrng.h