use core::{arch::asm, fmt::Debug}; use bit_field::BitField; use bitflags::bitflags; use crate::memory::PhyAddr; bitflags::bitflags! { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Cr0Flags: u64 { const PROTECTED_MODE_ENABLE = 1 << 0; const MONITOR_COPROCESSOR = 1 << 1; const EMULATE_COPROCESSOR = 1 << 2; const TASK_SWITCHED = 1 << 3; const EXTENSION_TYPE = 1 << 4; const NUMERIC_ERROR = 1 << 5; const WRITE_PROTECT = 1 << 16; const ALIGNMENT_MASK = 1 << 18; const NOT_WRITE_THROUGH = 1 << 29; const CACHE_DISABLE = 1 << 30; const PAGING = 1 << 31; } } impl Cr0Flags { pub fn read() -> Self { let value: u64; unsafe { asm!("mov {}, cr0", out(reg) value, options(nomem, nostack, preserves_flags)); } Self::from_bits_truncate(value) } pub unsafe fn write(&self) { unsafe { asm!("mov cr0, {}", in(reg) self.bits(), options(nomem, nostack, preserves_flags)); } } } bitflags::bitflags! { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Cr4: u64 { const VIRTUAL_8086_MODE_EXTENSIONS = 1 << 0; const PROTECTED_MODE_VIRTUAL_INTERRUPTS = 1 << 1; const TIME_STAMP_DISABLE = 1 << 2; const DEBUGGING_EXTENSIONS = 1 << 3; const PAGE_SIZE_EXTENSIONS = 1 << 4; const PHYSICAL_ADDRESS_EXTENSION = 1 << 5; const MACHINE_CHECK = 1 << 6; const PAGE_GLOBAL = 1 << 7; const PERFORMANCE_MONITOR_COUNTER = 1 << 8; const OSFXSR_SUPPORT = 1 << 9; const OSXMMEXCPT_SUPPORT = 1 << 10; const USER_MODE_INSTRUCTION_PREVENTION = 1 << 11; const LA57 = 1 << 12; const VMX = 1 << 13; const SMX = 1 << 14; const FSGSBASE = 1 << 16; const PCID = 1 << 17; const OSXSAVE = 1 << 18; const SMEP = 1 << 20; const SMAP = 1 << 21; } } pub struct Cr2(pub u64); impl Cr2 { pub fn read() -> Self { let value: u64; unsafe { asm!("mov {}, cr2", out(reg) value, options(nomem, nostack, preserves_flags)); } Self(value) } } impl Cr4 { pub fn read() -> Self { let value: u64; unsafe { asm!("mov {}, cr4", out(reg) value, options(nomem, nostack, preserves_flags)); } Self::from_bits_truncate(value) } pub unsafe fn write(&self) { unsafe { asm!("mov cr4, {}", in(reg) self.bits(), options(nomem, nostack, preserves_flags)); } } } bitflags::bitflags! { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct IA32EferFlags: u64 { const SYSTEM_CALL_EXTENSIONS = 1 << 0; const LONG_MODE_ENABLE = 1 << 8; const LONG_MODE_ACTIVE = 1 << 10; const NO_EXECUTE_ENABLE = 1 << 11; } } impl IA32EferFlags { pub fn read() -> Self { use super::instructions::msr::{MSR_EFER, read_msr}; let bits = unsafe { read_msr(MSR_EFER) }; Self::from_bits_truncate(bits) } pub unsafe fn write(&self) { use super::instructions::msr::{MSR_EFER, write_msr}; unsafe { write_msr(MSR_EFER, self.bits()) } } } pub struct IA32Pat(u64); const impl Default for IA32Pat { fn default() -> Self { Self::from_entries([ IA32PatEntry::WRITE_BACK, IA32PatEntry::WRITE_THROUGH, IA32PatEntry::UNCACHEABLE, IA32PatEntry::UNCACHED, IA32PatEntry::WRITE_BACK, IA32PatEntry::WRITE_THROUGH, IA32PatEntry::UNCACHEABLE, IA32PatEntry::UNCACHED, ]) } } impl IA32Pat { pub const fn from_entries(entries: [IA32PatEntry; 8]) -> Self { let [ IA32PatEntry(e0), IA32PatEntry(e1), IA32PatEntry(e2), IA32PatEntry(e3), IA32PatEntry(e4), IA32PatEntry(e5), IA32PatEntry(e6), IA32PatEntry(e7), ] = entries; let val = e0 as u64 | ((e1 as u64) << 8) | ((e2 as u64) << 16) | ((e3 as u64) << 24) | ((e4 as u64) << 32) | ((e5 as u64) << 40) | ((e6 as u64) << 48) | ((e7 as u64) << 56); Self(val) } pub fn get(&self, index: u8) -> IA32PatEntry { assert!(index < 8, "Index out of bounds for IA32Pat"); let entry = (self.0 >> (index * 8)) & 0xF; IA32PatEntry(entry as u8) } pub fn set(&mut self, index: u8, entry: IA32PatEntry) { assert!(index < 8, "Index out of bounds for IA32Pat"); let mask = !(0xF << (index * 8)); self.0 = (self.0 & mask) | ((entry.0 as u64) << (index * 8)); } } pub struct IA32PatEntry(u8); impl IA32PatEntry { pub const UNCACHEABLE: Self = Self(0); pub const WRITE_COMBINING: Self = Self(1); pub const WRITE_THROUGH: Self = Self(4); pub const WRITE_PROTECTED: Self = Self(5); pub const WRITE_BACK: Self = Self(6); pub const UNCACHED: Self = Self(7); } pub struct Cr3(u64); impl Debug for Cr3 { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("Cr3") .field("phy", &self.phy()) .field("flags", &self.flags()) .field("free_bits", &format_args!("{:#x}", self.free_bits())) .finish() } } bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Cr3Flags: u64 { const PAGE_LEVEL_WRITE_THROUGH = 1 << 3; const PAGE_LEVEL_CACHE_DISABLE = 1 << 4; } } impl Cr3 { pub fn read() -> Self { let value: u64; unsafe { asm!("mov {}, cr3", out(reg) value, options(nomem, nostack, preserves_flags)); } Self(value) } pub unsafe fn write(&self) { unsafe { asm!("mov cr3, {}", in(reg) self.0, options(nomem, nostack, preserves_flags)); } } pub fn flags(&self) -> Cr3Flags { Cr3Flags::from_bits_truncate(self.0) } pub fn set_flags(&mut self, flags: Cr3Flags) { const MASK: u64 = Cr3Flags::all().bits(); self.0 = (self.0 & !MASK) | flags.bits(); } pub fn phy(&self) -> PhyAddr { PhyAddr(self.0.get_bits(12..52) << 12) } pub fn free_bits(&self) -> u16 { let low = (self.0 & 0x7) as u16; let high = self.0.get_bits(5..12) as u16; low | (high << 3) } pub fn set_free_bits(&mut self, value: u16) { let low = (value & 0x7) as u64; let high = (value >> 3) as u64; self.0.set_bits(0..3, low); self.0.set_bits(5..12, high); } }