aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Gerd Zellweger <mail@gerdzellweger.com> 2019-05-18 13:00:27 -0700
committerGravatar Gerd Zellweger <mail@gerdzellweger.com> 2019-05-18 13:00:27 -0700
commit748e11a27c278c3f095c60d5e7120192eda66a6d (patch)
tree413641a5dd6b5ea222dcfba769a1919be3684c57
parentc5cb736d8d64bfda6b88a8b4610961a37a436f3d (diff)
downloadrust-x86-748e11a27c278c3f095c60d5e7120192eda66a6d.tar.gz
rust-x86-748e11a27c278c3f095c60d5e7120192eda66a6d.tar.zst
rust-x86-748e11a27c278c3f095c60d5e7120192eda66a6d.zip
Add support for random numbers. Improve docs.
-rw-r--r--Cargo.toml2
-rw-r--r--README.md6
-rw-r--r--src/bits16/mod.rs2
-rw-r--r--src/bits32/mod.rs2
-rw-r--r--src/controlregs.rs2
-rw-r--r--src/lib.rs52
-rw-r--r--src/random.rs263
-rw-r--r--src/segmentation.rs2
8 files changed, 326 insertions, 5 deletions
diff --git a/Cargo.toml b/Cargo.toml
index b9f4cde..4ae26c3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "x86"
-version = "0.17.0"
+version = "0.18.0"
authors = [
"Gerd Zellweger <mail@gerdzellweger.com>",
"Eric Kidd <git@randomhacks.net>",
diff --git a/README.md b/README.md
index 974cdb6..1abada8 100644
--- a/README.md
+++ b/README.md
@@ -10,11 +10,13 @@ Currently supports
* Segmentation
* Descriptor-tables (GDT, LDT, IDT)
* IA32-e page table layout
- * Interrupts
+ * Interrupts (with xAPIC and x2APIC registers)
* Task state
- * Querying CPUID (uses [raw_cpuid](https://github.com/gz/rust-cpuid) library)
* Performance counter information
* Intel SGX: Software Guard Extensions
+ * Random numbers (rdrand, rdseed)
+ * Time (rdtsc, rdtscp)
+ * Querying CPUID (uses [raw_cpuid](https://github.com/gz/rust-cpuid) library)
This library depends on libcore so it can be used in kernel level code.
diff --git a/src/bits16/mod.rs b/src/bits16/mod.rs
index 458319a..e7c002f 100644
--- a/src/bits16/mod.rs
+++ b/src/bits16/mod.rs
@@ -1 +1,3 @@
+//! Data structures and functions used by 16-bit mode.
+
pub mod segmentation;
diff --git a/src/bits32/mod.rs b/src/bits32/mod.rs
index 917398c..a90ef82 100644
--- a/src/bits32/mod.rs
+++ b/src/bits32/mod.rs
@@ -1,3 +1,5 @@
+//! Data structures and functions used by 32-bit mode.
+
pub mod eflags;
pub mod segmentation;
pub mod task;
diff --git a/src/controlregs.rs b/src/controlregs.rs
index 9da5dd7..4138a37 100644
--- a/src/controlregs.rs
+++ b/src/controlregs.rs
@@ -134,7 +134,7 @@ pub unsafe fn cr4() -> Cr4 {
///
/// # Example
///
-/// ```
+/// ```no-run
/// unsafe {
/// let cr4 = cr4();
/// let cr4 = cr4 | Cr4::CR4_ENABLE_PSE;
diff --git a/src/lib.rs b/src/lib.rs
index 36d77e0..c9c596b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -24,6 +24,7 @@ pub mod dtables;
pub mod io;
pub mod irq;
pub mod msr;
+pub mod random;
pub mod segmentation;
pub mod task;
pub mod time;
@@ -33,6 +34,7 @@ pub mod xapic;
#[cfg(feature = "performance-counter")]
pub mod perfcnt;
+/// A short-cut to the architecture (bits32 or bits64) this crate was compiled for.
pub mod current {
#[cfg(target_arch = "x86")]
pub use crate::bits32::*;
@@ -40,6 +42,7 @@ pub mod current {
pub use crate::bits64::*;
}
+/// Support for the CPUID instructions.
pub mod cpuid {
pub use raw_cpuid::*;
}
@@ -54,7 +57,9 @@ mod std {
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
/// x86 Protection levels
-/// Note: This should not contain values larger than 2 bits, otherwise
+///
+/// # Note
+/// This should not contain values larger than 2 bits, otherwise
/// segment descriptor code needs to be adjusted accordingly.
pub enum Ring {
Ring0 = 0b00,
@@ -63,7 +68,52 @@ pub enum Ring {
Ring3 = 0b11,
}
+
+/// Stops instruction execution and places the processor in a HALT state.
+///
+/// An enabled interrupt (including NMI and SMI), a debug exception, the BINIT#
+/// signal, the INIT# signal, or the RESET# signal will resume execution. If an
+/// interrupt (including NMI) is used to resume execution after a HLT instruction,
+/// the saved instruction pointer (CS:EIP) points to the instruction following
+/// the HLT instruction.
+///
+/// # Unsafe
+/// Will cause a general protection fault if used outside of ring 0.
#[inline(always)]
pub unsafe fn halt() {
asm!("hlt" :::: "volatile");
}
+
+/// Read Processor ID
+///
+/// Reads the value of the IA32_TSC_AUX MSR (address C0000103H)
+/// into the destination register.
+///
+/// # Unsafe
+/// May fail with #UD if rdpid is not supported (check CPUID).
+#[inline(always)]
+pub unsafe fn rdpid() -> u64 {
+ let mut pid: u64;
+ asm!("rdpid $0" : "=r"(pid));
+ return pid;
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_rdpid() {
+ let rdpid_support = cpuid::CpuId::new()
+ .get_extended_feature_info()
+ .map_or(false, |finfo| finfo.has_rdpid());
+ unsafe {
+ if rdpid_support {
+ let pid1 = rdpid();
+ let pid2 = rdpid();
+ // Let's hope we didn't migrate
+ assert!(pid1 == pid2, "RDPID not consistent values?");
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/random.rs b/src/random.rs
new file mode 100644
index 0000000..56a4668
--- /dev/null
+++ b/src/random.rs
@@ -0,0 +1,263 @@
+//! Instructions to generate random bits directly from the hardware (RDRAND and RDSEED).
+//!
+//! The decision process for which instruction to use is based on what
+//! the output will be used for. If you wish to seed another pseudorandom
+//! number generator (PRNG), use RDSEED. For all other purposes, use RDRAND
+//!
+//! See also: https://software.intel.com/en-us/blogs/2012/11/17/the-difference-between-rdrand-and-rdseed
+//!
+//! * RDRAND: Cryptographically secure pseudorandom number generator NIST:SP 800-90A
+//! * RDSEED: Non-deterministic random bit generator NIST: SP 800-90B & C (drafts)
+//!
+#[cfg(target_arch = "x86_64")]
+use core::arch::x86_64::{
+ _rdrand16_step, _rdrand32_step, _rdrand64_step, _rdseed16_step, _rdseed32_step, _rdseed64_step,
+};
+
+#[cfg(target_arch = "x86")]
+use core::arch::x86::{
+ _rdrand16_step, _rdrand32_step, _rdrand64_step, _rdseed16_step, _rdseed32_step, _rdseed64_step,
+};
+
+/// Generates a 16-bit random value and stores it in `e`.
+///
+/// # Unsafe
+/// Will crash if RDRAND instructions are not supported.
+#[inline(always)]
+pub unsafe fn rdrand16(e: &mut u16) -> bool {
+ _rdrand16_step(e) == 1
+}
+
+/// Generates a 32-bit random value and stores it in `e`.
+///
+/// # Unsafe
+/// Will crash if RDRAND instructions are not supported.
+#[inline(always)]
+pub unsafe fn rdrand32(e: &mut u32) -> bool {
+ _rdrand32_step(e) == 1
+}
+
+/// Generates a 64-bit random value and stores it in `e`.
+///
+/// # Unsafe
+/// Will crash if RDRAND instructions are not supported.
+#[inline(always)]
+pub unsafe fn rdrand64(e: &mut u64) -> bool {
+ _rdrand64_step(e) == 1
+}
+
+/// RdRand trait to implement the generic rdrand_slice function.
+pub trait RdRand {
+ /// Fills `self` with random bits. Returns true on success or false otherwise
+ ///
+ /// # Unsafe
+ /// RDRAND is not supported on all architctures, so using this may crash you.
+ unsafe fn fill_random(&mut self) -> bool;
+}
+
+impl RdRand for u16 {
+ /// Fills the 16-bit value with a random bit string
+ ///
+ /// # Unsafe
+ /// Will crash if RDRAND instructions are not supported.
+ unsafe fn fill_random(&mut self) -> bool {
+ rdrand16(self)
+ }
+}
+
+impl RdRand for u32 {
+ /// Fills the 32-bit value with a random bit string
+ ///
+ /// # Unsafe
+ /// Will crash if RDRAND instructions are not supported.
+ unsafe fn fill_random(&mut self) -> bool {
+ rdrand32(self)
+ }
+}
+
+impl RdRand for u64 {
+ /// Fills the 64-bit value with a random bit string
+ ///
+ /// # Unsafe
+ /// Will crash if RDRAND instructions are not supported.
+ unsafe fn fill_random(&mut self) -> bool {
+ rdrand64(self)
+ }
+}
+
+/// Fill a slice with random values.
+///
+/// Returns true if the iterator was successfully filled with
+/// random values, otherwise false.
+pub unsafe fn rdrand_slice<T: RdRand>(buffer: &mut [T]) -> bool {
+ let mut worked = true;
+ for element in buffer {
+ worked &= element.fill_random();
+ }
+ worked
+}
+
+/// Generates a 16-bit random value and stores it in `e`.
+///
+/// # Unsafe
+/// Will crash if RDSEED instructions are not supported.
+#[inline(always)]
+pub unsafe fn rdseed16(e: &mut u16) -> bool {
+ _rdseed16_step(e) == 1
+}
+
+/// Generates a 32-bit random value and stores it in `e`.
+///
+/// # Unsafe
+/// Will crash if RDSEED instructions are not supported.
+#[inline(always)]
+pub unsafe fn rdseed32(e: &mut u32) -> bool {
+ _rdseed32_step(e) == 1
+}
+
+/// Generates a 64-bit random value and stores it in `e`.
+///
+/// # Unsafe
+/// Will crash if RDSEED instructions are not supported.
+#[inline(always)]
+pub unsafe fn rdseed64(e: &mut u64) -> bool {
+ _rdseed64_step(e) == 1
+}
+
+/// RdSeed trait to implement the generic rdseed_slice function.
+pub trait RdSeed {
+ /// Fills `self` with random bits. Returns true on success or false otherwise
+ ///
+ /// # Unsafe
+ /// RDSEED is not supported on all architctures, so using this may crash you.
+ unsafe fn fill_random(&mut self) -> bool;
+}
+
+impl RdSeed for u16 {
+ /// Fills the 16-bit value with a random bit string
+ ///
+ /// # Unsafe
+ /// Will crash if RDSEED instructions are not supported.
+ unsafe fn fill_random(&mut self) -> bool {
+ rdseed16(self)
+ }
+}
+
+impl RdSeed for u32 {
+ /// Fills the 32-bit value with a random bit string
+ ///
+ /// # Unsafe
+ /// Will crash if RDSEED instructions are not supported.
+ unsafe fn fill_random(&mut self) -> bool {
+ rdseed32(self)
+ }
+}
+
+impl RdSeed for u64 {
+ /// Fills the 64-bit value with a random bit string
+ ///
+ /// # Unsafe
+ /// Will crash if RDSEED instructions are not supported.
+ unsafe fn fill_random(&mut self) -> bool {
+ rdseed64(self)
+ }
+}
+
+/// Fill a slice with random values.
+///
+/// Returns true if the iterator was successfully filled with
+/// random values, otherwise false.
+pub unsafe fn rdseed_slice<T: RdSeed>(buffer: &mut [T]) -> bool {
+ let mut worked = true;
+ for element in buffer {
+ worked &= element.fill_random();
+ }
+ worked
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn rdrand64_test() {
+ unsafe {
+ let mut buf: [u64; 4] = [0, 0, 0, 0];
+ rdrand_slice(&mut buf);
+
+ assert_ne!(buf[0], 0);
+ assert_ne!(buf[1], 0);
+ assert_ne!(buf[2], 0);
+ assert_ne!(buf[3], 0);
+ }
+ }
+
+
+ #[test]
+ fn rdrand32_test() {
+ unsafe {
+ let mut buf: [u32; 4] = [0, 0, 0, 0];
+ rdrand_slice(&mut buf);
+
+ assert_ne!(buf[0], 0);
+ assert_ne!(buf[1], 0);
+ assert_ne!(buf[2], 0);
+ assert_ne!(buf[3], 0);
+ }
+ }
+
+
+ #[test]
+ fn rdrand16_test() {
+ unsafe {
+ let mut buf: [u16; 4] = [0, 0, 0, 0];
+ rdrand_slice(&mut buf);
+ assert_ne!(buf[0], 0);
+ assert_ne!(buf[1], 0);
+ assert_ne!(buf[2], 0);
+ assert_ne!(buf[3], 0);
+ }
+ }
+
+
+ #[test]
+ fn rdseed64_test() {
+ unsafe {
+ let mut buf: [u64; 4] = [0, 0, 0, 0];
+ rdseed_slice(&mut buf);
+
+ assert_ne!(buf[0], 0);
+ assert_ne!(buf[1], 0);
+ assert_ne!(buf[2], 0);
+ assert_ne!(buf[3], 0);
+ }
+ }
+
+
+ #[test]
+ fn rdseed32_test() {
+ unsafe {
+ let mut buf: [u32; 4] = [0, 0, 0, 0];
+ rdseed_slice(&mut buf);
+
+ assert_ne!(buf[0], 0);
+ assert_ne!(buf[1], 0);
+ assert_ne!(buf[2], 0);
+ assert_ne!(buf[3], 0);
+ }
+ }
+
+
+ #[test]
+ fn rdseed16_test() {
+ unsafe {
+ let mut buf: [u16; 4] = [0, 0, 0, 0];
+ rdseed_slice(&mut buf);
+ assert_ne!(buf[0], 0);
+ assert_ne!(buf[1], 0);
+ assert_ne!(buf[2], 0);
+ assert_ne!(buf[3], 0);
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/segmentation.rs b/src/segmentation.rs
index 2f14cf4..8757add 100644
--- a/src/segmentation.rs
+++ b/src/segmentation.rs
@@ -1,3 +1,5 @@
+//! Functionality to manipulate segment registers, build segement
+//! descriptors and selectors.
use bitflags::*;
use core::fmt;