forked from luck/tmp_suning_uos_patched
a8b49c4bdf
[ Upstream commit 72d3e093afae79611fa38f8f2cfab9a888fe66f2 ] The UML random driver creates a dummy device under the guest, /dev/hw_random. When this file is read from the guest, the driver reads from the host machine's /dev/random, in-turn reading from the host kernel's entropy pool. This entropy pool could have been filled by a hardware random number generator or just the host kernel's internal software entropy generator. Currently the driver does not fill the guests kernel entropy pool, this requires a userspace tool running inside the guest (like rng-tools) to read from the dummy device provided by this driver, which then would fill the guest's internal entropy pool. This all seems quite pointless when we are already reading from an entropy pool, so this patch aims to register the device as a hwrng device using the hwrng-core framework. This not only improves and cleans up the driver, but also fills the guest's entropy pool without having to resort to using extra userspace tools in the guest. This is typically a nuisance when booting a guest: the random pool takes a long time (~200s) to build up enough entropy since the dummy hwrng is not used to fill the guest's pool. This port was originally attempted by Alexander Neville "dark" (in CC, discussion in Link), but the conversation there stalled since the handling of -EAGAIN errors were no removed and longer handled by the driver. This patch attempts to use the existing method of error handling but utilises the new hwrng core. The issue can be noticed when booting a UML guest: [ 2.560000] random: fast init done [ 214.000000] random: crng init done With the patch applied, filling the pool becomes a lot quicker: [ 2.560000] random: fast init done [ 12.000000] random: crng init done Cc: Alexander Neville <dark@volatile.bz> Link: https://lore.kernel.org/lkml/20190828204609.02a7ff70@TheDarkness/ Link: https://lore.kernel.org/lkml/20190829135001.6a5ff940@TheDarkness.local/ Cc: Sjoerd Simons <sjoerd.simons@collabora.co.uk> Signed-off-by: Christopher Obbard <chris.obbard@collabora.com> Acked-by: Anton Ivanov <anton.ivanov@cambridgegreys.com> Signed-off-by: Richard Weinberger <richard@nod.at> Signed-off-by: Sasha Levin <sashal@kernel.org>
123 lines
2.5 KiB
C
123 lines
2.5 KiB
C
/* Copyright (C) 2005 - 2008 Jeff Dike <jdike@{linux.intel,addtoit}.com> */
|
|
|
|
/* Much of this ripped from drivers/char/hw_random.c, see there for other
|
|
* copyright.
|
|
*
|
|
* This software may be used and distributed according to the terms
|
|
* of the GNU General Public License, incorporated herein by reference.
|
|
*/
|
|
#include <linux/sched/signal.h>
|
|
#include <linux/module.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/miscdevice.h>
|
|
#include <linux/hw_random.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/uaccess.h>
|
|
#include <init.h>
|
|
#include <irq_kern.h>
|
|
#include <os.h>
|
|
|
|
/*
|
|
* core module information
|
|
*/
|
|
#define RNG_MODULE_NAME "hw_random"
|
|
|
|
/* Changed at init time, in the non-modular case, and at module load
|
|
* time, in the module case. Presumably, the module subsystem
|
|
* protects against a module being loaded twice at the same time.
|
|
*/
|
|
static int random_fd = -1;
|
|
static struct hwrng hwrng = { 0, };
|
|
static DECLARE_COMPLETION(have_data);
|
|
|
|
static int rng_dev_read(struct hwrng *rng, void *buf, size_t max, bool block)
|
|
{
|
|
int ret;
|
|
|
|
for (;;) {
|
|
ret = os_read_file(random_fd, buf, max);
|
|
if (block && ret == -EAGAIN) {
|
|
add_sigio_fd(random_fd);
|
|
|
|
ret = wait_for_completion_killable(&have_data);
|
|
|
|
ignore_sigio_fd(random_fd);
|
|
deactivate_fd(random_fd, RANDOM_IRQ);
|
|
|
|
if (ret < 0)
|
|
break;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret != -EAGAIN ? ret : 0;
|
|
}
|
|
|
|
static irqreturn_t random_interrupt(int irq, void *data)
|
|
{
|
|
complete(&have_data);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
/*
|
|
* rng_init - initialize RNG module
|
|
*/
|
|
static int __init rng_init (void)
|
|
{
|
|
int err;
|
|
|
|
err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0);
|
|
if (err < 0)
|
|
goto out;
|
|
|
|
random_fd = err;
|
|
err = um_request_irq(RANDOM_IRQ, random_fd, IRQ_READ, random_interrupt,
|
|
0, "random", NULL);
|
|
if (err)
|
|
goto err_out_cleanup_hw;
|
|
|
|
sigio_broken(random_fd, 1);
|
|
hwrng.name = RNG_MODULE_NAME;
|
|
hwrng.read = rng_dev_read;
|
|
hwrng.quality = 1024;
|
|
|
|
err = hwrng_register(&hwrng);
|
|
if (err) {
|
|
pr_err(RNG_MODULE_NAME " registering failed (%d)\n", err);
|
|
goto err_out_cleanup_hw;
|
|
}
|
|
out:
|
|
return err;
|
|
|
|
err_out_cleanup_hw:
|
|
os_close_file(random_fd);
|
|
random_fd = -1;
|
|
goto out;
|
|
}
|
|
|
|
/*
|
|
* rng_cleanup - shutdown RNG module
|
|
*/
|
|
|
|
static void cleanup(void)
|
|
{
|
|
free_irq_by_fd(random_fd);
|
|
os_close_file(random_fd);
|
|
}
|
|
|
|
static void __exit rng_cleanup(void)
|
|
{
|
|
hwrng_unregister(&hwrng);
|
|
os_close_file(random_fd);
|
|
}
|
|
|
|
module_init (rng_init);
|
|
module_exit (rng_cleanup);
|
|
__uml_exitcall(cleanup);
|
|
|
|
MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver");
|
|
MODULE_LICENSE("GPL");
|