239 lines
6.6 KiB
Rust
239 lines
6.6 KiB
Rust
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);
|
|
}
|
|
}
|