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}