diff options
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | README.md | 6 | ||||
-rw-r--r-- | src/bits16/mod.rs | 2 | ||||
-rw-r--r-- | src/bits32/mod.rs | 2 | ||||
-rw-r--r-- | src/controlregs.rs | 2 | ||||
-rw-r--r-- | src/lib.rs | 52 | ||||
-rw-r--r-- | src/random.rs | 263 | ||||
-rw-r--r-- | src/segmentation.rs | 2 |
8 files changed, 326 insertions, 5 deletions
@@ -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>", @@ -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; @@ -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; |