1240135Skib/*- 2256670Skib * Copyright (c) 2013 The FreeBSD Foundation 3254147Sobrien * Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org> 4240135Skib * Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org> 5240135Skib * All rights reserved. 6240135Skib * 7256670Skib * Portions of this software were developed by Konstantin Belousov 8256670Skib * under sponsorship from the FreeBSD Foundation. 9256670Skib * 10240135Skib * Redistribution and use in source and binary forms, with or without 11240135Skib * modification, are permitted provided that the following conditions 12240135Skib * are met: 13240135Skib * 1. Redistributions of source code must retain the above copyright 14240135Skib * notice, this list of conditions and the following disclaimer 15240135Skib * in this position and unchanged. 16240135Skib * 2. Redistributions in binary form must reproduce the above copyright 17240135Skib * notice, this list of conditions and the following disclaimer in the 18240135Skib * documentation and/or other materials provided with the distribution. 19240135Skib * 20240135Skib * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21240135Skib * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22240135Skib * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23240135Skib * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24240135Skib * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25240135Skib * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26240135Skib * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27240135Skib * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28240135Skib * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29240135Skib * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30240135Skib * 31240135Skib */ 32240135Skib 33240135Skib#include <sys/cdefs.h> 34240135Skib__FBSDID("$FreeBSD$"); 35240135Skib 36240135Skib#include <sys/param.h> 37254147Sobrien#include <sys/kernel.h> 38273872Smarkm#include <sys/conf.h> 39240135Skib#include <sys/lock.h> 40256377Smarkm#include <sys/malloc.h> 41254147Sobrien#include <sys/module.h> 42256377Smarkm#include <sys/random.h> 43240135Skib#include <sys/systm.h> 44254147Sobrien 45254147Sobrien#include <machine/md_var.h> 46254147Sobrien#include <machine/specialreg.h> 47254147Sobrien 48256377Smarkm#include <dev/random/randomdev.h> 49240135Skib 50240135Skib#define RETRY_COUNT 10 51240135Skib 52273872Smarkmstatic u_int random_ivy_read(void *, u_int); 53240135Skib 54284959Smarkmstatic struct random_source random_ivy = { 55284959Smarkm .rs_ident = "Intel Secure Key RNG", 56284959Smarkm .rs_source = RANDOM_PURE_RDRAND, 57284959Smarkm .rs_read = random_ivy_read 58240135Skib}; 59240135Skib 60240135Skibstatic inline int 61274250Skibivy_rng_store(u_long *buf) 62240135Skib{ 63240135Skib#ifdef __GNUCLIKE_ASM 64274250Skib u_long rndval; 65256670Skib int retry; 66240135Skib 67256670Skib retry = RETRY_COUNT; 68240135Skib __asm __volatile( 69256670Skib "1:\n\t" 70274381Skib "rdrand %1\n\t" /* read randomness into rndval */ 71274250Skib "jc 2f\n\t" /* CF is set on success, exit retry loop */ 72256670Skib "dec %0\n\t" /* otherwise, retry-- */ 73256670Skib "jne 1b\n\t" /* and loop if retries are not exhausted */ 74274250Skib "2:" 75274250Skib : "+r" (retry), "=r" (rndval) : : "cc"); 76274250Skib *buf = rndval; 77256670Skib return (retry); 78240135Skib#else /* __GNUCLIKE_ASM */ 79240135Skib return (0); 80240135Skib#endif 81240135Skib} 82240135Skib 83274250Skib/* It is required that buf length is a multiple of sizeof(u_long). */ 84273872Smarkmstatic u_int 85273872Smarkmrandom_ivy_read(void *buf, u_int c) 86240135Skib{ 87274250Skib u_long *b, rndval; 88273872Smarkm u_int count; 89240135Skib 90273872Smarkm KASSERT(c % sizeof(*b) == 0, ("partial read %d", c)); 91273872Smarkm b = buf; 92273872Smarkm for (count = c; count > 0; count -= sizeof(*b)) { 93274250Skib if (ivy_rng_store(&rndval) == 0) 94240135Skib break; 95274250Skib *b++ = rndval; 96240135Skib } 97240135Skib return (c - count); 98240135Skib} 99240135Skib 100254147Sobrienstatic int 101254147Sobrienrdrand_modevent(module_t mod, int type, void *unused) 102254147Sobrien{ 103256377Smarkm int error = 0; 104254147Sobrien 105254147Sobrien switch (type) { 106254147Sobrien case MOD_LOAD: 107273872Smarkm if (cpu_feature2 & CPUID2_RDRAND) { 108284959Smarkm random_source_register(&random_ivy); 109284959Smarkm printf("random: fast provider: \"%s\"\n", random_ivy.rs_ident); 110273872Smarkm } 111256377Smarkm break; 112256377Smarkm 113256377Smarkm case MOD_UNLOAD: 114256377Smarkm if (cpu_feature2 & CPUID2_RDRAND) 115284959Smarkm random_source_deregister(&random_ivy); 116256377Smarkm break; 117256377Smarkm 118256377Smarkm case MOD_SHUTDOWN: 119256377Smarkm break; 120256377Smarkm 121256377Smarkm default: 122256377Smarkm error = EOPNOTSUPP; 123256377Smarkm break; 124256377Smarkm 125254147Sobrien } 126254147Sobrien 127256377Smarkm return (error); 128254147Sobrien} 129254147Sobrien 130273872SmarkmDEV_MODULE(rdrand, rdrand_modevent, NULL); 131273872SmarkmMODULE_VERSION(rdrand, 1); 132298102SkibMODULE_DEPEND(rdrand, random_device, 1, 1, 1); 133