x86 stuff

This commit is contained in:
janis 2026-07-24 01:18:32 +02:00
parent 30391aa2a1
commit 76506e919d
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
5 changed files with 264 additions and 26 deletions

View file

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

View file

@ -516,7 +516,11 @@ extern "C" fn global_interrupt_handler(
);
}
#[cfg_attr(test, test_case)]
#[cfg(test)]
mod tests {
use super::super::instructions;
use super::*;
#[test_case]
fn test_interrupt_handler_trait() {
use crate::sync::LazyLock;
static IDT: LazyLock<InterruptDescriptorTable> =
@ -524,7 +528,8 @@ fn test_interrupt_handler_trait() {
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.");
}
}

View file

@ -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

View file

@ -0,0 +1,35 @@
use bit_field::BitField;
#[repr(C, align(4096))]
pub struct PageTable<Entry> {
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
}
}

View file

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