#include #include #include #include "tests/malloc.h" typedef unsigned char UChar; typedef unsigned int UInt; typedef unsigned long int UWord; typedef unsigned long long int ULong; // What can we actually test here? The instructions take no input and // produce output which is by definition totally random. So apart from // not simply failing insn decode, there's nothing much to test. // Get 10 values of each size, and check that they are not all the same // (otherwise something's obviously wrong). Now, statistically, it's // highly unlikely that they are all the same. For 10 16 bit ints, the // probability of them being all the same is (I'd guess) (2^-16) ^ (10-1), // that is, 2^-144. ULong do_rdrand64 ( void ) { while (1) { ULong res = 0; ULong cflag = 0; __asm__ __volatile__( "movabsq $0x5555555555555555, %%r11 ; " "movq $0, %%r12 ; " "rdrand %%r11 ; " "setc %%r12b ; " "movq %%r11, %0 ; " "movq %%r12, %1" : "=r"(res), "=r"(cflag) : : "r11", "r12" ); if (cflag == 1) return res; } /*NOTREACHED*/ } ULong do_rdrand32 ( void ) { while (1) { ULong res = 0; ULong cflag = 0; __asm__ __volatile__( "movabsq $0x5555555555555555, %%r11 ; " "movq $0, %%r12 ; " "rdrand %%r11d ; " "setc %%r12b ; " "movq %%r11, %0 ; " "movq %%r12, %1" : "=r"(res), "=r"(cflag) : : "r11", "r12" ); if (cflag == 1) return res; } /*NOTREACHED*/ } ULong do_rdrand16 ( void ) { while (1) { ULong res = 0; ULong cflag = 0; __asm__ __volatile__( "movabsq $0x5555555555555555, %%r11 ; " "movq $0, %%r12 ; " "rdrand %%r11w ; " "setc %%r12b ; " "movq %%r11, %0 ; " "movq %%r12, %1" : "=r"(res), "=r"(cflag) : : "r11", "r12" ); if (cflag == 1) return res; } /*NOTREACHED*/ } void do_test ( ULong(*fn)(void), ULong mask /* with 1s indicating the random bits in the result */ ) { ULong arr[10]; for (UInt i = 0; i < 10; i++) { arr[i] = fn(); } // They really should all be different (to an extremely high probabilty. // See comment above. int allSame = 1/*true*/; // really, a Bool for (UInt i = 1; i < 10; i++) { if (arr[i] != arr[0]) { allSame = 0/*false*/; break; } } assert(!allSame); // The 0/32/48 leading bits of the result should have a particular value, // depending on the insn. So print them, with the random part masked out. for (UInt i = 0; i < 10; i++) { printf("0x%016llx\n", arr[i] & ~mask); } printf("\n"); } int main ( void ) { do_test( do_rdrand64, 0xFFFFFFFFFFFFFFFFULL ); do_test( do_rdrand32, 0x00000000FFFFFFFFULL ); do_test( do_rdrand16, 0x000000000000FFFFULL ); return 0; }