x86/registers/bits32/
eflags.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2025.
4
5// This is inspired and adapted for Tock from the [x86](https://github.com/gz/rust-x86) crate.
6
7use kernel::utilities::registers::register_bitfields;
8use tock_registers::LocalRegisterCopy;
9
10#[cfg(target_arch = "x86")]
11use core::arch::asm;
12
13register_bitfields![u32,
14    pub EFLAGS[
15        /// Carry Flag (CF)
16        FLAGS_CF OFFSET(0) NUMBITS(1),
17        /// Bit 1 is always 1.
18        FLAGS_A1 OFFSET(1) NUMBITS(1),
19        /// Parity Flag (PF)
20        FLAGS_PF OFFSET(2) NUMBITS(2),
21        /// Auxiliary Carry Flag (AF)
22        FLAGS_AF OFFSET(4) NUMBITS(2),
23        /// Zero Flag (ZF)
24        FLAGS_ZF OFFSET(6) NUMBITS(1),
25        /// Sign Flag (SF
26        FLAGS_SF OFFSET(7) NUMBITS(1),
27        /// Trap Flag (TF)
28        FLAGS_TF OFFSET(8) NUMBITS(1),
29        /// Interrupt Enable Flag (IF)
30        FLAGS_IF OFFSET(9) NUMBITS(1),
31        /// Direction Flag (DF)
32        FLAGS_DF OFFSET(10) NUMBITS(1),
33        /// Overflow Flag (OF)
34        FLAGS_OF OFFSET(11) NUMBITS(1),
35        /// I/O Privilege Level (IOPL) 3
36        FLAGS_IOPL OFFSET(12) NUMBITS(2),
37        /// Nested Task (NT)
38        FLAGS_NT OFFSET(14) NUMBITS(2),
39        /// Resume Flag (RF)
40        FLAGS_RF OFFSET(16) NUMBITS(1),
41        /// Virtual-8086 Mode (VM)
42        FLAGS_VM OFFSET(17) NUMBITS(1),
43        /// Alignment Check (AC)
44        FLAGS_AC OFFSET(18) NUMBITS(1),
45        /// Virtual Interrupt Flag (VIF)
46        FLAGS_VIF OFFSET(19) NUMBITS(1),
47        /// Virtual Interrupt Pending (VIP)
48        FLAGS_VIP OFFSET(20) NUMBITS(1),
49        /// ID Flag (ID)
50        FLAGS_ID OFFSET(21) NUMBITS(11),
51    ],
52];
53
54#[repr(transparent)]
55#[derive(Copy, Clone, Debug)]
56pub struct EFlags(pub LocalRegisterCopy<u32, EFLAGS::Register>);
57
58impl Default for EFlags {
59    fn default() -> Self {
60        Self::new()
61    }
62}
63
64impl EFlags {
65    /// Create a new SegmentSelector
66    /// # Arguments
67    ///  * `index` - index in GDT or LDT array.
68    ///  * `rpl` - Requested privilege level of the selector
69    pub fn new() -> EFlags {
70        let mut flags = LocalRegisterCopy::new(0);
71        flags.write(EFLAGS::FLAGS_A1::SET);
72        EFlags(flags)
73    }
74}
75
76#[cfg(target_arch = "x86")]
77#[inline(always)]
78pub unsafe fn read() -> EFlags {
79    let r: u32;
80    unsafe {
81        asm!("pushfl; popl {0}", out(reg) r, options(att_syntax));
82    }
83    EFlags(LocalRegisterCopy::new(r))
84}
85
86#[cfg(target_arch = "x86")]
87#[inline(always)]
88pub unsafe fn set(val: EFlags) {
89    unsafe {
90        asm!("pushl {0}; popfl", in(reg) val.0.get(), options(att_syntax));
91    }
92}
93
94//For CI only
95
96#[cfg(not(any(doc, target_arch = "x86")))]
97pub unsafe fn read() -> EFlags {
98    unimplemented!()
99}
100
101#[cfg(not(any(doc, target_arch = "x86")))]
102pub unsafe fn set(_val: EFlags) {
103    unimplemented!()
104}