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$"); 31 32 #include <sys/param.h> 33 #include <sys/time.h> 34 #include <sys/kernel.h> 35 #include <sys/lock.h> 36 #include <sys/module.h> 37 #include <sys/mutex.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/random_adaptors.h> 45 #include <dev/random/randomdev.h> 46 47 #define RETRY_COUNT 10 48 49 static void random_ivy_init(void); 50 static void random_ivy_deinit(void); 51 static int random_ivy_read(void *, int); 52 53 struct random_adaptor random_ivy = { 54 .ident = "Hardware, Intel IvyBridge+ RNG", 55 .init = random_ivy_init, 56 .deinit = random_ivy_deinit, 57 .read = random_ivy_read, 58 .write = (random_write_func_t *)random_null_func, 59 .reseed = (random_reseed_func_t *)random_null_func, 60 .seeded = 1, 61 }; 62 63 static inline int 64 ivy_rng_store(long *tmp) 65 { 66 #ifdef __GNUCLIKE_ASM 67 uint32_t count; 68 69 __asm __volatile( 70 #ifdef __amd64__ 71 ".byte\t0x48,0x0f,0xc7,0xf0\n\t" /* rdrand %rax */ 72 "jnc\t1f\n\t" 73 "movq\t%%rax,%1\n\t" 74 "movl\t$8,%%eax\n" 75 #else /* i386 */ 76 ".byte\t0x0f,0xc7,0xf0\n\t" /* rdrand %eax */ 77 "jnc\t1f\n\t" 78 "movl\t%%eax,%1\n\t" 79 "movl\t$4,%%eax\n" 80 #endif 81 "1:\n" /* %eax is cleared by processor on failure */ 82 : "=a" (count), "=g" (*tmp) : "a" (0) : "cc"); 83 return (count); 84 #else /* __GNUCLIKE_ASM */ 85 return (0); 86 #endif 87 } 88 89 static void 90 random_ivy_init(void) 91 { 92 } 93 94 void 95 random_ivy_deinit(void) 96 { 97 } 98 99 static int 100 random_ivy_read(void *buf, int c) 101 { 102 char *b; 103 long tmp; 104 int count, res, retry; 105 106 for (count = c, b = buf; count > 0; count -= res, b += res) { 107 for (retry = 0; retry < RETRY_COUNT; retry++) { 108 res = ivy_rng_store(&tmp); 109 if (res != 0) 110 break; 111 } 112 if (res == 0) 113 break; 114 if (res > count) 115 res = count; 116 memcpy(b, &tmp, res); 117 } 118 return (c - count); 119 } 120 121 static int 122 rdrand_modevent(module_t mod, int type, void *unused) 123 { 124 125 switch (type) { 126 case MOD_LOAD: 127 if (cpu_feature2 & CPUID2_RDRAND) { 128 random_adaptor_register("rdrand", &random_ivy); 129 EVENTHANDLER_INVOKE(random_adaptor_attach, &random_ivy); 130 return (0); 131 } else { 132 #ifndef KLD_MODULE 133 if (bootverbose) 134 #endif 135 printf( 136 "%s: RDRAND feature is not present on this CPU\n", 137 random_ivy.ident); 138 return (0); 139 } 140 } 141 142 return (EINVAL); 143 } 144 145 RANDOM_ADAPTOR_MODULE(random_rdrand, rdrand_modevent, 1); 146