endprologue
// First, check that this is even a thing, using the complicated
- // dance with the flags register.
+ // dance with the flags register. This is unnecessary on AMD64,
+ // which postdates the introduction of `cpuid'.
+#if CPUFAM_X86
pushf
pop DX // current flags in d
pop DX
test edx, EFLAGS_ID
jnz 8f
+#endif
// OK, that seemed to work.
cpuid
ret
// Failed.
+#if CPUFAM_X86
8: xor eax, eax
mov [OUT + 0], eax
mov [OUT + 4], eax
mov [OUT + 12], eax
mov eax, -1
jmp 9b
+#endif
ENDFUNC
///--------------------------------------------------------------------------
ENDFUNC
///--------------------------------------------------------------------------
+/// Checking extended control registers.
+
+FUNC(dispatch_x86ish_xgetbv)
+ // Call with two arguments: a pointer Z_OUT to 8 bytes of output space, and
+ // a 32-bit integer C. Read the 64-bit value of XCR(C), and store it
+ // at Z_OUT.
+
+#if CPUFAM_X86
+# define Z_OUT edi
+ pushreg edi
+ mov edi, [esp + 8]
+ mov ecx, [esp + 12]
+#endif
+#if CPUFAM_AMD64 && ABI_SYSV
+# define Z_OUT rdi
+ mov ecx, esi
+#endif
+#if CPUFAM_AMD64 && ABI_WIN
+# define Z_OUT r8
+ mov r8, rcx
+ mov ecx, edx
+#endif
+ endprologue
+
+ xgetbv
+ mov [Z_OUT + 0], eax
+ mov [Z_OUT + 4], edx
+
+#if CPUFAM_X86
+ popreg edi
+#endif
+ ret
+
+#undef Z_OUT
+ENDFUNC
+
+///--------------------------------------------------------------------------
/// Checking `rdrand'.
FUNC(dispatch_x86ish_rdrand)
- // Enter with two arguments: a code OP requesting `rdrand' (0), and a
- // pointer X_OUT to a 32-bit word. Try to generate a random word
- // using the requested instruction. If successful, set *X_OUT to the
- // generated word, and return zero; otherwise, return -1.
+ // Enter with two arguments: a code OP requesting either `rdrand' (0)
+ // or `rdseed' (1), and a pointer X_OUT to a 32-bit word. Try to
+ // generate a random word using the requested instruction'. If
+ // successful, set *X_OUT to the generated word, and return zero;
+ // otherwise, return -1.
#if CPUFAM_X86
# define OP eax
#endif
endprologue
+ cmp OP, 0
mov COUNT, 16 // fairly persistent
+ jne 1f
+
0: rdrand eax
jc 9f
dec COUNT
jnz 0b
jmp 8f
+1: rdseed eax
+ jc 9f
+ dec COUNT
+ jnz 1b
+ jmp 8f
+
// Failed to come up with a random value.
8: mov eax, -1
ret