curiOS/kernel/src/x86_64/registers.rs
2026-08-03 22:08:42 +02:00

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);
}
}