diff options
author | 2016-06-29 15:49:33 -0700 | |
---|---|---|
committer | 2016-06-29 15:49:33 -0700 | |
commit | fffa3ae71951c3b8f4b2a441764a44ab8e55416e (patch) | |
tree | 9a9897b863c845d7679bebeb3c46a774ecb5e33c /src | |
parent | aaf26598addf1ef47fd8422d688965f89302d21b (diff) | |
download | rust-x86-fffa3ae71951c3b8f4b2a441764a44ab8e55416e.tar.gz rust-x86-fffa3ae71951c3b8f4b2a441764a44ab8e55416e.tar.zst rust-x86-fffa3ae71951c3b8f4b2a441764a44ab8e55416e.zip |
Crudely throw everything together
Diffstat (limited to 'src')
-rw-r--r-- | src/bits32/mod.rs | 217 | ||||
-rw-r--r-- | src/bits64/controlregs.rs (renamed from src/controlregs.rs) | 0 | ||||
-rw-r--r-- | src/bits64/dtables.rs (renamed from src/dtables.rs) | 0 | ||||
-rw-r--r-- | src/bits64/io.rs (renamed from src/io.rs) | 0 | ||||
-rw-r--r-- | src/bits64/irq.rs (renamed from src/irq.rs) | 2 | ||||
-rw-r--r-- | src/bits64/mod.rs | 52 | ||||
-rw-r--r-- | src/bits64/msr.rs (renamed from src/msr.rs) | 0 | ||||
-rw-r--r-- | src/bits64/paging.rs (renamed from src/paging.rs) | 0 | ||||
-rw-r--r-- | src/bits64/perfcnt/intel/counters.rs (renamed from src/perfcnt/intel/counters.rs) | 0 | ||||
-rw-r--r-- | src/bits64/perfcnt/intel/description.rs (renamed from src/perfcnt/intel/description.rs) | 0 | ||||
-rw-r--r-- | src/bits64/perfcnt/intel/mod.rs (renamed from src/perfcnt/intel/mod.rs) | 0 | ||||
-rw-r--r-- | src/bits64/perfcnt/mod.rs (renamed from src/perfcnt/mod.rs) | 0 | ||||
-rw-r--r-- | src/bits64/rflags.rs (renamed from src/rflags.rs) | 0 | ||||
-rw-r--r-- | src/bits64/segmentation.rs (renamed from src/segmentation.rs) | 0 | ||||
-rw-r--r-- | src/bits64/sgx.rs (renamed from src/sgx.rs) | 10 | ||||
-rw-r--r-- | src/bits64/syscall.rs (renamed from src/syscall.rs) | 0 | ||||
-rw-r--r-- | src/bits64/task.rs (renamed from src/task.rs) | 2 | ||||
-rw-r--r-- | src/bits64/time.rs (renamed from src/time.rs) | 0 | ||||
-rw-r--r-- | src/bits64/tlb.rs (renamed from src/tlb.rs) | 2 | ||||
-rw-r--r-- | src/bits64/tobba.rs | 17 | ||||
-rw-r--r-- | src/lib.rs | 61 | ||||
-rw-r--r-- | src/shared/mod.rs | 418 |
22 files changed, 721 insertions, 60 deletions
diff --git a/src/bits32/mod.rs b/src/bits32/mod.rs new file mode 100644 index 0000000..acb73c7 --- /dev/null +++ b/src/bits32/mod.rs @@ -0,0 +1,217 @@ +//! Data structures and functions used by Protected Mode but not IA-32e. + +#![allow(non_upper_case_globals)] + +pub use shared::*; + +use core::mem::size_of; + +bitflags! { + pub flags GdtAccess: u8 { + const Accessed = 1 << 0, + const Writable = 1 << 1, + const Direction = 1 << 2, + const Executable = 1 << 3, + const NotTss = 1 << 4, + } +} + +#[derive(Copy, Clone, Debug)] +#[repr(C, packed)] +pub struct GdtEntry { + limit: u16, + base1: u16, + base2: u8, + access: u8, + flags: u8, + base3: u8, +} + +#[derive(Copy, Clone)] +#[repr(C, packed)] +pub struct IdtEntry { + offset1: u16, + selector: u16, + reserved: u8, + flags: u8, + offset2: u16 +} + +impl GdtEntry { + pub const NULL: GdtEntry = GdtEntry { + base1: 0, + base2: 0, + base3: 0, + access: 0, + limit: 0, + flags: 0 + }; + + pub fn new(base: *const (), limit: usize, access: GdtAccess, dpl: PrivilegeLevel) -> GdtEntry { + let (limit, flags) = if limit < 0x100000 { + ((limit & 0xFFFF) as u16, ((limit & 0xF0000) >> 16) as u8 | 0x40u8) + } else { + if ((limit - 0xFFF) & 0xFFF) > 0 { + panic!("bad segment limit for GDT entry"); + } + (((limit & 0xFFFF000) >> 12) as u16, ((limit & 0xF0000000) >> 28) as u8 | 0xC0u8) + }; + GdtEntry { + base1: base as u16, + base2: ((base as usize & 0xFF0000) >> 16) as u8, + base3: ((base as usize & 0xFF000000) >> 24) as u8, + access: access.bits() | ((dpl as u8) << 5) | 0x80, + limit: limit, + flags: flags + } + } +} + +impl IdtEntry { + pub const NULL: IdtEntry = IdtEntry { + offset1: 0, + selector: 0, + reserved: 0, + flags: 0, + offset2: 0 + }; + + pub fn new(f: unsafe extern "C" fn(), dpl: PrivilegeLevel, block: bool) -> IdtEntry { + IdtEntry { + offset1: f as u16, + offset2: ((f as usize & 0xFFFF0000) >> 16) as u16, + selector: 8, + reserved: 0, + flags: if block { 0x8E } else { 0x8F } | ((dpl as u8) << 5) + } + } +} + +#[derive(Copy, Clone, Debug)] +#[repr(C, packed)] +pub struct Tss { + pub link: u16, + reserved0: u16, + pub esp0: u32, + pub ss0: u16, + reserved1: u16, + pub esp1: u32, + pub ss1: u16, + reserved2: u16, + pub esp2: u32, + pub ss2: u16, + reserved3: u16, + + pub cr3: u32, + pub eip: u32, + pub eflags: u32, + + pub eax: u32, + pub ecx: u32, + pub edx: u32, + pub ebx: u32, + pub esp: u32, + pub ebp: u32, + pub esi: u32, + pub edi: u32, + + pub es: u16, + reserved4: u16, + pub cs: u16, + reserved5: u16, + pub ss: u16, + reserved6: u16, + pub ds: u16, + reserved7: u16, + pub fs: u16, + reserved8: u16, + pub gs: u16, + reserved9: u16, + pub ldtr: u16, + reserved10: u32, + pub iobp_offset: u16 +} + +impl Tss { + pub fn new() -> Tss { + Tss { + link: 0, + reserved0: 0, + esp0: 0, + ss0: 0, + reserved1: 0, + esp1: 0, + ss1: 0, + reserved2: 0, + esp2: 0, + ss2: 0, + reserved3: 0, + cr3: 0, + eip: 0, + eflags: 0, + eax: 0, + ecx: 0, + edx: 0, + ebx: 0, + esp: 0, + ebp: 0, + esi: 0, + edi: 0, + es: 0, + reserved4: 0, + cs: 0, + reserved5: 0, + ss: 0, + reserved6: 0, + ds: 0, + reserved7: 0, + fs: 0, + reserved8: 0, + gs: 0, + reserved9: 0, + ldtr: 0, + reserved10: 0, + iobp_offset: size_of::<Tss>() as u16 + } + } +} + +#[inline(always)] +pub fn get_flags() -> Flags { + unsafe { + let r: usize; + asm!("pushfd; pop $0" : "=r"(r) ::: "intel"); + Flags::from_bits_truncate(r) + } +} + +#[inline(always)] +pub unsafe fn set_flags(val: Flags) { + asm!("push $0; popfd" :: "r"(val.bits()) : "flags" : "volatile", "intel"); +} + +#[inline(always)] +pub unsafe fn set_gdt(gdt: &[GdtEntry]) { + #[repr(C, packed)] + struct GDTR { + limit: u16, + ptr: *const GdtEntry, + } + asm!("lgdtl $0" :: "*m"(&GDTR { ptr: gdt.as_ptr(), limit: (gdt.len()*size_of::<GdtEntry>() - 1) as u16 }) :: "volatile"); +} + +#[inline(always)] +pub unsafe fn set_idt(idt: &[IdtEntry]) { + #[repr(C, packed)] + struct IDTR { + limit: u16, + ptr: *const IdtEntry, + } + asm!("lidtl $0" :: "*m"(&IDTR { ptr: idt.as_ptr(), limit: idt.len() as u16 * 8 }) :: "volatile"); +} + +#[inline(always)] +pub unsafe fn stack_jmp(stack: *mut (), ip: *const ()) -> ! { + asm!("mov esp, $0; jmp $1" :: "rg"(stack), "r"(ip) :: "volatile", "intel"); + loop { } +} diff --git a/src/controlregs.rs b/src/bits64/controlregs.rs index c243caf..c243caf 100644 --- a/src/controlregs.rs +++ b/src/bits64/controlregs.rs diff --git a/src/dtables.rs b/src/bits64/dtables.rs index d2e3413..d2e3413 100644 --- a/src/dtables.rs +++ b/src/bits64/dtables.rs diff --git a/src/io.rs b/src/bits64/io.rs index bb7cfb0..bb7cfb0 100644 --- a/src/io.rs +++ b/src/bits64/io.rs diff --git a/src/irq.rs b/src/bits64/irq.rs index bd92834..a1b6d12 100644 --- a/src/irq.rs +++ b/src/bits64/irq.rs @@ -1,7 +1,7 @@ //! Interrupt description and set-up code. use core::fmt; -use paging::VAddr; +use super::paging::VAddr; /// x86 Exception description (see also Intel Vol. 3a Chapter 6). #[derive(Debug)] diff --git a/src/bits64/mod.rs b/src/bits64/mod.rs new file mode 100644 index 0000000..315af02 --- /dev/null +++ b/src/bits64/mod.rs @@ -0,0 +1,52 @@ +//! Data structures and functions used by IA-32e but not Protected Mode. + +macro_rules! bit { + ( $x:expr ) => { + 1 << $x + }; +} + +macro_rules! check_flag { + ($doc:meta, $fun:ident, $flag:ident) => ( + #[$doc] + pub fn $fun(&self) -> bool { + self.contains($flag) + } + ) +} + +macro_rules! is_bit_set { + ($field:expr, $bit:expr) => ( + $field & (1 << $bit) > 0 + ) +} + +macro_rules! check_bit_fn { + ($doc:meta, $fun:ident, $field:ident, $bit:expr) => ( + #[$doc] + pub fn $fun(&self) -> bool { + is_bit_set!(self.$field, $bit) + } + ) +} + +pub mod io; +pub mod controlregs; +pub mod msr; +pub mod time; +pub mod irq; +pub mod rflags; +pub mod paging; +pub mod segmentation; +pub mod task; +pub mod dtables; +pub mod syscall; +pub mod sgx; +#[cfg(feature = "performance-counter")] +pub mod perfcnt; +pub mod cpuid { + pub use raw_cpuid::*; +} +pub mod tlb; + +pub mod tobba; diff --git a/src/msr.rs b/src/bits64/msr.rs index 6b4613a..6b4613a 100644 --- a/src/msr.rs +++ b/src/bits64/msr.rs diff --git a/src/paging.rs b/src/bits64/paging.rs index cc519b2..cc519b2 100644 --- a/src/paging.rs +++ b/src/bits64/paging.rs diff --git a/src/perfcnt/intel/counters.rs b/src/bits64/perfcnt/intel/counters.rs index e2987cc..e2987cc 100644 --- a/src/perfcnt/intel/counters.rs +++ b/src/bits64/perfcnt/intel/counters.rs diff --git a/src/perfcnt/intel/description.rs b/src/bits64/perfcnt/intel/description.rs index f64426d..f64426d 100644 --- a/src/perfcnt/intel/description.rs +++ b/src/bits64/perfcnt/intel/description.rs diff --git a/src/perfcnt/intel/mod.rs b/src/bits64/perfcnt/intel/mod.rs index 960e0c6..960e0c6 100644 --- a/src/perfcnt/intel/mod.rs +++ b/src/bits64/perfcnt/intel/mod.rs diff --git a/src/perfcnt/mod.rs b/src/bits64/perfcnt/mod.rs index 74b80a2..74b80a2 100644 --- a/src/perfcnt/mod.rs +++ b/src/bits64/perfcnt/mod.rs diff --git a/src/rflags.rs b/src/bits64/rflags.rs index 7cf4bbd..7cf4bbd 100644 --- a/src/rflags.rs +++ b/src/bits64/rflags.rs diff --git a/src/segmentation.rs b/src/bits64/segmentation.rs index e46b333..e46b333 100644 --- a/src/segmentation.rs +++ b/src/bits64/segmentation.rs diff --git a/src/sgx.rs b/src/bits64/sgx.rs index e611620..c705e47 100644 --- a/src/sgx.rs +++ b/src/bits64/sgx.rs @@ -6,13 +6,13 @@ /// * Function needs to be executed in ring 0. macro_rules! encls { ($rax:expr, $rbx:expr) - => ( $crate::sgx::encls2($rax as u64, $rbx as u64) ); + => ( $crate::bits64::sgx::encls2($rax as u64, $rbx as u64) ); ($rax:expr, $rbx:expr, $rcx:expr) - => ( $crate::sgx::encls3($rax as u64, $rbx as u64, $rcx as u64) ); + => ( $crate::bits64::sgx::encls3($rax as u64, $rbx as u64, $rcx as u64) ); ($rax:expr, $rbx:expr, $rcx:expr, $rdx:expr) - => ( $crate::sgx::encls4($rax as u64, $rbx as u64, $rcx as u64, $rdx as u64) ); + => ( $crate::bits64::sgx::encls4($rax as u64, $rbx as u64, $rcx as u64, $rdx as u64) ); } /// encls with two arguments -- consider calling the encls! macro instead! @@ -226,10 +226,10 @@ pub unsafe fn encls_ewb(pageinfo: u64, epc_page: u64, va_slot: u64) -> u32 { /// * Function needs to be executed in ring 3. macro_rules! enclu { ($rax:expr, $rbx:expr, $rcx:expr) - => ( $crate::sgx::enclu3($rax as u64, $rbx as u64, $rcx as u64) ); + => ( $crate::bits64::sgx::enclu3($rax as u64, $rbx as u64, $rcx as u64) ); ($rax:expr, $rbx:expr, $rcx:expr, $rdx:expr) - => ( $crate::sgx::enclu4($rax as u64, $rbx as u64, $rcx as u64, $rdx as u64) ); + => ( $crate::bits64::sgx::enclu4($rax as u64, $rbx as u64, $rcx as u64, $rdx as u64) ); } /// enclu with three arguments -- consider calling the enclu! macro instead! diff --git a/src/syscall.rs b/src/bits64/syscall.rs index c554177..c554177 100644 --- a/src/syscall.rs +++ b/src/bits64/syscall.rs diff --git a/src/task.rs b/src/bits64/task.rs index f37bd8d..97d3341 100644 --- a/src/task.rs +++ b/src/bits64/task.rs @@ -1,6 +1,6 @@ //! Helpers to program the task state segment. -use segmentation; +use super::segmentation; pub type TaskStateDescriptorLow = segmentation::SegmentDescriptor; pub type TaskStateDescriptorHigh = u64; diff --git a/src/time.rs b/src/bits64/time.rs index eff567d..eff567d 100644 --- a/src/time.rs +++ b/src/bits64/time.rs diff --git a/src/tlb.rs b/src/bits64/tlb.rs index ec39e3e..6b27e8c 100644 --- a/src/tlb.rs +++ b/src/bits64/tlb.rs @@ -15,6 +15,6 @@ pub unsafe fn flush(addr: usize) { /// This function is unsafe as it causes a general protection fault (GP) if the current privilege /// level is not 0. pub unsafe fn flush_all() { - use controlregs::{cr3, cr3_write}; + use super::controlregs::{cr3, cr3_write}; cr3_write(cr3()) } diff --git a/src/bits64/tobba.rs b/src/bits64/tobba.rs new file mode 100644 index 0000000..2243098 --- /dev/null +++ b/src/bits64/tobba.rs @@ -0,0 +1,17 @@ +#![allow(non_upper_case_globals)] + +pub use shared::*; + +#[inline(always)] +pub fn get_flags() -> Flags { + unsafe { + let r: usize; + asm!("pushfq; pop $0" : "=r"(r) ::: "intel"); + Flags::from_bits_truncate(r) + } +} + +#[inline(always)] +pub unsafe fn set_flags(val: Flags) { + asm!("push $0; popfq" :: "r"(val.bits()) : "flags" : "volatile", "intel"); +} @@ -1,11 +1,11 @@ +#![cfg(any(target_arch="x86", target_arch="x86_64"))] + #![feature(const_fn)] #![feature(asm)] +#![feature(associated_consts)] #![no_std] #![cfg_attr(test, allow(unused_features))] -#![crate_name = "x86"] -#![crate_type = "lib"] - #[macro_use] extern crate bitflags; @@ -16,57 +16,14 @@ extern crate raw_cpuid; #[macro_use] extern crate phf; +#[cfg(target_arch="x86")] +pub mod bits32; +#[cfg(target_arch="x86_64")] +pub mod bits64; +pub mod shared; + mod std { pub use core::fmt; pub use core::ops; pub use core::option; } - -macro_rules! bit { - ( $x:expr ) => { - 1 << $x - }; -} - -macro_rules! check_flag { - ($doc:meta, $fun:ident, $flag:ident) => ( - #[$doc] - pub fn $fun(&self) -> bool { - self.contains($flag) - } - ) -} - -macro_rules! is_bit_set { - ($field:expr, $bit:expr) => ( - $field & (1 << $bit) > 0 - ) -} - -macro_rules! check_bit_fn { - ($doc:meta, $fun:ident, $field:ident, $bit:expr) => ( - #[$doc] - pub fn $fun(&self) -> bool { - is_bit_set!(self.$field, $bit) - } - ) -} - -pub mod io; -pub mod controlregs; -pub mod msr; -pub mod time; -pub mod irq; -pub mod rflags; -pub mod paging; -pub mod segmentation; -pub mod task; -pub mod dtables; -pub mod syscall; -pub mod sgx; -#[cfg(feature = "performance-counter")] -pub mod perfcnt; -pub mod cpuid { - pub use raw_cpuid::*; -} -pub mod tlb; diff --git a/src/shared/mod.rs b/src/shared/mod.rs new file mode 100644 index 0000000..9e5face --- /dev/null +++ b/src/shared/mod.rs @@ -0,0 +1,418 @@ +//! Data structures and functions used by both protected mode and IA-32e. + +// In a few rare-cases this module includes mode-specific +// *implementations*. This is usually because we cannot trust the LLVM inline +// assembler to infer instruction variants from argument size, and thus we add +// size-suffixes wherever possible. +// +// That said, *interfaces* must always be mode-portable + +#![allow(non_upper_case_globals)] + +bitflags! { + pub flags Flags: usize { + const CarryFlag = 1 << 0, + const ParityFlag = 1 << 2, + const AdjustFlag = 1 << 4, + const ZeroFlag = 1 << 6, + const SignFlag = 1 << 7, + const TrapFlag = 1 << 8, + const InterruptFlag = 1 << 9, + const DirectionFlag = 1 << 10, + const OverflowFlag = 1 << 11, + const Iopl1 = 1 << 12, + const Iopl2 = 1 << 13, + const NestedTaskFlag = 1 << 14, + const ResumeFlag = 1 << 16, + const Virtual8086Flag = 1 << 17, + const AlignmentFlag = 1 << 18, + const VirtualInterruptFlag = 1 << 19, + const VirtualInterruptPending = 1 << 20, + const CpuIdFlag = 1 << 21 + } +} + +bitflags! { + pub flags Cr0: usize { + const ProtectedMode = 1 << 0, + const MonitorCoprocessor = 1 << 1, + const EmulateCoprocessor = 1 << 2, + const TaskSwitched = 1 << 3, + const ExtensionType = 1 << 4, + const NumericError = 1 << 5, + const WriteProtect = 1 << 16, + const AlignmentMask = 1 << 18, + const NotWriteThrough = 1 << 29, + const CacheDisable = 1 << 30, + const EnablePaging = 1 << 31 + } +} + +bitflags! { + pub flags Cr4: usize { + const EnableVme = 1 << 0, + const VirtualInterrupts = 1 << 1, + const TimeStampDisable = 1 << 2, + const DebuggingExtensions = 1 << 3, + const EnablePse = 1 << 4, + const EnablePae = 1 << 5, + const EnableMachineCheck = 1 << 6, + const EnableGlobalPages = 1 << 7, + const EnablePpmc = 1 << 8, + const EnableSse = 1 << 9, + const UnmaskedSse = 1 << 10, + const EnableVmx = 1 << 13, + const EnableSmx = 1 << 14, + const EnablePcid = 1 << 17, + const EnableOsXSave = 1 << 18, + const EnableSmep = 1 << 20, + const EnableSmap = 1 << 21 + } +} + +bitflags!( + pub flags Features: u64 { + const Fpu = 1 << 0, + const Virtual8086 = 1 << 1, + const DebugExtension = 1 << 2, + const PageSizeExtension = 1 << 3, + const TimeStampCounter = 1 << 4, + const ModelSpecificRegister = 1 << 5, + const PhysicalAddressExtension = 1 << 6, + const MachineCheckException = 1 << 7, + const Cx8 = 1 << 8, // CMPXCHG8 + const Apic = 1 << 9, + const SysEnter = 1 << 11, + const MemoryTypeRange = 1 << 12, + const PageGlobal = 1 << 13, + const MachineCheckArchitecture = 1 << 14, + const CMov = 1 << 15, + const PageAttributeTable = 1 << 16, + const PageSizeExtension36 = 1 << 17, + const ProcessorSerial = 1 << 18, + const CacheFlush = 1 << 19, + const DebugStore = 1 << 21, + const Acpi = 1 << 22, + const Mmx = 1 << 23, + const FxSave = 1 << 24, + const Sse = 1 << 25, + const Sse2 = 1 << 26, + const SelfSnoop = 1 << 27, + const HyperThreading = 1 << 28, + const ThermalMonitor = 1 << 29, + const Ia64 = 1 << 30, + const PendingBreak = 1 << 31, + + const Sse3 = 1 << (32 + 0), + const PclMulQdq = 1 << (32 + 1), // what + const DebugStore64 = 1 << (32 + 2), + const Monitor = 1 << (32 + 3), + const CplDebugStore = 1 << (32 + 4), + const Vmx = 1 << (32 + 5), + const SaferMode = 1 << (32 + 6), + const EnhancedSpeedStep = 1 << (32 + 7), + const ThermalMonitor2 = 1 << (32 + 8), + const Ssse3 = 1 << (32 + 9), + const L1ContextId = 1 << (32 + 10), + const Fma = 1 << (32 + 12), + const Cx16 = 1 << (32 + 13), // CMPXCHG16B + const Xtpr = 1 << (32 + 14), // I have no idea what this is + const PerformanceMonitor = 1 << (32 + 15), + const ProcessContextId = 1 << (32 + 17), + const DirectCache = 1 << (32 + 18), + const Sse41 = 1 << (32 + 19), + const Sse42 = 1 << (32 + 20), + const X2Apic = 1 << (32 + 21), + const MovBe = 1 << (32 + 22), + const PopulationCount = 1 << (32 + 23), + const TscDeadline = 1 << (32 + 24), + const AesNi = 1 << (32 + 25), + const XSave = 1 << (32 + 26), + const OsXSave = 1 << (32 + 27), + const Avx = 1 << (32 + 28), + const HalfPrecision = 1 << (32 + 29), + const HwRandom = 1 << (32 + 30) + } +); + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum Exception { + DivisionByZero = 0, + Debug = 1, + Nmi = 2, + Breakpoint = 3, + Overflow = 4, + Bounds = 5, + InvalidOpcode = 6, + NotAvailable = 7, + DoubleFault = 8, + CoprocessorSegment = 9, + Tss = 10, + NotPresent = 11, + StackSegment = 12, + GeneralProtection = 13, + PageFault = 14, + Fpu = 16, + Alignment = 17, + MachineCheck = 18, + Simd = 19, + Virtualization = 20, + Security = 30 +} + +impl Exception { + pub fn from_code(code: u32) -> Option<Exception> { + Some(match code { + 0 => Exception::DivisionByZero, + 1 => Exception::Debug, + 2 => Exception::Nmi, + 3 => Exception::Breakpoint, + 4 => Exception::Overflow, + 5 => Exception::Bounds, + 6 => Exception::InvalidOpcode, + 7 => Exception::NotAvailable, + 8 => Exception::DoubleFault, + 9 => Exception::CoprocessorSegment, + 10 => Exception::Tss, + 11 => Exception::NotPresent, + 12 => Exception::StackSegment, + 13 => Exception::GeneralProtection, + 14 => Exception::PageFault, + 16 => Exception::Fpu, + 17 => Exception::Alignment, + 18 => Exception::MachineCheck, + 19 => Exception::Simd, + 20 => Exception::Virtualization, + 30 => Exception::Security, + + _ => return None + }) + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum Msr { + ApicBase = 0x1B +} + +#[inline(always)] +pub fn cpuid(function: u32) -> (u32, u32, u32, u32) { + unsafe { + let (eax, ebx, ecx, edx): (u32, u32, u32, u32); + asm!("cpuid" : "={eax}"(eax), "={ebx}"(ebx), "={ecx}"(ecx), "={edx}"(edx) : "{eax}"(function)); + (eax, ebx, ecx, edx) + } +} + +#[inline(always)] +pub fn supports() -> Features { + let (_, _, feature_ecx, feature_edx) = cpuid(1); + Features { + bits: ((feature_ecx as u64) << 32) | (feature_edx as u64) + } +} + +#[inline(always)] +pub unsafe fn read_msr(msr: Msr) -> u64 { + let (r1, r2): (u32, u32); + asm!("rdmsr" : "={eax}"(r1), "={edx}"(r2) : "{ecx}"(msr as u32) :: "intel"); + r1 as u64 | ((r2 as u64) << 32) +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum PrivilegeLevel { + Ring0 = 0, + Ring1 = 1, + Ring2 = 2, + Ring3 = 3, +} + +#[derive(Copy, Clone, PartialEq, Eq)] +#[repr(C, packed)] +pub struct SegmentSelector { + data: u16 +} + +impl SegmentSelector { + #[inline(always)] + pub fn new(index: u16, rpl: PrivilegeLevel) -> SegmentSelector { + SegmentSelector { + data: index << 3 | rpl as u16 + } + } + + pub fn bits(&self) -> u16 { + self.data + } +} + +#[inline(always)] +pub unsafe fn set_tr(selector: SegmentSelector) { + asm!("ltr $0" :: "r"(selector.bits()) :: "volatile", "intel"); +} + +#[inline(always)] +pub unsafe fn set_ss(selector: SegmentSelector) { + asm!("mov ss, $0" :: "r"(selector.bits()) :: "volatile", "intel"); +} + +#[inline(always)] +pub unsafe fn set_ds(selector: SegmentSelector) { + asm!("mov ds, $0" :: "r"(selector.bits()) :: "volatile", "intel"); +} + +#[inline(always)] +pub unsafe fn set_es(selector: SegmentSelector) { + asm!("mov es, $0" :: "r"(selector.bits()) :: "volatile", "intel"); +} + +#[inline(always)] +pub unsafe fn set_gs(selector: SegmentSelector) { + asm!("mov gs, $0" :: "r"(selector.bits()) :: "volatile", "intel"); +} + +#[inline(always)] +pub unsafe fn set_fs(selector: SegmentSelector) { + asm!("mov fs, $0" :: "r"(selector.bits()) :: "volatile", "intel"); +} + +#[inline(always)] +pub unsafe fn set_cs(selector: SegmentSelector) { + asm!("push $0; + push $$1f + lret; + 1:" :: "ri"(selector.bits() as usize) :: "volatile"); +} + +#[inline(always)] +pub fn get_cr0() -> Cr0 { + unsafe { + let r: usize; + asm!("mov $0, cr0" : "=r"(r) ::: "intel"); + Cr0::from_bits_truncate(r) + } +} + +#[inline(always)] +pub fn get_cr2() -> usize { + unsafe { + let r: usize; + asm!("mov $0, cr2" : "=r"(r) ::: "intel"); + r + } +} + +#[inline(always)] +pub fn get_cr3() -> usize { + unsafe { + let r: usize; + asm!("mov $0, cr3" : "=r"(r) ::: "intel"); + r + } +} + +#[inline(always)] +pub fn get_cr4() -> Cr4 { + unsafe { + let r: usize; + asm!("mov $0, cr4" : "=r"(r) ::: "intel"); + Cr4::from_bits_truncate(r) + } +} + +#[inline(always)] +pub unsafe fn set_cr0(flags: Cr0) { + asm!("mov cr0, $0" :: "r"(flags.bits()) :: "volatile", "intel"); +} + +#[inline(always)] +pub unsafe fn set_cr3(val: usize) { + asm!("mov cr3, $0" :: "r"(val) :: "volatile", "intel"); +} + +#[inline(always)] +pub unsafe fn set_cr4(flags: Cr4) { + asm!("mov cr4, $0" :: "r"(flags.bits()) :: "volatile", "intel"); +} + +#[inline(always)] +pub unsafe fn enable_interrupts() { + asm!("sti" :::: "volatile", "intel"); +} + +#[inline(always)] +pub unsafe fn disable_interrupts() { + asm!("cli" :::: "volatile", "intel"); +} + +#[inline(always)] +pub unsafe fn halt() { + asm!("hlt" :::: "volatile", "intel"); +} + +#[inline(always)] +pub unsafe fn out8(port: u16, value: u8) { + asm!("out $0, $1" :: "{dx}"(port), "{al}"(value) :: "volatile", "intel"); +} + +#[inline(always)] +pub unsafe fn out16(port: u16, value: u16) { + asm!("out $0, $1" :: "{dx}"(port), "{ax}"(value) :: "volatile", "intel"); +} + +#[inline(always)] +pub unsafe fn out32(port: u16, value: u32) { + asm!("out $0, $1" :: "{dx}"(port), "{eax}"(value) :: "volatile", "intel"); +} + +#[inline(always)] +pub unsafe fn outs8(port: u16, buf: &[u8]) { + asm!("rep outsb dx, [esi]" :: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr()) : "ecx", "edi" : "intel"); +} + +#[inline(always)] +pub unsafe fn outs16(port: u16, buf: &[u16]) { + asm!("rep outsw dx, [esi]" :: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr()) : "ecx", "edi" : "intel"); +} + +#[inline(always)] +pub unsafe fn outs32(port: u16, buf: &[u32]) { + asm!("rep outsd dx, [esi]" :: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr()) : "ecx", "edi" : "intel"); +} + + +#[inline(always)] +pub unsafe fn in8(port: u16) -> u8 { + let r: u8; + asm!("in $0, $1" : "={al}"(r) : "{dx}"(port) :: "intel"); + r +} + +#[inline(always)] +pub unsafe fn in16(port: u16) -> u16 { + let r: u16; + asm!("in $0, $1" : "={ax}"(r) : "{dx}"(port) :: "intel"); + r +} + +#[inline(always)] +pub unsafe fn in32(port: u16) -> u32 { + let r: u32; + asm!("in $0, $1" : "={eax}"(r) : "{dx}"(port) :: "intel"); + r +} + +#[inline(always)] +pub unsafe fn ins8(port: u16, buf: &mut [u8]) { + asm!("rep insb [edi], dx" :: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr()) : "ecx", "edi" : "intel"); +} + +#[inline(always)] +pub unsafe fn ins16(port: u16, buf: &mut [u16]) { + asm!("rep insw [edi], dx" :: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr()) : "ecx", "edi" : "intel"); +} + +#[inline(always)] +pub unsafe fn ins32(port: u16, buf: &mut [u32]) { + asm!("rep insd [edi], dx" :: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr()) : "ecx", "edi" : "intel"); +} |