From c3e6a24425bc9986da0d0a5a8c92e0b9ed7f18fa Mon Sep 17 00:00:00 2001
From: "Srivatsa S. Bhat" <srivatsa@csail.mit.edu>
Date: Thu, 28 Jun 2018 08:51:18 -0700
Subject: [PATCH] hwrng: rdrand - Add RNG driver based on x86 rdrand
 instruction

Add a Hardware Random Number Generator driver, which uses the
'rdrand' instruction available on modern Intel and AMD CPUs.

This can be used to feed the kernel's entropy pool on
entropy-starved virtual machines.

Signed-off-by: Srivatsa S. Bhat <srivatsa@csail.mit.edu>
---
 drivers/char/hw_random/Kconfig      | 14 +++++++++
 drivers/char/hw_random/Makefile     |  1 +
 drivers/char/hw_random/rdrand-rng.c | 61 +++++++++++++++++++++++++++++++++++++
 3 files changed, 76 insertions(+)
 create mode 100644 drivers/char/hw_random/rdrand-rng.c

diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index dbf2271..b4e558d 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -62,6 +62,20 @@ config HW_RANDOM_AMD
 
 	  If unsure, say Y.
 
+config HW_RANDOM_RDRAND
+	tristate "x86 rdrand Random Number Generator support"
+	depends on (X86_32 || X86_64) && ARCH_RANDOM
+	default HW_RANDOM
+	---help---
+	  This driver provides kernel-side support for a Random Number
+	  Generator that uses the 'rdrand' instruction on modern Intel
+	  and AMD CPUs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rdrand-rng.
+
+	  If unsure, say N.
+
 config HW_RANDOM_ATMEL
 	tristate "Atmel Random Number Generator support"
 	depends on ARCH_AT91 && HAVE_CLK && OF
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index 5ad3976..c186ddb 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -7,6 +7,7 @@ rng-core-y := core.o
 obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o
 obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o
 obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o
+obj-$(CONFIG_HW_RANDOM_RDRAND) += rdrand-rng.o
 obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o
 obj-$(CONFIG_HW_RANDOM_BCM63XX)	+= bcm63xx-rng.o
 obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
diff --git a/drivers/char/hw_random/rdrand-rng.c b/drivers/char/hw_random/rdrand-rng.c
new file mode 100644
index 0000000..e1cf7f3
--- /dev/null
+++ b/drivers/char/hw_random/rdrand-rng.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RNG driver that uses the 'rdrand' instruction (found on modern
+ * Intel and AMD CPUs).
+ *
+ * Author: Srivatsa S. Bhat <srivatsa@csail.mit.edu>
+ *
+ */
+
+#include <linux/hw_random.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/archrandom.h>
+
+#define PFX	KBUILD_MODNAME ": "
+
+static int rdrand_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+{
+	unsigned long *data = buf;
+	size_t read = 0;
+
+	while (read < max) {
+		arch_get_random_long(data);
+		data++;
+		read += sizeof(unsigned long);
+	}
+
+	return read;
+}
+
+static struct hwrng rdrand_rng = {
+	.name		= KBUILD_MODNAME,
+	.quality	= 1000,
+	.read		= rdrand_rng_read,
+};
+
+static int __init mod_init(void)
+{
+	int err = -ENODEV;
+
+	if (!arch_has_random())
+		return err; /* rdrand not available. */
+
+	err = hwrng_register(&rdrand_rng);
+	if (err)
+		pr_err(PFX "RNG registration failed (%d)\n", err);
+
+	return err;
+}
+
+static void __exit mod_exit(void)
+{
+	hwrng_unregister(&rdrand_rng);
+}
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("Srivatsa S. Bhat <srivatsa@csail.mit.edu>");
+MODULE_DESCRIPTION("H/W RNG driver for x86 CPUs that support rdrand");
+MODULE_LICENSE("GPL");
-- 
2.7.4