x86 stuff
This commit is contained in:
parent
30391aa2a1
commit
76506e919d
|
|
@ -3,6 +3,8 @@
|
||||||
pub mod gdt;
|
pub mod gdt;
|
||||||
pub mod idt;
|
pub mod idt;
|
||||||
pub mod instructions;
|
pub mod instructions;
|
||||||
|
pub mod paging;
|
||||||
|
pub mod registers;
|
||||||
|
|
||||||
pub use instructions::hlt;
|
pub use instructions::hlt;
|
||||||
|
|
||||||
|
|
@ -24,28 +26,12 @@ impl PortU16 {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn read(&self) -> u16 {
|
pub unsafe fn read(&self) -> u16 {
|
||||||
let value: u16;
|
unsafe { instructions::read_u16(self.0) }
|
||||||
unsafe {
|
|
||||||
core::arch::asm!(
|
|
||||||
"in ax, dx",
|
|
||||||
in("dx") self.0,
|
|
||||||
out("ax") value,
|
|
||||||
options(nomem, nostack, preserves_flags)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn write(&self, value: u16) {
|
pub unsafe fn write(&self, value: u16) {
|
||||||
unsafe {
|
unsafe { instructions::write_u16(self.0, value) }
|
||||||
core::arch::asm!(
|
|
||||||
"out dx, ax",
|
|
||||||
in("dx") self.0,
|
|
||||||
in("ax") value,
|
|
||||||
options(nomem, nostack, preserves_flags)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -516,15 +516,20 @@ extern "C" fn global_interrupt_handler(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(test, test_case)]
|
#[cfg(test)]
|
||||||
fn test_interrupt_handler_trait() {
|
mod tests {
|
||||||
use crate::sync::LazyLock;
|
use super::super::instructions;
|
||||||
static IDT: LazyLock<InterruptDescriptorTable> =
|
use super::*;
|
||||||
crate::sync::LazyLock::new(InterruptDescriptorTable::new_default);
|
#[test_case]
|
||||||
|
fn test_interrupt_handler_trait() {
|
||||||
|
use crate::sync::LazyLock;
|
||||||
|
static IDT: LazyLock<InterruptDescriptorTable> =
|
||||||
|
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.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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]
|
#[inline]
|
||||||
pub unsafe fn lidt(idt: &super::idt::IdtRegister) {
|
pub unsafe fn lidt(idt: &super::idt::IdtRegister) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
@ -54,6 +132,7 @@ pub mod msr {
|
||||||
pub const MSR_FS_BASE: u32 = 0xC000_0100;
|
pub const MSR_FS_BASE: u32 = 0xC000_0100;
|
||||||
pub const MSR_GS_BASE: u32 = 0xC000_0101;
|
pub const MSR_GS_BASE: u32 = 0xC000_0101;
|
||||||
pub const MSR_KERNEL_GS_BASE: u32 = 0xC000_0102;
|
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).
|
/// Reads the value of the specified Model-Specific Register (MSR).
|
||||||
/// # Safety
|
/// # 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