xref: /freebsd/sys/dev/random/ivy.c (revision ef9461ba0e07fe9e0858bc624001342c17f2918c)
1*ef9461baSKonstantin Belousov /*-
2*ef9461baSKonstantin Belousov  * Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
3*ef9461baSKonstantin Belousov  * All rights reserved.
4*ef9461baSKonstantin Belousov  *
5*ef9461baSKonstantin Belousov  * Redistribution and use in source and binary forms, with or without
6*ef9461baSKonstantin Belousov  * modification, are permitted provided that the following conditions
7*ef9461baSKonstantin Belousov  * are met:
8*ef9461baSKonstantin Belousov  * 1. Redistributions of source code must retain the above copyright
9*ef9461baSKonstantin Belousov  *    notice, this list of conditions and the following disclaimer
10*ef9461baSKonstantin Belousov  *    in this position and unchanged.
11*ef9461baSKonstantin Belousov  * 2. Redistributions in binary form must reproduce the above copyright
12*ef9461baSKonstantin Belousov  *    notice, this list of conditions and the following disclaimer in the
13*ef9461baSKonstantin Belousov  *    documentation and/or other materials provided with the distribution.
14*ef9461baSKonstantin Belousov  *
15*ef9461baSKonstantin Belousov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16*ef9461baSKonstantin Belousov  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17*ef9461baSKonstantin Belousov  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18*ef9461baSKonstantin Belousov  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19*ef9461baSKonstantin Belousov  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20*ef9461baSKonstantin Belousov  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21*ef9461baSKonstantin Belousov  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22*ef9461baSKonstantin Belousov  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23*ef9461baSKonstantin Belousov  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24*ef9461baSKonstantin Belousov  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*ef9461baSKonstantin Belousov  *
26*ef9461baSKonstantin Belousov  */
27*ef9461baSKonstantin Belousov 
28*ef9461baSKonstantin Belousov #include <sys/cdefs.h>
29*ef9461baSKonstantin Belousov __FBSDID("$FreeBSD$");
30*ef9461baSKonstantin Belousov 
31*ef9461baSKonstantin Belousov #include "opt_cpu.h"
32*ef9461baSKonstantin Belousov 
33*ef9461baSKonstantin Belousov #ifdef IVY_RNG
34*ef9461baSKonstantin Belousov 
35*ef9461baSKonstantin Belousov #include <sys/param.h>
36*ef9461baSKonstantin Belousov #include <sys/time.h>
37*ef9461baSKonstantin Belousov #include <sys/lock.h>
38*ef9461baSKonstantin Belousov #include <sys/mutex.h>
39*ef9461baSKonstantin Belousov #include <sys/selinfo.h>
40*ef9461baSKonstantin Belousov #include <sys/systm.h>
41*ef9461baSKonstantin Belousov #include <dev/random/randomdev.h>
42*ef9461baSKonstantin Belousov 
43*ef9461baSKonstantin Belousov #define	RETRY_COUNT	10
44*ef9461baSKonstantin Belousov 
45*ef9461baSKonstantin Belousov static void random_ivy_init(void);
46*ef9461baSKonstantin Belousov static void random_ivy_deinit(void);
47*ef9461baSKonstantin Belousov static int random_ivy_read(void *, int);
48*ef9461baSKonstantin Belousov 
49*ef9461baSKonstantin Belousov struct random_systat random_ivy = {
50*ef9461baSKonstantin Belousov 	.ident = "Hardware, Intel IvyBridge+ RNG",
51*ef9461baSKonstantin Belousov 	.init = random_ivy_init,
52*ef9461baSKonstantin Belousov 	.deinit = random_ivy_deinit,
53*ef9461baSKonstantin Belousov 	.read = random_ivy_read,
54*ef9461baSKonstantin Belousov 	.write = (random_write_func_t *)random_null_func,
55*ef9461baSKonstantin Belousov 	.reseed = (random_reseed_func_t *)random_null_func,
56*ef9461baSKonstantin Belousov 	.seeded = 1,
57*ef9461baSKonstantin Belousov };
58*ef9461baSKonstantin Belousov 
59*ef9461baSKonstantin Belousov static inline int
60*ef9461baSKonstantin Belousov ivy_rng_store(long *tmp)
61*ef9461baSKonstantin Belousov {
62*ef9461baSKonstantin Belousov #ifdef __GNUCLIKE_ASM
63*ef9461baSKonstantin Belousov 	uint32_t count;
64*ef9461baSKonstantin Belousov 
65*ef9461baSKonstantin Belousov 	__asm __volatile(
66*ef9461baSKonstantin Belousov #ifdef __amd64__
67*ef9461baSKonstantin Belousov 	    ".byte\t0x48,0x0f,0xc7,0xf0\n\t" /* rdrand %rax */
68*ef9461baSKonstantin Belousov 	    "jnc\t1f\n\t"
69*ef9461baSKonstantin Belousov 	    "movq\t%%rax,%1\n\t"
70*ef9461baSKonstantin Belousov 	    "movl\t$8,%%eax\n"
71*ef9461baSKonstantin Belousov #else /* i386 */
72*ef9461baSKonstantin Belousov 	    ".byte\t0x0f,0xc7,0xf0\n\t" /* rdrand %eax */
73*ef9461baSKonstantin Belousov 	    "jnc\t1f\n\t"
74*ef9461baSKonstantin Belousov 	    "movl\t%%eax,%1\n\t"
75*ef9461baSKonstantin Belousov 	    "movl\t$4,%%eax\n"
76*ef9461baSKonstantin Belousov #endif
77*ef9461baSKonstantin Belousov 	    "1:\n"	/* %eax is cleared by processor on failure */
78*ef9461baSKonstantin Belousov 	    : "=a" (count), "=g" (*tmp) : "a" (0) : "cc");
79*ef9461baSKonstantin Belousov 	return (count);
80*ef9461baSKonstantin Belousov #else /* __GNUCLIKE_ASM */
81*ef9461baSKonstantin Belousov 	return (0);
82*ef9461baSKonstantin Belousov #endif
83*ef9461baSKonstantin Belousov }
84*ef9461baSKonstantin Belousov 
85*ef9461baSKonstantin Belousov static void
86*ef9461baSKonstantin Belousov random_ivy_init(void)
87*ef9461baSKonstantin Belousov {
88*ef9461baSKonstantin Belousov }
89*ef9461baSKonstantin Belousov 
90*ef9461baSKonstantin Belousov void
91*ef9461baSKonstantin Belousov random_ivy_deinit(void)
92*ef9461baSKonstantin Belousov {
93*ef9461baSKonstantin Belousov }
94*ef9461baSKonstantin Belousov 
95*ef9461baSKonstantin Belousov static int
96*ef9461baSKonstantin Belousov random_ivy_read(void *buf, int c)
97*ef9461baSKonstantin Belousov {
98*ef9461baSKonstantin Belousov 	char *b;
99*ef9461baSKonstantin Belousov 	long tmp;
100*ef9461baSKonstantin Belousov 	int count, res, retry;
101*ef9461baSKonstantin Belousov 
102*ef9461baSKonstantin Belousov 	for (count = c, b = buf; count > 0; count -= res, b += res) {
103*ef9461baSKonstantin Belousov 		for (retry = 0; retry < RETRY_COUNT; retry++) {
104*ef9461baSKonstantin Belousov 			res = ivy_rng_store(&tmp);
105*ef9461baSKonstantin Belousov 			if (res != 0)
106*ef9461baSKonstantin Belousov 				break;
107*ef9461baSKonstantin Belousov 		}
108*ef9461baSKonstantin Belousov 		if (res == 0)
109*ef9461baSKonstantin Belousov 			break;
110*ef9461baSKonstantin Belousov 		if (res > count)
111*ef9461baSKonstantin Belousov 			res = count;
112*ef9461baSKonstantin Belousov 		memcpy(b, &tmp, res);
113*ef9461baSKonstantin Belousov 	}
114*ef9461baSKonstantin Belousov 	return (c - count);
115*ef9461baSKonstantin Belousov }
116*ef9461baSKonstantin Belousov 
117*ef9461baSKonstantin Belousov #endif
118