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 ret = -1; 29 int i; 30 31 if (pslid() == 0) 32 goto done; 33 CPUID(1, eax, ebx, ecx, edx); 34 if (edx & CPUID_TSC) { 35 uint32_t hi, lo, acc; 36 37 for (i = 0; i < buflen; i++) { 38 __asm volatile("rdtsc" : "=d" (hi), "=a" (lo)); 39 acc = hi ^ lo; 40 acc ^= acc >> 16; 41 acc ^= acc >> 8; 42 buf[i] ^= acc; 43 } 44 ret = 0; 45 } 46 if (ecx & CPUIDECX_RDRAND) { 47 unsigned long rand; 48 int retries; 49 uint8_t valid; 50 51 for (i = 0; i < buflen / sizeof(rand); i++) { 52 retries = 10; 53 do { 54 __asm volatile( 55 "rdrand %0;" 56 "setc %1;" 57 : "=r" (rand), "=qm" (valid)); 58 } while (!valid && --retries > 0); 59 ((unsigned long *)buf)[i] ^= rand; 60 } 61 ret = 0; 62 } 63 CPUID(0, eax, ebx, ecx, edx); 64 if (eax >= 7) { 65 CPUID_LEAF(7, 0, eax, ebx, ecx, edx); 66 if (ebx & SEFF0EBX_RDSEED) { 67 unsigned long rand; 68 int retries; 69 uint8_t valid; 70 71 for (i = 0; i < buflen / sizeof(rand); i++) { 72 retries = 10; 73 do { 74 __asm volatile( 75 "rdseed %0;" 76 "setc %1;" 77 : "=r" (rand), "=qm" (valid)); 78 } while (!valid && --retries > 0); 79 ((unsigned long *)buf)[i] ^= rand; 80 } 81 ret = 0; 82 } 83 } 84 done: 85 return ret; 86 } 87