x86/
lib.rs

1#![cfg(any(target_arch = "x86", target_arch = "x86_64"))]
2#![no_std]
3#![cfg_attr(test, allow(unused_features))]
4#![cfg_attr(all(test, feature = "vmtest"), feature(custom_test_frameworks))]
5#![cfg_attr(all(test, feature = "vmtest"), test_runner(x86test::runner::runner))]
6#![cfg_attr(feature = "unstable", feature(step_trait))]
7
8use core::arch::asm;
9#[cfg(target_arch = "x86")]
10pub(crate) use core::arch::x86 as arch;
11#[cfg(target_arch = "x86_64")]
12pub(crate) use core::arch::x86_64 as arch;
13
14macro_rules! bit {
15    ($x:expr) => {
16        1 << $x
17    };
18}
19
20pub mod bits16;
21pub mod bits32;
22pub mod bits64;
23
24pub mod apic;
25pub mod controlregs;
26pub mod debugregs;
27pub mod dtables;
28pub mod fence;
29pub mod io;
30pub mod irq;
31pub mod msr;
32pub mod random;
33pub mod segmentation;
34pub mod task;
35pub mod time;
36pub mod tlb;
37pub mod vmx;
38
39#[cfg(feature = "performance-counter")]
40pub mod perfcnt;
41
42/// A short-cut to the architecture (bits32 or bits64) this crate was compiled for.
43pub mod current {
44    #[cfg(target_arch = "x86")]
45    pub use crate::bits32::*;
46    #[cfg(target_arch = "x86_64")]
47    pub use crate::bits64::*;
48}
49
50/// Support for the CPUID instructions.
51pub mod cpuid {
52    pub use raw_cpuid::*;
53}
54
55#[cfg(not(test))]
56mod std {
57    pub use core::fmt;
58    pub use core::ops;
59    pub use core::option;
60}
61
62#[cfg(all(test, feature = "vmtest"))]
63extern crate klogger;
64#[cfg(all(test, feature = "vmtest"))]
65extern crate x86test;
66
67#[derive(Copy, Clone, Debug, Eq, PartialEq)]
68#[repr(u8)]
69/// x86 Protection levels
70///
71/// # Note
72/// This should not contain values larger than 2 bits, otherwise
73/// segment descriptor code needs to be adjusted accordingly.
74pub enum Ring {
75    Ring0 = 0b00,
76    Ring1 = 0b01,
77    Ring2 = 0b10,
78    Ring3 = 0b11,
79}
80
81/// Stops instruction execution and places the processor in a HALT state.
82///
83/// An enabled interrupt (including NMI and SMI), a debug exception, the BINIT#
84/// signal, the INIT# signal, or the RESET# signal will resume execution. If an
85/// interrupt (including NMI) is used to resume execution after a HLT instruction,
86/// the saved instruction pointer (CS:EIP) points to the instruction following
87/// the HLT instruction.
88///
89/// # Safety
90/// Will cause a general protection fault if used outside of ring 0.
91#[inline(always)]
92pub unsafe fn halt() {
93    asm!("hlt", options(att_syntax, nomem, nostack)); // check if preserves_flags
94}
95
96#[cfg(all(test, feature = "vmtest"))]
97mod x86testing {
98    use super::*;
99    use x86test::*;
100
101    #[x86test(should_halt)]
102    fn should_halt() {
103        unsafe { halt() }
104    }
105
106    #[x86test]
107    fn should_not_halt() {}
108}
109
110/// Read Processor ID
111///
112/// Reads the value of the IA32_TSC_AUX MSR (address C0000103H) into the
113/// destination register.
114///
115/// # See also
116/// `IA32_TSC_AUX` can also be read calling [`crate::time::rdtscp`].
117///
118/// # Safety
119/// May fail with #UD if rdpid is not supported (check CPUID).
120#[inline(always)]
121pub unsafe fn rdpid() -> u64 {
122    #[cfg(target_pointer_width = "64")]
123    let mut pid: u64;
124    #[cfg(target_pointer_width = "32")]
125    let mut pid: u32;
126    asm!("rdpid {pid}", pid = out(reg) pid, options(att_syntax));
127    pid.into()
128}
129
130#[cfg(all(test, feature = "utest"))]
131mod test {
132    use super::*;
133
134    #[test]
135    fn test_rdpid() {
136        let rdpid_support = cpuid::CpuId::new()
137            .get_extended_feature_info()
138            .map_or(false, |finfo| finfo.has_rdpid());
139        unsafe {
140            if rdpid_support {
141                let pid1 = rdpid();
142                let pid2 = rdpid();
143                // Let's hope we didn't migrate
144                assert!(pid1 == pid2, "RDPID not consistent values?");
145            }
146        }
147    }
148}