aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bits32/mod.rs217
-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.rs52
-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.rs17
-rw-r--r--src/lib.rs61
-rw-r--r--src/shared/mod.rs418
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");
+}
diff --git a/src/lib.rs b/src/lib.rs
index ad45d7c..85ac7f2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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");
+}