1240135Skib/*- 2257491Skib * 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 * 7257491Skib * Portions of this software were developed by Konstantin Belousov 8257491Skib * under sponsorship from the FreeBSD Foundation. 9257491Skib * 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: releng/10.3/sys/dev/random/ivy.c 268519 2014-07-11 00:26:57Z delphij $"); 35240135Skib 36240135Skib#include <sys/param.h> 37254147Sobrien#include <sys/kernel.h> 38240135Skib#include <sys/lock.h> 39256381Smarkm#include <sys/malloc.h> 40254147Sobrien#include <sys/module.h> 41256381Smarkm#include <sys/random.h> 42240135Skib#include <sys/selinfo.h> 43240135Skib#include <sys/systm.h> 44254147Sobrien 45254147Sobrien#include <machine/md_var.h> 46254147Sobrien#include <machine/specialreg.h> 47254147Sobrien 48256381Smarkm#include <dev/random/randomdev.h> 49256381Smarkm#include <dev/random/randomdev_soft.h> 50256381Smarkm#include <dev/random/random_harvestq.h> 51256381Smarkm#include <dev/random/live_entropy_sources.h> 52254147Sobrien#include <dev/random/random_adaptors.h> 53240135Skib 54240135Skib#define RETRY_COUNT 10 55240135Skib 56240135Skibstatic int random_ivy_read(void *, int); 57240135Skib 58256381Smarkmstatic struct random_hardware_source random_ivy = { 59268519Sdelphij .ident = "Hardware, Intel Secure Key RNG", 60256381Smarkm .source = RANDOM_PURE_RDRAND, 61256381Smarkm .read = random_ivy_read 62240135Skib}; 63240135Skib 64240135Skibstatic inline int 65257491Skibivy_rng_store(long *buf) 66240135Skib{ 67240135Skib#ifdef __GNUCLIKE_ASM 68257491Skib long tmp; 69257491Skib int retry; 70240135Skib 71257491Skib retry = RETRY_COUNT; 72240135Skib __asm __volatile( 73257491Skib "1:\n\t" 74257491Skib "rdrand %2\n\t" /* read randomness into tmp */ 75257491Skib "jb 2f\n\t" /* CF is set on success, exit retry loop */ 76257491Skib "dec %0\n\t" /* otherwise, retry-- */ 77257491Skib "jne 1b\n\t" /* and loop if retries are not exhausted */ 78257491Skib "jmp 3f\n" /* failure, retry is 0, used as return value */ 79257491Skib "2:\n\t" 80257491Skib "mov %2,%1\n\t" /* *buf = tmp */ 81257491Skib "3:" 82257491Skib : "+q" (retry), "=m" (*buf), "=q" (tmp) : : "cc"); 83257491Skib return (retry); 84240135Skib#else /* __GNUCLIKE_ASM */ 85240135Skib return (0); 86240135Skib#endif 87240135Skib} 88240135Skib 89240135Skibstatic int 90240135Skibrandom_ivy_read(void *buf, int c) 91240135Skib{ 92257491Skib long *b; 93257491Skib int count; 94240135Skib 95257491Skib KASSERT(c % sizeof(long) == 0, ("partial read %d", c)); 96257491Skib for (b = buf, count = c; count > 0; count -= sizeof(long), b++) { 97257491Skib if (ivy_rng_store(b) == 0) 98240135Skib break; 99240135Skib } 100240135Skib return (c - count); 101240135Skib} 102240135Skib 103254147Sobrienstatic int 104254147Sobrienrdrand_modevent(module_t mod, int type, void *unused) 105254147Sobrien{ 106256381Smarkm int error = 0; 107254147Sobrien 108254147Sobrien switch (type) { 109254147Sobrien case MOD_LOAD: 110256381Smarkm if (cpu_feature2 & CPUID2_RDRAND) 111256381Smarkm live_entropy_source_register(&random_ivy); 112256381Smarkm else 113254147Sobrien#ifndef KLD_MODULE 114254147Sobrien if (bootverbose) 115240135Skib#endif 116256381Smarkm printf("%s: RDRAND is not present\n", 117254147Sobrien random_ivy.ident); 118256381Smarkm break; 119256381Smarkm 120256381Smarkm case MOD_UNLOAD: 121256381Smarkm if (cpu_feature2 & CPUID2_RDRAND) 122256381Smarkm live_entropy_source_deregister(&random_ivy); 123256381Smarkm break; 124256381Smarkm 125256381Smarkm case MOD_SHUTDOWN: 126256381Smarkm break; 127256381Smarkm 128256381Smarkm default: 129256381Smarkm error = EOPNOTSUPP; 130256381Smarkm break; 131256381Smarkm 132254147Sobrien } 133254147Sobrien 134256381Smarkm return (error); 135254147Sobrien} 136254147Sobrien 137256381SmarkmLIVE_ENTROPY_SRC_MODULE(random_rdrand, rdrand_modevent, 1); 138