From 76506e919d65878b3b5876890a3cd5de00fd02f2 Mon Sep 17 00:00:00 2001 From: janis Date: Fri, 24 Jul 2026 01:18:32 +0200 Subject: [PATCH] x86 stuff --- kernel/src/x86_64.rs | 22 +---- kernel/src/x86_64/idt.rs | 21 +++-- kernel/src/x86_64/instructions.rs | 79 ++++++++++++++++++ kernel/src/x86_64/paging.rs | 35 ++++++++ kernel/src/x86_64/registers.rs | 133 ++++++++++++++++++++++++++++++ 5 files changed, 264 insertions(+), 26 deletions(-) create mode 100644 kernel/src/x86_64/paging.rs create mode 100644 kernel/src/x86_64/registers.rs diff --git a/kernel/src/x86_64.rs b/kernel/src/x86_64.rs index 1cce837..bff17f3 100644 --- a/kernel/src/x86_64.rs +++ b/kernel/src/x86_64.rs @@ -3,6 +3,8 @@ pub mod gdt; pub mod idt; pub mod instructions; +pub mod paging; +pub mod registers; pub use instructions::hlt; @@ -24,28 +26,12 @@ impl PortU16 { #[inline] pub unsafe fn read(&self) -> u16 { - let value: u16; - unsafe { - core::arch::asm!( - "in ax, dx", - in("dx") self.0, - out("ax") value, - options(nomem, nostack, preserves_flags) - ); - } - value + unsafe { instructions::read_u16(self.0) } } #[inline] pub unsafe fn write(&self, value: u16) { - unsafe { - core::arch::asm!( - "out dx, ax", - in("dx") self.0, - in("ax") value, - options(nomem, nostack, preserves_flags) - ); - } + unsafe { instructions::write_u16(self.0, value) } } } diff --git a/kernel/src/x86_64/idt.rs b/kernel/src/x86_64/idt.rs index 67675c6..6bcb3db 100644 --- a/kernel/src/x86_64/idt.rs +++ b/kernel/src/x86_64/idt.rs @@ -516,15 +516,20 @@ extern "C" fn global_interrupt_handler( ); } -#[cfg_attr(test, test_case)] -fn test_interrupt_handler_trait() { - use crate::sync::LazyLock; - static IDT: LazyLock = - crate::sync::LazyLock::new(InterruptDescriptorTable::new_default); +#[cfg(test)] +mod tests { + use super::super::instructions; + use super::*; + #[test_case] + fn test_interrupt_handler_trait() { + use crate::sync::LazyLock; + static IDT: LazyLock = + crate::sync::LazyLock::new(InterruptDescriptorTable::new_default); - unsafe { IDT.load_unsafe() }; + unsafe { IDT.load_unsafe() }; - super::instructions::int3(); // Trigger a breakpoint interrupt (interrupt 3) + instructions::int3(); // Trigger a breakpoint interrupt (interrupt 3) - serial_println!("Breakpoint interrupt handled successfully."); + serial_println!("Breakpoint interrupt handled successfully."); + } } diff --git a/kernel/src/x86_64/instructions.rs b/kernel/src/x86_64/instructions.rs index e113f8f..464437e 100644 --- a/kernel/src/x86_64/instructions.rs +++ b/kernel/src/x86_64/instructions.rs @@ -5,6 +5,84 @@ pub fn hlt() { } } +#[inline] +pub unsafe fn write_u8(port: u16, value: u8) { + unsafe { + core::arch::asm!( + "out dx, al", + in("dx") port, + in("al") value, + options(nomem, nostack, preserves_flags) + ); + } +} + +#[inline] +pub unsafe fn write_u16(port: u16, value: u16) { + unsafe { + core::arch::asm!( + "out dx, ax", + in("dx") port, + in("ax") value, + options(nomem, nostack, preserves_flags) + ); + } +} + +#[inline] +pub unsafe fn write_u32(port: u16, value: u32) { + unsafe { + core::arch::asm!( + "out dx, eax", + in("dx") port, + in("eax") value, + options(nomem, nostack, preserves_flags) + ); + } +} + +#[inline] +pub unsafe fn read_u8(port: u16) -> u8 { + let value: u8; + unsafe { + core::arch::asm!( + "in al, dx", + in("dx") port, + out("al") value, + options(nomem, nostack, preserves_flags) + ); + } + value +} + +#[inline] +pub unsafe fn read_u16(port: u16) -> u16 { + let value: u16; + unsafe { + core::arch::asm!( + "in ax, dx", + in("dx") port, + out("ax") value, + options(nomem, nostack, preserves_flags) + ); + } + value +} + +#[inline] +pub unsafe fn read_u32(port: u16) -> u32 { + let value: u32; + unsafe { + core::arch::asm!( + "in eax, dx", + in("dx") port, + out("eax") value, + options(nomem, nostack, preserves_flags) + ); + } + value +} + #[inline] pub unsafe fn lidt(idt: &super::idt::IdtRegister) { unsafe { @@ -54,6 +132,7 @@ pub mod msr { pub const MSR_FS_BASE: u32 = 0xC000_0100; pub const MSR_GS_BASE: u32 = 0xC000_0101; pub const MSR_KERNEL_GS_BASE: u32 = 0xC000_0102; + pub const MSR_EFER: u32 = 0xC000_0080; /// Reads the value of the specified Model-Specific Register (MSR). /// # Safety diff --git a/kernel/src/x86_64/paging.rs b/kernel/src/x86_64/paging.rs new file mode 100644 index 0000000..fcd7321 --- /dev/null +++ b/kernel/src/x86_64/paging.rs @@ -0,0 +1,35 @@ +use bit_field::BitField; + +#[repr(C, align(4096))] +pub struct PageTable { + entries: [Entry; 512], +} + +bitflags::bitflags! { + #[repr(transparent)] + pub struct PageTableEntryFlags: u64 { + const PRESENT = 1 << 0; + const WRITABLE = 1 << 1; + const USER_ACCESSIBLE = 1 << 2; + const WRITE_THROUGH = 1 << 3; + const NO_CACHE = 1 << 4; + const ACCESSED = 1 << 5; + const DIRTY = 1 << 6; + const HUGE_PAGE = 1 << 7; + const GLOBAL = 1 << 8; + const NO_EXECUTE = 1 << 63; + } +} + +impl PageTableEntryFlags { + pub fn from_raw(bits: u64) -> Self { + Self::from_bits_retain(bits) + } + pub fn as_raw(&self) -> u64 { + self.bits() + } + + pub fn phy(&self) -> u64 { + self.bits().get_bits(12..52) << 12 + } +} diff --git a/kernel/src/x86_64/registers.rs b/kernel/src/x86_64/registers.rs new file mode 100644 index 0000000..08e2854 --- /dev/null +++ b/kernel/src/x86_64/registers.rs @@ -0,0 +1,133 @@ +use core::{arch::asm, ops::Index}; + +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 Cr4Flags: 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_ENABLE = 1 << 6; + const PAGE_GLOBAL_ENABLE = 1 << 7; + const PERFORMANCE_MONITOR_COUNTER_ENABLE = 1 << 8; + const OSFXSR_SUPPORT = 1 << 9; + const OSXMMEXCPT_SUPPORT = 1 << 10; + const USER_MODE_INSTRUCTION_PREVENTION = 1 << 11; + const VMX_ENABLE = 1 << 13; + const SMX_ENABLE = 1 << 14; + const FSGSBASE_ENABLE = 1 << 16; + const PCID_ENABLE = 1 << 17; + const OSXSAVE_ENABLE = 1 << 18; + const SMEP_ENABLE = 1 << 20; + const SMAP_ENABLE = 1 << 21; + } +} + +impl Cr4Flags { + 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); + +impl IA32Pat { + pub fn from_entries(entries: [IA32PatEntry; 8]) -> Self { + let mut value = 0u64; + for (i, entry) in entries.iter().enumerate() { + value |= (entry.0 as u64) << (i * 8); + } + Self(value) + } + 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); +}