]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
amd64: Implement RDSEED
authorAlexandra Hájková <ahajkova@redhat.com>
Fri, 31 Jul 2020 11:19:16 +0000 (13:19 +0200)
committerMark Wielaard <mark@klomp.org>
Thu, 3 Sep 2020 21:33:07 +0000 (23:33 +0200)
This commit implements amd64 RDSEED instruction, on hosts that have it
and adds the new test case - none/tests/amd64/rdseed based on the existing
rdrand support.

https://bugs.kde.org/show_bug.cgi?id=424298

15 files changed:
NEWS
VEX/priv/guest_amd64_defs.h
VEX/priv/guest_amd64_helpers.c
VEX/priv/guest_amd64_toIR.c
VEX/priv/host_amd64_isel.c
VEX/priv/main_main.c
VEX/pub/libvex.h
configure.ac
coregrind/m_machine.c
none/tests/amd64/Makefile.am
none/tests/amd64/rdseed.c [new file with mode: 0644]
none/tests/amd64/rdseed.stderr.exp [new file with mode: 0644]
none/tests/amd64/rdseed.stdout.exp [new file with mode: 0644]
none/tests/amd64/rdseed.vgtest [new file with mode: 0644]
tests/x86_amd64_features.c

diff --git a/NEWS b/NEWS
index 248d90892a416ef4708c69b2b0151561a99c1590..ce27f392ecfa1a33ac813762cf8c61b5d7952a1e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -47,6 +47,7 @@ n-i-bz  helgrind: If hg_cli__realloc fails, return NULL.
 422174  unhandled instruction bytes: 0x48 0xE9 (REX prefixed JMP instruction)
 422623  epoll_ctl warns for uninitialized padding on non-amd64 64bit arches
 423021  PPC:  Add missing ISA 3.0 documentation link and HWCAPS test.
+424298  amd64: Implement RDSEED
 
 
 Release 3.16.1 (?? June 2020)
index 54672dc225dfe28e97c215f5b2980de649cbb876..f9a9a90975c1c827c8c9cfa949c06a1f154cf843 100644 (file)
@@ -164,9 +164,13 @@ extern void  amd64g_dirtyhelper_CPUID_sse3_and_cx16 ( VexGuestAMD64State* st );
 extern void  amd64g_dirtyhelper_CPUID_sse42_and_cx16 ( VexGuestAMD64State* st );
 extern void  amd64g_dirtyhelper_CPUID_avx_and_cx16 ( VexGuestAMD64State* st,
                                                      ULong hasF16C,
-                                                     ULong hasRDRAND );
-extern void  amd64g_dirtyhelper_CPUID_avx2 ( VexGuestAMD64State* st,
-                                             ULong hasF16C, ULong hasRDRAND );
+                                                     ULong hasRDRAND,
+                                                     ULong hasRDSEED );
+
+extern void amd64g_dirtyhelper_CPUID_avx2 ( VexGuestAMD64State* st,
+                                            ULong hasF16C, ULong hasRDRAND,
+                                            ULong hasRDSEED );
+
 
 extern void  amd64g_dirtyhelper_FINIT ( VexGuestAMD64State* );
 
