1 /* $OpenBSD: mdrandom.c,v 1.4 2024/09/26 10:12:02 jsg 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/specialreg.h> 21 22 #include "libsa.h" 23 24 int 25 mdrandom(char *buf, size_t buflen) 26 { 27 u_int eax, ebx, ecx, edx; 28 int i; 29 30 for (i = 0; i < buflen; i++) { 31 uint32_t hi, lo, acc; 32 33 __asm volatile("rdtsc" : "=d" (hi), "=a" (lo)); 34 acc = hi ^ lo; 35 acc ^= acc >> 16; 36 acc ^= acc >> 8; 37 buf[i] ^= acc; 38 } 39 40 CPUID(1, eax, ebx, ecx, edx); 41 if (ecx & CPUIDECX_RDRAND) { 42 unsigned long rand; 43 int retries; 44 uint8_t valid; 45 46 for (i = 0; i < buflen / sizeof(rand); i++) { 47 retries = 10; 48 do { 49 __asm volatile( 50 "rdrand %0;" 51 "setc %1;" 52 : "=r" (rand), "=qm" (valid)); 53 } while (!valid && --retries > 0); 54 ((unsigned long *)buf)[i] ^= rand; 55 } 56 } 57 58 CPUID(0, eax, ebx, ecx, edx); 59 if (eax >= 7) { 60 CPUID_LEAF(7, 0, eax, ebx, ecx, edx); 61 if (ebx & SEFF0EBX_RDSEED) { 62 unsigned long rand; 63 int retries; 64 uint8_t valid; 65 66 for (i = 0; i < buflen / sizeof(rand); i++) { 67 retries = 10; 68 do { 69 __asm volatile( 70 "rdseed %0;" 71 "setc %1;" 72 : "=r" (rand), "=qm" (valid)); 73 } while (!valid && --retries > 0); 74 ((unsigned long *)buf)[i] ^= rand; 75 } 76 } 77 } 78 return (0); 79 } 80