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
mdrandom(char * buf,size_t buflen)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