Skip to main content

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#[doc(alias = "FMask")]
60#[derive(Debug)]
61pub struct SFMask;
62
63/// IA32_U_CET: user mode CET configuration
64#[derive(Debug)]
65pub struct UCet;
66
67/// IA32_S_CET: supervisor mode CET configuration
68#[derive(Debug)]
69pub struct SCet;
70
71/// IA32_APIC_BASE: status and location of the local APIC
72///
73/// IA32_APIC_BASE must be supported on the CPU, otherwise, a general protection exception will occur. Support can be detected using the `cpuid` instruction.
74#[derive(Debug)]
75pub struct ApicBase;
76
77impl Efer {
78    /// The underlying model specific register.
79    pub const MSR: Msr = Msr(0xC000_0080);
80}
81
82impl FsBase {
83    /// The underlying model specific register.
84    pub const MSR: Msr = Msr(0xC000_0100);
85}
86
87impl GsBase {
88    /// The underlying model specific register.
89    pub const MSR: Msr = Msr(0xC000_0101);
90}
91
92impl KernelGsBase {
93    /// The underlying model specific register.
94    pub const MSR: Msr = Msr(0xC000_0102);
95}
96
97impl Star {
98    /// The underlying model specific register.
99    pub const MSR: Msr = Msr(0xC000_0081);
100}
101
102impl LStar {
103    /// The underlying model specific register.
104    pub const MSR: Msr = Msr(0xC000_0082);
105}
106
107impl SFMask {
108    /// The underlying model specific register.
109    pub const MSR: Msr = Msr(0xC000_0084);
110}
111
112impl UCet {
113    /// The underlying model specific register.
114    pub const MSR: Msr = Msr(0x6A0);
115}
116
117impl SCet {
118    /// The underlying model specific register.
119    pub const MSR: Msr = Msr(0x6A2);
120}
121
122impl ApicBase {
123    /// The underlying model specific register.
124    pub const MSR: Msr = Msr(0x1B);
125}
126
127bitflags! {
128    /// Flags of the Extended Feature Enable Register.
129    #[repr(transparent)]
130    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
131    pub struct EferFlags: u64 {
132        /// Enables the `syscall` and `sysret` instructions.
133        const SYSTEM_CALL_EXTENSIONS = 1;
134        /// Activates long mode, requires activating paging.
135        const LONG_MODE_ENABLE = 1 << 8;
136        /// Indicates that long mode is active.
137        const LONG_MODE_ACTIVE = 1 << 10;
138        /// Enables the no-execute page-protection feature.
139        const NO_EXECUTE_ENABLE = 1 << 11;
140        /// Enables SVM extensions.
141        const SECURE_VIRTUAL_MACHINE_ENABLE = 1 << 12;
142        /// Enable certain limit checks in 64-bit mode.
143        const LONG_MODE_SEGMENT_LIMIT_ENABLE = 1 << 13;
144        /// Enable the `fxsave` and `fxrstor` instructions to execute faster in 64-bit mode.
145        const FAST_FXSAVE_FXRSTOR = 1 << 14;
146        /// Changes how the `invlpg` instruction operates on TLB entries of upper-level entries.
147        const TRANSLATION_CACHE_EXTENSION = 1 << 15;
148    }
149}
150
151bitflags! {
152    /// Flags stored in IA32_U_CET and IA32_S_CET (Table-2-2 in Intel SDM Volume
153    /// 4). The Intel SDM-equivalent names are described in parentheses.
154    #[repr(transparent)]
155    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
156    pub struct CetFlags: u64 {
157        /// Enable shadow stack (SH_STK_EN)
158        const SS_ENABLE = 1 << 0;
159        /// Enable WRSS{D,Q}W instructions (WR_SHTK_EN)
160        const SS_WRITE_ENABLE = 1 << 1;
161        /// Enable indirect branch tracking (ENDBR_EN)
162        const IBT_ENABLE = 1 << 2;
163        /// Enable legacy treatment for indirect branch tracking (LEG_IW_EN)
164        const IBT_LEGACY_ENABLE = 1 << 3;
165        /// Enable no-track opcode prefix for indirect branch tracking (NO_TRACK_EN)
166        const IBT_NO_TRACK_ENABLE = 1 << 4;
167        /// Disable suppression of CET on legacy compatibility (SUPPRESS_DIS)
168        const IBT_LEGACY_SUPPRESS_ENABLE = 1 << 5;
169        /// Enable suppression of indirect branch tracking (SUPPRESS)
170        const IBT_SUPPRESS_ENABLE = 1 << 10;
171        /// Is IBT waiting for a branch to return? (read-only, TRACKER)
172        const IBT_TRACKED = 1 << 11;
173    }
174}
175
176bitflags! {
177    /// Flags for the Advanced Programmable Interrupt Controller Base Register.
178    #[repr(transparent)]
179    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
180    pub struct ApicBaseFlags: u64 {
181        // bits 0 - 7 are reserved.
182        /// Indicates whether the current processor is the bootstrap processor
183        const BSP = 1 << 8;
184        // bit 9 is reserved.
185        /// Places the local APIC in the x2APIC mode. Processor support for x2APIC feature can be
186        /// detected using the `cpuid` instruction. (CPUID.(EAX=1):ECX.21)
187        const X2APIC_ENABLE = 1 << 10;
188        /// Enables or disables the local Apic
189        const LAPIC_ENABLE = 1 << 11;
190    }
191}
192
193#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
194mod x86_64 {
195    use super::*;
196    use crate::addr::VirtAddr;
197    use crate::registers::rflags::RFlags;
198    use crate::structures::gdt::SegmentSelector;
199    use crate::structures::paging::Page;
200    use crate::structures::paging::PhysFrame;
201    use crate::structures::paging::Size4KiB;
202    use crate::PhysAddr;
203    use crate::PrivilegeLevel;
204    use bit_field::BitField;
205    use core::convert::TryInto;
206    use core::fmt;
207    // imports for intra doc links
208    #[cfg(doc)]
209    use crate::registers::{
210        control::Cr4Flags,
211        segmentation::{Segment, Segment64, CS, SS},
212    };
213    use core::arch::asm;
214
215    impl Msr {
216        /// Read 64 bits msr register.
217        ///
218        /// ## Safety
219        ///
220        /// The caller must ensure that this read operation has no unsafe side
221        /// effects.
222        #[inline]
223        pub unsafe fn read(&self) -> u64 {
224            let (high, low): (u32, u32);
225            unsafe {
226                asm!(
227                    "rdmsr",
228                    in("ecx") self.0,
229                    out("eax") low, out("edx") high,
230                    options(nomem, nostack, preserves_flags),
231                );
232            }
233            ((high as u64) << 32) | (low as u64)
234        }
235
236        /// Write 64 bits to msr register.
237        ///
238        /// ## Safety
239        ///
240        /// The caller must ensure that this write operation has no unsafe side
241        /// effects.
242        #[inline]
243        pub unsafe fn write(&mut self, value: u64) {
244            let low = value as u32;
245            let high = (value >> 32) as u32;
246
247            unsafe {
248                asm!(
249                    "wrmsr",
250                    in("ecx") self.0,
251                    in("eax") low, in("edx") high,
252                    options(nostack, preserves_flags),
253                );
254            }
255        }
256    }
257
258    impl Efer {
259        /// Read the current EFER flags.
260        #[inline]
261        pub fn read() -> EferFlags {
262            EferFlags::from_bits_truncate(Self::read_raw())
263        }
264
265        /// Read the current raw EFER flags.
266        #[inline]
267        pub fn read_raw() -> u64 {
268            unsafe { Self::MSR.read() }
269        }
270
271        /// Write the EFER flags, preserving reserved values.
272        ///
273        /// Preserves the value of reserved fields.
274        ///
275        /// ## Safety
276        ///
277        /// Unsafe because it's possible to break memory
278        /// safety with wrong flags, e.g. by disabling long mode.
279        #[inline]
280        pub unsafe fn write(flags: EferFlags) {
281            let old_value = Self::read_raw();
282            let reserved = old_value & !(EferFlags::all().bits());
283            let new_value = reserved | flags.bits();
284
285            unsafe {
286                Self::write_raw(new_value);
287            }
288        }
289
290        /// Write the EFER flags.
291        ///
292        /// Does not preserve any bits, including reserved fields.
293        ///
294        /// ## Safety
295        ///
296        /// Unsafe because it's possible to
297        /// break memory safety with wrong flags, e.g. by disabling long mode.
298        #[inline]
299        pub unsafe fn write_raw(flags: u64) {
300            let mut msr = Self::MSR;
301            unsafe {
302                msr.write(flags);
303            }
304        }
305
306        /// Update EFER flags.
307        ///
308        /// Preserves the value of reserved fields.
309        ///
310        /// ## Safety
311        ///
312        /// Unsafe because it's possible to break memory
313        /// safety with wrong flags, e.g. by disabling long mode.
314        #[inline]
315        pub unsafe fn update<F>(f: F)
316        where
317            F: FnOnce(&mut EferFlags),
318        {
319            let mut flags = Self::read();
320            f(&mut flags);
321            unsafe {
322                Self::write(flags);
323            }
324        }
325    }
326
327    impl FsBase {
328        /// Read the current FsBase register.
329        ///
330        /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is set, the more efficient
331        /// [`FS::read_base`] can be used instead.
332        #[inline]
333        pub fn read() -> VirtAddr {
334            VirtAddr::new(unsafe { Self::MSR.read() })
335        }
336
337        /// Write a given virtual address to the FS.Base register.
338        ///
339        /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is set, the more efficient
340        /// [`FS::write_base`] can be used instead.
341        #[inline]
342        pub fn write(address: VirtAddr) {
343            let mut msr = Self::MSR;
344            unsafe { msr.write(address.as_u64()) };
345        }
346    }
347
348    impl GsBase {
349        /// Read the current GsBase register.
350        ///
351        /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is set, the more efficient
352        /// [`GS::read_base`] can be used instead.
353        #[inline]
354        pub fn read() -> VirtAddr {
355            VirtAddr::new(unsafe { Self::MSR.read() })
356        }
357
358        /// Write a given virtual address to the GS.Base register.
359        ///
360        /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is set, the more efficient
361        /// [`GS::write_base`] can be used instead.
362        #[inline]
363        pub fn write(address: VirtAddr) {
364            let mut msr = Self::MSR;
365            unsafe { msr.write(address.as_u64()) };
366        }
367    }
368
369    impl KernelGsBase {
370        /// Read the current KernelGsBase register.
371        #[inline]
372        pub fn read() -> VirtAddr {
373            VirtAddr::new(unsafe { Self::MSR.read() })
374        }
375
376        /// Write a given virtual address to the KernelGsBase register.
377        #[inline]
378        pub fn write(address: VirtAddr) {
379            let mut msr = Self::MSR;
380            unsafe { msr.write(address.as_u64()) };
381        }
382    }
383
384    impl Star {
385        /// Read the Ring 0 and Ring 3 segment bases.
386        /// The remaining fields are ignored because they are
387        /// not valid for long mode.
388        ///
389        /// # Returns
390        /// - Field 1 (SYSRET): The CS selector is set to this field + 16. SS.Sel is set to
391        ///   this field + 8. Because SYSRET always returns to CPL 3, the
392        ///   RPL bits 1:0 should be initialized to 11b.
393        /// - Field 2 (SYSCALL): This field is copied directly into CS.Sel. SS.Sel is set to
394        ///   this field + 8. Because SYSCALL always switches to CPL 0, the RPL bits
395        ///   33:32 should be initialized to 00b.
396        #[inline]
397        pub fn read_raw() -> (u16, u16) {
398            let msr_value = unsafe { Self::MSR.read() };
399            let sysret = msr_value.get_bits(48..64);
400            let syscall = msr_value.get_bits(32..48);
401            (sysret.try_into().unwrap(), syscall.try_into().unwrap())
402        }
403
404        /// Read the Ring 0 and Ring 3 segment bases.
405        /// Returns
406        /// - CS Selector SYSRET
407        /// - SS Selector SYSRET
408        /// - CS Selector SYSCALL
409        /// - SS Selector SYSCALL
410        #[inline]
411        pub fn read() -> (
412            SegmentSelector,
413            SegmentSelector,
414            SegmentSelector,
415            SegmentSelector,
416        ) {
417            let raw = Self::read_raw();
418            (
419                SegmentSelector(raw.0 + 16),
420                SegmentSelector(raw.0 + 8),
421                SegmentSelector(raw.1),
422                SegmentSelector(raw.1 + 8),
423            )
424        }
425
426        /// Write the Ring 0 and Ring 3 segment bases.
427        /// The remaining fields are ignored because they are
428        /// not valid for long mode.
429        ///
430        /// # Parameters
431        ///
432        /// - sysret: For SYSRETQ (64-bit), the CS selector is set to this
433        ///   field + 16. For SYSRET (32-bit), the CS selector is set to this
434        ///   field. SS.Sel is set to this field + 8. Because SYSRETQ/SYSRET
435        ///   always returns to CPL 3, the RPL bits 1:0 should be initialized
436        ///   to 11b.
437        /// - syscall: This field is copied directly into CS.Sel. SS.Sel is set to
438        ///   this field + 8. Because SYSCALL always switches to CPL 0, the RPL bits
439        ///   33:32 should be initialized to 00b.
440        ///
441        /// # Safety
442        ///
443        /// Unsafe because this can cause system instability if passed in the
444        /// wrong values for the fields.
445        #[inline]
446        pub unsafe fn write_raw(sysret: u16, syscall: u16) {
447            let mut msr_value = 0u64;
448            msr_value.set_bits(48..64, sysret.into());
449            msr_value.set_bits(32..48, syscall.into());
450            let mut msr = Self::MSR;
451            unsafe {
452                msr.write(msr_value);
453            }
454        }
455
456        /// Write the Ring 0 and Ring 3 segment bases.
457        ///
458        /// The remaining fields are ignored because they are
459        /// not valid for long mode.
460        ///
461        /// This function will fail if the segment selectors are
462        /// not in the correct offset of each other or if the
463        /// segment selectors do not have correct privileges.
464        ///
465        /// Note that `cs_sysret` should contain the segment to be used for
466        /// SYSRETQ (64-bit), not SYSRET (32-bit).
467        #[inline]
468        pub fn write(
469            cs_sysret: SegmentSelector,
470            ss_sysret: SegmentSelector,
471            cs_syscall: SegmentSelector,
472            ss_syscall: SegmentSelector,
473        ) -> Result<(), InvalidStarSegmentSelectors> {
474            // Convert to i32 to prevent underflows.
475            let cs_sysret_cmp = i32::from(cs_sysret.0) - 16;
476            let ss_sysret_cmp = i32::from(ss_sysret.0) - 8;
477            let cs_syscall_cmp = i32::from(cs_syscall.0);
478            let ss_syscall_cmp = i32::from(ss_syscall.0) - 8;
479
480            if cs_sysret_cmp != ss_sysret_cmp {
481                return Err(InvalidStarSegmentSelectors::SysretOffset);
482            }
483
484            if cs_syscall_cmp != ss_syscall_cmp {
485                return Err(InvalidStarSegmentSelectors::SyscallOffset);
486            }
487
488            if ss_sysret.rpl() != PrivilegeLevel::Ring3 {
489                return Err(InvalidStarSegmentSelectors::SysretPrivilegeLevel);
490            }
491
492            if ss_syscall.rpl() != PrivilegeLevel::Ring0 {
493                return Err(InvalidStarSegmentSelectors::SyscallPrivilegeLevel);
494            }
495
496            unsafe { Self::write_raw(ss_sysret.0 - 8, cs_syscall.0) };
497
498            Ok(())
499        }
500    }
501
502    #[derive(Debug)]
503    pub enum InvalidStarSegmentSelectors {
504        SysretOffset,
505        SyscallOffset,
506        SysretPrivilegeLevel,
507        SyscallPrivilegeLevel,
508    }
509
510    impl fmt::Display for InvalidStarSegmentSelectors {
511        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
512            match self {
513                Self::SysretOffset => write!(f, "Sysret CS and SS are not offset by 8."),
514                Self::SyscallOffset => write!(f, "Syscall CS and SS are not offset by 8."),
515                Self::SysretPrivilegeLevel => {
516                    write!(f, "Sysret's segment must be a Ring3 segment.")
517                }
518                Self::SyscallPrivilegeLevel => {
519                    write!(f, "Syscall's segment must be a Ring0 segment.")
520                }
521            }
522        }
523    }
524
525    impl LStar {
526        /// Read the current LStar register.
527        /// This holds the target RIP of a syscall.
528        #[inline]
529        pub fn read() -> VirtAddr {
530            VirtAddr::new(unsafe { Self::MSR.read() })
531        }
532
533        /// Write a given virtual address to the LStar register.
534        /// This holds the target RIP of a syscall.
535        #[inline]
536        pub fn write(address: VirtAddr) {
537            let mut msr = Self::MSR;
538            unsafe { msr.write(address.as_u64()) };
539        }
540    }
541
542    impl SFMask {
543        /// Read to the SFMask register.
544        /// The SFMASK register is used to specify which RFLAGS bits
545        /// are cleared during a SYSCALL. In long mode, SFMASK is used
546        /// to specify which RFLAGS bits are cleared when SYSCALL is
547        /// executed. If a bit in SFMASK is set to 1, the corresponding
548        /// bit in RFLAGS is cleared to 0. If a bit in SFMASK is cleared
549        /// to 0, the corresponding rFLAGS bit is not modified.
550        #[inline]
551        pub fn read() -> RFlags {
552            RFlags::from_bits(unsafe { Self::MSR.read() }).unwrap()
553        }
554
555        /// Write to the SFMask register.
556        /// The SFMASK register is used to specify which RFLAGS bits
557        /// are cleared during a SYSCALL. In long mode, SFMASK is used
558        /// to specify which RFLAGS bits are cleared when SYSCALL is
559        /// executed. If a bit in SFMASK is set to 1, the corresponding
560        /// bit in RFLAGS is cleared to 0. If a bit in SFMASK is cleared
561        /// to 0, the corresponding rFLAGS bit is not modified.
562        #[inline]
563        pub fn write(value: RFlags) {
564            let mut msr = Self::MSR;
565            unsafe { msr.write(value.bits()) };
566        }
567
568        /// Update the SFMask register.
569        ///
570        /// The SFMASK register is used to specify which RFLAGS bits
571        /// are cleared during a SYSCALL. In long mode, SFMASK is used
572        /// to specify which RFLAGS bits are cleared when SYSCALL is
573        /// executed. If a bit in SFMASK is set to 1, the corresponding
574        /// bit in RFLAGS is cleared to 0. If a bit in SFMASK is cleared
575        /// to 0, the corresponding rFLAGS bit is not modified.
576        #[inline]
577        pub fn update<F>(f: F)
578        where
579            F: FnOnce(&mut RFlags),
580        {
581            let mut flags = Self::read();
582            f(&mut flags);
583            Self::write(flags);
584        }
585    }
586
587    impl UCet {
588        /// Read the raw IA32_U_CET.
589        #[inline]
590        fn read_raw() -> u64 {
591            unsafe { Self::MSR.read() }
592        }
593
594        /// Write the raw IA32_U_CET.
595        #[inline]
596        fn write_raw(value: u64) {
597            let mut msr = Self::MSR;
598            unsafe {
599                msr.write(value);
600            }
601        }
602
603        /// Read IA32_U_CET. Returns a tuple of the flags and the address to the legacy code page bitmap.
604        #[inline]
605        pub fn read() -> (CetFlags, Page) {
606            let value = Self::read_raw();
607            let cet_flags = CetFlags::from_bits_truncate(value);
608            let legacy_bitmap =
609                Page::from_start_address(VirtAddr::new(value & !(Page::<Size4KiB>::SIZE - 1)))
610                    .unwrap();
611
612            (cet_flags, legacy_bitmap)
613        }
614
615        /// Write IA32_U_CET.
616        #[inline]
617        pub fn write(flags: CetFlags, legacy_bitmap: Page) {
618            Self::write_raw(flags.bits() | legacy_bitmap.start_address().as_u64());
619        }
620
621        /// Updates IA32_U_CET.
622        #[inline]
623        pub fn update<F>(f: F)
624        where
625            F: FnOnce(&mut CetFlags, &mut Page),
626        {
627            let (mut flags, mut legacy_bitmap) = Self::read();
628            f(&mut flags, &mut legacy_bitmap);
629            Self::write(flags, legacy_bitmap);
630        }
631    }
632
633    impl SCet {
634        /// Read the raw IA32_S_CET.
635        #[inline]
636        fn read_raw() -> u64 {
637            unsafe { Self::MSR.read() }
638        }
639
640        /// Write the raw IA32_S_CET.
641        #[inline]
642        fn write_raw(value: u64) {
643            let mut msr = Self::MSR;
644            unsafe {
645                msr.write(value);
646            }
647        }
648
649        /// Read IA32_S_CET. Returns a tuple of the flags and the address to the legacy code page bitmap.
650        #[inline]
651        pub fn read() -> (CetFlags, Page) {
652            let value = Self::read_raw();
653            let cet_flags = CetFlags::from_bits_truncate(value);
654            let legacy_bitmap =
655                Page::from_start_address(VirtAddr::new(value & !(Page::<Size4KiB>::SIZE - 1)))
656                    .unwrap();
657
658            (cet_flags, legacy_bitmap)
659        }
660
661        /// Write IA32_S_CET.
662        #[inline]
663        pub fn write(flags: CetFlags, legacy_bitmap: Page) {
664            Self::write_raw(flags.bits() | legacy_bitmap.start_address().as_u64());
665        }
666
667        /// Updates IA32_S_CET.
668        #[inline]
669        pub fn update<F>(f: F)
670        where
671            F: FnOnce(&mut CetFlags, &mut Page),
672        {
673            let (mut flags, mut legacy_bitmap) = Self::read();
674            f(&mut flags, &mut legacy_bitmap);
675            Self::write(flags, legacy_bitmap);
676        }
677    }
678
679    impl ApicBase {
680        /// Reads the IA32_APIC_BASE MSR.
681        #[inline]
682        pub fn read() -> (PhysFrame, ApicBaseFlags) {
683            let (frame, flags) = Self::read_raw();
684            (frame, ApicBaseFlags::from_bits_truncate(flags))
685        }
686
687        /// Reads the raw IA32_APIC_BASE MSR.
688        #[inline]
689        pub fn read_raw() -> (PhysFrame, u64) {
690            let raw = unsafe { Self::MSR.read() };
691            // extract bits 12 - 51 (incl.)
692            let addr = PhysAddr::new_truncate(raw);
693            let frame = PhysFrame::containing_address(addr);
694            (frame, raw)
695        }
696
697        /// Writes the IA32_APIC_BASE MSR preserving reserved values.
698        ///
699        /// Preserves the value of reserved fields.
700        ///
701        /// ## Safety
702        ///
703        /// Unsafe because changing the APIC base address allows hijacking a page of physical memory space in ways that would violate Rust's memory rules.
704        #[inline]
705        pub unsafe fn write(frame: PhysFrame, flags: ApicBaseFlags) {
706            let (_, old_flags) = Self::read_raw();
707            let reserved = old_flags & !(ApicBaseFlags::all().bits());
708            let new_flags = reserved | flags.bits();
709
710            unsafe {
711                Self::write_raw(frame, new_flags);
712            }
713        }
714
715        /// Writes the IA32_APIC_BASE MSR flags.
716        ///
717        /// Does not preserve any bits, including reserved fields.
718        ///
719        /// ## Safety
720        ///
721        /// Unsafe because it's possible to set reserved bits to `1` and changing the APIC base address allows hijacking a page of physical memory space in ways that would violate Rust's memory rules.
722        #[inline]
723        pub unsafe fn write_raw(frame: PhysFrame, flags: u64) {
724            let addr = frame.start_address();
725            let mut msr = Self::MSR;
726            unsafe {
727                msr.write(flags | addr.as_u64());
728            }
729        }
730    }
731}