Skip to content

Commit 32327c0

Browse files
committed
feat(msr): add IA32_APIC_BASE support
1 parent ffe34b0 commit 32327c0

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed

src/registers/model_specific.rs

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

74+
/// IA32_APIC_BASE: status and location of the local APIC
75+
#[derive(Debug)]
76+
pub struct Apic;
77+
7478
impl Efer {
7579
/// The underlying model specific register.
7680
pub const MSR: Msr = Msr(0xC000_0080);
@@ -132,6 +136,11 @@ impl Pat {
132136
];
133137
}
134138

139+
impl Apic {
140+
/// The underlying model specific register.
141+
pub const MSR: Msr = Msr(0x1B);
142+
}
143+
135144
bitflags! {
136145
/// Flags of the Extended Feature Enable Register.
137146
#[repr(transparent)]
@@ -218,6 +227,31 @@ impl PatMemoryType {
218227
}
219228
}
220229

230+
bitflags! {
231+
/// Flags for the Advanced Programmable Interrupt Controler Base Register.
232+
#[repr(transparent)]
233+
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
234+
pub struct ApicFlags: u64 {
235+
// bits 0 - 7 are reserved.
236+
/// Indicates whether the current processor is the bootstrap processor
237+
const BSP = 1 << 8;
238+
// bits 9 - 10 are reserved.
239+
/// Enables or disables the local Apic
240+
const LAPIC_ENABLE = 1 << 11;
241+
/// 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.
242+
const APIC_BASE = 0b111111111111111111111111 << 12;
243+
// bits 36-63 reserved
244+
}
245+
}
246+
247+
impl ApicFlags {
248+
/// Returns the physical address of the apic registers
249+
#[inline]
250+
pub fn address(&self) -> u64 {
251+
self.bits() & 0b11111111111111111111000000000000
252+
}
253+
}
254+
221255
#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
222256
mod x86_64 {
223257
use super::*;
@@ -725,4 +759,75 @@ mod x86_64 {
725759
}
726760
}
727761
}
762+
763+
impl Apic {
764+
/// Reads the IA32_APIC_BASE.
765+
///
766+
/// The APIC_BASE must be supported on the CPU, otherwise a general protection exception will
767+
/// occur. Support can be detected using the `cpuid` instruction.
768+
#[inline]
769+
pub fn read() -> ApicFlags {
770+
ApicFlags::from_bits_truncate(Self::read_raw())
771+
}
772+
773+
/// Reads the raw IA32_APIC_BASE.
774+
///
775+
/// The APIC_BASE must be supported on the CPU, otherwise a general protection exception will
776+
/// occur. Support can be detected using the `cpuid` instruction.
777+
#[inline]
778+
pub fn read_raw() -> u64 {
779+
unsafe { Self::MSR.read() }
780+
}
781+
782+
/// Writes the IA32_APIC_BASE preserving reserved values.
783+
///
784+
/// Preserves the value of reserved fields.
785+
///
786+
/// The APIC_BASE must be supported on the CPU, otherwise a general protection exception will
787+
/// occur. Support can be detected using the `cpuid` instruction.
788+
#[inline]
789+
pub fn write(flags: ApicFlags) {
790+
let old_value = Self::read_raw();
791+
let reserved = old_value & !(ApicFlags::all().bits());
792+
let new_value = reserved | flags.bits();
793+
794+
unsafe {
795+
Self::write_raw(new_value);
796+
}
797+
}
798+
799+
/// Writes the IA32_APIC_BASE flags.
800+
///
801+
/// Does not preserve any bits, including reserved fields.
802+
///
803+
/// The APIC_BASE must be supported on the CPU, otherwise a general protection exception will
804+
/// occur. Support can be detected using the `cpuid` instruction.
805+
///
806+
/// ## Safety
807+
///
808+
/// Unsafe because it's possible to set reserved bits to `1`.
809+
#[inline]
810+
pub unsafe fn write_raw(flags: u64) {
811+
let mut msr = Self::MSR;
812+
unsafe {
813+
msr.write(flags);
814+
}
815+
}
816+
817+
/// Update IA32_APIC_BASE flags.
818+
///
819+
/// Preserves the value of reserved fields.
820+
///
821+
/// The APIC_BASE must be supported on the CPU, otherwise a general protection exception will
822+
/// occur. Support can be detected using the `cpuid` instruction.
823+
#[inline]
824+
pub fn update<F>(f: F)
825+
where
826+
F: FnOnce(&mut ApicFlags),
827+
{
828+
let mut flags = Self::read();
829+
f(&mut flags);
830+
Self::write(flags);
831+
}
832+
}
728833
}

0 commit comments

Comments
 (0)