x86 stuff
This commit is contained in:
parent
30391aa2a1
commit
76506e919d
|
|
@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
35
kernel/src/x86_64/paging.rs
Normal file
35
kernel/src/x86_64/paging.rs
Normal 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
|
||||
}
|
||||
}
|
||||
133
kernel/src/x86_64/registers.rs
Normal file
133
kernel/src/x86_64/registers.rs
Normal 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);
|
||||
}
|
||||
Loading…
Reference in a new issue