Skip to content

Commit dc43e5a

Browse files
authored
Merge pull request #532 from hannahfluch/master
feat(msr): add IA32_APIC_BASE support
2 parents 564bcc3 + 9e38b08 commit dc43e5a

File tree

1 file changed

+83
-0
lines changed

1 file changed

+83
-0
lines changed

src/registers/model_specific.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ pub struct SCet;
7171
#[derive(Debug)]
7272
pub struct Pat;
7373

74+
/// IA32_APIC_BASE: status and location of the local APIC
75+
///
76+
/// IA32_APIC_BASE must be supported on the CPU, otherwise, a general protection exception will occur. Support can be detected using the `cpuid` instruction.
77+
#[derive(Debug)]
78+
pub struct ApicBase;
79+
7480
impl Efer {
7581
/// The underlying model specific register.
7682
pub const MSR: Msr = Msr(0xC000_0080);
@@ -132,6 +138,11 @@ impl Pat {
132138
];
133139
}
134140

141+
impl ApicBase {
142+
/// The underlying model specific register.
143+
pub const MSR: Msr = Msr(0x1B);
144+
}
145+
135146
bitflags! {
136147
/// Flags of the Extended Feature Enable Register.
137148
#[repr(transparent)]
@@ -218,14 +229,33 @@ impl PatMemoryType {
218229
}
219230
}
220231

232+
bitflags! {
233+
/// Flags for the Advanced Programmable Interrupt Controler Base Register.
234+
#[repr(transparent)]
235+
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
236+
pub struct ApicBaseFlags: u64 {
237+
// bits 0 - 7 are reserved.
238+
/// Indicates whether the current processor is the bootstrap processor
239+
const BSP = 1 << 8;
240+
// bit 9 is reserved.
241+
/// Places the local APIC in the x2APIC mode. Processor support for x2APIC feature can be
242+
/// detected using the `cpuid` instruction. (CPUID.(EAX=1):ECX.21)
243+
const X2APIC_ENABLE = 1 << 10;
244+
/// Enables or disables the local Apic
245+
const LAPIC_ENABLE = 1 << 11;
246+
}
247+
}
248+
221249
#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
222250
mod x86_64 {
223251
use super::*;
224252
use crate::addr::VirtAddr;
225253
use crate::registers::rflags::RFlags;
226254
use crate::structures::gdt::SegmentSelector;
227255
use crate::structures::paging::Page;
256+
use crate::structures::paging::PhysFrame;
228257
use crate::structures::paging::Size4KiB;
258+
use crate::PhysAddr;
229259
use crate::PrivilegeLevel;
230260
use bit_field::BitField;
231261
use core::convert::TryInto;
@@ -725,4 +755,57 @@ mod x86_64 {
725755
}
726756
}
727757
}
758+
759+
impl ApicBase {
760+
/// Reads the IA32_APIC_BASE MSR.
761+
#[inline]
762+
pub fn read() -> (PhysFrame, ApicBaseFlags) {
763+
let (frame, flags) = Self::read_raw();
764+
(frame, ApicBaseFlags::from_bits_truncate(flags))
765+
}
766+
767+
/// Reads the raw IA32_APIC_BASE MSR.
768+
#[inline]
769+
pub fn read_raw() -> (PhysFrame, u64) {
770+
let raw = unsafe { Self::MSR.read() };
771+
// extract bits 12 - 51 (incl.)
772+
let addr = PhysAddr::new_truncate(raw);
773+
let frame = PhysFrame::containing_address(addr);
774+
(frame, raw)
775+
}
776+
777+
/// Writes the IA32_APIC_BASE MSR preserving reserved values.
778+
///
779+
/// Preserves the value of reserved fields.
780+
///
781+
/// ## Safety
782+
///
783+
/// Unsafe because changing the APIC base address allows hijacking a page of physical memory space in ways that would violate Rust's memory rules.
784+
#[inline]
785+
pub unsafe fn write(frame: PhysFrame, flags: ApicBaseFlags) {
786+
let (_, old_flags) = Self::read_raw();
787+
let reserved = old_flags & !(ApicBaseFlags::all().bits());
788+
let new_flags = reserved | flags.bits();
789+
790+
unsafe {
791+
Self::write_raw(frame, new_flags);
792+
}
793+
}
794+
795+
/// Writes the IA32_APIC_BASE MSR flags.
796+
///
797+
/// Does not preserve any bits, including reserved fields.
798+
///
799+
/// ## Safety
800+
///
801+
/// 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.
802+
#[inline]
803+
pub unsafe fn write_raw(frame: PhysFrame, flags: u64) {
804+
let addr = frame.start_address();
805+
let mut msr = Self::MSR;
806+
unsafe {
807+
msr.write(flags | addr.as_u64());
808+
}
809+
}
810+
}
728811
}

0 commit comments

Comments
 (0)