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