x86_64/registers/
rflags.rs

1//! Processor state stored in the RFLAGS register.
2
3#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
4pub use self::x86_64::*;
5
6use bitflags::bitflags;
7
8bitflags! {
9    /// The RFLAGS register. All bit patterns are valid representations for this type.
10    #[repr(transparent)]
11    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
12    pub struct RFlags: u64 {
13        /// Processor feature identification flag.
14        ///
15        /// If this flag is modifiable, the CPU supports CPUID.
16        const ID = 1 << 21;
17        /// Indicates that an external, maskable interrupt is pending.
18        ///
19        /// Used when virtual-8086 mode extensions (CR4.VME) or protected-mode virtual
20        /// interrupts (CR4.PVI) are activated.
21        const VIRTUAL_INTERRUPT_PENDING = 1 << 20;
22        /// Virtual image of the INTERRUPT_FLAG bit.
23        ///
24        /// Used when virtual-8086 mode extensions (CR4.VME) or protected-mode virtual
25        /// interrupts (CR4.PVI) are activated.
26        const VIRTUAL_INTERRUPT = 1 << 19;
27        /// Enable automatic alignment checking if CR0.AM is set. Only works if CPL is 3.
28        const ALIGNMENT_CHECK = 1 << 18;
29        /// Enable the virtual-8086 mode.
30        const VIRTUAL_8086_MODE = 1 << 17;
31        /// Allows to restart an instruction following an instruction breakpoint.
32        const RESUME_FLAG = 1 << 16;
33        /// Used by `iret` in hardware task switch mode to determine if current task is nested.
34        const NESTED_TASK = 1 << 14;
35        /// The high bit of the I/O Privilege Level field.
36        ///
37        /// Specifies the privilege level required for executing I/O address-space instructions.
38        const IOPL_HIGH = 1 << 13;
39        /// The low bit of the I/O Privilege Level field.
40        ///
41        /// Specifies the privilege level required for executing I/O address-space instructions.
42        const IOPL_LOW = 1 << 12;
43        /// Set by hardware to indicate that the sign bit of the result of the last signed integer
44        /// operation differs from the source operands.
45        const OVERFLOW_FLAG = 1 << 11;
46        /// Determines the order in which strings are processed.
47        const DIRECTION_FLAG = 1 << 10;
48        /// Enable interrupts.
49        const INTERRUPT_FLAG = 1 << 9;
50        /// Enable single-step mode for debugging.
51        const TRAP_FLAG = 1 << 8;
52        /// Set by hardware if last arithmetic operation resulted in a negative value.
53        const SIGN_FLAG = 1 << 7;
54        /// Set by hardware if last arithmetic operation resulted in a zero value.
55        const ZERO_FLAG = 1 << 6;
56        /// Set by hardware if last arithmetic operation generated a carry ouf of bit 3 of the
57        /// result.
58        const AUXILIARY_CARRY_FLAG = 1 << 4;
59        /// Set by hardware if last result has an even number of 1 bits (only for some operations).
60        const PARITY_FLAG = 1 << 2;
61        /// Set by hardware if last arithmetic operation generated a carry out of the
62        /// most-significant bit of the result.
63        const CARRY_FLAG = 1;
64    }
65}
66
67#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
68mod x86_64 {
69    use super::*;
70    use core::arch::asm;
71
72    /// Returns the current value of the RFLAGS register.
73    ///
74    /// Drops any unknown bits.
75    #[inline]
76    pub fn read() -> RFlags {
77        RFlags::from_bits_truncate(read_raw())
78    }
79
80    /// Returns the raw current value of the RFLAGS register.
81    #[inline]
82    pub fn read_raw() -> u64 {
83        let r: u64;
84
85        unsafe {
86            asm!("pushfq; pop {}", out(reg) r, options(nomem, preserves_flags));
87        }
88
89        r
90    }
91
92    /// Writes the RFLAGS register, preserves reserved bits.
93    ///
94    /// ## Safety
95    ///
96    /// Unsafe because undefined becavior can occur if certain flags are modified. For example,
97    /// the `DF` flag must be unset in all Rust code. Also, modifying `CF`, `PF`, or any other
98    /// flags also used by Rust/LLVM can result in undefined behavior too.
99    #[inline]
100    pub unsafe fn write(flags: RFlags) {
101        let old_value = read_raw();
102        let reserved = old_value & !(RFlags::all().bits());
103        let new_value = reserved | flags.bits();
104
105        unsafe {
106            write_raw(new_value);
107        }
108    }
109
110    /// Writes the RFLAGS register.
111    ///
112    /// Does not preserve any bits, including reserved bits.
113    ///
114    ///
115    /// ## Safety
116    ///
117    /// Unsafe because undefined becavior can occur if certain flags are modified. For example,
118    /// the `DF` flag must be unset in all Rust code. Also, modifying `CF`, `PF`, or any other
119    /// flags also used by Rust/LLVM can result in undefined behavior too.
120    #[inline]
121    pub unsafe fn write_raw(val: u64) {
122        // HACK: we mark this function as preserves_flags to prevent Rust from restoring
123        // saved flags after the "popf" below. See above note on safety.
124        unsafe {
125            asm!("push {}; popfq", in(reg) val, options(nomem, preserves_flags));
126        }
127    }
128
129    #[cfg(test)]
130    mod test {
131        use crate::registers::rflags::read;
132
133        #[test]
134        fn rflags_read() {
135            let rflags = read();
136            println!("{:#?}", rflags);
137        }
138    }
139}