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