aboutsummaryrefslogtreecommitdiff
path: root/src/shared/flags.rs
blob: 55dad6d0a82364d8e62234d778582b4ebfcf2eb4 (plain) (blame)
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
//! Processor state stored in the FLAGS, EFLAGS, or RFLAGS register.

use shared::PrivilegeLevel;

/// The RFLAGS register. All variants are backwards compatable so only one
/// bitflags struct needed.
bitflags! {
    pub flags Flags: usize {
        /// ID Flag (ID)
        const FLAGS_ID = 1 << 21,
        /// Virtual Interrupt Pending (VIP)
        const FLAGS_VIP = 1 << 20,
        /// Virtual Interrupt Flag (VIF)
        const FLAGS_VIF = 1 << 19,
        /// Alignment Check (AC)
        const FLAGS_AC = 1 << 18,
        /// Virtual-8086 Mode (VM)
        const FLAGS_VM = 1 << 17,
        /// Resume Flag (RF)
        const FLAGS_RF = 1 << 16,
        /// Nested Task (NT)
        const FLAGS_NT = 1 << 14,
        /// I/O Privilege Level (IOPL) 0
        const FLAGS_IOPL0 = 0 << 12,
        /// I/O Privilege Level (IOPL) 1
        const FLAGS_IOPL1 = 1 << 12,
        /// I/O Privilege Level (IOPL) 2
        const FLAGS_IOPL2 = 2 << 12,
        /// I/O Privilege Level (IOPL) 3
        const FLAGS_IOPL3 = 3 << 12,
        /// Overflow Flag (OF)
        const FLAGS_OF = 1 << 11,
        /// Direction Flag (DF)
        const FLAGS_DF = 1 << 10,
        /// Interrupt Enable Flag (IF)
        const FLAGS_IF = 1 << 9,
        /// Trap Flag (TF)
        const FLAGS_TF = 1 << 8,
        /// Sign Flag (SF)
        const FLAGS_SF = 1 << 7,
        /// Zero Flag (ZF)
        const FLAGS_ZF = 1 << 6,
        /// Auxiliary Carry Flag (AF)
        const FLAGS_AF = 1 << 4,
        /// Parity Flag (PF)
        const FLAGS_PF = 1 << 2,
        /// Bit 1 is always 1.
        const FLAGS_A1 = 1 << 1,
        /// Carry Flag (CF)
        const FLAGS_CF = 1 << 0,
    }
}

impl Flags {
    /// Creates a new Flags entry. Ensures bit 1 is set.
    pub const fn new() -> Flags {
        FLAGS_A1
    }

    /// Creates a new Flags with the given I/O privilege level.
    pub const fn from_priv(iopl: PrivilegeLevel) -> Flags {
        Flags { bits: (iopl as usize) << 12 }
    }
}

pub fn flags() -> Flags {

    #[cfg(target_arch="x86")]
    #[inline(always)]
    unsafe fn inner() -> Flags {
        let r: usize;
        asm!("pushfl; popl $0" : "=r"(r) :: "memory");
        Flags::from_bits_truncate(r)
    }

    #[cfg(target_arch="x86_64")]
    #[inline(always)]
    unsafe fn inner() -> Flags {
        let r: usize;
        asm!("pushfq; popq $0" : "=r"(r) :: "memory");
        Flags::from_bits_truncate(r)
    }

    unsafe { inner() }
}

pub fn set(val: Flags) {

    #[cfg(target_arch="x86")]
    #[inline(always)]
    unsafe fn inner(val: Flags) {
        asm!("pushl $0; popfl" :: "r"(val.bits()) : "memory" "flags");
    }

    #[cfg(target_arch="x86_64")]
    #[inline(always)]
    unsafe fn inner(val: Flags) {
        asm!("pushq $0; popfq" :: "r"(val.bits()) : "memory" "flags");
    }

    unsafe { inner(val) }
}