Skip to content

Commit 7a97e48

Browse files
committed
refactor(msr): handle apic base as seperate value
1 parent 6286c51 commit 7a97e48

File tree

1 file changed

+24
-39
lines changed

1 file changed

+24
-39
lines changed

src/registers/model_specific.rs

Lines changed: 24 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -241,17 +241,6 @@ bitflags! {
241241
const X2APIC_ENABLE = 1 << 10;
242242
/// Enables or disables the local Apic
243243
const LAPIC_ENABLE = 1 << 11;
244-
/// Specifies the base address of the APIC registers. This 24-bit value is extended by 12 bits at the low end to form the base address.
245-
const APIC_BASE = 0b111111111111111111111111 << 12;
246-
// bits 36-63 reserved
247-
}
248-
}
249-
250-
impl ApicFlags {
251-
/// Returns the physical address of the apic registers
252-
#[inline]
253-
pub fn address(&self) -> u64 {
254-
self.bits() & 0b11111111111111111111000000000000
255244
}
256245
}
257246

@@ -262,7 +251,9 @@ mod x86_64 {
262251
use crate::registers::rflags::RFlags;
263252
use crate::structures::gdt::SegmentSelector;
264253
use crate::structures::paging::Page;
254+
use crate::structures::paging::PhysFrame;
265255
use crate::structures::paging::Size4KiB;
256+
use crate::PhysAddr;
266257
use crate::PrivilegeLevel;
267258
use bit_field::BitField;
268259
use core::convert::TryInto;
@@ -769,17 +760,22 @@ mod x86_64 {
769760
/// The APIC_BASE must be supported on the CPU, otherwise a general protection exception will
770761
/// occur. Support can be detected using the `cpuid` instruction.
771762
#[inline]
772-
pub fn read() -> ApicFlags {
773-
ApicFlags::from_bits_truncate(Self::read_raw())
763+
pub fn read() -> (PhysFrame, ApicFlags) {
764+
let (frame, flags) = Self::read_raw();
765+
(frame, ApicFlags::from_bits_truncate(flags))
774766
}
775767

776768
/// Reads the raw IA32_APIC_BASE.
777769
///
778770
/// The APIC_BASE must be supported on the CPU, otherwise a general protection exception will
779771
/// occur. Support can be detected using the `cpuid` instruction.
780772
#[inline]
781-
pub fn read_raw() -> u64 {
782-
unsafe { Self::MSR.read() }
773+
pub fn read_raw() -> (PhysFrame, u64) {
774+
let raw = unsafe { Self::MSR.read() };
775+
// extract bits 32 - 51 (incl.)
776+
let addr = PhysAddr::new((raw >> 32) & 0xFFFFF);
777+
let frame = PhysFrame::containing_address(addr);
778+
(frame, raw)
783779
}
784780

785781
/// Writes the IA32_APIC_BASE preserving reserved values.
@@ -788,14 +784,18 @@ mod x86_64 {
788784
///
789785
/// The APIC_BASE must be supported on the CPU, otherwise a general protection exception will
790786
/// occur. Support can be detected using the `cpuid` instruction.
787+
///
788+
/// ## Safety
789+
///
790+
/// Unsafe because changing the APIC base address allows hijacking a page of physical memory space in ways that would violate Rust's memory rules.
791791
#[inline]
792-
pub fn write(flags: ApicFlags) {
793-
let old_value = Self::read_raw();
794-
let reserved = old_value & !(ApicFlags::all().bits());
795-
let new_value = reserved | flags.bits();
792+
pub unsafe fn write(frame: PhysFrame, flags: ApicFlags) {
793+
let (_, old_flags) = Self::read_raw();
794+
let reserved = old_flags & !(ApicFlags::all().bits());
795+
let new_flags = reserved | flags.bits();
796796

797797
unsafe {
798-
Self::write_raw(new_value);
798+
Self::write_raw(frame, new_flags);
799799
}
800800
}
801801

@@ -808,29 +808,14 @@ mod x86_64 {
808808
///
809809
/// ## Safety
810810
///
811-
/// Unsafe because it's possible to set reserved bits to `1`.
811+
/// 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.
812812
#[inline]
813-
pub unsafe fn write_raw(flags: u64) {
813+
pub unsafe fn write_raw(frame: PhysFrame, flags: u64) {
814+
let addr = frame.start_address();
814815
let mut msr = Self::MSR;
815816
unsafe {
816-
msr.write(flags);
817+
msr.write(flags | addr.as_u64());
817818
}
818819
}
819-
820-
/// Update IA32_APIC_BASE flags.
821-
///
822-
/// Preserves the value of reserved fields.
823-
///
824-
/// The APIC_BASE must be supported on the CPU, otherwise a general protection exception will
825-
/// occur. Support can be detected using the `cpuid` instruction.
826-
#[inline]
827-
pub fn update<F>(f: F)
828-
where
829-
F: FnOnce(&mut ApicFlags),
830-
{
831-
let mut flags = Self::read();
832-
f(&mut flags);
833-
Self::write(flags);
834-
}
835820
}
836821
}

0 commit comments

Comments
 (0)