^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* Copyright (C) 2005 - 2008 Jeff Dike <jdike@{linux.intel,addtoit}.com> */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) /* Much of this ripped from drivers/char/hw_random.c, see there for other
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * copyright.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * This software may be used and distributed according to the terms
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * of the GNU General Public License, incorporated herein by reference.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/sched/signal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/miscdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/hw_random.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <irq_kern.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <os.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * core module information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define RNG_MODULE_NAME "hw_random"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /* Changed at init time, in the non-modular case, and at module load
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * time, in the module case. Presumably, the module subsystem
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * protects against a module being loaded twice at the same time.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static int random_fd = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static struct hwrng hwrng = { 0, };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static DECLARE_COMPLETION(have_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static int rng_dev_read(struct hwrng *rng, void *buf, size_t max, bool block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) ret = os_read_file(random_fd, buf, max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) if (block && ret == -EAGAIN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) add_sigio_fd(random_fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) ret = wait_for_completion_killable(&have_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) ignore_sigio_fd(random_fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) deactivate_fd(random_fd, RANDOM_IRQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return ret != -EAGAIN ? ret : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static irqreturn_t random_interrupt(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) complete(&have_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * rng_init - initialize RNG module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static int __init rng_init (void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) random_fd = err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) err = um_request_irq(RANDOM_IRQ, random_fd, IRQ_READ, random_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) 0, "random", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) goto err_out_cleanup_hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) sigio_broken(random_fd, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) hwrng.name = RNG_MODULE_NAME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) hwrng.read = rng_dev_read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) hwrng.quality = 1024;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) err = hwrng_register(&hwrng);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) pr_err(RNG_MODULE_NAME " registering failed (%d)\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) goto err_out_cleanup_hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) err_out_cleanup_hw:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) os_close_file(random_fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) random_fd = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * rng_cleanup - shutdown RNG module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static void cleanup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) free_irq_by_fd(random_fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) os_close_file(random_fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static void __exit rng_cleanup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) hwrng_unregister(&hwrng);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) os_close_file(random_fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) module_init (rng_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) module_exit (rng_cleanup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) __uml_exitcall(cleanup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) MODULE_LICENSE("GPL");