1 /* $OpenBSD: mdrandom.c,v 1.3 2020/06/19 15:00:45 naddy Exp $ */ 2 3 /* 4 * Copyright (c) 2020 Theo de Raadt 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <machine/psl.h> 21 #include <machine/specialreg.h> 22 23 #include "libsa.h" 24 25 int 26 mdrandom(char *buf, size_t buflen) 27 { 28 u_int eax, ebx, ecx, edx; 29 int i; 30 31 for (i = 0; i < buflen; i++) { 32 uint32_t hi, lo, acc; 33 34 __asm volatile("rdtsc" : "=d" (hi), "=a" (lo)); 35 acc = hi ^ lo; 36 acc ^= acc >> 16; 37 acc ^= acc >> 8; 38 buf[i] ^= acc; 39 } 40 41 CPUID(1, eax, ebx, ecx, edx); 42 if (ecx & CPUIDECX_RDRAND) { 43 unsigned long rand; 44 int retries; 45 uint8_t valid; 46 47 for (i = 0; i < buflen / sizeof(rand); i++) { 48 retries = 10; 49 do { 50 __asm volatile( 51 "rdrand %0;" 52 "setc %1;" 53 : "=r" (rand), "=qm" (valid)); 54 } while (!valid && --retries > 0); 55 ((unsigned long *)buf)[i] ^= rand; 56 } 57 } 58 59 CPUID(0, eax, ebx, ecx, edx); 60 if (eax >= 7) { 61 CPUID_LEAF(7, 0, eax, ebx, ecx, edx); 62 if (ebx & SEFF0EBX_RDSEED) { 63 unsigned long rand; 64 int retries; 65 uint8_t valid; 66 67 for (i = 0; i < buflen / sizeof(rand); i++) { 68 retries = 10; 69 do { 70 __asm volatile( 71 "rdseed %0;" 72 "setc %1;" 73 : "=r" (rand), "=qm" (valid)); 74 } while (!valid && --retries > 0); 75 ((unsigned long *)buf)[i] ^= rand; 76 } 77 } 78 } 79 return (0); 80 } 81