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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
use core::{arch::asm, convert::Infallible, fmt, mem};
use mycelium_util::bits;

pub mod entropy;
pub mod intrinsics;
#[cfg(feature = "alloc")]
pub mod local;
pub mod msr;
pub use self::msr::Msr;

#[repr(transparent)]
pub struct Port {
    num: u16,
}

/// Describes which descriptor table ([GDT], [LDT], or [IDT]) a selector references.
///
/// [GDT]: crate::segment::Gdt
/// [LDT]: https://en.wikipedia.org/wiki/Global_Descriptor_Table#Local_Descriptor_Table
/// [IDT]: crate::interrupt::Idt
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum DescriptorTable {
    /// The selector references a descriptor in the [Global Descriptor Table
    /// (GDT)][gdt].
    ///
    /// [gdt]: crate::segment::Gdt
    Gdt,

    /// The selector references an entry in a [Local Descriptor Table
    /// (LDT)][ldt]
    ///
    /// [ldt]: https://en.wikipedia.org/wiki/Global_Descriptor_Table#Local_Descriptor_Table
    Ldt,

    /// The selector references an interrupt handler in the [Interrupt
    /// Descriptor Table(IDT)][idt].
    ///
    /// [idt]: crate::interrupt::Idt
    Idt,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum Ring {
    Ring0 = 0b00,
    Ring1 = 0b01,
    Ring2 = 0b10,
    Ring3 = 0b11,
}

#[repr(C, packed)]
pub(crate) struct DtablePtr {
    limit: u16,
    base: *const (),
}

/// An error indicating that a given CPU feature source is not supported on this
/// CPU.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct FeatureNotSupported(&'static str);

/// Halt the CPU.
///
/// This disables interrupts and performs the `hlt` instruction in a loop,
/// forever.
///
/// # Notes
///
/// This halts the CPU.
#[inline(always)]
pub fn halt() -> ! {
    unsafe {
        // safety: this does exactly what it says on the tin lol
        intrinsics::cli();
        loop {
            intrinsics::hlt();
        }
    }
}

/// Wait for an interrupt in a spin loop.
///
/// This is distinct from `core::hint::spin_loop`, as it is intended
/// specifically for waiting for an interrupt, rather than progress from another
/// thread. This should be called on each iteration of a loop that waits on a condition
/// set by an interrupt handler.
///
/// This function will execute one [`intrinsics::sti`] instruction to enable interrupts
/// followed by one [`intrinsics::hlt`] instruction to halt the CPU.
#[inline(always)]
pub fn wait_for_interrupt() {
    unsafe {
        intrinsics::sti();
        intrinsics::hlt();
    }
}

// === impl Port ===

impl fmt::Debug for Port {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let Self { num } = self;
        f.debug_struct("Port")
            .field("num", &format_args!("{num:#02x}"))
            .finish()
    }
}

impl Port {
    pub const fn at(address: u16) -> Self {
        Port { num: address }
    }

    /// # Safety
    ///
    /// Reading from a CPU port is unsafe.
    pub unsafe fn readb(&self) -> u8 {
        let result: u8;
        asm!("in al, dx", in("dx") self.num, out("al") result);
        result
    }

    /// # Safety
    ///
    /// Writing to a CPU port is unsafe.
    pub unsafe fn writeb(&self, value: u8) {
        asm!("out dx, al", in("dx") self.num, in("al") value)
    }

    /// # Safety
    ///
    /// Reading from a CPU port is unsafe.
    pub unsafe fn readl(&self) -> u32 {
        let result: u32;
        asm!("in eax, dx", in("dx") self.num, out("eax") result);
        result
    }

    /// # Safety
    ///
    /// Writing to a CPU port is unsafe.
    pub unsafe fn writel(&self, value: u32) {
        asm!("out dx, eax", in("dx") self.num, in("eax") value)
    }
}

// === impl DescriptorTable ===

impl fmt::Display for DescriptorTable {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Gdt => f.pad("GDT"),
            Self::Ldt => f.pad("LDT"),
            Self::Idt => f.pad("IDT"),
        }
    }
}

impl bits::FromBits<u16> for DescriptorTable {
    type Error = Infallible;
    const BITS: u32 = 2;
    fn try_from_bits(bits: u16) -> Result<Self, Self::Error> {
        Ok(match bits {
            0b00 => Self::Gdt,
            0b01 => Self::Idt,
            0b10 => Self::Ldt,
            0b11 => Self::Idt,
            _ => unreachable!("only 2 bits should be unpacked!"),
        })
    }

    fn into_bits(self) -> u16 {
        todo!("eliza")
    }
}

// === impl Ring ===

impl Ring {
    pub fn from_u8(u: u8) -> Self {
        match u {
            0b00 => Ring::Ring0,
            0b01 => Ring::Ring1,
            0b10 => Ring::Ring2,
            0b11 => Ring::Ring3,
            bits => panic!("invalid ring {bits:#02b}"),
        }
    }
}

impl bits::FromBits<u64> for Ring {
    const BITS: u32 = 2;
    type Error = core::convert::Infallible;

    fn try_from_bits(u: u64) -> Result<Self, Self::Error> {
        Ok(Self::from_u8(u as u8))
    }

    fn into_bits(self) -> u64 {
        self as u8 as u64
    }
}

impl bits::FromBits<u16> for Ring {
    const BITS: u32 = 2;
    type Error = core::convert::Infallible;

    fn try_from_bits(u: u16) -> Result<Self, Self::Error> {
        Ok(Self::from_u8(u as u8))
    }

    fn into_bits(self) -> u16 {
        self as u8 as u16
    }
}

impl bits::FromBits<u8> for Ring {
    const BITS: u32 = 2;
    type Error = core::convert::Infallible;

    fn try_from_bits(u: u8) -> Result<Self, Self::Error> {
        Ok(Self::from_u8(u))
    }

    fn into_bits(self) -> u8 {
        self as u8
    }
}

// === impl DtablePtr ===

impl DtablePtr {
    pub(crate) fn new<T>(t: &'static T) -> Self {
        unsafe {
            // safety: the `'static` lifetime ensures the pointed dtable is
            // never going away
            Self::new_unchecked(t)
        }
    }

    pub(crate) unsafe fn new_unchecked<T>(t: &T) -> Self {
        let limit = (mem::size_of::<T>() - 1) as u16;
        let base = t as *const _ as *const ();

        Self { limit, base }
    }
}

impl fmt::Debug for DtablePtr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // avoid creating misaligned references by moving these i guess? idk why
        // rustc is okay with this but i'll trust it.
        let Self { limit, base } = *self;
        f.debug_struct("DtablePtr")
            .field("base", &format_args!("{base:0p}",))
            .field("limit", &limit)
            .finish()
    }
}

// === impl FeatureNotSupported ===

impl fmt::Display for FeatureNotSupported {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "this CPU does not support {}", self.0)
    }
}

impl FeatureNotSupported {
    pub fn feature_name(&self) -> &'static str {
        self.0
    }

    pub(crate) fn new(feature_name: &'static str) -> Self {
        Self(feature_name)
    }
}