xref: /freebsd/sys/dev/random/ivy.c (revision f02e47dc1e9d7e175ed72ec38c6c14f6375eb3c5)
1ef9461baSKonstantin Belousov /*-
25711939bSDavid E. O'Brien  * Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org>
3ef9461baSKonstantin Belousov  * Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
4ef9461baSKonstantin Belousov  * All rights reserved.
5ef9461baSKonstantin Belousov  *
6ef9461baSKonstantin Belousov  * Redistribution and use in source and binary forms, with or without
7ef9461baSKonstantin Belousov  * modification, are permitted provided that the following conditions
8ef9461baSKonstantin Belousov  * are met:
9ef9461baSKonstantin Belousov  * 1. Redistributions of source code must retain the above copyright
10ef9461baSKonstantin Belousov  *    notice, this list of conditions and the following disclaimer
11ef9461baSKonstantin Belousov  *    in this position and unchanged.
12ef9461baSKonstantin Belousov  * 2. Redistributions in binary form must reproduce the above copyright
13ef9461baSKonstantin Belousov  *    notice, this list of conditions and the following disclaimer in the
14ef9461baSKonstantin Belousov  *    documentation and/or other materials provided with the distribution.
15ef9461baSKonstantin Belousov  *
16ef9461baSKonstantin Belousov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17ef9461baSKonstantin Belousov  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18ef9461baSKonstantin Belousov  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19ef9461baSKonstantin Belousov  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20ef9461baSKonstantin Belousov  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21ef9461baSKonstantin Belousov  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22ef9461baSKonstantin Belousov  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23ef9461baSKonstantin Belousov  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24ef9461baSKonstantin Belousov  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25ef9461baSKonstantin Belousov  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26ef9461baSKonstantin Belousov  *
27ef9461baSKonstantin Belousov  */
28ef9461baSKonstantin Belousov 
29ef9461baSKonstantin Belousov #include <sys/cdefs.h>
30ef9461baSKonstantin Belousov __FBSDID("$FreeBSD$");
31ef9461baSKonstantin Belousov 
32ef9461baSKonstantin Belousov #include <sys/param.h>
335711939bSDavid E. O'Brien #include <sys/kernel.h>
34ef9461baSKonstantin Belousov #include <sys/lock.h>
355711939bSDavid E. O'Brien #include <sys/module.h>
36*f02e47dcSMark Murray #include <sys/random.h>
37ef9461baSKonstantin Belousov #include <sys/selinfo.h>
38ef9461baSKonstantin Belousov #include <sys/systm.h>
395711939bSDavid E. O'Brien 
405711939bSDavid E. O'Brien #include <machine/md_var.h>
415711939bSDavid E. O'Brien #include <machine/specialreg.h>
425711939bSDavid E. O'Brien 
43*f02e47dcSMark Murray #include <dev/random/live_entropy_sources.h>
445711939bSDavid E. O'Brien #include <dev/random/random_adaptors.h>
45ef9461baSKonstantin Belousov #include <dev/random/randomdev.h>
46ef9461baSKonstantin Belousov 
47ef9461baSKonstantin Belousov #define	RETRY_COUNT	10
48ef9461baSKonstantin Belousov 
49ef9461baSKonstantin Belousov static int random_ivy_read(void *, int);
50ef9461baSKonstantin Belousov 
51*f02e47dcSMark Murray struct random_hardware_source random_ivy = {
52ef9461baSKonstantin Belousov 	.ident = "Hardware, Intel IvyBridge+ RNG",
53*f02e47dcSMark Murray 	.source = RANDOM_PURE_RDRAND,
54*f02e47dcSMark Murray 	.read = random_ivy_read
55ef9461baSKonstantin Belousov };
56ef9461baSKonstantin Belousov 
57ef9461baSKonstantin Belousov static inline int
58*f02e47dcSMark Murray ivy_rng_store(uint64_t *tmp)
59ef9461baSKonstantin Belousov {
60ef9461baSKonstantin Belousov #ifdef __GNUCLIKE_ASM
61ef9461baSKonstantin Belousov 	uint32_t count;
62ef9461baSKonstantin Belousov 
63ef9461baSKonstantin Belousov 	__asm __volatile(
64ef9461baSKonstantin Belousov #ifdef __amd64__
65*f02e47dcSMark Murray 	    "rdrand\t%%rax\n\t"
66ef9461baSKonstantin Belousov 	    "jnc\t1f\n\t"
67ef9461baSKonstantin Belousov 	    "movq\t%%rax,%1\n\t"
68ef9461baSKonstantin Belousov 	    "movl\t$8,%%eax\n"
69ef9461baSKonstantin Belousov #else /* i386 */
70*f02e47dcSMark Murray 	    "rdrand\t%%eax\n\t"
71ef9461baSKonstantin Belousov 	    "jnc\t1f\n\t"
72ef9461baSKonstantin Belousov 	    "movl\t%%eax,%1\n\t"
73ef9461baSKonstantin Belousov 	    "movl\t$4,%%eax\n"
74ef9461baSKonstantin Belousov #endif
75ef9461baSKonstantin Belousov 	    "1:\n"	/* %eax is cleared by processor on failure */
76ef9461baSKonstantin Belousov 	    : "=a" (count), "=g" (*tmp) : "a" (0) : "cc");
77ef9461baSKonstantin Belousov 	return (count);
78ef9461baSKonstantin Belousov #else /* __GNUCLIKE_ASM */
79ef9461baSKonstantin Belousov 	return (0);
80ef9461baSKonstantin Belousov #endif
81ef9461baSKonstantin Belousov }
82ef9461baSKonstantin Belousov 
83ef9461baSKonstantin Belousov static int
84ef9461baSKonstantin Belousov random_ivy_read(void *buf, int c)
85ef9461baSKonstantin Belousov {
86*f02e47dcSMark Murray 	uint8_t *b;
87*f02e47dcSMark Murray 	int count, ret, retry;
88*f02e47dcSMark Murray 	uint64_t tmp;
89ef9461baSKonstantin Belousov 
90*f02e47dcSMark Murray 	b = buf;
91*f02e47dcSMark Murray 	for (count = c; count > 0; count -= ret) {
92ef9461baSKonstantin Belousov 		for (retry = 0; retry < RETRY_COUNT; retry++) {
93*f02e47dcSMark Murray 			ret = ivy_rng_store(&tmp);
94*f02e47dcSMark Murray 			if (ret != 0)
95ef9461baSKonstantin Belousov 				break;
96ef9461baSKonstantin Belousov 		}
97*f02e47dcSMark Murray 		if (ret == 0)
98ef9461baSKonstantin Belousov 			break;
99*f02e47dcSMark Murray 		if (ret > count)
100*f02e47dcSMark Murray 			ret = count;
101*f02e47dcSMark Murray 		memcpy(b, &tmp, ret);
102*f02e47dcSMark Murray 		b += ret;
103ef9461baSKonstantin Belousov 	}
104ef9461baSKonstantin Belousov 	return (c - count);
105ef9461baSKonstantin Belousov }
106ef9461baSKonstantin Belousov 
1075711939bSDavid E. O'Brien static int
1085711939bSDavid E. O'Brien rdrand_modevent(module_t mod, int type, void *unused)
1095711939bSDavid E. O'Brien {
110*f02e47dcSMark Murray 	int error = 0;
1115711939bSDavid E. O'Brien 
1125711939bSDavid E. O'Brien 	switch (type) {
1135711939bSDavid E. O'Brien 	case MOD_LOAD:
114*f02e47dcSMark Murray 		if (cpu_feature2 & CPUID2_RDRAND)
115*f02e47dcSMark Murray 			live_entropy_source_register(&random_ivy);
116*f02e47dcSMark Murray 		else
1175711939bSDavid E. O'Brien #ifndef KLD_MODULE
1185711939bSDavid E. O'Brien 			if (bootverbose)
119ef9461baSKonstantin Belousov #endif
120*f02e47dcSMark Murray 				printf("%s: RDRAND is not present\n",
1215711939bSDavid E. O'Brien 				    random_ivy.ident);
122*f02e47dcSMark Murray 		break;
123*f02e47dcSMark Murray 
124*f02e47dcSMark Murray 	case MOD_UNLOAD:
125*f02e47dcSMark Murray 		if (cpu_feature2 & CPUID2_RDRAND)
126*f02e47dcSMark Murray 			live_entropy_source_deregister(&random_ivy);
127*f02e47dcSMark Murray 		break;
128*f02e47dcSMark Murray 
129*f02e47dcSMark Murray 	case MOD_SHUTDOWN:
130*f02e47dcSMark Murray 		break;
131*f02e47dcSMark Murray 
132*f02e47dcSMark Murray 	default:
133*f02e47dcSMark Murray 		error = EOPNOTSUPP;
134*f02e47dcSMark Murray 		break;
135*f02e47dcSMark Murray 
1365711939bSDavid E. O'Brien 	}
1375711939bSDavid E. O'Brien 
138*f02e47dcSMark Murray 	return (error);
1395711939bSDavid E. O'Brien }
1405711939bSDavid E. O'Brien 
141*f02e47dcSMark Murray LIVE_ENTROPY_SRC_MODULE(random_rdrand, rdrand_modevent, 1);
142