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}