+#if defined(__x86_64__)
+#include <i386/cpuid.h>
+
+static int rdseed_step(uint64_t *seed)
+{
+ uint8_t ok;
+
+ asm volatile ("rdseed %0; setc %1" : "=r" (*seed), "=qm" (ok));
+
+ return (int) ok;
+}
+
+static int rdseed_retry(uint64_t *seed, size_t nretries)
+{
+ size_t i;
+
+ for (i = 0; i < nretries; i += 1) {
+ if (rdseed_step(seed)) {
+ return 1;
+ } else {
+ asm volatile ("pause");
+ }
+ }
+
+ return 0;
+}
+
+static size_t rdseed_seed(void *buf, size_t nwords)
+{
+ uint64_t *buf_words;
+ size_t i;
+
+ if (nwords > 8) {
+ nwords = 8;
+ }
+
+ buf_words = buf;
+ for (i = 0; i < nwords; i += 1) {
+ if (!rdseed_retry(buf_words + i, 10)) {
+ return i;
+ }
+ }
+
+ return nwords;
+}
+
+static int rdrand_step(uint64_t *rand)
+{
+ uint8_t ok;
+
+ asm volatile ("rdrand %0; setc %1" : "=r" (*rand), "=qm" (ok));
+
+ return (int) ok;
+}
+
+static int rdrand_retry(uint64_t *rand, size_t nretries)
+{
+ size_t i;
+
+ for (i = 0; i < nretries; i += 1) {
+ if (rdrand_step(rand)) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static size_t rdrand_seed(void *buf, size_t nwords)
+{
+ size_t i;
+ uint64_t w;
+ uint8_t hash[CCSHA256_OUTPUT_SIZE];
+ const struct ccdigest_info *di = &ccsha256_ltc_di;
+
+ ccdigest_di_decl(di, ctx);
+ ccdigest_init(di, ctx);
+
+ for (i = 0; i < 1023; i += 1) {
+ if (!rdrand_retry(&w, 10)) {
+ nwords = 0;
+ goto out;
+ }
+ ccdigest_update(di, ctx, sizeof w, &w);
+ }
+
+ ccdigest_final(di, ctx, hash);
+
+ if (nwords > 2) {
+ nwords = 2;
+ }
+
+ memcpy(buf, hash, nwords * sizeof (uint64_t));
+
+out:
+ ccdigest_di_clear(di, ctx);
+ bzero(hash, sizeof hash);
+ bzero(&w, sizeof w);
+
+ return nwords;
+}
+
+static void intel_entropysource(void *buf, size_t *nbytes)
+{
+ size_t nwords;
+
+ /* only handle complete words */
+ assert(*nbytes % sizeof (uint64_t) == 0);
+
+ nwords = (*nbytes) / sizeof (uint64_t);
+ if (cpuid_leaf7_features() & CPUID_LEAF7_FEATURE_RDSEED) {
+ nwords = rdseed_seed(buf, nwords);
+ *nbytes = nwords * sizeof (uint64_t);
+ } else if (cpuid_features() & CPUID_FEATURE_RDRAND) {
+ nwords = rdrand_seed(buf, nwords);
+ *nbytes = nwords * sizeof (uint64_t);
+ } else {
+ *nbytes = 0;
+ }
+}
+
+#endif
+
+typedef void (*entropysource)(void *buf, size_t *nbytes);
+
+static const entropysource entropysources[] = {
+ entropy_buffer_read,
+#if defined(__x86_64__)
+ intel_entropysource,
+#endif
+};
+
+static const size_t nsources = sizeof entropysources / sizeof entropysources[0];
+
+static size_t entropy_readall(void *buf, size_t nbytes_persource)
+{
+ uint8_t *buf_bytes = buf;
+ size_t i;
+ size_t nbytes_total = 0;
+
+ for (i = 0; i < nsources; i += 1) {
+ size_t nbytes = nbytes_persource;
+ entropysources[i](buf_bytes, &nbytes);
+ bzero(buf_bytes + nbytes, nbytes_persource - nbytes);
+ nbytes_total += nbytes;
+ buf_bytes += nbytes_persource;
+ }
+
+ return nbytes_total;
+}
+
+static struct {
+ lck_grp_t *group;
+ lck_attr_t *attrs;
+ lck_grp_attr_t *group_attrs;
+ lck_mtx_t *mutex;
+} lock;