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 Controler 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        /// - sysret: The CS selector is set to this field + 16. SS.Sel is set to
432        ///   this field + 8. Because SYSRET always returns to CPL 3, the
433        ///   RPL bits 1:0 should be initialized to 11b.
434        /// - syscall: This field is copied directly into CS.Sel. SS.Sel is set to
435        ///   this field + 8. Because SYSCALL always switches to CPL 0, the RPL bits
436        ///   33:32 should be initialized to 00b.
437        ///
438        /// # Safety
439        ///
440        /// Unsafe because this can cause system instability if passed in the
441        /// wrong values for the fields.
442        #[inline]
443        pub unsafe fn write_raw(sysret: u16, syscall: u16) {
444            let mut msr_value = 0u64;
445            msr_value.set_bits(48..64, sysret.into());
446            msr_value.set_bits(32..48, syscall.into());
447            let mut msr = Self::MSR;
448            unsafe {
449                msr.write(msr_value);
450            }
451        }
452
453        /// Write the Ring 0 and Ring 3 segment bases.
454        /// The remaining fields are ignored because they are
455        /// not valid for long mode.
456        /// This function will fail if the segment selectors are
457        /// not in the correct offset of each other or if the
458        /// segment selectors do not have correct privileges.
459        #[inline]
460        pub fn write(
461            cs_sysret: SegmentSelector,
462            ss_sysret: SegmentSelector,
463            cs_syscall: SegmentSelector,
464            ss_syscall: SegmentSelector,
465        ) -> Result<(), InvalidStarSegmentSelectors> {
466            // Convert to i32 to prevent underflows.
467            let cs_sysret_cmp = i32::from(cs_sysret.0) - 16;
468            let ss_sysret_cmp = i32::from(ss_sysret.0) - 8;
469            let cs_syscall_cmp = i32::from(cs_syscall.0);
470            let ss_syscall_cmp = i32::from(ss_syscall.0) - 8;
471
472            if cs_sysret_cmp != ss_sysret_cmp {
473                return Err(InvalidStarSegmentSelectors::SysretOffset);
474            }
475
476            if cs_syscall_cmp != ss_syscall_cmp {
477                return Err(InvalidStarSegmentSelectors::SyscallOffset);
478            }
479
480            if ss_sysret.rpl() != PrivilegeLevel::Ring3 {
481                return Err(InvalidStarSegmentSelectors::SysretPrivilegeLevel);
482            }
483
484            if ss_syscall.rpl() != PrivilegeLevel::Ring0 {
485                return Err(InvalidStarSegmentSelectors::SyscallPrivilegeLevel);
486            }
487
488            unsafe { Self::write_raw(ss_sysret.0 - 8, cs_syscall.0) };
489
490            Ok(())
491        }
492    }
493
494    #[derive(Debug)]
495    pub enum InvalidStarSegmentSelectors {
496        SysretOffset,
497        SyscallOffset,
498        SysretPrivilegeLevel,
499        SyscallPrivilegeLevel,
500    }
501
502    impl fmt::Display for InvalidStarSegmentSelectors {
503        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
504            match self {
505                Self::SysretOffset => write!(f, "Sysret CS and SS are not offset by 8."),
506                Self::SyscallOffset => write!(f, "Syscall CS and SS are not offset by 8."),
507                Self::SysretPrivilegeLevel => {
508                    write!(f, "Sysret's segment must be a Ring3 segment.")
509                }
510                Self::SyscallPrivilegeLevel => {
511                    write!(f, "Syscall's segment must be a Ring0 segment.")
512                }
513            }
514        }
515    }
516
517    impl LStar {
518        /// Read the current LStar register.
519        /// This holds the target RIP of a syscall.
520        #[inline]
521        pub fn read() -> VirtAddr {
522            VirtAddr::new(unsafe { Self::MSR.read() })
523        }
524
525        /// Write a given virtual address to the LStar register.
526        /// This holds the target RIP of a syscall.
527        #[inline]
528        pub fn write(address: VirtAddr) {
529            let mut msr = Self::MSR;
530            unsafe { msr.write(address.as_u64()) };
531        }
532    }
533
534    impl SFMask {
535        /// Read to the SFMask register.
536        /// The SFMASK register is used to specify which RFLAGS bits
537        /// are cleared during a SYSCALL. In long mode, SFMASK is used
538        /// to specify which RFLAGS bits are cleared when SYSCALL is
539        /// executed. If a bit in SFMASK is set to 1, the corresponding
540        /// bit in RFLAGS is cleared to 0. If a bit in SFMASK is cleared
541        /// to 0, the corresponding rFLAGS bit is not modified.
542        #[inline]
543        pub fn read() -> RFlags {
544            RFlags::from_bits(unsafe { Self::MSR.read() }).unwrap()
545        }
546
547        /// Write to the SFMask register.
548        /// The SFMASK register is used to specify which RFLAGS bits
549        /// are cleared during a SYSCALL. In long mode, SFMASK is used
550        /// to specify which RFLAGS bits are cleared when SYSCALL is
551        /// executed. If a bit in SFMASK is set to 1, the corresponding
552        /// bit in RFLAGS is cleared to 0. If a bit in SFMASK is cleared
553        /// to 0, the corresponding rFLAGS bit is not modified.
554        #[inline]
555        pub fn write(value: RFlags) {
556            let mut msr = Self::MSR;
557            unsafe { msr.write(value.bits()) };
558        }
559
560        /// Update the SFMask register.
561        ///
562        /// The SFMASK register is used to specify which RFLAGS bits
563        /// are cleared during a SYSCALL. In long mode, SFMASK is used
564        /// to specify which RFLAGS bits are cleared when SYSCALL is
565        /// executed. If a bit in SFMASK is set to 1, the corresponding
566        /// bit in RFLAGS is cleared to 0. If a bit in SFMASK is cleared
567        /// to 0, the corresponding rFLAGS bit is not modified.
568        #[inline]
569        pub fn update<F>(f: F)
570        where
571            F: FnOnce(&mut RFlags),
572        {
573            let mut flags = Self::read();
574            f(&mut flags);
575            Self::write(flags);
576        }
577    }
578
579    impl UCet {
580        /// Read the raw IA32_U_CET.
581        #[inline]
582        fn read_raw() -> u64 {
583            unsafe { Self::MSR.read() }
584        }
585
586        /// Write the raw IA32_U_CET.
587        #[inline]
588        fn write_raw(value: u64) {
589            let mut msr = Self::MSR;
590            unsafe {
591                msr.write(value);
592            }
593        }
594
595        /// Read IA32_U_CET. Returns a tuple of the flags and the address to the legacy code page bitmap.
596        #[inline]
597        pub fn read() -> (CetFlags, Page) {
598            let value = Self::read_raw();
599            let cet_flags = CetFlags::from_bits_truncate(value);
600            let legacy_bitmap =
601                Page::from_start_address(VirtAddr::new(value & !(Page::<Size4KiB>::SIZE - 1)))
602                    .unwrap();
603
604            (cet_flags, legacy_bitmap)
605        }
606
607        /// Write IA32_U_CET.
608        #[inline]
609        pub fn write(flags: CetFlags, legacy_bitmap: Page) {
610            Self::write_raw(flags.bits() | legacy_bitmap.start_address().as_u64());
611        }
612
613        /// Updates IA32_U_CET.
614        #[inline]
615        pub fn update<F>(f: F)
616        where
617            F: FnOnce(&mut CetFlags, &mut Page),
618        {
619            let (mut flags, mut legacy_bitmap) = Self::read();
620            f(&mut flags, &mut legacy_bitmap);
621            Self::write(flags, legacy_bitmap);
622        }
623    }
624
625    impl SCet {
626        /// Read the raw IA32_S_CET.
627        #[inline]
628        fn read_raw() -> u64 {
629            unsafe { Self::MSR.read() }
630        }
631
632        /// Write the raw IA32_S_CET.
633        #[inline]
634        fn write_raw(value: u64) {
635            let mut msr = Self::MSR;
636            unsafe {
637                msr.write(value);
638            }
639        }
640
641        /// Read IA32_S_CET. Returns a tuple of the flags and the address to the legacy code page bitmap.
642        #[inline]
643        pub fn read() -> (CetFlags, Page) {
644            let value = Self::read_raw();
645            let cet_flags = CetFlags::from_bits_truncate(value);
646            let legacy_bitmap =
647                Page::from_start_address(VirtAddr::new(value & !(Page::<Size4KiB>::SIZE - 1)))
648                    .unwrap();
649
650            (cet_flags, legacy_bitmap)
651        }
652
653        /// Write IA32_S_CET.
654        #[inline]
655        pub fn write(flags: CetFlags, legacy_bitmap: Page) {
656            Self::write_raw(flags.bits() | legacy_bitmap.start_address().as_u64());
657        }
658
659        /// Updates IA32_S_CET.
660        #[inline]
661        pub fn update<F>(f: F)
662        where
663            F: FnOnce(&mut CetFlags, &mut Page),
664        {
665            let (mut flags, mut legacy_bitmap) = Self::read();
666            f(&mut flags, &mut legacy_bitmap);
667            Self::write(flags, legacy_bitmap);
668        }
669    }
670
671    impl ApicBase {
672        /// Reads the IA32_APIC_BASE MSR.
673        #[inline]
674        pub fn read() -> (PhysFrame, ApicBaseFlags) {
675            let (frame, flags) = Self::read_raw();
676            (frame, ApicBaseFlags::from_bits_truncate(flags))
677        }
678
679        /// Reads the raw IA32_APIC_BASE MSR.
680        #[inline]
681        pub fn read_raw() -> (PhysFrame, u64) {
682            let raw = unsafe { Self::MSR.read() };
683            // extract bits 12 - 51 (incl.)
684            let addr = PhysAddr::new_truncate(raw);
685            let frame = PhysFrame::containing_address(addr);
686            (frame, raw)
687        }
688
689        /// Writes the IA32_APIC_BASE MSR preserving reserved values.
690        ///
691        /// Preserves the value of reserved fields.
692        ///
693        /// ## Safety
694        ///
695        /// Unsafe because changing the APIC base address allows hijacking a page of physical memory space in ways that would violate Rust's memory rules.
696        #[inline]
697        pub unsafe fn write(frame: PhysFrame, flags: ApicBaseFlags) {
698            let (_, old_flags) = Self::read_raw();
699            let reserved = old_flags & !(ApicBaseFlags::all().bits());
700            let new_flags = reserved | flags.bits();
701
702            unsafe {
703                Self::write_raw(frame, new_flags);
704            }
705        }
706
707        /// Writes the IA32_APIC_BASE MSR flags.
708        ///
709        /// Does not preserve any bits, including reserved fields.
710        ///
711        /// ## Safety
712        ///
713        /// 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.
714        #[inline]
715        pub unsafe fn write_raw(frame: PhysFrame, flags: u64) {
716            let addr = frame.start_address();
717            let mut msr = Self::MSR;
718            unsafe {
719                msr.write(flags | addr.as_u64());
720            }
721        }
722    }
723}