base/dispatch-x86ish.S (dispatch_x86ish_xgetbv): Preserve `edi' on i386.
[catacomb] / base / dispatch-x86ish.S
index b3b6d1c..8a4c7b2 100644 (file)
@@ -155,13 +155,51 @@ FUNC(dispatch_x86ish_xmmregisters_p)
 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
@@ -182,13 +220,22 @@ FUNC(dispatch_x86ish_rdrand)
 #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