@@ -194,6 +198,7 @@ extern void amd64g_dirtyhelper_SxDT ( void* address,
 // resulting C flag value in bit 32.
 extern ULong amd64g_dirtyhelper_RDRAND ( void );
 
+extern ULong amd64g_dirtyhelper_RDSEED ( void );
 
 /* Helps with PCMP{I,E}STR{I,M}.
 
index 182bae0bc5023d2c7e050914608fbee3fd14e5ba..ab7b64bcc1ac8fa3fb2ba7bf50669f30d8b3af6f 100644 (file)
@@ -3142,7 +3142,8 @@ void amd64g_dirtyhelper_CPUID_sse42_and_cx16 ( VexGuestAMD64State* st )
    power management:
 */
 void amd64g_dirtyhelper_CPUID_avx_and_cx16 ( VexGuestAMD64State* st,
-                                             ULong hasF16C, ULong hasRDRAND )
+                                             ULong hasF16C, ULong hasRDRAND,
+                                             ULong hasRDSEED )
 {
    vassert((hasF16C >> 1) == 0ULL);
    vassert((hasRDRAND >> 1) == 0ULL);
@@ -3194,9 +3195,14 @@ void amd64g_dirtyhelper_CPUID_avx_and_cx16 ( VexGuestAMD64State* st,
       case 0x00000006:
          SET_ABCD(0x00000077, 0x00000002, 0x00000009, 0x00000000);
          break;
-      case 0x00000007:
-         SET_ABCD(0x00000000, 0x00000800, 0x00000000, 0x00000000);
+      case 0x00000007: {
+         UInt ebx_extra = 0;
+         if (old_ecx == 0)
+             ebx_extra = hasRDSEED ? (1U << 18) : 0;
+         SET_ABCD(0x00000000, 0x00000800 | ebx_extra, 0x00000000,
+                  0x00000000);
          break;
+                       }
       case 0x00000008:
          SET_ABCD(0x00000000, 0x00000000, 0x00000000, 0x00000000);
          break;
@@ -3320,7 +3326,8 @@ void amd64g_dirtyhelper_CPUID_avx_and_cx16 ( VexGuestAMD64State* st,
    power management:
 */
 void amd64g_dirtyhelper_CPUID_avx2 ( VexGuestAMD64State* st,
-                                     ULong hasF16C, ULong hasRDRAND )
+                                     ULong hasF16C, ULong hasRDRAND,
+                                     ULong hasRDSEED )
 {
    vassert((hasF16C >> 1) == 0ULL);
    vassert((hasRDRAND >> 1) == 0ULL);
@@ -3375,8 +3382,12 @@ void amd64g_dirtyhelper_CPUID_avx2 ( VexGuestAMD64State* st,
       case 0x00000007:
          switch (old_ecx) {
             /* Don't advertise FSGSBASE support, bit 0 in EBX.  */
-            case 0x00000000: SET_ABCD(0x00000000, 0x000027aa,
-                                      0x00000000, 0x00000000); break;
+
+            case 0x00000000: {
+               UInt ebx_extra = hasRDSEED ? (1U << 18) : 0;
+               SET_ABCD(0x00000000, 0x000027aa | ebx_extra,
+                        0x00000000, 0x00000000); break;
+                             }
             default:         SET_ABCD(0x00000000, 0x00000000,
                                       0x00000000, 0x00000000); break;
          }
@@ -3781,6 +3792,29 @@ ULong amd64g_dirtyhelper_RDRAND ( void ) {
 #  endif
 }
 
+ULong amd64g_dirtyhelper_RDSEED ( void ) {
+#  if defined(__x86_64__)
+   ULong res   = 0;
+   ULong cflag = 0;
+   __asm__ __volatile__(
+      "movq $0, %%r11 ; "
+      "movq $0, %%r12 ; "
+      "rdseed %%r11d ; "
+      "setc %%r12b ; "
+      "movq %%r11, %0 ; "
+      "movq %%r12, %1"
+      : "=r"(res), "=r"(cflag) : : "r11", "r12"
+   );
+   res &= 0xFFFFFFFFULL;
+   cflag &= 1ULL;
+   return (cflag << 32) | res;
+#  else
+   /* There's nothing we can sensibly do.  Return a value denoting
+      "I succeeded, and the random bits are all zero" :-/ */
+   return 1ULL << 32;
+#  endif
+}
+
 /*---------------------------------------------------------------*/
 /*--- Helpers for MMX/SSE/SSE2.                               ---*/
 /*---------------------------------------------------------------*/
index 7888132ebda8253c44bd07ebea7dcfc4f6c92d1d..2faca7d03febab7b4b3d297d853a139203a18bf4 100644 (file)
@@ -21989,9 +21989,11 @@ Long dis_ESC_0F (
           || fAddr == &amd64g_dirtyhelper_CPUID_avx_and_cx16) {
          Bool hasF16C   = (archinfo->hwcaps & VEX_HWCAPS_AMD64_F16C) != 0;
          Bool hasRDRAND = (archinfo->hwcaps & VEX_HWCAPS_AMD64_RDRAND) != 0;
-         args = mkIRExprVec_3(IRExpr_GSPTR(),
+         Bool hasRDSEED = (archinfo->hwcaps & VEX_HWCAPS_AMD64_RDSEED) != 0;
+         args = mkIRExprVec_4(IRExpr_GSPTR(),
                               mkIRExpr_HWord(hasF16C ? 1 : 0),
-                              mkIRExpr_HWord(hasRDRAND ? 1 : 0));
+                              mkIRExpr_HWord(hasRDRAND ? 1 : 0),
+                              mkIRExpr_HWord(hasRDSEED ? 1 : 0));
       } else {
          args = mkIRExprVec_1(IRExpr_GSPTR());
       }
@@ -22344,20 +22346,28 @@ Long dis_ESC_0F (
          return delta;
       } // if (isValidCMPXCHG)
 
-      /* 0F C7 /6 no-F2-or-F3 = RDRAND */
-      if (gregLO3ofRM(modrm) == 6/*RDRAND*/
-          && (archinfo->hwcaps & VEX_HWCAPS_AMD64_RDRAND)
+      /* 0F C7 /6 no-F2-or-F3 = RDRAND, 0F C7 /7 = RDSEED */
+      int insn = gregLO3ofRM(modrm);
+      if (((insn == 6 && (archinfo->hwcaps & VEX_HWCAPS_AMD64_RDRAND))
+           || (insn == 7 && (archinfo->hwcaps & VEX_HWCAPS_AMD64_RDSEED)))
           && epartIsReg(modrm) && haveNoF2noF3(pfx)
           && (sz == 8 || sz == 4 || sz == 2)) {
+
          delta++; // move past modrm
          IRType   ty    = szToITy(sz);
 
          // Pull a first 32 bits of randomness, plus C flag, out of the host.
          IRTemp pairLO = newTemp(Ity_I64);
-         IRDirty* dLO
-            = unsafeIRDirty_1_N(pairLO, 0/*regparms*/,
-                                "amd64g_dirtyhelper_RDRAND",
-                                &amd64g_dirtyhelper_RDRAND, mkIRExprVec_0());
+         IRDirty* dLO;
+         if (insn == 6) /* RDRAND */
+             dLO = unsafeIRDirty_1_N(pairLO, 0/*regparms*/,
+                                     "amd64g_dirtyhelper_RDRAND",
+                                     &amd64g_dirtyhelper_RDRAND, mkIRExprVec_0());
+         else /* RDSEED */
+             dLO = unsafeIRDirty_1_N(pairLO, 0/*regparms*/,
+                                     "amd64g_dirtyhelper_RDSEED",
+                                     &amd64g_dirtyhelper_RDSEED, mkIRExprVec_0());
+
          // There are no guest state or memory effects to declare for |dLO|.
          stmt( IRStmt_Dirty(dLO) );
 
@@ -22373,10 +22383,16 @@ Long dis_ESC_0F (
          if (ty == Ity_I64) {
             // Pull another 32 bits of randomness out of the host.
             IRTemp pairHI = newTemp(Ity_I64);
-            IRDirty* dHI
-               = unsafeIRDirty_1_N(pairHI, 0/*regparms*/,
-                                   "amd64g_dirtyhelper_RDRAND",
-                                   &amd64g_dirtyhelper_RDRAND, mkIRExprVec_0());
+            IRDirty* dHI;
+            if (insn == 6) /* RDRAND */
+                dHI = unsafeIRDirty_1_N(pairHI, 0/*regparms*/,
+                                        "amd64g_dirtyhelper_RDRAND",
+                                        &amd64g_dirtyhelper_RDRAND, mkIRExprVec_0());
+            else /* RDSEED */
+                dHI = unsafeIRDirty_1_N(pairHI, 0/*regparms*/,
+                                        "amd64g_dirtyhelper_RDSEED",
+                                        &amd64g_dirtyhelper_RDSEED, mkIRExprVec_0());
+
             // There are no guest state or memory effects to declare for |dHI|.
             stmt( IRStmt_Dirty(dHI) );
 
@@ -22420,7 +22436,12 @@ Long dis_ESC_0F (
          stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
          stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
 
-         DIP("rdrand %s", nameIRegE(sz, pfx, modrm));
+         if (insn == 6) {
+             DIP("rdrand %s", nameIRegE(sz, pfx, modrm));
+        } else {
+             DIP("rdseed %s", nameIRegE(sz, pfx, modrm));
+        }
+
          return delta;
       }
 
index c3cd61c1f376e2bc22ec6297e56aa84243e46922..3299c3df9177a045df92fea6b5ca039c2496586b 100644 (file)
@@ -5303,7 +5303,8 @@ HInstrArray* iselSB_AMD64 ( const IRSB* bb,
                      | VEX_HWCAPS_AMD64_BMI
                      | VEX_HWCAPS_AMD64_AVX2
                      | VEX_HWCAPS_AMD64_F16C
-                     | VEX_HWCAPS_AMD64_RDRAND)));
+                     | VEX_HWCAPS_AMD64_RDRAND
+                     | VEX_HWCAPS_AMD64_RDSEED)));
 
    /* Check that the host's endianness is as expected. */
    vassert(archinfo_host->endness == VexEndnessLE);
index 7a3cb75caf9f44fec61368fe3cfb73a824343007..3e788d524054ec890e4f71c52147b71ee3bb3d21 100644 (file)
@@ -1648,6 +1648,7 @@ static const HChar* show_hwcaps_amd64 ( UInt hwcaps )
       { VEX_HWCAPS_AMD64_BMI,    "bmi"    },
       { VEX_HWCAPS_AMD64_F16C,   "f16c"   },
       { VEX_HWCAPS_AMD64_RDRAND, "rdrand" },
+      { VEX_HWCAPS_AMD64_RDSEED, "rdseed" },
    };
    /* Allocate a large enough buffer */
    static HChar buf[sizeof prefix + 
index 6da26dcb5f85c5aa3edf85c02199c7e25dcbb774..4eb97162faf85c5a250d4efbbe1d539591bf6b93 100644 (file)
@@ -100,6 +100,7 @@ typedef
 #define VEX_HWCAPS_AMD64_AVX2   (1<<11) /* AVX2 instructions */
 #define VEX_HWCAPS_AMD64_RDRAND (1<<13) /* RDRAND instructions */
 #define VEX_HWCAPS_AMD64_F16C   (1<<14) /* F16C instructions */
+#define VEX_HWCAPS_AMD64_RDSEED (1<<15) /* RDSEED instructions */
 
 /* ppc32: baseline capability is integer only */
 #define VEX_HWCAPS_PPC32_F     (1<<8)  /* basic (non-optional) FP */
index 49f2ba83de3ab48105c0f1bdb581f955e9881f82..1a89d05e5e2ad75c6a043e8924822d99ff829b9a 100755 (executable)
@@ -3034,6 +3034,26 @@ AC_MSG_RESULT([no])
 
 AM_CONDITIONAL(BUILD_RDRAND_TESTS, test x$ac_have_as_rdrand = xyes)
 
+# does the amd64 assembler understand the RDSEED instruction?
+# Note, this doesn't generate a C-level symbol.  It generates a
+# automake-level symbol (BUILD_RDSEED_TESTS), used in test Makefile.am's
+AC_MSG_CHECKING([if amd64 assembler knows the RDSEED instruction])
+
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
+  do {
+    asm ("rdseed %r14");
+    asm ("rdseed %r14d");
+    asm ("rdseed %r14w");
+  } while (0)
+]])], [
+ac_have_as_rdseed=yes
+AC_MSG_RESULT([yes])
+], [
+ac_have_as_rdseed=no
+AC_MSG_RESULT([no])
+])
+
+AM_CONDITIONAL(BUILD_RDSEED_TESTS, test x$ac_have_as_rdseed = xyes)
 
 # does the amd64 assembler understand the F16C instructions (VCVTPH2PS and
 # VCVTPS2PH) ?
