hal_x86_64/cpu/
msr.rs

1//! x86_64 [Model-Specific Register][msr] (MSR)s.
2//!
3//! Model-specific registers are used to configure features of the CPU that may
4//! not be available on all x86 processors, such as memory type-range,
5//! sysenter/sysexit, local APIC, et cetera.
6//!
7//! This module contains the [`Msr`] type for accessing model-specific
8//! registers. In addition, since most MSRs contain bitflags, this module also
9//! contains bitflags types defining the flags that can be set in a particular
10//! MSR.
11//!
12//! See the documentation for the [`Msr`] type for details on using MSRs.
13//!
14//! [msr]: https://wiki.osdev.org/MSR
15#![warn(missing_docs)]
16use core::{arch::asm, marker::PhantomData};
17use mycelium_util::{
18    bits::{bitfield, FromBits},
19    fmt,
20};
21use raw_cpuid::CpuId;
22
23/// An x86_64 [Model-Specific Register][msr] (MSR).
24///
25/// Model-specific registers are used to configure features of the CPU that may
26/// not be available on all x86 processors, such as memory type-range,
27/// sysenter/sysexit, local APIC, et cetera. MSRs are available on P6 and later
28/// x86 processors (and are present on all 64-bit x86 CPUs). The
29/// [`Msr::has_msrs`] method can be used to check if the CPU has MSRs. Note
30/// that this method does *not* check whether a particular MSR is available.
31///
32/// See [sandpile.org's MSR list][sandpile] for a list of documented MSRs and
33/// their values.
34///
35/// # Typed MSRs
36///
37/// MSRs may be accessed as raw `u64` values (using [`Msr::read_raw`] and
38/// [`Msr::write_raw`]), or may be constructed with a type parameter
39/// implementing the [`mycelium_util::bits::FromBits`] trait, which is
40/// automatically converted to and from its binary representation when
41/// reading/writing to the MSR.
42///
43/// When a typed representation of a MSR's value is available, a special
44/// constructor is provided for accessing that MSR in a typed manner.
45///
46/// # MSR Constructors
47///
48/// This type provides a number of constructors which construct a [`Msr`] for
49/// accessing a specific model-specific register by name. The following
50/// constructors are currently provided:
51///
52/// - [`Msr::ia32_apic_base`] for accessing the [`IA32_APIC_BASE`] MSR, which
53///   stores the base address of the local APIC's memory-mapped configuration
54///   area.
55///
56/// - [`Msr::ia32_gs_base`] for accessing the [`IA32_GS_BASE`] MSR, which stores
57///   the base address of the `GS` segment.
58///
59/// - [`Msr::ia32_efer`] for accessing the [Extended Flags Enable Register
60///   (EFER)][efer], which contains flags for enabling long mode and controlling
61///   long-mode-specific features.
62///
63///   Flags for the `IA32_EFER` MSR are represented by the [`Efer`] type.
64///
65/// [sandpile]: https://sandpile.org/x86/msr.htm
66/// [msr]: https://wiki.osdev.org/MSR
67/// [efer]: https://wiki.osdev.org/CPU_Registers_x86-64#IA32_EFER
68/// [`IA32_APIC_BASE`]: https://wiki.osdev.org/APIC#Local_APIC_configuration
69/// [`IA32_GS_BASE`]: https://wiki.osdev.org/CPU_Registers_x86-64#FS.base.2C_GS.base
70pub struct Msr<V = u64> {
71    pub(crate) num: u32,
72    name: Option<&'static str>,
73    _ty: PhantomData<fn(V)>,
74}
75
76bitfield! {
77    /// Bit flags for the [Extended Feature Enable Register (EFER)][efer] [`Msr`].
78    ///
79    /// This MSR was added by AMD in the K6 processor, and became part of the
80    /// architecture in AMD64. It controls features related to entering long mode.
81    ///
82    /// To access the EFER, use the [`Msr::ia32_efer`] constructor.
83    ///
84    /// [efer]: https://wiki.osdev.org/CPU_Registers_x86-64#IA32_EFER
85    pub struct Efer<u64> {
86        /// System Call Extensions (SCE).
87        ///
88        /// This enables the `SYSCALL` and `SYSRET` instructions.
89        pub const SYSTEM_CALL_EXTENSIONS: bool;
90        const _RESERVED_0 = 7;
91        /// Long Mode Enable (LME).
92        ///
93        /// Setting this bit enables long mode.
94        pub const LONG_MODE_ENABLE: bool;
95        const _RESERVED_1 = 1;
96        /// Long Mode Active (LMA).
97        ///
98        /// This bit is set if the processor is in long mode.
99        pub const LONG_MODE_ACTIVE: bool;
100        /// No-Execute Enable (NXE).
101        pub const NO_EXECUTE_ENABLE: bool;
102        /// Secure Virtual Machine Enable (SVME).
103        pub const SECURE_VM_ENABLE: bool;
104        /// Long Mode Segment Limit Enable (LMSLE).
105        pub const LONG_MODE_SEGMENT_LIMIT_ENABLE: bool;
106        /// Fast `FXSAVE`/`FXRSTOR` (FFXSR).
107        pub const FAST_FXSAVE_FXRSTOR: bool;
108        /// Translation Cache Extension (TCE).
109        pub const TRANSLATION_CACHE_EXTENSION: bool;
110    }
111}
112
113impl Msr {
114    /// Returns `true` if this processor has MSRs.
115    ///
116    /// # Notes
117    ///
118    /// This does *not* check whether the given MSR number is valid on this platform.
119    #[must_use]
120    pub fn has_msrs() -> bool {
121        CpuId::new()
122            .get_feature_info()
123            .map(|features| features.has_msr())
124            .unwrap_or(false)
125    }
126
127    /// Returns a new `Msr` for reading/writing to the given MSR number, or
128    /// `None` if this CPU does not support MSRs.
129    ///
130    /// # Notes
131    ///
132    /// This does *not* check whether the given MSR number is valid on this platform.
133    #[inline]
134    #[must_use]
135    pub fn try_new(num: u32) -> Option<Self> {
136        if Self::has_msrs() {
137            Some(Msr {
138                num,
139                name: None,
140                _ty: PhantomData,
141            })
142        } else {
143            None
144        }
145    }
146
147    /// Returns a new `Msr` for reading/writing to the given MSR number.
148    ///
149    /// # Panics
150    ///
151    /// If this CPU does not support MSRs.
152    ///
153    /// # Notes
154    ///
155    /// This does *not* check whether the given MSR number is valid on this platform.
156    pub fn new(num: u32) -> Self {
157        Self::try_new(num)
158            .expect("CPU does not support model-specific registers (must be pre-Pentium...)")
159    }
160
161    /// Returns a `Msr` for reading and writing to the [`IA32_APIC_BASE`]
162    /// model-specific register.
163    ///
164    /// This register has MSR number 0x1B, and stores the base address of the
165    /// [local APIC] memory-mapped configuration area.
166    ///
167    /// [`IA32_APIC_BASE`]: https://wiki.osdev.org/APIC#Local_APIC_configuration
168    /// [local APIC]: crate::interrupt::apic::LocalApic
169    #[must_use]
170    pub const fn ia32_apic_base() -> Self {
171        Self {
172            name: Some("IA32_APIC_BASE"),
173            num: 0x1b,
174            _ty: PhantomData,
175        }
176    }
177
178    /// Returns a `Msr` for reading and writing to the [`IA32_GS_BASE`]
179    /// model-specific register.
180    ///
181    /// This register has MSR number 0xC0000101, and contains the base address
182    /// of the `GS` segment.
183    ///
184    /// [`IA32_GS_BASE`]: https://wiki.osdev.org/CPU_Registers_x86-64#FS.base.2C_GS.base
185    #[must_use]
186    pub const fn ia32_gs_base() -> Self {
187        Self {
188            name: Some("IA32_GS_BASE"),
189            num: 0xc000_0101,
190            _ty: PhantomData,
191        }
192    }
193
194    /// Returns a `Msr` for reading and writing to the [`IA32_EFER` (Extended
195    /// Flags Enable Register)][efer] MSR.
196    ///
197    /// The EFER register has MSR number 0xC0000080, and contains flags for
198    /// enabling the `SYSCALL` and `SYSRET` instructions, and for entering and
199    /// exiting long mode, and for enabling features related to long mode.
200    ///
201    /// Flags for the `IA32_EFER` MSR are represented by the [`Efer`]
202    /// type.
203    ///
204    /// [efer]: https://wiki.osdev.org/CPU_Registers_x86-64#IA32_EFER
205    #[must_use]
206    pub const fn ia32_efer() -> Msr<Efer> {
207        Msr {
208            name: Some("IA32_EFER"),
209            num: 0xc0000080,
210            _ty: PhantomData,
211        }
212    }
213}
214
215impl<V: FromBits<u64>> Msr<V> {
216    /// Attempt to read a `V`-typed value from the MSR, returning an error if
217    /// that value is an invalid bit pattern for a `V`-typed value.
218    ///
219    /// # Returns
220    ///
221    /// - [`Ok`]`(V`)` if a `V`-typed value was successfully read from the MSR.
222    /// - [`Err`]`(V::Error)` if the value read from the MSR was an invalid bit
223    ///   pattern for a `V`, as determined by `V`'s implementation of the
224    ///   [`FromBits::try_from_bits`]) method.
225    pub fn try_read(self) -> Result<V, V::Error> {
226        V::try_from_bits(self.read_raw())
227    }
228
229    /// Read a `V`-typed value from the MSR.
230    ///
231    /// # Panics
232    ///
233    /// If the bits in the MSR are an invalid bit pattern for a `V`-typed value
234    /// (as determined by `V`'s implementation of the
235    /// [`FromBits::try_from_bits`]) method).
236    #[must_use]
237    pub fn read(self) -> V {
238        match self.try_read() {
239            Ok(value) => value,
240            Err(error) => panic!("invalid value for {self}: {error}"),
241        }
242    }
243
244    /// Write a value to this MSR.
245    ///
246    /// # Safety
247    ///
248    /// The caller is responsible for ensuring that writing the provided value
249    /// to this MSR doesn't violate memory safety.
250    pub unsafe fn write(self, value: V) {
251        self.write_raw(value.into_bits());
252    }
253
254    /// Read this MSR's current value, modify it using a closure, and write back
255    /// the modified value.
256    ///
257    /// This is a convenience method for cases where some bits in a MSR should
258    /// be changed while leaving other values in place.
259    ///
260    /// # Safety
261    ///
262    /// The caller is responsible for ensuring that writing the provided value
263    /// to this MSR doesn't violate memory safety.
264    pub unsafe fn update(self, f: impl FnOnce(V) -> V) {
265        self.write(f(self.read()));
266    }
267}
268
269impl<V> Msr<V> {
270    /// Reads this MSR, returning the raw `u64` value.
271    #[inline]
272    #[must_use]
273    pub fn read_raw(self) -> u64 {
274        let (hi, lo): (u32, u32);
275        unsafe {
276            asm!(
277                "rdmsr",
278                in("ecx") self.num,
279                out("eax") lo,
280                out("edx") hi,
281                options(nomem, nostack, preserves_flags)
282            );
283        }
284        ((hi as u64) << 32) | (lo as u64)
285    }
286
287    /// Writes the given raw `u64` value to this MSR.
288    ///
289    /// # Safety
290    ///
291    /// The caller is responsible for ensuring that writing the provided value
292    /// to this MSR doesn't violate memory safety.
293    pub unsafe fn write_raw(self, value: u64) {
294        tracing::trace!(wrmsr = %self, value = fmt::hex(value));
295        let lo = value as u32;
296        let hi = (value >> 32) as u32;
297        asm!(
298            "wrmsr",
299            in("ecx") self.num,
300            in("eax") lo,
301            in("edx") hi,
302            options(nostack, preserves_flags)
303        );
304    }
305}
306
307impl<V> Clone for Msr<V> {
308    #[inline]
309    fn clone(&self) -> Self {
310        *self
311    }
312}
313
314impl<V> Copy for Msr<V> {}
315
316impl<V> PartialEq for Msr<V> {
317    #[inline]
318    fn eq(&self, other: &Self) -> bool {
319        self.num == other.num
320    }
321}
322
323impl<V> Eq for Msr<V> {}
324
325impl<V> fmt::Debug for Msr<V> {
326    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
327        let Self { num, name, .. } = self;
328        match name {
329            Some(name) => write!(f, "Msr({num:#x}, {name})"),
330            None => write!(f, "Msr({num:#x})"),
331        }
332    }
333}
334
335impl<V> fmt::Display for Msr<V> {
336    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
337        let Self { num, name, .. } = self;
338        match name {
339            Some(name) => write!(f, "MSR {num:#x} ({name})"),
340            None => write!(f, "MSR {num:#x})"),
341        }
342    }
343}
344
345#[cfg(test)]
346mod tests {
347    use super::*;
348
349    #[test]
350    fn efer_valid() {
351        Efer::assert_valid();
352        println!("{}", Efer::new())
353    }
354
355    #[test]
356    fn efer_bitoffsets() {
357        assert_eq!(
358            Efer::LONG_MODE_ENABLE.least_significant_index(),
359            8,
360            "LONG_MODE_ENABLE LSB",
361        );
362        assert_eq!(
363            Efer::TRANSLATION_CACHE_EXTENSION.least_significant_index(),
364            15,
365            "TCE LSB"
366        );
367    }
368}