xref: /openbsd-src/sys/arch/amd64/stand/libsa/mdrandom.c (revision 54b0a309fb3f2a8ec180dc311cfa629a40bad568)
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