xref: /openbsd/sys/arch/i386/stand/libsa/mdrandom.c (revision 54b0a309)
1*54b0a309Sjsg /*	$OpenBSD: mdrandom.c,v 1.4 2024/09/26 10:12:02 jsg Exp $	*/
255f8664cSderaadt 
355f8664cSderaadt /*
455f8664cSderaadt  * Copyright (c) 2020 Theo de Raadt
555f8664cSderaadt  *
655f8664cSderaadt  * Permission to use, copy, modify, and distribute this software for any
755f8664cSderaadt  * purpose with or without fee is hereby granted, provided that the above
855f8664cSderaadt  * copyright notice and this permission notice appear in all copies.
955f8664cSderaadt  *
1055f8664cSderaadt  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1155f8664cSderaadt  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1255f8664cSderaadt  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1355f8664cSderaadt  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1455f8664cSderaadt  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1555f8664cSderaadt  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1655f8664cSderaadt  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1755f8664cSderaadt  */
1855f8664cSderaadt 
1955f8664cSderaadt #include <sys/param.h>
2055f8664cSderaadt #include <machine/specialreg.h>
2155f8664cSderaadt 
2255f8664cSderaadt #include "libsa.h"
2355f8664cSderaadt 
2455f8664cSderaadt int
mdrandom(char * buf,size_t buflen)2555f8664cSderaadt mdrandom(char *buf, size_t buflen)
2655f8664cSderaadt {
2755f8664cSderaadt 	u_int eax, ebx, ecx, edx;
2855f8664cSderaadt 	int ret = -1;
2955f8664cSderaadt 	int i;
3055f8664cSderaadt 
3155f8664cSderaadt 	if (pslid() == 0)
3255f8664cSderaadt 		goto done;
3355f8664cSderaadt 	CPUID(1, eax, ebx, ecx, edx);
3455f8664cSderaadt 	if (edx & CPUID_TSC) {
35ec4ed3a2Snaddy 		uint32_t hi, lo, acc;
3655f8664cSderaadt 
3755f8664cSderaadt 		for (i = 0; i < buflen; i++) {
3855f8664cSderaadt 			__asm volatile("rdtsc" : "=d" (hi), "=a" (lo));
39ec4ed3a2Snaddy 			acc = hi ^ lo;
40ec4ed3a2Snaddy 			acc ^= acc >> 16;
41ec4ed3a2Snaddy 			acc ^= acc >>  8;
42ec4ed3a2Snaddy 			buf[i] ^= acc;
4355f8664cSderaadt 		}
4455f8664cSderaadt 		ret = 0;
4555f8664cSderaadt 	}
4655f8664cSderaadt 	if (ecx & CPUIDECX_RDRAND) {
4755f8664cSderaadt 		unsigned long rand;
48dd423e20Snaddy 		int retries;
49dd423e20Snaddy 		uint8_t valid;
5055f8664cSderaadt 
5155f8664cSderaadt 		for (i = 0; i < buflen / sizeof(rand); i++) {
52dd423e20Snaddy 			retries = 10;
53dd423e20Snaddy 			do {
54dd423e20Snaddy 				__asm volatile(
55dd423e20Snaddy 				    "rdrand	%0;"
56dd423e20Snaddy 				    "setc	%1;"
57dd423e20Snaddy 				    : "=r" (rand), "=qm" (valid));
58dd423e20Snaddy 			} while (!valid && --retries > 0);
5955f8664cSderaadt 			((unsigned long *)buf)[i] ^= rand;
6055f8664cSderaadt 		}
6155f8664cSderaadt 		ret = 0;
6255f8664cSderaadt 	}
6355f8664cSderaadt 	CPUID(0, eax, ebx, ecx, edx);
6455f8664cSderaadt 	if (eax >= 7) {
6555f8664cSderaadt 		CPUID_LEAF(7, 0, eax, ebx, ecx, edx);
6655f8664cSderaadt 		if (ebx & SEFF0EBX_RDSEED) {
6755f8664cSderaadt 			unsigned long rand;
68dd423e20Snaddy 			int retries;
69dd423e20Snaddy 			uint8_t valid;
7055f8664cSderaadt 
7155f8664cSderaadt 			for (i = 0; i < buflen / sizeof(rand); i++) {
72dd423e20Snaddy 				retries = 10;
73dd423e20Snaddy 				do {
74dd423e20Snaddy 					__asm volatile(
75dd423e20Snaddy 					    "rdseed	%0;"
76dd423e20Snaddy 					    "setc	%1;"
77dd423e20Snaddy 					    : "=r" (rand), "=qm" (valid));
78dd423e20Snaddy 				} while (!valid && --retries > 0);
7955f8664cSderaadt 				((unsigned long *)buf)[i] ^= rand;
8055f8664cSderaadt 			}
8155f8664cSderaadt 			ret = 0;
8255f8664cSderaadt 		}
8355f8664cSderaadt 	}
8455f8664cSderaadt done:
8555f8664cSderaadt 	return ret;
8655f8664cSderaadt }
87