aboutsummaryrefslogtreecommitdiffstats
path: root/src/arch/x86
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2023-02-17 16:56:11 +0000
committerMichael Brown <mcb30@ipxe.org>2023-02-17 21:29:51 +0000
commit9f17d1116d27696ec76c48c5c77df34cba521380 (patch)
tree381ddb4988380ab1c5c4c59bb27ab7aea9bfc081 /src/arch/x86
parent2733c4763a50b9eb0c206e7430d4d0638451e5e9 (diff)
downloadipxe-9f17d1116d27696ec76c48c5c77df34cba521380.tar.gz
[rng] Allow entropy source to be selected at runtime
As noted in commit 3c83843 ("[rng] Check for several functioning RTC interrupts"), experimentation shows that Hyper-V cannot be trusted to reliably generate RTC interrupts. (As noted in commit f3ba0fb ("[hyperv] Provide timer based on the 10MHz time reference count MSR"), Hyper-V appears to suffer from a general problem in reliably generating any legacy interrupts.) An alternative entropy source is therefore required for an image that may be used in a Hyper-V Gen1 virtual machine. The x86 RDRAND instruction provides a suitable alternative entropy source, but may not be supported by all CPUs. We must therefore allow for multiple entropy sources to be compiled in, with the single active entropy source selected only at runtime. Restructure the internal entropy API to allow a working entropy source to be detected and chosen at runtime. Enable the RDRAND entropy source for all x86 builds, since it is likely to be substantially faster than any other source. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/arch/x86')
-rw-r--r--src/arch/x86/core/rdrand.c32
-rw-r--r--src/arch/x86/include/bits/entropy.h15
-rw-r--r--src/arch/x86/include/ipxe/rdrand.h37
-rw-r--r--src/arch/x86/include/ipxe/rtc_entropy.h62
-rw-r--r--src/arch/x86/interface/pcbios/rtc_entropy.c38
5 files changed, 48 insertions, 136 deletions
diff --git a/src/arch/x86/core/rdrand.c b/src/arch/x86/core/rdrand.c
index 29605ab2f..850ab1f11 100644
--- a/src/arch/x86/core/rdrand.c
+++ b/src/arch/x86/core/rdrand.c
@@ -32,12 +32,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h>
#include <ipxe/cpuid.h>
#include <ipxe/entropy.h>
+#include <ipxe/drbg.h>
+
+struct entropy_source rdrand_entropy __entropy_source ( ENTROPY_PREFERRED );
/** Number of times to retry RDRAND instruction */
#define RDRAND_RETRY_COUNT 16
/** Colour for debug messages */
-#define colour CPUID_FEATURES_INTEL_ECX_RDRAND
+#define colour &rdrand_entropy
/**
* Enable entropy gathering
@@ -54,16 +57,15 @@ static int rdrand_entropy_enable ( void ) {
return -ENOTSUP;
}
- return 0;
-}
-
-/**
- * Disable entropy gathering
- *
- */
-static void rdrand_entropy_disable ( void ) {
+ /* Data returned by RDRAND is theoretically full entropy, up
+ * to a security strength of 128 bits, so assume that each
+ * sample contains exactly 8 bits of entropy.
+ */
+ if ( DRBG_SECURITY_STRENGTH > 128 )
+ return -ENOTSUP;
+ entropy_init ( &rdrand_entropy, MIN_ENTROPY ( 8.0 ) );
- /* Nothing to do */
+ return 0;
}
/**
@@ -93,7 +95,9 @@ static int rdrand_get_noise ( noise_sample_t *noise ) {
return 0;
}
-PROVIDE_ENTROPY_INLINE ( rdrand, min_entropy_per_sample );
-PROVIDE_ENTROPY ( rdrand, entropy_enable, rdrand_entropy_enable );
-PROVIDE_ENTROPY ( rdrand, entropy_disable, rdrand_entropy_disable );
-PROVIDE_ENTROPY ( rdrand, get_noise, rdrand_get_noise );
+/** Hardware random number generator entropy source */
+struct entropy_source rdrand_entropy __entropy_source ( ENTROPY_PREFERRED ) = {
+ .name = "rdrand",
+ .enable = rdrand_entropy_enable,
+ .get_noise = rdrand_get_noise,
+};
diff --git a/src/arch/x86/include/bits/entropy.h b/src/arch/x86/include/bits/entropy.h
deleted file mode 100644
index 7accea33f..000000000
--- a/src/arch/x86/include/bits/entropy.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef _BITS_ENTROPY_H
-#define _BITS_ENTROPY_H
-
-/** @file
- *
- * x86-specific entropy API implementations
- *
- */
-
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-
-#include <ipxe/rtc_entropy.h>
-#include <ipxe/rdrand.h>
-
-#endif /* _BITS_ENTROPY_H */
diff --git a/src/arch/x86/include/ipxe/rdrand.h b/src/arch/x86/include/ipxe/rdrand.h
deleted file mode 100644
index c9c170fb0..000000000
--- a/src/arch/x86/include/ipxe/rdrand.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef _IPXE_RDRAND_H
-#define _IPXE_RDRAND_H
-
-/** @file
- *
- * Hardware random number generator
- *
- */
-
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-
-#include <stdint.h>
-#include <ipxe/drbg.h>
-
-#ifdef ENTROPY_RDRAND
-#define ENTROPY_PREFIX_rdrand
-#else
-#define ENTROPY_PREFIX_rdrand __rdrand_
-#endif
-
-/**
- * min-entropy per sample
- *
- * @ret min_entropy min-entropy of each sample
- */
-static inline __always_inline min_entropy_t
-ENTROPY_INLINE ( rdrand, min_entropy_per_sample ) ( void ) {
-
- /* Data returned by RDRAND is theoretically full entropy, up
- * to a security strength of 128 bits.
- */
- if ( DRBG_SECURITY_STRENGTH > 128 )
- return 0;
- return MIN_ENTROPY ( 8 * sizeof ( noise_sample_t ) );
-}
-
-#endif /* _IPXE_RDRAND_H */
diff --git a/src/arch/x86/include/ipxe/rtc_entropy.h b/src/arch/x86/include/ipxe/rtc_entropy.h
deleted file mode 100644
index 581abcd3e..000000000
--- a/src/arch/x86/include/ipxe/rtc_entropy.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef _IPXE_RTC_ENTROPY_H
-#define _IPXE_RTC_ENTROPY_H
-
-/** @file
- *
- * RTC-based entropy source
- *
- */
-
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-
-#include <stdint.h>
-
-#ifdef ENTROPY_RTC
-#define ENTROPY_PREFIX_rtc
-#else
-#define ENTROPY_PREFIX_rtc __rtc_
-#endif
-
-/**
- * min-entropy per sample
- *
- * @ret min_entropy min-entropy of each sample
- */
-static inline __always_inline min_entropy_t
-ENTROPY_INLINE ( rtc, min_entropy_per_sample ) ( void ) {
-
- /* The min-entropy has been measured on several platforms
- * using the entropy_sample test code. Modelling the samples
- * as independent, and using a confidence level of 99.99%, the
- * measurements were as follows:
- *
- * qemu-kvm : 7.38 bits
- * VMware : 7.46 bits
- * Physical hardware : 2.67 bits
- *
- * We choose the lowest of these (2.67 bits) and apply a 50%
- * safety margin to allow for some potential non-independence
- * of samples.
- */
- return MIN_ENTROPY ( 1.3 );
-}
-
-extern uint8_t rtc_sample ( void );
-
-/**
- * Get noise sample
- *
- * @ret noise Noise sample
- * @ret rc Return status code
- */
-static inline __always_inline int
-ENTROPY_INLINE ( rtc, get_noise ) ( noise_sample_t *noise ) {
-
- /* Get sample */
- *noise = rtc_sample();
-
- /* Always successful */
- return 0;
-}
-
-#endif /* _IPXE_RTC_ENTROPY_H */
diff --git a/src/arch/x86/interface/pcbios/rtc_entropy.c b/src/arch/x86/interface/pcbios/rtc_entropy.c
index c400d8a78..8f47ff6b8 100644
--- a/src/arch/x86/interface/pcbios/rtc_entropy.c
+++ b/src/arch/x86/interface/pcbios/rtc_entropy.c
@@ -39,6 +39,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/cpuid.h>
#include <ipxe/entropy.h>
+struct entropy_source rtc_entropy __entropy_source ( ENTROPY_NORMAL );
+
/** Maximum time to wait for an RTC interrupt, in milliseconds */
#define RTC_MAX_WAIT_MS 100
@@ -203,6 +205,21 @@ static int rtc_entropy_enable ( void ) {
if ( ( rc = rtc_entropy_check() ) != 0 )
goto err_check;
+ /* The min-entropy has been measured on several platforms
+ * using the entropy_sample test code. Modelling the samples
+ * as independent, and using a confidence level of 99.99%, the
+ * measurements were as follows:
+ *
+ * qemu-kvm : 7.38 bits
+ * VMware : 7.46 bits
+ * Physical hardware : 2.67 bits
+ *
+ * We choose the lowest of these (2.67 bits) and apply a 50%
+ * safety margin to allow for some potential non-independence
+ * of samples.
+ */
+ entropy_init ( &rtc_entropy, MIN_ENTROPY ( 1.3 ) );
+
return 0;
err_check:
@@ -226,11 +243,12 @@ static void rtc_entropy_disable ( void ) {
}
/**
- * Measure a single RTC tick
+ * Get noise sample
*
- * @ret delta Length of RTC tick (in TSC units)
+ * @ret noise Noise sample
+ * @ret rc Return status code
*/
-uint8_t rtc_sample ( void ) {
+static int rtc_get_noise ( noise_sample_t *noise ) {
uint32_t before;
uint32_t after;
uint32_t temp;
@@ -265,10 +283,14 @@ uint8_t rtc_sample ( void ) {
: "=a" ( after ), "=d" ( before ), "=Q" ( temp )
: "2" ( 0 ) );
- return ( after - before );
+ *noise = ( after - before );
+ return 0;
}
-PROVIDE_ENTROPY_INLINE ( rtc, min_entropy_per_sample );
-PROVIDE_ENTROPY ( rtc, entropy_enable, rtc_entropy_enable );
-PROVIDE_ENTROPY ( rtc, entropy_disable, rtc_entropy_disable );
-PROVIDE_ENTROPY_INLINE ( rtc, get_noise );
+/** RTC entropy source */
+struct entropy_source rtc_entropy __entropy_source ( ENTROPY_NORMAL ) = {
+ .name = "rtc",
+ .enable = rtc_entropy_enable,
+ .disable = rtc_entropy_disable,
+ .get_noise = rtc_get_noise,
+};