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}