Created
January 11, 2021 23:13
-
-
Save edwintorok/190ccbccbbd8454ca4b060bd82dec7f1 to your computer and use it in GitHub Desktop.
gcc rdrand.c -O2 -o rdrand -fopenmp -Wall
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* SPDX-License-Identifier: LGPL-2.1-or-later */ | |
#if defined(__i386__) || defined(__x86_64__) | |
#include <cpuid.h> | |
#endif | |
#include <errno.h> | |
#include <limits.h> | |
#include <stdbool.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
/* from systemd random-util.c: */ | |
static int detect_rdrand() | |
{ | |
bool have_rdrand; | |
uint32_t eax, ebx, ecx, edx; | |
/* Check if RDRAND is supported by the CPU */ | |
if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) == 0) { | |
have_rdrand = false; | |
return -EOPNOTSUPP; | |
} | |
/* Compat with old gcc where bit_RDRND didn't exist yet */ | |
#ifndef bit_RDRND | |
#define bit_RDRND (1U << 30) | |
#endif | |
have_rdrand = !!(ecx & bit_RDRND); | |
#if 0 | |
if (have_rdrand > 0) { | |
/* Allow disabling use of RDRAND with SYSTEMD_RDRAND=0 | |
If it is unset getenv_bool_secure will return a negative value. */ | |
if (getenv_bool_secure("SYSTEMD_RDRAND") == 0) { | |
have_rdrand = false; | |
return -EOPNOTSUPP; | |
} | |
} | |
#endif | |
if (have_rdrand == 0) | |
return -EOPNOTSUPP; | |
return 0; | |
} | |
static inline int rdrand(unsigned long *ret) { | |
#if defined(__i386__) || defined(__x86_64__) | |
unsigned long v; | |
uint8_t success; | |
asm volatile("rdrand %0;" | |
"setc %1" | |
: "=r" (v), | |
"=qm" (success)); | |
#if 0 | |
msan_unpoison(&success, sizeof(success)); | |
#endif | |
if (!success) | |
return -EAGAIN; | |
/* Apparently on some AMD CPUs RDRAND will sometimes (after a suspend/resume cycle?) report success | |
* via the carry flag but nonetheless return the same fixed value -1 in all cases. This appears to be | |
* a bad bug in the CPU or firmware. Let's deal with that and work-around this by explicitly checking | |
* for this special value (and also 0, just to be sure) and filtering it out. This is a work-around | |
* only however and something AMD really should fix properly. The Linux kernel should probably work | |
* around this issue by turning off RDRAND altogether on those CPUs. See: | |
* https://github.com/systemd/systemd/issues/11810 */ | |
if (v == 0 || v == ULONG_MAX) | |
#if 0 | |
return log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN), | |
"RDRAND returned suspicious value %lx, assuming bad hardware RNG, not using value.", v); | |
#else | |
{ | |
fprintf(stderr, "RDRAND returned suspicious value %lx, assuming bad hardware RNG\n", v); | |
return EUCLEAN; | |
} | |
#endif | |
*ret = v; | |
return 0; | |
#else | |
return -EOPNOTSUPP; | |
#endif | |
} | |
int main(int argc, char *argv[]) | |
{ | |
unsigned long val[32*1024]; | |
errno = -detect_rdrand(); | |
if (errno) { | |
perror("rdrand cpuid"); | |
exit(1); | |
} | |
do { | |
#pragma omp parallel for | |
for(int i=0;i < sizeof(val)/sizeof(*val);i+=8) { | |
/* errno = -rdrand(&val[i]); | |
if (errno) { | |
perror("rdrand"); | |
exit(2); | |
} | |
*/ | |
rdrand(&val[i]); | |
rdrand(&val[i+1]); | |
rdrand(&val[i+2]); | |
rdrand(&val[i+3]); | |
rdrand(&val[i+4]); | |
rdrand(&val[i+5]); | |
rdrand(&val[i+6]); | |
rdrand(&val[i+7]); | |
} | |
fwrite(val, sizeof(val), 1, stdout); | |
} while(1); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment