1*83c37607SAlex Hornung /* 2*83c37607SAlex Hornung * Copyright (c) 2012 Alex Hornung <alex@alexhornung.com>. 3*83c37607SAlex Hornung * All rights reserved. 4*83c37607SAlex Hornung * 5*83c37607SAlex Hornung * Redistribution and use in source and binary forms, with or without 6*83c37607SAlex Hornung * modification, are permitted provided that the following conditions 7*83c37607SAlex Hornung * are met: 8*83c37607SAlex Hornung * 9*83c37607SAlex Hornung * 1. Redistributions of source code must retain the above copyright 10*83c37607SAlex Hornung * notice, this list of conditions and the following disclaimer. 11*83c37607SAlex Hornung * 2. Redistributions in binary form must reproduce the above copyright 12*83c37607SAlex Hornung * notice, this list of conditions and the following disclaimer in 13*83c37607SAlex Hornung * the documentation and/or other materials provided with the 14*83c37607SAlex Hornung * distribution. 15*83c37607SAlex Hornung * 16*83c37607SAlex Hornung * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17*83c37607SAlex Hornung * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18*83c37607SAlex Hornung * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19*83c37607SAlex Hornung * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 20*83c37607SAlex Hornung * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21*83c37607SAlex Hornung * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 22*83c37607SAlex Hornung * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23*83c37607SAlex Hornung * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24*83c37607SAlex Hornung * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25*83c37607SAlex Hornung * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26*83c37607SAlex Hornung * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*83c37607SAlex Hornung * SUCH DAMAGE. 28*83c37607SAlex Hornung */ 29*83c37607SAlex Hornung #include <sys/param.h> 30*83c37607SAlex Hornung #include <sys/systm.h> 31*83c37607SAlex Hornung #include <sys/kernel.h> 32*83c37607SAlex Hornung #include <sys/kobj.h> 33*83c37607SAlex Hornung #include <sys/libkern.h> 34*83c37607SAlex Hornung #include <sys/module.h> 35*83c37607SAlex Hornung #include <sys/malloc.h> 36*83c37607SAlex Hornung #include <sys/bus.h> 37*83c37607SAlex Hornung #include <sys/random.h> 38*83c37607SAlex Hornung 39*83c37607SAlex Hornung #include <machine/specialreg.h> 40*83c37607SAlex Hornung 41*83c37607SAlex Hornung #define RDRAND_ALIGN(p) (void *)(roundup2((uintptr_t)(p), 16)) 42*83c37607SAlex Hornung 43*83c37607SAlex Hornung 44*83c37607SAlex Hornung struct rdrand_softc { 45*83c37607SAlex Hornung struct callout sc_rng_co; 46*83c37607SAlex Hornung int32_t sc_rng_ticks; 47*83c37607SAlex Hornung }; 48*83c37607SAlex Hornung 49*83c37607SAlex Hornung 50*83c37607SAlex Hornung static void rdrand_rng_harvest(void *); 51*83c37607SAlex Hornung int rdrand_rng(uint8_t *out, int limit); 52*83c37607SAlex Hornung 53*83c37607SAlex Hornung 54*83c37607SAlex Hornung MALLOC_DEFINE(M_RDRAND, "rdrand_data", "RdRand Data"); 55*83c37607SAlex Hornung 56*83c37607SAlex Hornung 57*83c37607SAlex Hornung static void 58*83c37607SAlex Hornung rdrand_identify(driver_t *drv, device_t parent) 59*83c37607SAlex Hornung { 60*83c37607SAlex Hornung 61*83c37607SAlex Hornung /* NB: order 10 is so we get attached after h/w devices */ 62*83c37607SAlex Hornung if (device_find_child(parent, "rdrand", -1) == NULL && 63*83c37607SAlex Hornung BUS_ADD_CHILD(parent, parent, 10, "rdrand", -1) == 0) 64*83c37607SAlex Hornung panic("rdrand: could not attach"); 65*83c37607SAlex Hornung } 66*83c37607SAlex Hornung 67*83c37607SAlex Hornung 68*83c37607SAlex Hornung static int 69*83c37607SAlex Hornung rdrand_probe(device_t dev) 70*83c37607SAlex Hornung { 71*83c37607SAlex Hornung 72*83c37607SAlex Hornung if ((cpu_feature2 & CPUID2_RDRAND) == 0) { 73*83c37607SAlex Hornung device_printf(dev, "No RdRand support.\n"); 74*83c37607SAlex Hornung return (EINVAL); 75*83c37607SAlex Hornung } 76*83c37607SAlex Hornung 77*83c37607SAlex Hornung device_set_desc(dev, "RdRand RNG"); 78*83c37607SAlex Hornung return 0; 79*83c37607SAlex Hornung } 80*83c37607SAlex Hornung 81*83c37607SAlex Hornung 82*83c37607SAlex Hornung static int 83*83c37607SAlex Hornung rdrand_attach(device_t dev) 84*83c37607SAlex Hornung { 85*83c37607SAlex Hornung struct rdrand_softc *sc; 86*83c37607SAlex Hornung 87*83c37607SAlex Hornung sc = device_get_softc(dev); 88*83c37607SAlex Hornung 89*83c37607SAlex Hornung if (hz > 100) 90*83c37607SAlex Hornung sc->sc_rng_ticks = hz/100; 91*83c37607SAlex Hornung else 92*83c37607SAlex Hornung sc->sc_rng_ticks = 1; 93*83c37607SAlex Hornung 94*83c37607SAlex Hornung callout_init_mp(&sc->sc_rng_co); 95*83c37607SAlex Hornung callout_reset(&sc->sc_rng_co, sc->sc_rng_ticks, 96*83c37607SAlex Hornung rdrand_rng_harvest, sc); 97*83c37607SAlex Hornung 98*83c37607SAlex Hornung return 0; 99*83c37607SAlex Hornung } 100*83c37607SAlex Hornung 101*83c37607SAlex Hornung 102*83c37607SAlex Hornung static int 103*83c37607SAlex Hornung rdrand_detach(device_t dev) 104*83c37607SAlex Hornung { 105*83c37607SAlex Hornung struct rdrand_softc *sc; 106*83c37607SAlex Hornung 107*83c37607SAlex Hornung sc = device_get_softc(dev); 108*83c37607SAlex Hornung 109*83c37607SAlex Hornung callout_stop_sync(&sc->sc_rng_co); 110*83c37607SAlex Hornung 111*83c37607SAlex Hornung return (0); 112*83c37607SAlex Hornung } 113*83c37607SAlex Hornung 114*83c37607SAlex Hornung 115*83c37607SAlex Hornung static int random_count = 512; /* in bytes */ 116*83c37607SAlex Hornung 117*83c37607SAlex Hornung static void 118*83c37607SAlex Hornung rdrand_rng_harvest(void *arg) 119*83c37607SAlex Hornung { 120*83c37607SAlex Hornung struct rdrand_softc *sc = arg; 121*83c37607SAlex Hornung uint8_t randomness[2048]; 122*83c37607SAlex Hornung uint8_t *arandomness; /* randomness aligned */ 123*83c37607SAlex Hornung int i, cnt; 124*83c37607SAlex Hornung 125*83c37607SAlex Hornung arandomness = RDRAND_ALIGN(randomness); 126*83c37607SAlex Hornung cnt = rdrand_rng(arandomness, random_count); 127*83c37607SAlex Hornung 128*83c37607SAlex Hornung for (i = 0; i < cnt; i++) 129*83c37607SAlex Hornung add_true_randomness((int)arandomness[i]); 130*83c37607SAlex Hornung 131*83c37607SAlex Hornung callout_reset(&sc->sc_rng_co, sc->sc_rng_ticks, 132*83c37607SAlex Hornung rdrand_rng_harvest, sc); 133*83c37607SAlex Hornung } 134*83c37607SAlex Hornung 135*83c37607SAlex Hornung 136*83c37607SAlex Hornung static device_method_t rdrand_methods[] = { 137*83c37607SAlex Hornung DEVMETHOD(device_identify, rdrand_identify), 138*83c37607SAlex Hornung DEVMETHOD(device_probe, rdrand_probe), 139*83c37607SAlex Hornung DEVMETHOD(device_attach, rdrand_attach), 140*83c37607SAlex Hornung DEVMETHOD(device_detach, rdrand_detach), 141*83c37607SAlex Hornung 142*83c37607SAlex Hornung {0, 0}, 143*83c37607SAlex Hornung }; 144*83c37607SAlex Hornung 145*83c37607SAlex Hornung 146*83c37607SAlex Hornung static driver_t rdrand_driver = { 147*83c37607SAlex Hornung "rdrand", 148*83c37607SAlex Hornung rdrand_methods, 149*83c37607SAlex Hornung sizeof(struct rdrand_softc), 150*83c37607SAlex Hornung }; 151*83c37607SAlex Hornung 152*83c37607SAlex Hornung static devclass_t rdrand_devclass; 153*83c37607SAlex Hornung 154*83c37607SAlex Hornung DRIVER_MODULE(rdrand, nexus, rdrand_driver, rdrand_devclass, NULL, NULL); 155*83c37607SAlex Hornung MODULE_VERSION(rdrand, 1); 156*83c37607SAlex Hornung MODULE_DEPEND(rdrand, crypto, 1, 1, 1); 157