Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/random/ivy.c
Show All 38 Lines | |||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/random.h> | #include <sys/random.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <machine/md_var.h> | #include <machine/md_var.h> | ||||
#include <machine/specialreg.h> | #include <machine/specialreg.h> | ||||
#include <x86/ifunc.h> | |||||
#include <dev/random/randomdev.h> | #include <dev/random/randomdev.h> | ||||
#define RETRY_COUNT 10 | #define RETRY_COUNT 10 | ||||
static bool has_rdrand, has_rdseed; | |||||
static u_int random_ivy_read(void *, u_int); | static u_int random_ivy_read(void *, u_int); | ||||
static struct random_source random_ivy = { | static struct random_source random_ivy = { | ||||
.rs_ident = "Intel Secure Key RNG", | .rs_ident = "Intel Secure Key RNG", | ||||
.rs_source = RANDOM_PURE_RDRAND, | .rs_source = RANDOM_PURE_RDRAND, | ||||
.rs_read = random_ivy_read | .rs_read = random_ivy_read | ||||
}; | }; | ||||
static inline int | static int | ||||
ivy_rng_store(u_long *buf) | x86_rdrand_store(u_long *buf) | ||||
{ | { | ||||
#ifdef __GNUCLIKE_ASM | |||||
u_long rndval; | u_long rndval; | ||||
int retry; | int retry; | ||||
retry = RETRY_COUNT; | retry = RETRY_COUNT; | ||||
__asm __volatile( | __asm __volatile( | ||||
"1:\n\t" | "1:\n\t" | ||||
"rdrand %1\n\t" /* read randomness into rndval */ | "rdrand %1\n\t" /* read randomness into rndval */ | ||||
"jc 2f\n\t" /* CF is set on success, exit retry loop */ | "jc 2f\n\t" /* CF is set on success, exit retry loop */ | ||||
"dec %0\n\t" /* otherwise, retry-- */ | "dec %0\n\t" /* otherwise, retry-- */ | ||||
"jne 1b\n\t" /* and loop if retries are not exhausted */ | "jne 1b\n\t" /* and loop if retries are not exhausted */ | ||||
"2:" | "2:" | ||||
: "+r" (retry), "=r" (rndval) : : "cc"); | : "+r" (retry), "=r" (rndval) : : "cc"); | ||||
*buf = rndval; | *buf = rndval; | ||||
return (retry); | return (retry); | ||||
#else /* __GNUCLIKE_ASM */ | |||||
return (0); | |||||
#endif | |||||
} | } | ||||
static int | |||||
x86_rdseed_store(u_long *buf) | |||||
{ | |||||
u_long rndval; | |||||
int retry; | |||||
retry = RETRY_COUNT; | |||||
__asm __volatile( | |||||
"1:\n\t" | |||||
"rdseed %1\n\t" /* read randomness into rndval */ | |||||
"jc 2f\n\t" /* CF is set on success, exit retry loop */ | |||||
"dec %0\n\t" /* otherwise, retry-- */ | |||||
"jne 1b\n\t" /* and loop if retries are not exhausted */ | |||||
"2:" | |||||
: "+r" (retry), "=r" (rndval) : : "cc"); | |||||
*buf = rndval; | |||||
return (retry); | |||||
} | |||||
DEFINE_IFUNC(static, int, x86_rng_store, (u_long *buf), static) | |||||
{ | |||||
has_rdrand = (cpu_feature2 & CPUID2_RDRAND); | |||||
has_rdseed = (cpu_stdext_feature & CPUID_STDEXT_RDSEED); | |||||
if (has_rdseed) | |||||
return (x86_rdseed_store); | |||||
else if (has_rdrand) | |||||
return (x86_rdrand_store); | |||||
else | |||||
return (NULL); | |||||
} | |||||
/* It is required that buf length is a multiple of sizeof(u_long). */ | /* It is required that buf length is a multiple of sizeof(u_long). */ | ||||
static u_int | static u_int | ||||
random_ivy_read(void *buf, u_int c) | random_ivy_read(void *buf, u_int c) | ||||
{ | { | ||||
u_long *b, rndval; | u_long *b, rndval; | ||||
u_int count; | u_int count; | ||||
KASSERT(c % sizeof(*b) == 0, ("partial read %d", c)); | KASSERT(c % sizeof(*b) == 0, ("partial read %d", c)); | ||||
b = buf; | b = buf; | ||||
for (count = c; count > 0; count -= sizeof(*b)) { | for (count = c; count > 0; count -= sizeof(*b)) { | ||||
if (ivy_rng_store(&rndval) == 0) | if (x86_rng_store(&rndval) == 0) | ||||
break; | break; | ||||
*b++ = rndval; | *b++ = rndval; | ||||
} | } | ||||
return (c - count); | return (c - count); | ||||
} | } | ||||
static int | static int | ||||
rdrand_modevent(module_t mod, int type, void *unused) | rdrand_modevent(module_t mod, int type, void *unused) | ||||
{ | { | ||||
int error = 0; | int error = 0; | ||||
switch (type) { | switch (type) { | ||||
case MOD_LOAD: | case MOD_LOAD: | ||||
if (cpu_feature2 & CPUID2_RDRAND) { | if (has_rdrand || has_rdseed) { | ||||
random_source_register(&random_ivy); | random_source_register(&random_ivy); | ||||
printf("random: fast provider: \"%s\"\n", random_ivy.rs_ident); | printf("random: fast provider: \"%s\"\n", random_ivy.rs_ident); | ||||
} | } | ||||
break; | break; | ||||
case MOD_UNLOAD: | case MOD_UNLOAD: | ||||
if (cpu_feature2 & CPUID2_RDRAND) | if (has_rdrand || has_rdseed) | ||||
random_source_deregister(&random_ivy); | random_source_deregister(&random_ivy); | ||||
break; | break; | ||||
case MOD_SHUTDOWN: | case MOD_SHUTDOWN: | ||||
break; | break; | ||||
default: | default: | ||||
error = EOPNOTSUPP; | error = EOPNOTSUPP; | ||||
Show All 10 Lines |