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
//! i386 registers reading

#![allow(unused_macros)]
#![allow(dead_code)]

/// Gets the current $eip.
#[inline(never)]
pub extern fn eip() -> usize {
    let eip;
    unsafe { llvm_asm!("mov $0, [ebp + 4]" : "=r"(eip) ::: "intel"); }
    eip
}

/// Gets the current $ebp.
macro_rules! ebp {
    () => {{
        let ebp;
        unsafe { llvm_asm!("mov $0, ebp" : "=r"(ebp) ::: "intel"); }
        ebp
    }}
}

/// Gets the current $esp.
macro_rules! esp {
    () => {{
        let esp;
        unsafe { llvm_asm!("mov $0, esp" : "=r"(esp) ::: "intel"); }
        esp
    }}
}

pub mod eflags {
    //! Processor state stored in the EFLAGS register.

    bitflags! {
        /// The EFLAGS register.
        pub struct EFlags: u32 {
            /// 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 instrucion 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 << 0;
        }
    }

    /// Returns the current value of the EFLAGS register.
    ///
    /// Drops any unknown bits.
    pub fn read() -> EFlags {
        EFlags::from_bits_truncate(read_raw())
    }

    /// Returns the raw current value of the EFLAGS register.
    pub fn read_raw() -> u32 {
        let r: u32;
        unsafe { llvm_asm!("pushfd; pop $0" : "=r"(r) :: "memory") };
        r
    }

    /// Writes the EFLAGS register, preserves reserved bits.
    pub fn write(flags: EFlags) {
        let old_value = read_raw();
        let reserved = old_value & !(EFlags::all().bits());
        let new_value = reserved | flags.bits();

        write_raw(new_value);
    }

    /// Writes the EFLAGS register.
    ///
    /// Does not preserve any bits, including reserved bits.
    pub fn write_raw(val: u32) {
        unsafe { llvm_asm!("pushd $0; popfd" :: "r"(val) : "memory" "flags") };
    }
}