x86_64/registers/
model_specific.rs

1//! Functions to read and write model specific registers.
2
3use bitflags::bitflags;
4// imports for intra doc links
5#[cfg(doc)]
6use crate::registers::segmentation::{FS, GS};
7
8/// A model specific register.
9#[cfg_attr(
10    not(all(feature = "instructions", target_arch = "x86_64")),
11    allow(dead_code)
12)] // FIXME
13#[derive(Debug)]
14pub struct Msr(u32);
15
16impl Msr {
17    /// Create an instance from a register.
18    #[inline]
19    pub const fn new(reg: u32) -> Msr {
20        Msr(reg)
21    }
22}
23
24/// The Extended Feature Enable Register.
25#[derive(Debug)]
26pub struct Efer;
27
28/// [FS].Base Model Specific Register.
29#[derive(Debug)]
30pub struct FsBase;
31
32/// [GS].Base Model Specific Register.
33///
34#[cfg_attr(
35    all(feature = "instructions", target_arch = "x86_64"),
36    doc = "[`GS::swap`] swaps this register with [`KernelGsBase`]."
37)]
38#[derive(Debug)]
39pub struct GsBase;
40
41/// KernelGsBase Model Specific Register.
42///
43#[cfg_attr(
44    all(feature = "instructions", target_arch = "x86_64"),
45    doc = "[`GS::swap`] swaps this register with [`GsBase`]."
46)]
47#[derive(Debug)]
48pub struct KernelGsBase;
49
50/// Syscall Register: STAR
51#[derive(Debug)]
52pub struct Star;
53
54/// Syscall Register: LSTAR
55#[derive(Debug)]
56pub struct LStar;
57
58/// Syscall Register: SFMASK
59#[derive(Debug)]
60pub struct SFMask;
61
62/// IA32_U_CET: user mode CET configuration
63#[derive(Debug)]
64pub struct UCet;
65
66/// IA32_S_CET: supervisor mode CET configuration
67#[derive(Debug)]
68pub struct SCet;
69
70impl Efer {
71    /// The underlying model specific register.
72    pub const MSR: Msr = Msr(0xC000_0080);
73}
74
75impl FsBase {
76    /// The underlying model specific register.
77    pub const MSR: Msr = Msr(0xC000_0100);
78}
79
80impl GsBase {
81    /// The underlying model specific register.
82    pub const MSR: Msr = Msr(0xC000_0101);
83}
84
85impl KernelGsBase {
86    /// The underlying model specific register.
87    pub const MSR: Msr = Msr(0xC000_0102);
88}
89
90impl Star {
91    /// The underlying model specific register.
92    pub const MSR: Msr = Msr(0xC000_0081);
93}
94
95impl LStar {
96    /// The underlying model specific register.
97    pub const MSR: Msr = Msr(0xC000_0082);
98}
99
100impl SFMask {
101    /// The underlying model specific register.
102    pub const MSR: Msr = Msr(0xC000_0084);
103}
104
105impl UCet {
106    /// The underlying model specific register.
107    pub const MSR: Msr = Msr(0x6A0);
108}
109
110impl SCet {
111    /// The underlying model specific register.
112    pub const MSR: Msr = Msr(0x6A2);
113}
114
115bitflags! {
116    /// Flags of the Extended Feature Enable Register.
117    #[repr(transparent)]
118    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
119    pub struct EferFlags: u64 {
120        /// Enables the `syscall` and `sysret` instructions.
121        const SYSTEM_CALL_EXTENSIONS = 1;
122        /// Activates long mode, requires activating paging.
123        const LONG_MODE_ENABLE = 1 << 8;
124        /// Indicates that long mode is active.
125        const LONG_MODE_ACTIVE = 1 << 10;
126        /// Enables the no-execute page-protection feature.
127        const NO_EXECUTE_ENABLE = 1 << 11;
128        /// Enables SVM extensions.
129        const SECURE_VIRTUAL_MACHINE_ENABLE = 1 << 12;
130        /// Enable certain limit checks in 64-bit mode.
131        const LONG_MODE_SEGMENT_LIMIT_ENABLE = 1 << 13;
132        /// Enable the `fxsave` and `fxrstor` instructions to execute faster in 64-bit mode.
133        const FAST_FXSAVE_FXRSTOR = 1 << 14;
134        /// Changes how the `invlpg` instruction operates on TLB entries of upper-level entries.
135        const TRANSLATION_CACHE_EXTENSION = 1 << 15;
136    }
137}
138
139bitflags! {
140    /// Flags stored in IA32_U_CET and IA32_S_CET (Table-2-2 in Intel SDM Volume
141    /// 4). The Intel SDM-equivalent names are described in parentheses.
142    #[repr(transparent)]
143    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
144    pub struct CetFlags: u64 {
145        /// Enable shadow stack (SH_STK_EN)
146        const SS_ENABLE = 1 << 0;
147        /// Enable WRSS{D,Q}W instructions (WR_SHTK_EN)
148        const SS_WRITE_ENABLE = 1 << 1;
149        /// Enable indirect branch tracking (ENDBR_EN)
150        const IBT_ENABLE = 1 << 2;
151        /// Enable legacy treatment for indirect branch tracking (LEG_IW_EN)
152        const IBT_LEGACY_ENABLE = 1 << 3;
153        /// Enable no-track opcode prefix for indirect branch tracking (NO_TRACK_EN)
154        const IBT_NO_TRACK_ENABLE = 1 << 4;
155        /// Disable suppression of CET on legacy compatibility (SUPPRESS_DIS)
156        const IBT_LEGACY_SUPPRESS_ENABLE = 1 << 5;
157        /// Enable suppression of indirect branch tracking (SUPPRESS)
158        const IBT_SUPPRESS_ENABLE = 1 << 10;
159        /// Is IBT waiting for a branch to return? (read-only, TRACKER)
160        const IBT_TRACKED = 1 << 11;
161    }
162}
163
164#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
165mod x86_64 {
166    use super::*;
167    use crate::addr::VirtAddr;
168    use crate::registers::rflags::RFlags;
169    use crate::structures::gdt::SegmentSelector;
170    use crate::structures::paging::Page;
171    use crate::structures::paging::Size4KiB;
172    use crate::PrivilegeLevel;
173    use bit_field::BitField;
174    use core::convert::TryInto;
175    use core::fmt;
176    // imports for intra doc links
177    #[cfg(doc)]
178    use crate::registers::{
179        control::Cr4Flags,
180        segmentation::{Segment, Segment64, CS, SS},
181    };
182    use core::arch::asm;
183
184    impl Msr {
185        /// Read 64 bits msr register.
186        ///
187        /// ## Safety
188        ///
189        /// The caller must ensure that this read operation has no unsafe side
190        /// effects.
191        #[inline]
192        pub unsafe fn read(&self) -> u64 {
193            let (high, low): (u32, u32);
194            unsafe {
195                asm!(
196                    "rdmsr",
197                    in("ecx") self.0,
198                    out("eax") low, out("edx") high,
199                    options(nomem, nostack, preserves_flags),
200                );
201            }
202            ((high as u64) << 32) | (low as u64)
203        }
204
205        /// Write 64 bits to msr register.
206        ///
207        /// ## Safety
208        ///
209        /// The caller must ensure that this write operation has no unsafe side
210        /// effects.
211        #[inline]
212        pub unsafe fn write(&mut self, value: u64) {
213            let low = value as u32;
214            let high = (value >> 32) as u32;
215
216            unsafe {
217                asm!(
218                    "wrmsr",
219                    in("ecx") self.0,
220                    in("eax") low, in("edx") high,
221                    options(nostack, preserves_flags),
222                );
223            }
224        }
225    }
226
227    impl Efer {
228        /// Read the current EFER flags.
229        #[inline]
230        pub fn read() -> EferFlags {
231            EferFlags::from_bits_truncate(Self::read_raw())
232        }
233
234        /// Read the current raw EFER flags.
235        #[inline]
236        pub fn read_raw() -> u64 {
237            unsafe { Self::MSR.read() }
238        }
239
240        /// Write the EFER flags, preserving reserved values.
241        ///
242        /// Preserves the value of reserved fields.
243        ///
244        /// ## Safety
245        ///
246        /// Unsafe because it's possible to break memory
247        /// safety with wrong flags, e.g. by disabling long mode.
248        #[inline]
249        pub unsafe fn write(flags: EferFlags) {
250            let old_value = Self::read_raw();
251            let reserved = old_value & !(EferFlags::all().bits());
252            let new_value = reserved | flags.bits();
253
254            unsafe {
255                Self::write_raw(new_value);
256            }
257        }
258
259        /// Write the EFER flags.
260        ///
261        /// Does not preserve any bits, including reserved fields.
262        ///
263        /// ## Safety
264        ///
265        /// Unsafe because it's possible to
266        /// break memory safety with wrong flags, e.g. by disabling long mode.
267        #[inline]
268        pub unsafe fn write_raw(flags: u64) {
269            let mut msr = Self::MSR;
270            unsafe {
271                msr.write(flags);
272            }
273        }
274
275        /// Update EFER flags.
276        ///
277        /// Preserves the value of reserved fields.
278        ///
279        /// ## Safety
280        ///
281        /// Unsafe because it's possible to break memory
282        /// safety with wrong flags, e.g. by disabling long mode.
283        #[inline]
284        pub unsafe fn update<F>(f: F)
285        where
286            F: FnOnce(&mut EferFlags),
287        {
288            let mut flags = Self::read();
289            f(&mut flags);
290            unsafe {
291                Self::write(flags);
292            }
293        }
294    }
295
296    impl FsBase {
297        /// Read the current FsBase register.
298        ///
299        /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is set, the more efficient
300        /// [`FS::read_base`] can be used instead.
301        #[inline]
302        pub fn read() -> VirtAddr {
303            VirtAddr::new(unsafe { Self::MSR.read() })
304        }
305
306        /// Write a given virtual address to the FS.Base register.
307        ///
308        /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is set, the more efficient
309        /// [`FS::write_base`] can be used instead.
310        #[inline]
311        pub fn write(address: VirtAddr) {
312            let mut msr = Self::MSR;
313            unsafe { msr.write(address.as_u64()) };
314        }
315    }
316
317    impl GsBase {
318        /// Read the current GsBase register.
319        ///
320        /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is set, the more efficient
321        /// [`GS::read_base`] can be used instead.
322        #[inline]
323        pub fn read() -> VirtAddr {
324            VirtAddr::new(unsafe { Self::MSR.read() })
325        }
326
327        /// Write a given virtual address to the GS.Base register.
328        ///
329        /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is set, the more efficient
330        /// [`GS::write_base`] can be used instead.
331        #[inline]
332        pub fn write(address: VirtAddr) {
333            let mut msr = Self::MSR;
334            unsafe { msr.write(address.as_u64()) };
335        }
336    }
337
338    impl KernelGsBase {
339        /// Read the current KernelGsBase register.
340        #[inline]
341        pub fn read() -> VirtAddr {
342            VirtAddr::new(unsafe { Self::MSR.read() })
343        }
344
345        /// Write a given virtual address to the KernelGsBase register.
346        #[inline]
347        pub fn write(address: VirtAddr) {
348            let mut msr = Self::MSR;
349            unsafe { msr.write(address.as_u64()) };
350        }
351    }
352
353    impl Star {
354        /// Read the Ring 0 and Ring 3 segment bases.
355        /// The remaining fields are ignored because they are
356        /// not valid for long mode.
357        ///
358        /// # Returns
359        /// - Field 1 (SYSRET): The CS selector is set to this field + 16. SS.Sel is set to
360        ///   this field + 8. Because SYSRET always returns to CPL 3, the
361        ///   RPL bits 1:0 should be initialized to 11b.
362        /// - Field 2 (SYSCALL): This field is copied directly into CS.Sel. SS.Sel is set to
363        ///   this field + 8. Because SYSCALL always switches to CPL 0, the RPL bits
364        ///   33:32 should be initialized to 00b.
365        #[inline]
366        pub fn read_raw() -> (u16, u16) {
367            let msr_value = unsafe { Self::MSR.read() };
368            let sysret = msr_value.get_bits(48..64);
369            let syscall = msr_value.get_bits(32..48);
370            (sysret.try_into().unwrap(), syscall.try_into().unwrap())
371        }
372
373        /// Read the Ring 0 and Ring 3 segment bases.
374        /// Returns
375        /// - CS Selector SYSRET
376        /// - SS Selector SYSRET
377        /// - CS Selector SYSCALL
378        /// - SS Selector SYSCALL
379        #[inline]
380        pub fn read() -> (
381            SegmentSelector,
382            SegmentSelector,
383            SegmentSelector,
384            SegmentSelector,
385        ) {
386            let raw = Self::read_raw();
387            (
388                SegmentSelector(raw.0 + 16),
389                SegmentSelector(raw.0 + 8),
390                SegmentSelector(raw.1),
391                SegmentSelector(raw.1 + 8),
392            )
393        }
394
395        /// Write the Ring 0 and Ring 3 segment bases.
396        /// The remaining fields are ignored because they are
397        /// not valid for long mode.
398        ///
399        /// # Parameters
400        /// - sysret: The CS selector is set to this field + 16. SS.Sel is set to
401        ///   this field + 8. Because SYSRET always returns to CPL 3, the
402        ///   RPL bits 1:0 should be initialized to 11b.
403        /// - syscall: This field is copied directly into CS.Sel. SS.Sel is set to
404        ///   this field + 8. Because SYSCALL always switches to CPL 0, the RPL bits
405        ///   33:32 should be initialized to 00b.
406        ///
407        /// # Safety
408        ///
409        /// Unsafe because this can cause system instability if passed in the
410        /// wrong values for the fields.
411        #[inline]
412        pub unsafe fn write_raw(sysret: u16, syscall: u16) {
413            let mut msr_value = 0u64;
414            msr_value.set_bits(48..64, sysret.into());
415            msr_value.set_bits(32..48, syscall.into());
416            let mut msr = Self::MSR;
417            unsafe {
418                msr.write(msr_value);
419            }
420        }
421
422        /// Write the Ring 0 and Ring 3 segment bases.
423        /// The remaining fields are ignored because they are
424        /// not valid for long mode.
425        /// This function will fail if the segment selectors are
426        /// not in the correct offset of each other or if the
427        /// segment selectors do not have correct privileges.
428        #[inline]
429        pub fn write(
430            cs_sysret: SegmentSelector,
431            ss_sysret: SegmentSelector,
432            cs_syscall: SegmentSelector,
433            ss_syscall: SegmentSelector,
434        ) -> Result<(), InvalidStarSegmentSelectors> {
435            // Convert to i32 to prevent underflows.
436            let cs_sysret_cmp = i32::from(cs_sysret.0) - 16;
437            let ss_sysret_cmp = i32::from(ss_sysret.0) - 8;
438            let cs_syscall_cmp = i32::from(cs_syscall.0);
439            let ss_syscall_cmp = i32::from(ss_syscall.0) - 8;
440
441            if cs_sysret_cmp != ss_sysret_cmp {
442                return Err(InvalidStarSegmentSelectors::SysretOffset);
443            }
444
445            if cs_syscall_cmp != ss_syscall_cmp {
446                return Err(InvalidStarSegmentSelectors::SyscallOffset);
447            }
448
449            if ss_sysret.rpl() != PrivilegeLevel::Ring3 {
450                return Err(InvalidStarSegmentSelectors::SysretPrivilegeLevel);
451            }
452
453            if ss_syscall.rpl() != PrivilegeLevel::Ring0 {
454                return Err(InvalidStarSegmentSelectors::SyscallPrivilegeLevel);
455            }
456
457            unsafe { Self::write_raw(ss_sysret.0 - 8, cs_syscall.0) };
458
459            Ok(())
460        }
461    }
462
463    #[derive(Debug)]
464    pub enum InvalidStarSegmentSelectors {
465        SysretOffset,
466        SyscallOffset,
467        SysretPrivilegeLevel,
468        SyscallPrivilegeLevel,
469    }
470
471    impl fmt::Display for InvalidStarSegmentSelectors {
472        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
473            match self {
474                Self::SysretOffset => write!(f, "Sysret CS and SS are not offset by 8."),
475                Self::SyscallOffset => write!(f, "Syscall CS and SS are not offset by 8."),
476                Self::SysretPrivilegeLevel => {
477                    write!(f, "Sysret's segment must be a Ring3 segment.")
478                }
479                Self::SyscallPrivilegeLevel => {
480                    write!(f, "Syscall's segment must be a Ring0 segment.")
481                }
482            }
483        }
484    }
485
486    impl LStar {
487        /// Read the current LStar register.
488        /// This holds the target RIP of a syscall.
489        #[inline]
490        pub fn read() -> VirtAddr {
491            VirtAddr::new(unsafe { Self::MSR.read() })
492        }
493
494        /// Write a given virtual address to the LStar register.
495        /// This holds the target RIP of a syscall.
496        #[inline]
497        pub fn write(address: VirtAddr) {
498            let mut msr = Self::MSR;
499            unsafe { msr.write(address.as_u64()) };
500        }
501    }
502
503    impl SFMask {
504        /// Read to the SFMask register.
505        /// The SFMASK register is used to specify which RFLAGS bits
506        /// are cleared during a SYSCALL. In long mode, SFMASK is used
507        /// to specify which RFLAGS bits are cleared when SYSCALL is
508        /// executed. If a bit in SFMASK is set to 1, the corresponding
509        /// bit in RFLAGS is cleared to 0. If a bit in SFMASK is cleared
510        /// to 0, the corresponding rFLAGS bit is not modified.
511        #[inline]
512        pub fn read() -> RFlags {
513            RFlags::from_bits(unsafe { Self::MSR.read() }).unwrap()
514        }
515
516        /// Write to the SFMask register.
517        /// The SFMASK register is used to specify which RFLAGS bits
518        /// are cleared during a SYSCALL. In long mode, SFMASK is used
519        /// to specify which RFLAGS bits are cleared when SYSCALL is
520        /// executed. If a bit in SFMASK is set to 1, the corresponding
521        /// bit in RFLAGS is cleared to 0. If a bit in SFMASK is cleared
522        /// to 0, the corresponding rFLAGS bit is not modified.
523        #[inline]
524        pub fn write(value: RFlags) {
525            let mut msr = Self::MSR;
526            unsafe { msr.write(value.bits()) };
527        }
528    }
529
530    impl UCet {
531        /// Read the raw IA32_U_CET.
532        #[inline]
533        fn read_raw() -> u64 {
534            unsafe { Self::MSR.read() }
535        }
536
537        /// Write the raw IA32_U_CET.
538        #[inline]
539        fn write_raw(value: u64) {
540            let mut msr = Self::MSR;
541            unsafe {
542                msr.write(value);
543            }
544        }
545
546        /// Read IA32_U_CET. Returns a tuple of the flags and the address to the legacy code page bitmap.
547        #[inline]
548        pub fn read() -> (CetFlags, Page) {
549            let value = Self::read_raw();
550            let cet_flags = CetFlags::from_bits_truncate(value);
551            let legacy_bitmap =
552                Page::from_start_address(VirtAddr::new(value & !(Page::<Size4KiB>::SIZE - 1)))
553                    .unwrap();
554
555            (cet_flags, legacy_bitmap)
556        }
557
558        /// Write IA32_U_CET.
559        #[inline]
560        pub fn write(flags: CetFlags, legacy_bitmap: Page) {
561            Self::write_raw(flags.bits() | legacy_bitmap.start_address().as_u64());
562        }
563    }
564
565    impl SCet {
566        /// Read the raw IA32_S_CET.
567        #[inline]
568        fn read_raw() -> u64 {
569            unsafe { Self::MSR.read() }
570        }
571
572        /// Write the raw IA32_S_CET.
573        #[inline]
574        fn write_raw(value: u64) {
575            let mut msr = Self::MSR;
576            unsafe {
577                msr.write(value);
578            }
579        }
580
581        /// Read IA32_S_CET. Returns a tuple of the flags and the address to the legacy code page bitmap.
582        #[inline]
583        pub fn read() -> (CetFlags, Page) {
584            let value = Self::read_raw();
585            let cet_flags = CetFlags::from_bits_truncate(value);
586            let legacy_bitmap =
587                Page::from_start_address(VirtAddr::new(value & !(Page::<Size4KiB>::SIZE - 1)))
588                    .unwrap();
589
590            (cet_flags, legacy_bitmap)
591        }
592
593        /// Write IA32_S_CET.
594        #[inline]
595        pub fn write(flags: CetFlags, legacy_bitmap: Page) {
596            Self::write_raw(flags.bits() | legacy_bitmap.start_address().as_u64());
597        }
598    }
599}