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}