index 0fd1d21c78ea7adcdfaf4a2877e25612e43612c9..5594923fdb3593eccaffe4a7b9909c0fec7f4056 100644 (file)
@@ -967,7 +967,7 @@ Bool VG_(machine_get_hwcaps)( void )
 #elif defined(VGA_amd64)
    { Bool have_sse3, have_ssse3, have_cx8, have_cx16;
      Bool have_lzcnt, have_avx, have_bmi, have_avx2;
-     Bool have_rdtscp, have_rdrand, have_f16c;
+     Bool have_rdtscp, have_rdrand, have_f16c, have_rdseed;
      UInt eax, ebx, ecx, edx, max_basic, max_extended;
      ULong xgetbv_0 = 0;
      HChar vstr[13];
@@ -975,7 +975,7 @@ Bool VG_(machine_get_hwcaps)( void )
 
      have_sse3 = have_ssse3 = have_cx8 = have_cx16
                = have_lzcnt = have_avx = have_bmi = have_avx2
-               = have_rdtscp = have_rdrand = have_f16c = False;
+               = have_rdtscp = have_rdrand = have_f16c = have_rdseed = False;
 
      eax = ebx = ecx = edx = max_basic = max_extended = 0;
 
@@ -1079,6 +1079,7 @@ Bool VG_(machine_get_hwcaps)( void )
         VG_(cpuid)(7, 0, &eax, &ebx, &ecx, &edx);
         have_bmi  = (ebx & (1<<3)) != 0; /* True => have BMI1 */
         have_avx2 = (ebx & (1<<5)) != 0; /* True => have AVX2 */
+        have_rdseed = (ebx & (1<<18)) != 0; /* True => have RDSEED insns */
      }
 
      /* Sanity check for RDRAND and F16C.  These don't actually *need* AVX, but
@@ -1087,6 +1088,7 @@ Bool VG_(machine_get_hwcaps)( void )
      if (!have_avx) {
         have_f16c   = False;
         have_rdrand = False;
+        have_rdseed = False;
      }
 
      va          = VexArchAMD64;
@@ -1100,7 +1102,8 @@ Bool VG_(machine_get_hwcaps)( void )
                  | (have_avx2   ? VEX_HWCAPS_AMD64_AVX2   : 0)
                  | (have_rdtscp ? VEX_HWCAPS_AMD64_RDTSCP : 0)
                  | (have_f16c   ? VEX_HWCAPS_AMD64_F16C   : 0)
-                 | (have_rdrand ? VEX_HWCAPS_AMD64_RDRAND : 0);
+                 | (have_rdrand ? VEX_HWCAPS_AMD64_RDRAND : 0)
+                 | (have_rdseed ? VEX_HWCAPS_AMD64_RDSEED : 0);
 
      VG_(machine_get_cache_info)(&vai);
 
index 88dc9b4da94d5713ff8b1207b1d43e25f614bb51..79d9e4f57d4afbe9f54dc891c54aa46260bf259a 100644 (file)
@@ -82,6 +82,7 @@ EXTRA_DIST = \
        pcmpxstrx64w.vgtest \
        rcl-amd64.vgtest rcl-amd64.stdout.exp rcl-amd64.stderr.exp \
        rdrand.vgtest rdrand.stdout.exp rdrand.stderr.exp \
+       rdseed.vgtest rdseed.stdout.exp rdseed.stderr.exp \
        redundantRexW.vgtest redundantRexW.stdout.exp \
        redundantRexW.stderr.exp \
        smc1.stderr.exp smc1.stdout.exp smc1.vgtest \
@@ -168,6 +169,9 @@ endif
 if BUILD_RDRAND_TESTS
  check_PROGRAMS += rdrand
 endif
+if BUILD_RDSEED_TESTS
+ check_PROGRAMS += rdseed
+endif
 
 
 # DDD: these need to be made to work on Darwin like the x86/ ones were.
diff --git a/none/tests/amd64/rdseed.c b/none/tests/amd64/rdseed.c
new file mode 100644 (file)
index 0000000..784c4e9
--- /dev/null
@@ -0,0 +1,116 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#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_rdseed64 ( void )
+{
+   while (1) {
+      ULong res = 0;
+      ULong cflag = 0;
+      __asm__ __volatile__(
+         "movabsq $0x5555555555555555, %%r11 ; "
+         "movq $0, %%r12 ; "
+         "rdseed %%r11 ; "
+         "setc %%r12b ; "
+         "movq %%r11, %0 ; "
+         "movq %%r12, %1"
+         : "=r"(res), "=r"(cflag) : : "r11", "r12"
+      );
+      if (cflag == 1)
+         return res;
+   }
+   /*NOTREACHED*/
+}
+
+ULong do_rdseed32 ( void )
+{
+   while (1) {
+      ULong res = 0;
+      ULong cflag = 0;
+      __asm__ __volatile__(
+         "movabsq $0x5555555555555555, %%r11 ; "
+         "movq $0, %%r12 ; "
+         "rdseed %%r11d ; "
+         "setc %%r12b ; "
+         "movq %%r11, %0 ; "
+         "movq %%r12, %1"
+         : "=r"(res), "=r"(cflag) : : "r11", "r12"
+      );
+      if (cflag == 1)
+         return res;
+   }
+   /*NOTREACHED*/
+}
+
+ULong do_rdseed16 ( void )
+{
+   while (1) {
+      ULong res = 0;
+      ULong cflag = 0;
+      __asm__ __volatile__(
+         "movabsq $0x5555555555555555, %%r11 ; "
+         "movq $0, %%r12 ; "
+         "rdseed %%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_rdseed64, 0xFFFFFFFFFFFFFFFFULL );
+   do_test( do_rdseed32, 0x00000000FFFFFFFFULL );
+   do_test( do_rdseed16, 0x000000000000FFFFULL );
+   return 0;
+}
diff --git a/none/tests/amd64/rdseed.stderr.exp b/none/tests/amd64/rdseed.stderr.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/none/tests/amd64/rdseed.stdout.exp b/none/tests/amd64/rdseed.stdout.exp
new file mode 100644 (file)
index 0000000..dccfdc9
--- /dev/null
@@ -0,0 +1,33 @@
+0x0000000000000000
+0x0000000000000000
+0x0000000000000000
+0x0000000000000000
+0x0000000000000000
+0x0000000000000000
+0x0000000000000000
+0x0000000000000000
+0x0000000000000000
+0x0000000000000000
+
+0x0000000000000000
+0x0000000000000000
+0x0000000000000000
+0x0000000000000000
+0x0000000000000000
+0x0000000000000000
+0x0000000000000000
+0x0000000000000000
+0x0000000000000000
+0x0000000000000000
+
+0x5555555555550000
+0x5555555555550000
+0x5555555555550000
+0x5555555555550000
+0x5555555555550000
+0x5555555555550000
+0x5555555555550000
+0x5555555555550000
+0x5555555555550000
+0x5555555555550000
+
diff --git a/none/tests/amd64/rdseed.vgtest b/none/tests/amd64/rdseed.vgtest
new file mode 100644 (file)
index 0000000..2d2deff
--- /dev/null
@@ -0,0 +1,4 @@
+prog: rdseed
+prereq: test -x rdseed && ../../../tests/x86_amd64_features amd64-rdseed
+vgopts: -q
+
index 3f6d3a73681b9934965d590b964046990534cc10..488f155b64f5dca678ee4b70d2150d62bb7fc738 100644 (file)
@@ -25,14 +25,14 @@ typedef int    Bool;
 
 
 #if defined(VGA_x86) || defined(VGA_amd64)
-static void cpuid ( unsigned int n,
+static void cpuid ( unsigned int n, unsigned int m,
                     unsigned int* a, unsigned int* b,
                     unsigned int* c, unsigned int* d )
 {
    __asm__ __volatile__ (
       "cpuid"
       : "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)      /* output */
-      : "0" (n)         /* input */
+      : "0" (n), "2" (m)         /* input */
    );
 }
 
@@ -40,7 +40,7 @@ static Bool vendorStringEquals ( char* str )
 {
    char vstr[13];
    unsigned int a, b, c, d;
-   cpuid(0, &a, &b, &c, &d);
+   cpuid(0, 0, &a, &b, &c, &d);
    memcpy(&vstr[0], &b, 4);
    memcpy(&vstr[4], &d, 4);
    memcpy(&vstr[8], &c, 4);
@@ -70,7 +70,9 @@ static Bool have_xgetbv ( void )
 
 static Bool go(char* cpu)
 { 
-   unsigned int level = 0, cmask = 0, dmask = 0, a, b, c, d;
+   unsigned int level = 0, sublevel = 0;
+   unsigned int amask = 0, bmask = 0, cmask = 0, dmask = 0;
+   unsigned int a, b, c, d;
    Bool require_amd = False;
    Bool require_xgetbv = False;
    if        ( strcmp( cpu, "x86-fpu" ) == 0 ) {
@@ -135,22 +137,31 @@ static Bool go(char* cpu)
    } else if (strcmp (cpu,  "amd64-rdrand" ) == 0) {
       level = 1;
       cmask = 1 << 30;
+   } else if (strcmp (cpu,  "amd64-rdseed" ) == 0) {
+      level = 7;
+      bmask = 1 << 18;
 #endif
    } else {
      return UNRECOGNISED_FEATURE;
    }
 
-   assert( !(cmask != 0 && dmask != 0) );
-   assert( !(cmask == 0 && dmask == 0) );
+   assert( !(cmask != 0 && dmask != 0 && bmask != 0) );
+   assert( !(cmask == 0 && dmask == 0 && bmask == 0) );
 
    if (require_amd && !vendorStringEquals("AuthenticAMD"))
       return FEATURE_NOT_PRESENT;
       // regardless of what that feature actually is
 
-   cpuid( level & 0x80000000, &a, &b, &c, &d );
+   cpuid( level & 0x80000000, 0, &a, &b, &c, &d );
 
    if ( a >= level ) {
-      cpuid( level, &a, &b, &c, &d );
+      cpuid( level, sublevel, &a, &b, &c, &d );
+
+      if (amask > 0 && (a & amask) == amask)
+         return FEATURE_PRESENT;
+
+      if (bmask > 0 && (b & bmask) == bmask)
+         return FEATURE_PRESENT;
 
       if (dmask > 0 && (d & dmask) == dmask) {
          if (require_xgetbv && !have_xgetbv())