2 * Copyright (c) 2012 Alex Hornung <alex@alexhornung.com>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
33 #include <sys/libkern.h>
34 #include <sys/module.h>
36 #include <sys/random.h>
37 #include <sys/sysctl.h>
39 #include <machine/specialreg.h>
41 #define RDRAND_ALIGN(p) (void *)(roundup2((uintptr_t)(p), 16))
42 #define RDRAND_SIZE 512
44 static int rdrand_debug
;
45 SYSCTL_INT(_debug
, OID_AUTO
, rdrand
, CTLFLAG_RW
, &rdrand_debug
, 0,
46 "Enable rdrand debugging");
49 struct callout sc_rng_co
;
54 static void rdrand_rng_harvest(void *);
55 int rdrand_rng(uint8_t *out
, long limit
);
59 rdrand_identify(driver_t
*drv
, device_t parent
)
62 /* NB: order 10 is so we get attached after h/w devices */
63 if (device_find_child(parent
, "rdrand", -1) == NULL
&&
64 BUS_ADD_CHILD(parent
, parent
, 10, "rdrand", -1) == 0)
65 panic("rdrand: could not attach");
70 rdrand_probe(device_t dev
)
73 if ((cpu_feature2
& CPUID2_RDRAND
) == 0) {
74 device_printf(dev
, "No RdRand support.\n");
78 device_set_desc(dev
, "RdRand RNG");
84 rdrand_attach(device_t dev
)
86 struct rdrand_softc
*sc
;
88 sc
= device_get_softc(dev
);
91 sc
->sc_rng_ticks
= hz
/ 10;
95 callout_init_mp(&sc
->sc_rng_co
);
96 callout_reset(&sc
->sc_rng_co
, sc
->sc_rng_ticks
,
97 rdrand_rng_harvest
, sc
);
104 rdrand_detach(device_t dev
)
106 struct rdrand_softc
*sc
;
108 sc
= device_get_softc(dev
);
110 callout_terminate(&sc
->sc_rng_co
);
117 rdrand_rng_harvest(void *arg
)
119 struct rdrand_softc
*sc
= arg
;
120 uint8_t randomness
[RDRAND_SIZE
+ 32];
121 uint8_t *arandomness
; /* randomness aligned */
124 arandomness
= RDRAND_ALIGN(randomness
);
126 cnt
= rdrand_rng(arandomness
, RDRAND_SIZE
);
127 if (cnt
> 0 && cnt
< sizeof(randomness
)) {
128 add_buffer_randomness_src(arandomness
, cnt
, RAND_SRC_RDRAND
);
131 kprintf("rdrand(%d): %02x %02x %02x %02x...\n",
140 callout_reset(&sc
->sc_rng_co
, sc
->sc_rng_ticks
,
141 rdrand_rng_harvest
, sc
);
145 static device_method_t rdrand_methods
[] = {
146 DEVMETHOD(device_identify
, rdrand_identify
),
147 DEVMETHOD(device_probe
, rdrand_probe
),
148 DEVMETHOD(device_attach
, rdrand_attach
),
149 DEVMETHOD(device_detach
, rdrand_detach
),
155 static driver_t rdrand_driver
= {
158 sizeof(struct rdrand_softc
),
161 static devclass_t rdrand_devclass
;
163 DRIVER_MODULE(rdrand
, nexus
, rdrand_driver
, rdrand_devclass
, NULL
, NULL
);
164 MODULE_VERSION(rdrand
, 1);
165 MODULE_DEPEND(rdrand
, crypto
, 1, 1, 1);