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