aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Gerd Zellweger <mail@gerdzellweger.com> 2016-07-04 14:08:17 +0200
committerGravatar GitHub <noreply@github.com> 2016-07-04 14:08:17 +0200
commitc12e050a69dd1a9b04f07ab78a166c6371d35a6f (patch)
treefea35bcf5b507efdd4c1c0f5dab146360c70478a /src
parent32257991aaa3700620f1d6c180cfec3e2d65a360 (diff)
parentbd2950de1a48d72cbb718cc9a367142e0eb97b72 (diff)
downloadrust-x86-c12e050a69dd1a9b04f07ab78a166c6371d35a6f.tar.gz
rust-x86-c12e050a69dd1a9b04f07ab78a166c6371d35a6f.tar.zst
rust-x86-c12e050a69dd1a9b04f07ab78a166c6371d35a6f.zip
Merge pull request #16 from QuiltOS/master
Fix #15: Combine with https://github.com/Tobba/libcpu
Diffstat (limited to 'src')
-rw-r--r--src/bitflags.rs163
-rw-r--r--src/bits32/irq.rs57
-rw-r--r--src/bits32/mod.rs8
-rw-r--r--src/bits32/task.rs93
-rw-r--r--src/bits64/irq.rs143
-rw-r--r--src/bits64/mod.rs44
-rw-r--r--src/bits64/paging.rs (renamed from src/paging.rs)60
-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/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)14
-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/controlregs.rs43
-rw-r--r--src/dtables.rs27
-rw-r--r--src/io.rs37
-rw-r--r--src/irq.rs340
-rw-r--r--src/lib.rs70
-rw-r--r--src/rflags.rs56
-rw-r--r--src/segmentation.rs214
-rw-r--r--src/shared/control_regs.rs84
-rw-r--r--src/shared/descriptor.rs194
-rw-r--r--src/shared/dtables.rs61
-rw-r--r--src/shared/flags.rs102
-rw-r--r--src/shared/io.rs80
-rw-r--r--src/shared/irq.rs207
-rw-r--r--src/shared/mod.rs24
-rw-r--r--src/shared/msr.rs (renamed from src/msr.rs)4
-rw-r--r--src/shared/paging.rs48
-rw-r--r--src/shared/segmentation.rs262
-rw-r--r--src/shared/task.rs9
34 files changed, 1452 insertions, 1004 deletions
diff --git a/src/bitflags.rs b/src/bitflags.rs
deleted file mode 100644
index 8d16e41..0000000
--- a/src/bitflags.rs
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-macro_rules! bitflags {
- ($(#[$attr:meta])* flags $BitFlags:ident: $T:ty {
- $($(#[$Flag_attr:meta])* const $Flag:ident = $value:expr),+
- }) => {
- #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
- $(#[$attr])*
- pub struct $BitFlags {
- bits: $T,
- }
-
- $($(#[$Flag_attr])* pub const $Flag: $BitFlags = $BitFlags { bits: $value };)+
-
- impl $BitFlags {
- /// Returns an empty set of flags.
- #[inline]
- pub fn empty() -> $BitFlags {
- $BitFlags { bits: 0 }
- }
-
- /// Returns the set containing all flags.
- #[inline]
- pub fn all() -> $BitFlags {
- $BitFlags { bits: $($value)|+ }
- }
-
- /// Returns the raw value of the flags currently stored.
- #[inline]
- pub fn bits(&self) -> $T {
- self.bits
- }
-
- /// Convert from underlying bit representation, unless that
- /// representation contains bits that do not correspond to a flag.
- #[inline]
- pub fn from_bits(bits: $T) -> ::std::option::Option<$BitFlags> {
- if (bits & !$BitFlags::all().bits()) != 0 {
- ::std::option::Option::None
- } else {
- ::std::option::Option::Some($BitFlags { bits: bits })
- }
- }
-
- /// Convert from underlying bit representation, dropping any bits
- /// that do not correspond to flags.
- #[inline]
- pub fn from_bits_truncate(bits: $T) -> $BitFlags {
- $BitFlags { bits: bits } & $BitFlags::all()
- }
-
- /// Returns `true` if no flags are currently stored.
- #[inline]
- pub fn is_empty(&self) -> bool {
- *self == $BitFlags::empty()
- }
-
- /// Returns `true` if all flags are currently set.
- #[inline]
- pub fn is_all(&self) -> bool {
- *self == $BitFlags::all()
- }
-
- /// Returns `true` if there are flags common to both `self` and `other`.
- #[inline]
- pub fn intersects(&self, other: $BitFlags) -> bool {
- !(*self & other).is_empty()
- }
-
- /// Returns `true` all of the flags in `other` are contained within `self`.
- #[inline]
- pub fn contains(&self, other: $BitFlags) -> bool {
- (*self & other) == other
- }
-
- /// Inserts the specified flags in-place.
- #[inline]
- pub fn insert(&mut self, other: $BitFlags) {
- self.bits |= other.bits;
- }
-
- /// Removes the specified flags in-place.
- #[inline]
- pub fn remove(&mut self, other: $BitFlags) {
- self.bits &= !other.bits;
- }
-
- /// Toggles the specified flags in-place.
- #[inline]
- pub fn toggle(&mut self, other: $BitFlags) {
- self.bits ^= other.bits;
- }
- }
-
- impl ::std::ops::BitOr for $BitFlags {
- type Output = $BitFlags;
-
- /// Returns the union of the two sets of flags.
- #[inline]
- fn bitor(self, other: $BitFlags) -> $BitFlags {
- $BitFlags { bits: self.bits | other.bits }
- }
- }
-
- impl ::std::ops::BitXor for $BitFlags {
- type Output = $BitFlags;
-
- /// Returns the left flags, but with all the right flags toggled.
- #[inline]
- fn bitxor(self, other: $BitFlags) -> $BitFlags {
- $BitFlags { bits: self.bits ^ other.bits }
- }
- }
-
- impl ::std::ops::BitAnd for $BitFlags {
- type Output = $BitFlags;
-
- /// Returns the intersection between the two sets of flags.
- #[inline]
- fn bitand(self, other: $BitFlags) -> $BitFlags {
- $BitFlags { bits: self.bits & other.bits }
- }
- }
-
- impl ::std::ops::Sub for $BitFlags {
- type Output = $BitFlags;
-
- /// Returns the set difference of the two sets of flags.
- #[inline]
- fn sub(self, other: $BitFlags) -> $BitFlags {
- $BitFlags { bits: self.bits & !other.bits }
- }
- }
-
- impl ::std::ops::Not for $BitFlags {
- type Output = $BitFlags;
-
- /// Returns the complement of this set of flags.
- #[inline]
- fn not(self) -> $BitFlags {
- $BitFlags { bits: !self.bits } & $BitFlags::all()
- }
- }
- };
- ($(#[$attr:meta])* flags $BitFlags:ident: $T:ty {
- $($(#[$Flag_attr:meta])* const $Flag:ident = $value:expr),+,
- }) => {
- bitflags! {
- $(#[$attr])*
- flags $BitFlags: $T {
- $($(#[$Flag_attr])* const $Flag = $value),+
- }
- }
- };
-}
diff --git a/src/bits32/irq.rs b/src/bits32/irq.rs
new file mode 100644
index 0000000..5d6eb0d
--- /dev/null
+++ b/src/bits32/irq.rs
@@ -0,0 +1,57 @@
+//! Interrupt description and set-up code.
+
+use shared::descriptor::*;
+use shared::paging::VAddr;
+use shared::PrivilegeLevel;
+
+/// An interrupt gate or trap gate descriptor.
+///
+/// See Intel manual 3a for details, specifically section 6.11.
+#[derive(Debug, Copy, Clone)]
+#[repr(C, packed)]
+pub struct IdtEntry {
+ /// Lower 16 bits of ISR.
+ pub offset_lo: u16,
+ /// Segment selector.
+ pub selector: u16,
+ /// This must always be zero.
+ pub reserved: u8,
+ /// flags.
+ pub flags: Flags,
+ /// The upper 16 bits of ISR.
+ pub offset_hi: u16
+}
+
+impl IdtEntry {
+ pub const MISSING: IdtEntry = IdtEntry {
+ offset_lo: 0,
+ selector: 0,
+ reserved: 0,
+ flags: Flags::BLANK,
+ offset_hi: 0
+ };
+
+ /// Create a new IdtEntry pointing at `handler`, which must be a function
+ /// with interrupt calling conventions. (This must be currently defined in
+ /// assembly language.) The `gdt_code_selector` value must be the offset of
+ /// code segment entry in the GDT.
+ ///
+ /// The "Present" flag set, which is the most common case. If you need
+ /// something else, you can construct it manually.
+ pub const fn new(handler: VAddr, gdt_code_selector: u16,
+ dpl: PrivilegeLevel, block: bool) -> IdtEntry {
+ IdtEntry {
+ offset_lo: ((handler.as_usize() as u32) & 0xFFFF) as u16,
+ offset_hi: ((handler.as_usize() as u32 & 0xFFFF0000) >> 16) as u16,
+ selector: gdt_code_selector,
+ reserved: 0,
+ // Nice bitflags operations don't work in const fn, hence these
+ // ad-hoc methods.
+ flags: Flags::from_priv(dpl)
+ .const_or(FLAGS_TYPE_SYS_NATIVE_INTERRUPT_GATE
+ .const_mux(FLAGS_TYPE_SYS_NATIVE_TRAP_GATE,
+ block))
+ .const_or(FLAGS_PRESENT),
+ }
+ }
+}
diff --git a/src/bits32/mod.rs b/src/bits32/mod.rs
new file mode 100644
index 0000000..e98b862
--- /dev/null
+++ b/src/bits32/mod.rs
@@ -0,0 +1,8 @@
+pub mod irq;
+pub mod task;
+
+#[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/bits32/task.rs b/src/bits32/task.rs
new file mode 100644
index 0000000..17bdcd4
--- /dev/null
+++ b/src/bits32/task.rs
@@ -0,0 +1,93 @@
+//! Helpers to program the task state segment.
+//! See Intel 3a, Chapter 7
+
+use core::mem::size_of;
+
+#[derive(Copy, Clone, Debug)]
+#[repr(C, packed)]
+pub struct TaskStateSegment {
+ 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 TaskStateSegment {
+ pub fn new() -> TaskStateSegment {
+ TaskStateSegment {
+ 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::<TaskStateSegment>() as u16
+ }
+ }
+}
diff --git a/src/bits64/irq.rs b/src/bits64/irq.rs
new file mode 100644
index 0000000..84ee0e6
--- /dev/null
+++ b/src/bits64/irq.rs
@@ -0,0 +1,143 @@
+//! Interrupt description and set-up code.
+
+use core::fmt;
+
+use shared::descriptor::*;
+use shared::paging::VAddr;
+use shared::PrivilegeLevel;
+
+/// An interrupt gate descriptor.
+///
+/// See Intel manual 3a for details, specifically section "6.14.1 64-Bit Mode
+/// IDT" and "Table 3-2. System-Segment and Gate-Descriptor Types".
+#[derive(Debug, Clone, Copy)]
+#[repr(C, packed)]
+pub struct IdtEntry {
+ /// Lower 16 bits of ISR.
+ pub base_lo: u16,
+ /// Segment selector.
+ pub selector: u16,
+ /// This must always be zero.
+ pub reserved0: u8,
+ /// Flags.
+ pub flags: Flags,
+ /// The upper 48 bits of ISR (the last 16 bits must be zero).
+ pub base_hi: u64,
+ /// Must be zero.
+ pub reserved1: u16,
+}
+
+impl IdtEntry {
+ /// A "missing" IdtEntry.
+ ///
+ /// If the CPU tries to invoke a missing interrupt, it will instead
+ /// send a General Protection fault (13), with the interrupt number and
+ /// some other data stored in the error code.
+ pub const MISSING: IdtEntry = IdtEntry {
+ base_lo: 0,
+ selector: 0,
+ reserved0: 0,
+ flags: Flags::BLANK,
+ base_hi: 0,
+ reserved1: 0,
+ };
+
+ /// Create a new IdtEntry pointing at `handler`, which must be a function
+ /// with interrupt calling conventions. (This must be currently defined in
+ /// assembly language.) The `gdt_code_selector` value must be the offset of
+ /// code segment entry in the GDT.
+ ///
+ /// The "Present" flag set, which is the most common case. If you need
+ /// something else, you can construct it manually.
+ pub const fn new(handler: VAddr, gdt_code_selector: u16,
+ dpl: PrivilegeLevel, block: bool) -> IdtEntry {
+ IdtEntry {
+ base_lo: ((handler.as_usize() as u64) & 0xFFFF) as u16,
+ base_hi: handler.as_usize() as u64 >> 16,
+ selector: gdt_code_selector,
+ reserved0: 0,
+ // Nice bitflags operations don't work in const fn, hence these
+ // ad-hoc methods.
+ flags: Flags::from_priv(dpl)
+ .const_or(FLAGS_TYPE_SYS_NATIVE_INTERRUPT_GATE
+ .const_mux(FLAGS_TYPE_SYS_NATIVE_TRAP_GATE,
+ block))
+ .const_or(FLAGS_PRESENT),
+ reserved1: 0,
+ }
+ }
+}
+
+bitflags!{
+ // Taken from Intel Manual Section 4.7 Page-Fault Exceptions.
+ pub flags PageFaultError: u32 {
+ /// 0: The fault was caused by a non-present page.
+ /// 1: The fault was caused by a page-level protection violation
+ const PFAULT_ERROR_P = bit!(0),
+
+ /// 0: The access causing the fault was a read.
+ /// 1: The access causing the fault was a write.
+ const PFAULT_ERROR_WR = bit!(1),
+
+ /// 0: The access causing the fault originated when the processor
+ /// was executing in supervisor mode.
+ /// 1: The access causing the fault originated when the processor
+ /// was executing in user mode.
+ const PFAULT_ERROR_US = bit!(2),
+
+ /// 0: The fault was not caused by reserved bit violation.
+ /// 1: The fault was caused by reserved bits set to 1 in a page directory.
+ const PFAULT_ERROR_RSVD = bit!(3),
+
+ /// 0: The fault was not caused by an instruction fetch.
+ /// 1: The fault was caused by an instruction fetch.
+ const PFAULT_ERROR_ID = bit!(4),
+
+ /// 0: The fault was not by protection keys.
+ /// 1: There was a protection key violation.
+ const PFAULT_ERROR_PK = bit!(5),
+ }
+}
+
+impl fmt::Display for PageFaultError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let p = match self.contains(PFAULT_ERROR_P) {
+ false => "The fault was caused by a non-present page.",
+ true => "The fault was caused by a page-level protection violation.",
+ };
+ let wr = match self.contains(PFAULT_ERROR_WR) {
+ false => "The access causing the fault was a read.",
+ true => "The access causing the fault was a write.",
+ };
+ let us = match self.contains(PFAULT_ERROR_US) {
+ false => {
+ "The access causing the fault originated when the processor was executing in \
+ supervisor mode."
+ }
+ true => {
+ "The access causing the fault originated when the processor was executing in user \
+ mode."
+ }
+ };
+ let rsvd = match self.contains(PFAULT_ERROR_RSVD) {
+ false => "The fault was not caused by reserved bit violation.",
+ true => "The fault was caused by reserved bits set to 1 in a page directory.",
+ };
+ let id = match self.contains(PFAULT_ERROR_ID) {
+ false => "The fault was not caused by an instruction fetch.",
+ true => "The fault was caused by an instruction fetch.",
+ };
+
+ write!(f, "{}\n{}\n{}\n{}\n{}", p, wr, us, rsvd, id)
+ }
+}
+
+#[test]
+fn bit_macro() {
+ assert!(PFAULT_ERROR_PK.bits() == 0b100000);
+ assert!(PFAULT_ERROR_ID.bits() == 0b10000);
+ assert!(PFAULT_ERROR_RSVD.bits() == 0b1000);
+ assert!(PFAULT_ERROR_US.bits() == 0b100);
+ assert!(PFAULT_ERROR_WR.bits() == 0b10);
+ assert!(PFAULT_ERROR_P.bits() == 0b1);
+}
diff --git a/src/bits64/mod.rs b/src/bits64/mod.rs
new file mode 100644
index 0000000..4b83c7c
--- /dev/null
+++ b/src/bits64/mod.rs
@@ -0,0 +1,44 @@
+//! 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 time;
+pub mod irq;
+pub mod paging;
+pub mod task;
+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/paging.rs b/src/bits64/paging.rs
index 22d9526..47ac8ed 100644
--- a/src/paging.rs
+++ b/src/bits64/paging.rs
@@ -1,14 +1,13 @@
//! Description of the data-structures for IA-32e paging mode.
+
use core::fmt;
+use shared::paging::*;
+
/// Represents a physical memory address
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct PAddr(u64);
-/// Represent a virtual (linear) memory address
-#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
-pub struct VAddr(usize);
-
impl PAddr {
/// Convert to `u64`
pub const fn as_u64(&self) -> u64 {
@@ -20,17 +19,6 @@ impl PAddr {
}
}
-impl VAddr {
- /// Convert to `usize`
- pub const fn as_usize(&self) -> usize {
- self.0
- }
- /// Convert from `usize`
- pub const fn from_usize(v: usize) -> Self {
- VAddr(v)
- }
-}
-
impl fmt::Binary for PAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
@@ -61,36 +49,6 @@ impl fmt::UpperHex for PAddr {
}
}
-impl fmt::Binary for VAddr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.0.fmt(f)
- }
-}
-
-impl fmt::Display for VAddr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.0.fmt(f)
- }
-}
-
-impl fmt::LowerHex for VAddr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.0.fmt(f)
- }
-}
-
-impl fmt::Octal for VAddr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.0.fmt(f)
- }
-}
-
-impl fmt::UpperHex for VAddr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.0.fmt(f)
- }
-}
-
pub const BASE_PAGE_SIZE: u64 = 4096; // 4 KiB
pub const LARGE_PAGE_SIZE: u64 = 1024 * 1024 * 2; // 2 MiB
pub const HUGE_PAGE_SIZE: u64 = 1024 * 1024 * 1024; // 1 GiB
@@ -140,8 +98,7 @@ pub fn pt_index(addr: VAddr) -> usize {
/// PML4 Entry bits description.
bitflags! {
- #[derive(Debug)]
- flags PML4Entry: u64 {
+ pub flags PML4Entry: u64 {
/// Present; must be 1 to reference a page-directory-pointer table
const PML4_P = bit!(0),
/// Read/write; if 0, writes may not be allowed to the 512-GByte region
@@ -200,8 +157,7 @@ impl PML4Entry {
/// PDPT Entry bits description.
bitflags! {
- #[derive(Debug)]
- flags PDPTEntry: u64 {
+ pub flags PDPTEntry: u64 {
/// Present; must be 1 to map a 1-GByte page or reference a page directory.
const PDPT_P = bit!(0),
/// Read/write; if 0, writes may not be allowed to the 1-GByte region controlled by this entry
@@ -269,8 +225,7 @@ impl PDPTEntry {
/// PD Entry bits description.
bitflags! {
- #[derive(Debug)]
- flags PDEntry: u64 {
+ pub flags PDEntry: u64 {
/// Present; must be 1 to map a 2-MByte page or reference a page table.
const PD_P = bit!(0),
/// Read/write; if 0, writes may not be allowed to the 2-MByte region controlled by this entry
@@ -345,8 +300,7 @@ impl PDEntry {
/// PT Entry bits description.
bitflags! {
- #[derive(Debug)]
- flags PTEntry: u64 {
+ pub flags PTEntry: u64 {
/// Present; must be 1 to map a 4-KByte page.
const PT_P = bit!(0),
/// Read/write; if 0, writes may not be allowed to the 4-KByte region controlled by this entry
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/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..1d98bad 100644
--- a/src/task.rs
+++ b/src/bits64/task.rs
@@ -1,6 +1,7 @@
//! Helpers to program the task state segment.
+//! See Intel 3a, Chapter 7, Section 7
-use segmentation;
+use shared::segmentation;
pub type TaskStateDescriptorLow = segmentation::SegmentDescriptor;
pub type TaskStateDescriptorHigh = u64;
@@ -25,20 +26,15 @@ pub struct TaskStateSegment {
}
impl TaskStateSegment {
- pub fn new() -> TaskStateSegment {
+ pub const fn new() -> TaskStateSegment {
TaskStateSegment {
reserved: 0,
- rsp: [0, 0, 0],
+ rsp: [0; 3],
reserved2: 0,
- ist: [0, 0, 0, 0, 0, 0, 0],
+ ist: [0; 7],
reserved3: 0,
reserved4: 0,
iomap_base: 0,
}
}
}
-
-/// Load the task state register.
-pub unsafe fn load_ltr(sel: segmentation::SegmentSelector) {
- asm!("ltr $0" :: "r" (sel));
-}
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..f99604f 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 shared::control_regs::{cr3, cr3_write};
cr3_write(cr3())
}
diff --git a/src/controlregs.rs b/src/controlregs.rs
deleted file mode 100644
index c243caf..0000000
--- a/src/controlregs.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-//! Functions to read and write control registers.
-
-pub unsafe fn cr0() -> u64 {
- let ret: u64;
- asm!("mov %cr0, $0" : "=r" (ret));
- ret
-}
-
-/// Write cr0.
-pub unsafe fn cr0_write(val: u64) {
- asm!("mov $0, %cr0" :: "r" (val) : "memory");
-}
-
-/// Contains page-fault linear address.
-pub unsafe fn cr2() -> u64 {
- let ret: u64;
- asm!("mov %cr2, $0" : "=r" (ret));
- ret
-}
-
-/// Contains page-table root pointer.
-pub unsafe fn cr3() -> u64 {
- let ret: u64;
- asm!("mov %cr3, $0" : "=r" (ret));
- ret
-}
-
-/// Switch page-table PML4 pointer.
-pub unsafe fn cr3_write(val: u64) {
- asm!("mov $0, %cr3" :: "r" (val) : "memory");
-}
-
-/// Contains various flags to control operations in protected mode.
-pub unsafe fn cr4() -> u64 {
- let ret: u64;
- asm!("mov %cr4, $0" : "=r" (ret));
- ret
-}
-
-/// Write cr4.
-pub unsafe fn cr4_write(val: u64) {
- asm!("mov $0, %cr4" :: "r" (val) : "memory");
-}
diff --git a/src/dtables.rs b/src/dtables.rs
deleted file mode 100644
index d2e3413..0000000
--- a/src/dtables.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-//! Functions and data-structures to load descriptor tables.
-
-/// A struct describing a pointer to a descriptor table (GDT / IDT).
-/// This is in a format suitable for giving to 'lgdt' or 'lidt'.
-#[derive(Debug)]
-#[repr(C, packed)]
-pub struct DescriptorTablePointer {
- /// Size of the DT.
- pub limit: u16,
- /// Pointer to the memory region containing the DT.
- pub base: u64,
-}
-
-/// Load GDT table.
-pub unsafe fn lgdt(gdt: &DescriptorTablePointer) {
- asm!("lgdt ($0)" :: "r" (gdt) : "memory");
-}
-
-/// Load LDT table.
-pub unsafe fn lldt(ldt: &DescriptorTablePointer) {
- asm!("lldt ($0)" :: "r" (ldt) : "memory");
-}
-
-/// Load IDT table.
-pub unsafe fn lidt(idt: &DescriptorTablePointer) {
- asm!("lidt ($0)" :: "r" (idt) : "memory");
-}
diff --git a/src/io.rs b/src/io.rs
deleted file mode 100644
index bb7cfb0..0000000
--- a/src/io.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-//! I/O port functionality.
-
-/// Write 8 bits to port
-pub unsafe fn outb(port: u16, val: u8) {
- asm!("outb %al, %dx" :: "{dx}"(port), "{al}"(val));
-}
-
-/// Read 8 bits from port
-pub unsafe fn inb(port: u16) -> u8 {
- let ret: u8;
- asm!("inb %dx, %al" : "={ax}"(ret) : "{dx}"(port) :: "volatile");
- return ret;
-}
-
-/// Write 16 bits to port
-pub unsafe fn outw(port: u16, val: u16) {
- asm!("outw %ax, %dx" :: "{dx}"(port), "{al}"(val));
-}
-
-/// Read 16 bits from port
-pub unsafe fn inw(port: u16) -> u16 {
- let ret: u16;
- asm!("inw %dx, %ax" : "={ax}"(ret) : "{dx}"(port) :: "volatile");
- return ret;
-}
-
-/// Write 32 bits to port
-pub unsafe fn outl(port: u16, val: u32) {
- asm!("outl %eax, %dx" :: "{dx}"(port), "{al}"(val));
-}
-
-/// Read 32 bits from port
-pub unsafe fn inl(port: u16) -> u32 {
- let ret: u32;
- asm!("inl %dx, %eax" : "={ax}"(ret) : "{dx}"(port) :: "volatile");
- return ret;
-}
diff --git a/src/irq.rs b/src/irq.rs
deleted file mode 100644
index 10be7fa..0000000
--- a/src/irq.rs
+++ /dev/null
@@ -1,340 +0,0 @@
-//! Interrupt description and set-up code.
-
-use core::fmt;
-use paging::VAddr;
-
-/// x86 Exception description (see also Intel Vol. 3a Chapter 6).
-#[derive(Debug)]
-pub struct InterruptDescription {
- pub vector: u8,
- pub mnemonic: &'static str,
- pub description: &'static str,
- pub irqtype: &'static str,
- pub source: &'static str,
-}
-
-impl fmt::Display for InterruptDescription {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f,
- "{} ({}, vec={}) {}",
- self.mnemonic,
- self.irqtype,
- self.vector,
- self.description)
- }
-}
-
-
-/// x86 External Interrupts (1-16).
-pub static EXCEPTIONS: [InterruptDescription; 21] = [InterruptDescription {
- vector: 0,
- mnemonic: "#DE",
- description: "Divide Error",
- irqtype: "Fault",
- source: "DIV and IDIV instructions.",
- },
- InterruptDescription {
- vector: 1,
- mnemonic: "#DB",
- description: "Debug",
- irqtype: "Fault/ Trap",
- source: "Debug condition",
- },
- InterruptDescription {
- vector: 2,
- mnemonic: "NMI",
- description: "Nonmaskable Interrupt",
- irqtype: "Interrupt",
- source: "Nonmaskable external interrupt.",
- },
- InterruptDescription {
- vector: 3,
- mnemonic: "#BP",
- description: "Breakpoint",
- irqtype: "Trap",
- source: "INT 3 instruction.",
- },
- InterruptDescription {
- vector: 4,
- mnemonic: "#OF",
- description: "Overflow",
- irqtype: "Trap",
- source: "INTO instruction.",
- },
- InterruptDescription {
- vector: 5,
- mnemonic: "#BR",
- description: "BOUND Range Exceeded",
- irqtype: "Fault",
- source: "BOUND instruction.",
- },
- InterruptDescription {
- vector: 6,
- mnemonic: "#UD",
- description: "Invalid Opcode (Undefined \
- Opcode)",
- irqtype: "Fault",
- source: "UD2 instruction or reserved \
- opcode.",
- },
- InterruptDescription {
- vector: 7,
- mnemonic: "#NM",
- description: "Device Not Available (No \
- Math Coprocessor)",
- irqtype: "Fault",
- source: "Floating-point or WAIT/FWAIT \
- instruction.",
- },
- InterruptDescription {
- vector: 8,
- mnemonic: "#DF",
- description: "Double Fault",
- irqtype: "Abort",
- source: "Any instruction that can \
- generate an exception, an NMI, \
- or an INTR.",
- },
- InterruptDescription {
- vector: 9,
- mnemonic: "",
- description: "Coprocessor Segment Overrun",
- irqtype: "Fault",
- source: "Floating-point instruction.",
- },
- InterruptDescription {
- vector: 10,
- mnemonic: "#TS",
- description: "Invalid TSS",
- irqtype: "Fault",
- source: "Task switch or TSS access.",
- },
- InterruptDescription {
- vector: 11,
- mnemonic: "#NP",
- description: "Segment Not Present",
- irqtype: "Fault",
- source: "Loading segment registers or \
- accessing system segments.",
- },
- InterruptDescription {
- vector: 12,
- mnemonic: "#SS",
- description: "Stack-Segment Fault",
- irqtype: "Fault",
- source: "Stack operations and SS register \
- loads.",
- },
- InterruptDescription {
- vector: 13,
- mnemonic: "#GP",
- description: "General Protection",
- irqtype: "Fault",
- source: "Any memory reference and other \
- protection checks.",
- },
- InterruptDescription {
- vector: 14,
- mnemonic: "#PF",
- description: "Page Fault",
- irqtype: "Fault",
- source: "Any memory reference.",
- },
- InterruptDescription {
- vector: 15,
- mnemonic: "",
- description: "RESERVED",
- irqtype: "",
- source: "None.",
- },
- InterruptDescription {
- vector: 16,
- mnemonic: "#MF",
- description: "x87 FPU Floating-Point",
- irqtype: "Fault",
- source: "x87 FPU instructions.",
- },
- InterruptDescription {
- vector: 17,
- mnemonic: "#AC",
- description: "Alignment Check",
- irqtype: "Fault",
- source: "Unaligned memory access.",
- },
- InterruptDescription {
- vector: 18,
- mnemonic: "#MC",
- description: "Machine Check",
- irqtype: "Abort",
- source: "Internal machine error.",
- },
- InterruptDescription {
- vector: 19,
- mnemonic: "#XM",
- description: "SIMD Floating-Point",
- irqtype: "Fault",
- source: "SSE SIMD instructions.",
- },
- InterruptDescription {
- vector: 20,
- mnemonic: "#VE",
- description: "Virtualization",
- irqtype: "Fault",
- source: "EPT violation.",
- }];
-
-
-/// Enable Interrupts.
-pub unsafe fn enable() {
- asm!("sti");
-}
-
-/// Disable Interrupts.
-pub unsafe fn disable() {
- asm!("cli");
-}
-
-/// Generate a software interrupt.
-/// This is a macro argument needs to be an immediate.
-#[macro_export]
-macro_rules! int {
- ( $x:expr ) => {
- {
- asm!("int $0" :: "N" ($x));
- }
- };
-}
-
-/// A struct describing an interrupt gate. See the Intel manual mentioned
-/// above for details, specifically, the section "6.14.1 64-Bit Mode IDT"
-/// and "Table 3-2. System-Segment and Gate-Descriptor Types".
-#[derive(Debug, Clone, Copy)]
-#[repr(C, packed)]
-pub struct IdtEntry {
- /// Lower 16 bits of ISR.
- pub base_lo: u16,
- /// Segment selector.
- pub sel: u16,
- /// This must always be zero.
- pub res0: u8,
- /// Flags.
- pub flags: u8,
- /// The upper 48 bits of ISR (the last 16 bits must be zero).
- pub base_hi: u64,
- /// Must be zero.
- pub res1: u16,
-}
-
-impl IdtEntry {
- /// Create a "missing" IdtEntry. This is a `const` function, so we can
- /// call it at compile time to initialize static variables.
- ///
- /// If the CPU tries to invoke a missing interrupt, it will instead
- /// send a General Protection fault (13), with the interrupt number and
- /// some other data stored in the error code.
- pub const fn missing() -> IdtEntry {
- IdtEntry {
- base_lo: 0,
- sel: 0,
- res0: 0,
- flags: 0,
- base_hi: 0,
- res1: 0,
- }
- }
-
- /// Create a new IdtEntry pointing at `handler`, which must be a
- /// function with interrupt calling conventions. (This must be
- /// currently defined in assembly language.) The `gdt_code_selector`
- /// value must be the offset of code segment entry in the GDT.
- ///
- /// Create an interrupt gate with the "Present" flag set, which is the
- /// most common case. If you need something else, you can construct it
- /// manually.
- pub const fn interrupt_gate(gdt_code_selector: u16, handler: VAddr) -> IdtEntry {
- IdtEntry {
- base_lo: ((handler.as_usize() as u64) & 0xFFFF) as u16,
- sel: gdt_code_selector,
- res0: 0,
- // Bit 7: "Present" flag set.
- // Bits 0-4: This is an interrupt gate.
- flags: 0b1000_1110,
- base_hi: handler.as_usize() as u64 >> 16,
- res1: 0,
- }
- }
-}
-
-bitflags!{
- // Taken from Intel Manual Section 4.7 Page-Fault Exceptions.
- flags PageFaultError: u32 {
- /// 0: The fault was caused by a non-present page.
- /// 1: The fault was caused by a page-level protection violation
- const PFAULT_ERROR_P = bit!(0),
-
- /// 0: The access causing the fault was a read.
- /// 1: The access causing the fault was a write.
- const PFAULT_ERROR_WR = bit!(1),
-
- /// 0: The access causing the fault originated when the processor
- /// was executing in supervisor mode.
- /// 1: The access causing the fault originated when the processor
- /// was executing in user mode.
- const PFAULT_ERROR_US = bit!(2),
-
- /// 0: The fault was not caused by reserved bit violation.
- /// 1: The fault was caused by reserved bits set to 1 in a page directory.
- const PFAULT_ERROR_RSVD = bit!(3),
-
- /// 0: The fault was not caused by an instruction fetch.
- /// 1: The fault was caused by an instruction fetch.
- const PFAULT_ERROR_ID = bit!(4),
-
- /// 0: The fault was not by protection keys.
- /// 1: There was a protection key violation.
- const PFAULT_ERROR_PK = bit!(5),
- }
-}
-
-impl fmt::Debug for PageFaultError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let p = match self.contains(PFAULT_ERROR_P) {
- false => "The fault was caused by a non-present page.",
- true => "The fault was caused by a page-level protection violation.",
- };
- let wr = match self.contains(PFAULT_ERROR_WR) {
- false => "The access causing the fault was a read.",
- true => "The access causing the fault was a write.",
- };
- let us = match self.contains(PFAULT_ERROR_US) {
- false => {
- "The access causing the fault originated when the processor was executing in \
- supervisor mode."
- }
- true => {
- "The access causing the fault originated when the processor was executing in user \
- mode."
- }
- };
- let rsvd = match self.contains(PFAULT_ERROR_RSVD) {
- false => "The fault was not caused by reserved bit violation.",
- true => "The fault was caused by reserved bits set to 1 in a page directory.",
- };
- let id = match self.contains(PFAULT_ERROR_ID) {
- false => "The fault was not caused by an instruction fetch.",
- true => "The fault was caused by an instruction fetch.",
- };
-
- write!(f, "{}\n{}\n{}\n{}\n{}", p, wr, us, rsvd, id)
- }
-}
-
-#[test]
-fn bit_macro() {
- assert!(PFAULT_ERROR_PK.bits() == 0b100000);
- assert!(PFAULT_ERROR_ID.bits() == 0b10000);
- assert!(PFAULT_ERROR_RSVD.bits() == 0b1000);
- assert!(PFAULT_ERROR_US.bits() == 0b100);
- assert!(PFAULT_ERROR_WR.bits() == 0b10);
- assert!(PFAULT_ERROR_P.bits() == 0b1);
-}
diff --git a/src/lib.rs b/src/lib.rs
index 3d2ead5..27bd00f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,13 +1,13 @@
+#![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]
-mod bitflags;
+extern crate bitflags;
#[macro_use]
extern crate raw_cpuid;
@@ -16,57 +16,21 @@ 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;
+
+pub mod current {
+ #[cfg(target_arch="x86")]
+ pub use bits32::*;
+ #[cfg(target_arch="x86_64")]
+ pub use bits64::*;
+}
+
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/rflags.rs b/src/rflags.rs
deleted file mode 100644
index 6af25b1..0000000
--- a/src/rflags.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-//! Description of RFlag values that store the results of operations and the state of the processor.
-
-/// RFLAGS description.
-bitflags! {
- flags RFlags: u64 {
- /// ID Flag (ID)
- const RFLAGS_ID = 1 << 21,
- /// Virtual Interrupt Pending (VIP)
- const RFLAGS_VIP = 1 << 20,
- /// Virtual Interrupt Flag (VIF)
- const RFLAGS_VIF = 1 << 19,
- /// Alignment Check (AC)
- const RFLAGS_AC = 1 << 18,
- /// Virtual-8086 Mode (VM)
- const RFLAGS_VM = 1 << 17,
- /// Resume Flag (RF)
- const RFLAGS_RF = 1 << 16,
- /// Nested Task (NT)
- const RFLAGS_NT = 1 << 14,
- /// I/O Privilege Level (IOPL) 0
- const RFLAGS_IOPL0 = 0 << 12,
- /// I/O Privilege Level (IOPL) 1
- const RFLAGS_IOPL1 = 1 << 12,
- /// I/O Privilege Level (IOPL) 2
- const RFLAGS_IOPL2 = 2 << 12,
- /// I/O Privilege Level (IOPL) 3
- const RFLAGS_IOPL3 = 3 << 12,
- /// Overflow Flag (OF)
- const RFLAGS_OF = 1 << 11,
- /// Direction Flag (DF)
- const RFLAGS_DF = 1 << 10,
- /// Interrupt Enable Flag (IF)
- const RFLAGS_IF = 1 << 9,
- /// Trap Flag (TF)
- const RFLAGS_TF = 1 << 8,
- /// Sign Flag (SF)
- const RFLAGS_SF = 1 << 7,
- /// Zero Flag (ZF)
- const RFLAGS_ZF = 1 << 6,
- /// Auxiliary Carry Flag (AF)
- const RFLAGS_AF = 1 << 4,
- /// Parity Flag (PF)
- const RFLAGS_PF = 1 << 2,
- /// Bit 1 is always 1.
- const RFLAGS_A1 = 1 << 1,
- /// Carry Flag (CF)
- const RFLAGS_CF = 1 << 0,
- }
-}
-
-impl RFlags {
- /// Creates a new RFlags entry. Ensures bit 1 is set.
- pub fn new() -> RFlags {
- RFLAGS_A1
- }
-}
diff --git a/src/segmentation.rs b/src/segmentation.rs
deleted file mode 100644
index e3c259e..0000000
--- a/src/segmentation.rs
+++ /dev/null
@@ -1,214 +0,0 @@
-//! Program x86 segmentation hardware.
-
-use core::fmt;
-
-/// Specifies which element to load into a segment from
-/// descriptor tables (i.e., is a index to LDT or GDT table
-/// with some additional flags).
-bitflags! {
- flags SegmentSelector: u16 {
- /// Requestor Privilege Level
- const RPL_0 = 0b00,
- const RPL_1 = 0b01,
- const RPL_2 = 0b10,
- const RPL_3 = 0b11,
-
- /// Table Indicator (TI) 0 means GDT is used.
- const TI_GDT = 0 << 3,
- /// Table Indicator (TI) 1 means LDT is used.
- const TI_LDT = 1 << 3,
- }
-}
-
-impl SegmentSelector {
- /// Create a new SegmentSelector
- ///
- /// # Arguments
- /// * `index` index in GDT or LDT array.
- ///
- pub fn new(index: u16) -> SegmentSelector {
- SegmentSelector { bits: index << 3 }
- }
-
- pub fn from_raw(bits: u16) -> SegmentSelector {
- SegmentSelector { bits: bits }
- }
-}
-
-impl fmt::Debug for SegmentSelector {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let r0 = match self.contains(RPL_0) {
- false => "",
- true => "Ring 0 segment selector.",
- };
- let r1 = match self.contains(RPL_1) {
- false => "",
- true => "Ring 1 segment selector.",
- };
- let r2 = match self.contains(RPL_2) {
- false => "",
- true => "Ring 2 segment selector.",
- };
- let r3 = match self.contains(RPL_3) {
- false => "",
- true => "Ring 3 segment selector.",
- };
- let tbl = match self.contains(TI_LDT) {
- false => "GDT Table",
- true => "LDT Table",
- };
-
- write!(f,
- "Index {} in {}, {}{}{}{}",
- self.bits >> 3,
- tbl,
- r0,
- r1,
- r2,
- r3)
- // write!(f, "Index")
- }
-}
-
-
-/// Entry for GDT or LDT. Provides size and location of a segment.
-bitflags! {
- flags SegmentDescriptor: u64 {
- /// Descriptor type (0 = system; 1 = code or data).
- const DESC_S = 1 << (32+12),
- /// Descriptor privilege level 0.
- const DESC_DPL0 = 0b00 << (32+13),
- /// Descriptor privilege level 1.
- const DESC_DPL1 = 0b01 << (32+13),
- /// Descriptor privilege level 2.
- const DESC_DPL2 = 0b10 << (32+13),
- /// Descriptor privilege level 3.
- const DESC_DPL3 = 0b11 << (32+13),
- /// Descriptor is Present.
- const DESC_P = 1 << (32+15),
- /// Available for use by system software.
- const DESC_AVL = 1 << (32+20),
- /// 64-bit code segment (IA-32e mode only).
- const DESC_L = 1 << (32+21),
- /// Default operation size (0 = 16-bit segment, 1 = 32-bit segment)
- const DESC_DB = 1 << (32+22),
- /// Granularity.
- const DESC_G = 1 << (32+23),
-
- // System-Segment and Gate-Descriptor Types for IA32e mode.
- // When the S (descriptor type) flag in a segment descriptor is clear,
- // the descriptor type is a system descriptor.
-
- const TYPE_SYS_LDT = 0b0010 << (32+8),
- const TYPE_SYS_TSS_AVAILABLE = 0b1001 << (32+8),
- const TYPE_SYS_TSS_BUSY = 0b1011 << (32+8),
- const TYPE_SYS_CALL_GATE = 0b1100 << (32+8),
- const TYPE_SYS_INTERRUPT_GATE = 0b1110 << (32+8),
- const TYPE_SYS_TRAP_GATE = 0b1111 << (32+8),
-
- // Code- and Data-Segment Descriptor Types.
- // When the S (descriptor type) flag in a segment descriptor is set,
- // the descriptor is for either a code or a data segment.
-
- /// Data Read-Only
- const TYPE_D_RO = 0b0000 << (32+8),
- /// Data Read-Only, accessed
- const TYPE_D_ROA = 0b0001 << (32+8),
- /// Data Read/Write
- const TYPE_D_RW = 0b0010 << (32+8),
- /// Data Read/Write, accessed
- const TYPE_D_RWA = 0b0011 << (32+8),
- /// Data Read-Only, expand-down
- const TYPE_D_ROEXD = 0b0100 << (32+8),
- /// Data Read-Only, expand-down, accessed
- const TYPE_D_ROEXDA = 0b0101 << (32+8),
- /// Data Read/Write, expand-down
- const TYPE_D_RWEXD = 0b0110 << (32+8),
- /// Data Read/Write, expand-down, accessed
- const TYPE_D_RWEXDA = 0b0111 << (32+8),
-
- /// Code Execute-Only
- const TYPE_C_EO = 0b1000 << (32+8),
- /// Code Execute-Only, accessed
- const TYPE_C_EOA = 0b1001 << (32+8),
- /// Code Execute/Read
- const TYPE_C_ER = 0b1010 << (32+8),
- /// Code Execute/Read, accessed
- const TYPE_C_ERA = 0b1011 << (32+8),
- /// Code Execute-Only, conforming
- const TYPE_C_EOC = 0b1100 << (32+8),
- /// Code Execute-Only, conforming, accessed
- const TYPE_C_EOCA = 0b1101 << (32+8),
- /// Code Execute/Read, conforming
- const TYPE_C_ERC = 0b1110 << (32+8),
- /// Code Execute/Read, conforming, accessed
- const TYPE_C_ERCA = 0b1111 << (32+8),
- }
-}
-
-/// This is data-structure is a ugly mess thing so we provide some
-/// convenience function to program it.
-impl SegmentDescriptor {
- pub fn new(base: u32, limit: u32) -> SegmentDescriptor {
- let base_low: u64 = base as u64 & 0xffffff;
- let base_high: u64 = (base as u64 >> 24) & 0xff;
-
- let limit_low: u64 = limit as u64 & 0xffff;
- let limit_high: u64 = (limit as u64 & (0b1111 << 16)) >> 16;
-
- SegmentDescriptor {
- bits: limit_low | base_low << 16 | limit_high << (32 + 16) | base_high << (32 + 24),
- }
- }
-}
-
-impl fmt::Debug for SegmentDescriptor {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "SD: 0x{:x}", self.bits)
- }
-}
-
-/// Reload stack segment register.
-pub unsafe fn load_ss(sel: SegmentSelector) {
- asm!("movw $0, %ss " :: "r" (sel) : "memory");
-}
-
-/// Reload data segment register.
-pub unsafe fn load_ds(sel: SegmentSelector) {
- asm!("movw $0, %ds " :: "r" (sel) : "memory");
-}
-
-/// Reload es segment register.
-pub unsafe fn load_es(sel: SegmentSelector) {
- asm!("movw $0, %es " :: "r" (sel) : "memory");
-}
-
-/// Reload fs segment register.
-pub unsafe fn load_fs(sel: SegmentSelector) {
- asm!("movw $0, %fs " :: "r" (sel) : "memory");
-}
-
-/// Reload gs segment register.
-pub unsafe fn load_gs(sel: SegmentSelector) {
- asm!("movw $0, %gs " :: "r" (sel) : "memory");
-}
-
-/// Reload code segment register.
-/// Note this is special since we can not directly move
-/// to %cs. Instead we push the new segment selector
-/// and return value on the stack and use lretq
-/// to reload cs and continue at 1:.
-pub unsafe fn load_cs(sel: SegmentSelector) {
- asm!("pushq $0
- lea 1f(%rip), %rax
- pushq %rax
- lretq
- 1:" :: "r" (sel.bits() as u64) : "{rax}" "memory");
-}
-
-/// Returns the current value of the code segment register.
-pub fn cs() -> SegmentSelector {
- let segment: u16;
- unsafe { asm!("mov %cs, $0" : "=r" (segment) ) };
- SegmentSelector::from_raw(segment)
-}
diff --git a/src/shared/control_regs.rs b/src/shared/control_regs.rs
new file mode 100644
index 0000000..ab03eba
--- /dev/null
+++ b/src/shared/control_regs.rs
@@ -0,0 +1,84 @@
+//! Functions to read and write control registers.
+//! See Intel Vol. 3a Section 2.5, especially Figure 2.6.
+
+bitflags! {
+ pub flags Cr0: usize {
+ const CR0_ENABLE_PAGING = 1 << 31,
+ const CR0_CACHE_DISABLE = 1 << 30,
+ const CR0_NOT_WRITE_THROUGH = 1 << 29,
+ const CR0_ALIGNMENT_MASK = 1 << 18,
+ const CR0_WRITE_PROTECT = 1 << 16,
+ const CR0_NUMERIC_ERROR = 1 << 5,
+ const CR0_EXTENSION_TYPE = 1 << 4,
+ const CR0_TASK_SWITCHED = 1 << 3,
+ const CR0_EMULATE_COPROCESSOR = 1 << 2,
+ const CR0_MONITOR_COPROCESSOR = 1 << 1,
+ const CR0_PROTECTED_MODE = 1 << 0,
+ }
+}
+
+bitflags! {
+ pub flags Cr4: usize {
+ const CR4_ENABLE_SMAP = 1 << 21,
+ const CR4_ENABLE_SMEP = 1 << 20,
+ const CR4_ENABLE_OS_XSAVE = 1 << 18,
+ const CR4_ENABLE_PCID = 1 << 17,
+ const CR4_ENABLE_SMX = 1 << 14,
+ const CR4_ENABLE_VMX = 1 << 13,
+ const CR4_UNMASKED_SSE = 1 << 10,
+ const CR4_ENABLE_SSE = 1 << 9,
+ const CR4_ENABLE_PPMC = 1 << 8,
+ const CR4_ENABLE_GLOBAL_PAGES = 1 << 7,
+ const CR4_ENABLE_MACHINE_CHECK = 1 << 6,
+ const CR4_ENABLE_PAE = 1 << 5,
+ const CR4_ENABLE_PSE = 1 << 4,
+ const CR4_DEBUGGING_EXTENSIONS = 1 << 3,
+ const CR4_TIME_STAMP_DISABLE = 1 << 2,
+ const CR4_VIRTUAL_INTERRUPTS = 1 << 1,
+ const CR4_ENABLE_VME = 1 << 0,
+ }
+}
+
+
+/// Read cr0
+pub unsafe fn cr0() -> Cr0 {
+ let ret: usize;
+ asm!("mov %cr0, $0" : "=r" (ret));
+ Cr0::from_bits_truncate(ret)
+}
+
+/// Write cr0.
+pub unsafe fn cr0_write(val: Cr0) {
+ asm!("mov $0, %cr0" :: "r" (val.bits) : "memory");
+}
+
+/// Contains page-fault linear address.
+pub unsafe fn cr2() -> usize {
+ let ret: usize;
+ asm!("mov %cr2, $0" : "=r" (ret));
+ ret
+}
+
+/// Contains page-table root pointer.
+pub unsafe fn cr3() -> usize {
+ let ret: usize;
+ asm!("mov %cr3, $0" : "=r" (ret));
+ ret
+}
+
+/// Switch page-table PML4 pointer.
+pub unsafe fn cr3_write(val: usize) {
+ asm!("mov $0, %cr3" :: "r" (val) : "memory");
+}
+
+/// Contains various flags to control operations in protected mode.
+pub unsafe fn cr4() -> Cr4 {
+ let ret: usize;
+ asm!("mov %cr4, $0" : "=r" (ret));
+ Cr4::from_bits_truncate(ret)
+}
+
+/// Write cr4.
+pub unsafe fn cr4_write(val: Cr4) {
+ asm!("mov $0, %cr4" :: "r" (val.bits) : "memory");
+}
diff --git a/src/shared/descriptor.rs b/src/shared/descriptor.rs
new file mode 100644
index 0000000..32abb79
--- /dev/null
+++ b/src/shared/descriptor.rs
@@ -0,0 +1,194 @@
+//! Fields which are common to all segment-section and gate descriptors
+
+use shared::PrivilegeLevel;
+use shared::segmentation;
+
+/// System-Segment and Gate-Descriptor Types for IA32e mode. When the `S`
+/// (descriptor type) flag in a segment descriptor is clear, the descriptor type
+/// is a system descriptor.
+///
+/// See Intel manual 3a, 3.5 "System Descriptor Types", and Table 3-2,
+/// System-Segment and Gate-Descriptor Types".
+#[repr(u8)]
+pub enum SystemType {
+ // Reserved = 0
+ TssAvailable = 1,
+ /// Only for 16-bit
+ LocalDescriptorTable = 2,
+ TssBusy = 3,
+ CallGate = 4,
+ /// Only for 16-bit
+ TaskGate = 5,
+ InterruptGate = 6,
+ TrapGate = 7,
+}
+
+/// A high-level representation of a descriptor type. One can convert to and
+/// from the `Flags` bitfield to encode/decode an actual descriptor.
+#[repr(u8)]
+pub enum Type {
+ SystemDescriptor {
+ /// false/0: 16-bit
+ /// true/1: native (32- or 64-bit)
+ size: bool,
+ ty: SystemType
+ },
+ SegmentDescriptor {
+ ty: segmentation::Type,
+ accessed: bool
+ }
+}
+
+impl Type {
+ pub fn pack(self) -> u8 {
+ match self {
+ Type::SystemDescriptor { size, ty } =>
+ (size as u8) << 3 | (ty as u8) | FLAGS_TYPE_SYS.bits,
+ Type::SegmentDescriptor { ty, accessed } =>
+ (accessed as u8) | ty.pack() | FLAGS_TYPE_SYS.bits,
+ }
+ }
+}
+
+
+bitflags!{
+ /// Actual encoding of the flags in byte 6 common to all descriptors.
+ ///
+ /// See Intel manual 3a, figures 3-8, 6-2, and 6-7.
+ pub flags Flags: u8 {
+ /// Descriptor is Present.
+ const FLAGS_PRESENT = 1 << 7,
+
+ // Descriptor privilege level
+ const FLAGS_DPL_RING_0 = 0b00 << 5,
+ const FLAGS_DPL_RING_1 = 0b01 << 5,
+ const FLAGS_DPL_RING_2 = 0b10 << 5,
+ const FLAGS_DPL_RING_3 = 0b11 << 5,
+
+ // Is system descriptor
+ const FLAGS_TYPE_SYS = 0 << 4,
+ const FLAGS_TYPE_SEG = 1 << 4,
+
+ // System-Segment and Gate-Descriptor Types.
+ // When the S (descriptor type) flag in a segment descriptor is clear,
+ // the descriptor type is a system descriptor
+
+ // All modes (supporting segments)
+ const TYPE_SYS_LDT = 0b0_0010,
+
+ // Protected Mode and older
+ const FLAGS_TYPE_SYS_16BIT_TSS_AVAILABLE = 0b0_0001,
+ const FLAGS_TYPE_SYS_16BIT_TSS_BUSY = 0b0_0011,
+ const FLAGS_TYPE_SYS_16BIT_CALL_GATE = 0b0_0100,
+ const FLAGS_TYPE_SYS_16BIT_TASK_GATE = 0b0_0101,
+ const FLAGS_TYPE_SYS_16BIT_INTERRUPT_GATE = 0b0_0110,
+ const FLAGS_TYPE_SYS_16BIT_TRAP_GATE = 0b0_0111,
+
+ // 64-bit in IA-32e Mode (either submode), 32-bit in Protected Mode
+ const FLAGS_TYPE_SYS_NATIVE_TSS_AVAILABLE = 0b0_1001,
+ const FLAGS_TYPE_SYS_NATIVE_TSS_BUSY = 0b0_1011,
+ const FLAGS_TYPE_SYS_NATIVE_CALL_GATE = 0b0_1100,
+ const FLAGS_TYPE_SYS_NATIVE_INTERRUPT_GATE = 0b0_1110,
+ const FLAGS_TYPE_SYS_NATIVE_TRAP_GATE = 0b0_1111,
+
+ // Code- and Data-Segment Descriptor Types.
+ // When the S (descriptor type) flag in a segment descriptor is set,
+ // the descriptor is for either a code or a data segment.
+
+ /// Data or code, accessed
+ const FLAGS_TYPE_SEG_ACCESSED = 0b1_0001,
+
+ const FLAGS_TYPE_DATA = 0b1_0000,
+ const FLAGS_TYPE_CODE = 0b1_1000,
+
+ // Data => permissions
+ const FLAGS_TYPE_SEG_D_WRITE = 0b1_0010,
+ const FLAGS_TYPE_SEG_D_EXPAND_DOWN = 0b1_0100,
+
+ // Code => permissions
+ const FLAGS_TYPE_SEG_C_READ = 0b1_0010,
+ const FLAGS_TYPE_SEG_D_CONFORMING = 0b1_0100,
+
+ /// Data Read-Only
+ const FLAGS_TYPE_SEG_D_RO = FLAGS_TYPE_DATA.bits,
+ /// Data Read-Only, accessed
+ const FLAGS_TYPE_SEG_D_ROA = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_ACCESSED.bits,
+ /// Data Read/Write
+ const FLAGS_TYPE_SEG_D_RW = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_D_WRITE.bits,
+ /// Data Read/Write, accessed
+ const FLAGS_TYPE_SEG_D_RWA = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_D_WRITE.bits
+ | FLAGS_TYPE_SEG_ACCESSED.bits,
+ /// Data Read-Only, expand-down
+ const FLAGS_TYPE_SEG_D_ROEXD = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_D_EXPAND_DOWN.bits,
+ /// Data Read-Only, expand-down, accessed
+ const FLAGS_TYPE_SEG_D_ROEXDA = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_D_EXPAND_DOWN.bits
+ | FLAGS_TYPE_SEG_ACCESSED.bits,
+ /// Data Read/Write, expand-down
+ const FLAGS_TYPE_SEG_D_RWEXD = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_D_WRITE.bits
+ | FLAGS_TYPE_SEG_D_EXPAND_DOWN.bits,
+ /// Data Read/Write, expand-down, accessed
+ const FLAGS_TYPE_SEG_D_RWEXDA = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_D_WRITE.bits
+ | FLAGS_TYPE_SEG_D_EXPAND_DOWN.bits
+ | FLAGS_TYPE_SEG_ACCESSED.bits,
+
+ /// Code Execute-Only
+ const FLAGS_TYPE_SEG_C_EO = FLAGS_TYPE_DATA.bits,
+ /// Code Execute-Only, accessed
+ const FLAGS_TYPE_SEG_C_EOA = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_ACCESSED.bits,
+ /// Code Execute/Read
+ const FLAGS_TYPE_SEG_C_ER = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_C_READ.bits,
+ /// Code Execute/Read, accessed
+ const FLAGS_TYPE_SEG_C_ERA = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_C_READ.bits
+ | FLAGS_TYPE_SEG_ACCESSED.bits,
+ /// Code Execute-Only, conforming
+ const FLAGS_TYPE_SEG_C_EOC = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_D_CONFORMING.bits,
+ /// Code Execute-Only, conforming, accessed
+ const FLAGS_TYPE_SEG_C_EOCA = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_D_CONFORMING.bits
+ | FLAGS_TYPE_SEG_ACCESSED.bits,
+ /// Code Execute/Read, conforming
+ const FLAGS_TYPE_SEG_C_ERC = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_C_READ.bits
+ | FLAGS_TYPE_SEG_D_CONFORMING.bits,
+ /// Code Execute/Read, conforming, accessed
+ const FLAGS_TYPE_SEG_C_ERCA = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_C_READ.bits
+ | FLAGS_TYPE_SEG_D_CONFORMING.bits
+ | FLAGS_TYPE_SEG_ACCESSED.bits,
+ }
+}
+
+impl Flags {
+ pub const BLANK: Flags = Flags { bits: 0 };
+
+ pub const fn from_priv(dpl: PrivilegeLevel) -> Flags {
+ Flags { bits: (dpl as u8) << 5 }
+ }
+
+ pub fn from_type(ty: Type) -> Flags {
+ Flags { bits: ty.pack() }
+ }
+
+ pub const fn const_or(self, other: Self) -> Flags {
+ Flags { bits: self.bits | other.bits }
+ }
+
+ pub const fn cond(self, cond: bool) -> Flags {
+ Flags { bits: (-(cond as i8) as u8) & self.bits }
+ }
+
+ pub const fn const_mux(self, other: Self, cond: bool) -> Flags {
+ self.cond(cond).const_or(other.cond(!cond))
+ }
+}
diff --git a/src/shared/dtables.rs b/src/shared/dtables.rs
new file mode 100644
index 0000000..c5337fb
--- /dev/null
+++ b/src/shared/dtables.rs
@@ -0,0 +1,61 @@
+//! Functions and data-structures to load descriptor tables.
+
+use core::mem::size_of;
+
+use current::irq::IdtEntry;
+use shared::segmentation::SegmentDescriptor;
+
+/// A struct describing a pointer to a descriptor table (GDT / IDT).
+/// This is in a format suitable for giving to 'lgdt' or 'lidt'.
+#[derive(Debug)]
+#[repr(C, packed)]
+pub struct DescriptorTablePointer<Entry> {
+ /// Size of the DT.
+ pub limit: u16,
+ /// Pointer to the memory region containing the DT.
+ pub base: *const Entry,
+}
+
+impl<T> DescriptorTablePointer<T> {
+ fn new(slice: &[T]) -> Self {
+ let len = slice.len() * size_of::<T>();
+ assert!(len < 0x10000);
+ DescriptorTablePointer {
+ base: slice.as_ptr(),
+ limit: len as u16,
+ }
+ }
+}
+
+impl DescriptorTablePointer<SegmentDescriptor> {
+ pub fn new_gdtp(gdt: &[SegmentDescriptor]) -> Self {
+ let mut p = Self::new(gdt);
+ p.limit -= 1;
+ p
+ }
+ pub fn new_ldtp(ldt: &[SegmentDescriptor]) -> Self {
+ Self::new(ldt)
+ }
+}
+
+impl DescriptorTablePointer<IdtEntry> {
+ pub fn new_idtp(idt: &[IdtEntry]) -> Self {
+ Self::new(idt)
+ }
+}
+
+
+/// Load GDT table.
+pub unsafe fn lgdt(gdt: &DescriptorTablePointer<SegmentDescriptor>) {
+ asm!("lgdt ($0)" :: "r" (gdt) : "memory");
+}
+
+/// Load LDT table.
+pub unsafe fn lldt(ldt: &DescriptorTablePointer<SegmentDescriptor>) {
+ asm!("lldt ($0)" :: "r" (ldt) : "memory");
+}
+
+/// Load IDT table.
+pub unsafe fn lidt(idt: &DescriptorTablePointer<IdtEntry>) {
+ asm!("lidt ($0)" :: "r" (idt) : "memory");
+}
diff --git a/src/shared/flags.rs b/src/shared/flags.rs
new file mode 100644
index 0000000..55dad6d
--- /dev/null
+++ b/src/shared/flags.rs
@@ -0,0 +1,102 @@
+//! Processor state stored in the FLAGS, EFLAGS, or RFLAGS register.
+
+use shared::PrivilegeLevel;
+
+/// The RFLAGS register. All variants are backwards compatable so only one
+/// bitflags struct needed.
+bitflags! {
+ pub flags Flags: usize {
+ /// ID Flag (ID)
+ const FLAGS_ID = 1 << 21,
+ /// Virtual Interrupt Pending (VIP)
+ const FLAGS_VIP = 1 << 20,
+ /// Virtual Interrupt Flag (VIF)
+ const FLAGS_VIF = 1 << 19,
+ /// Alignment Check (AC)
+ const FLAGS_AC = 1 << 18,
+ /// Virtual-8086 Mode (VM)
+ const FLAGS_VM = 1 << 17,
+ /// Resume Flag (RF)
+ const FLAGS_RF = 1 << 16,
+ /// Nested Task (NT)
+ const FLAGS_NT = 1 << 14,
+ /// I/O Privilege Level (IOPL) 0
+ const FLAGS_IOPL0 = 0 << 12,
+ /// I/O Privilege Level (IOPL) 1
+ const FLAGS_IOPL1 = 1 << 12,
+ /// I/O Privilege Level (IOPL) 2
+ const FLAGS_IOPL2 = 2 << 12,
+ /// I/O Privilege Level (IOPL) 3
+ const FLAGS_IOPL3 = 3 << 12,
+ /// Overflow Flag (OF)
+ const FLAGS_OF = 1 << 11,
+ /// Direction Flag (DF)
+ const FLAGS_DF = 1 << 10,
+ /// Interrupt Enable Flag (IF)
+ const FLAGS_IF = 1 << 9,
+ /// Trap Flag (TF)
+ const FLAGS_TF = 1 << 8,
+ /// Sign Flag (SF)
+ const FLAGS_SF = 1 << 7,
+ /// Zero Flag (ZF)
+ const FLAGS_ZF = 1 << 6,
+ /// Auxiliary Carry Flag (AF)
+ const FLAGS_AF = 1 << 4,
+ /// Parity Flag (PF)
+ const FLAGS_PF = 1 << 2,
+ /// Bit 1 is always 1.
+ const FLAGS_A1 = 1 << 1,
+ /// Carry Flag (CF)
+ const FLAGS_CF = 1 << 0,
+ }
+}
+
+impl Flags {
+ /// Creates a new Flags entry. Ensures bit 1 is set.
+ pub const fn new() -> Flags {
+ FLAGS_A1
+ }
+
+ /// Creates a new Flags with the given I/O privilege level.
+ pub const fn from_priv(iopl: PrivilegeLevel) -> Flags {
+ Flags { bits: (iopl as usize) << 12 }
+ }
+}
+
+pub fn flags() -> Flags {
+
+ #[cfg(target_arch="x86")]
+ #[inline(always)]
+ unsafe fn inner() -> Flags {
+ let r: usize;
+ asm!("pushfl; popl $0" : "=r"(r) :: "memory");
+ Flags::from_bits_truncate(r)
+ }
+
+ #[cfg(target_arch="x86_64")]
+ #[inline(always)]
+ unsafe fn inner() -> Flags {
+ let r: usize;
+ asm!("pushfq; popq $0" : "=r"(r) :: "memory");
+ Flags::from_bits_truncate(r)
+ }
+
+ unsafe { inner() }
+}
+
+pub fn set(val: Flags) {
+
+ #[cfg(target_arch="x86")]
+ #[inline(always)]
+ unsafe fn inner(val: Flags) {
+ asm!("pushl $0; popfl" :: "r"(val.bits()) : "memory" "flags");
+ }
+
+ #[cfg(target_arch="x86_64")]
+ #[inline(always)]
+ unsafe fn inner(val: Flags) {
+ asm!("pushq $0; popfq" :: "r"(val.bits()) : "memory" "flags");
+ }
+
+ unsafe { inner(val) }
+}
diff --git a/src/shared/io.rs b/src/shared/io.rs
new file mode 100644
index 0000000..16f641c
--- /dev/null
+++ b/src/shared/io.rs
@@ -0,0 +1,80 @@
+//! I/O port functionality.
+
+/// Write 8 bits to port
+pub unsafe fn outb(port: u16, val: u8) {
+ asm!("outb %al, %dx" :: "{dx}"(port), "{al}"(val));
+}
+
+/// Read 8 bits from port
+pub unsafe fn inb(port: u16) -> u8 {
+ let ret: u8;
+ asm!("inb %dx, %al" : "={ax}"(ret) : "{dx}"(port) :: "volatile");
+ ret
+}
+
+/// Write 16 bits to port
+pub unsafe fn outw(port: u16, val: u16) {
+ asm!("outw %ax, %dx" :: "{dx}"(port), "{al}"(val));
+}
+
+/// Read 16 bits from port
+pub unsafe fn inw(port: u16) -> u16 {
+ let ret: u16;
+ asm!("inw %dx, %ax" : "={ax}"(ret) : "{dx}"(port) :: "volatile");
+ ret
+}
+
+/// Write 32 bits to port
+pub unsafe fn outl(port: u16, val: u32) {
+ asm!("outl %eax, %dx" :: "{dx}"(port), "{al}"(val));
+}
+
+/// Read 32 bits from port
+pub unsafe fn inl(port: u16) -> u32 {
+ let ret: u32;
+ asm!("inl %dx, %eax" : "={ax}"(ret) : "{dx}"(port) :: "volatile");
+ ret
+}
+
+
+// Write 8-bit array to port
+pub unsafe fn outsb(port: u16, buf: &[u8]) {
+ asm!("rep outsb (%esi), %dx"
+ :: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr())
+ : "ecx", "edi");
+}
+
+// Read 8-bit array from port
+pub unsafe fn insb(port: u16, buf: &mut [u8]) {
+ asm!("rep insb %dx, (%edi)"
+ :: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr())
+ : "ecx", "edi" : "volatile");
+}
+
+// Write 16-bit array to port
+pub unsafe fn outsw(port: u16, buf: &[u16]) {
+ asm!("rep outsw (%esi), %dx"
+ :: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr())
+ : "ecx", "edi");
+}
+
+// Read 16-bit array from port
+pub unsafe fn insw(port: u16, buf: &mut [u16]) {
+ asm!("rep insw %dx, (%edi)"
+ :: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr())
+ : "ecx", "edi" : "volatile");
+}
+
+// Write 32-bit array to port
+pub unsafe fn outsl(port: u16, buf: &[u32]) {
+ asm!("rep outsl (%esi), %dx"
+ :: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr())
+ : "ecx", "edi");
+}
+
+// Read 32-bit array from port
+pub unsafe fn insl(port: u16, buf: &mut [u32]) {
+ asm!("rep insl %dx, (%edi)"
+ :: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr())
+ : "ecx", "edi" : "volatile");
+}
diff --git a/src/shared/irq.rs b/src/shared/irq.rs
new file mode 100644
index 0000000..4654ad3
--- /dev/null
+++ b/src/shared/irq.rs
@@ -0,0 +1,207 @@
+//! Shared interrupt description and set-up code.
+//! See the `bits*::irq` modules for arch-specific portions.
+
+use core::fmt;
+
+/// x86 Exception description (see also Intel Vol. 3a Chapter 6).
+#[derive(Debug)]
+pub struct InterruptDescription {
+ pub vector: u8,
+ pub mnemonic: &'static str,
+ pub description: &'static str,
+ pub irqtype: &'static str,
+ pub source: &'static str,
+}
+
+impl fmt::Display for InterruptDescription {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f,
+ "{} ({}, vec={}) {}",
+ self.mnemonic,
+ self.irqtype,
+ self.vector,
+ self.description)
+ }
+}
+
+
+/// x86 External Interrupts (1-16).
+pub static EXCEPTIONS: [InterruptDescription; 21] = [
+ InterruptDescription {
+ vector: 0,
+ mnemonic: "#DE",
+ description: "Divide Error",
+ irqtype: "Fault",
+ source: "DIV and IDIV instructions.",
+ },
+ InterruptDescription {
+ vector: 1,
+ mnemonic: "#DB",
+ description: "Debug",
+ irqtype: "Fault/ Trap",
+ source: "Debug condition",
+ },
+ InterruptDescription {
+ vector: 2,
+ mnemonic: "NMI",
+ description: "Nonmaskable Interrupt",
+ irqtype: "Interrupt",
+ source: "Nonmaskable external interrupt.",
+ },
+ InterruptDescription {
+ vector: 3,
+ mnemonic: "#BP",
+ description: "Breakpoint",
+ irqtype: "Trap",
+ source: "INT 3 instruction.",
+ },
+ InterruptDescription {
+ vector: 4,
+ mnemonic: "#OF",
+ description: "Overflow",
+ irqtype: "Trap",
+ source: "INTO instruction.",
+ },
+ InterruptDescription {
+ vector: 5,
+ mnemonic: "#BR",
+ description: "BOUND Range Exceeded",
+ irqtype: "Fault",
+ source: "BOUND instruction.",
+ },
+ InterruptDescription {
+ vector: 6,
+ mnemonic: "#UD",
+ description: "Invalid Opcode (Undefined \
+ Opcode)",
+ irqtype: "Fault",
+ source: "UD2 instruction or reserved \
+ opcode.",
+ },
+ InterruptDescription {
+ vector: 7,
+ mnemonic: "#NM",
+ description: "Device Not Available (No \
+ Math Coprocessor)",
+ irqtype: "Fault",
+ source: "Floating-point or WAIT/FWAIT \
+ instruction.",
+ },
+ InterruptDescription {
+ vector: 8,
+ mnemonic: "#DF",
+ description: "Double Fault",
+ irqtype: "Abort",
+ source: "Any instruction that can \
+ generate an exception, an NMI, \
+ or an INTR.",
+ },
+ InterruptDescription {
+ vector: 9,
+ mnemonic: "",
+ description: "Coprocessor Segment Overrun",
+ irqtype: "Fault",
+ source: "Floating-point instruction.",
+ },
+ InterruptDescription {
+ vector: 10,
+ mnemonic: "#TS",
+ description: "Invalid TSS",
+ irqtype: "Fault",
+ source: "Task switch or TSS access.",
+ },
+ InterruptDescription {
+ vector: 11,
+ mnemonic: "#NP",
+ description: "Segment Not Present",
+ irqtype: "Fault",
+ source: "Loading segment registers or \
+ accessing system segments.",
+ },
+ InterruptDescription {
+ vector: 12,
+ mnemonic: "#SS",
+ description: "Stack-Segment Fault",
+ irqtype: "Fault",
+ source: "Stack operations and SS register \
+ loads.",
+ },
+ InterruptDescription {
+ vector: 13,
+ mnemonic: "#GP",
+ description: "General Protection",
+ irqtype: "Fault",
+ source: "Any memory reference and other \
+ protection checks.",
+ },
+ InterruptDescription {
+ vector: 14,
+ mnemonic: "#PF",
+ description: "Page Fault",
+ irqtype: "Fault",
+ source: "Any memory reference.",
+ },
+ InterruptDescription {
+ vector: 15,
+ mnemonic: "",
+ description: "RESERVED",
+ irqtype: "",
+ source: "None.",
+ },
+ InterruptDescription {
+ vector: 16,
+ mnemonic: "#MF",
+ description: "x87 FPU Floating-Point",
+ irqtype: "Fault",
+ source: "x87 FPU instructions.",
+ },
+ InterruptDescription {
+ vector: 17,
+ mnemonic: "#AC",
+ description: "Alignment Check",
+ irqtype: "Fault",
+ source: "Unaligned memory access.",
+ },
+ InterruptDescription {
+ vector: 18,
+ mnemonic: "#MC",
+ description: "Machine Check",
+ irqtype: "Abort",
+ source: "Internal machine error.",
+ },
+ InterruptDescription {
+ vector: 19,
+ mnemonic: "#XM",
+ description: "SIMD Floating-Point",
+ irqtype: "Fault",
+ source: "SSE SIMD instructions.",
+ },
+ InterruptDescription {
+ vector: 20,
+ mnemonic: "#VE",
+ description: "Virtualization",
+ irqtype: "Fault",
+ source: "EPT violation.",
+ },
+];
+
+/// Enable Interrupts.
+pub unsafe fn enable() {
+ asm!("sti");
+}
+
+/// Disable Interrupts.
+pub unsafe fn disable() {
+ asm!("cli");
+}
+
+/// Generate a software interrupt.
+/// This is a macro argument needs to be an immediate.
+#[macro_export]
+macro_rules! int {
+ ( $x:expr ) => {
+ {
+ asm!("int $0" :: "N" ($x));
+ }
+ };
+}
diff --git a/src/shared/mod.rs b/src/shared/mod.rs
new file mode 100644
index 0000000..42a7aa4
--- /dev/null
+++ b/src/shared/mod.rs
@@ -0,0 +1,24 @@
+pub mod control_regs;
+pub mod descriptor;
+pub mod dtables;
+pub mod io;
+pub mod irq;
+pub mod msr;
+pub mod paging;
+pub mod flags;
+pub mod segmentation;
+pub mod task;
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+#[repr(u8)]
+pub enum PrivilegeLevel {
+ Ring0 = 0,
+ Ring1 = 1,
+ Ring2 = 2,
+ Ring3 = 3,
+}
+
+#[inline(always)]
+pub unsafe fn halt() {
+ asm!("hlt" :::: "volatile", "intel");
+}
diff --git a/src/msr.rs b/src/shared/msr.rs
index 6b4613a..1520232 100644
--- a/src/msr.rs
+++ b/src/shared/msr.rs
@@ -10,10 +10,8 @@ pub unsafe fn wrmsr(msr: u32, value: u64) {
/// Read 64 bits msr register.
#[allow(unused_mut)]
pub unsafe fn rdmsr(msr: u32) -> u64 {
- let mut low: u32;
- let mut high: u32;
+ let (high, low): (u32, u32);
asm!("rdmsr" : "={eax}" (low), "={edx}" (high) : "{ecx}" (msr) : "memory" : "volatile");
-
((high as u64) << 32) | (low as u64)
}
diff --git a/src/shared/paging.rs b/src/shared/paging.rs
new file mode 100644
index 0000000..41705a9
--- /dev/null
+++ b/src/shared/paging.rs
@@ -0,0 +1,48 @@
+//! Description of the data-structures for IA-32e paging mode.
+
+use core::fmt;
+
+/// Represent a virtual (linear) memory address
+#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
+pub struct VAddr(usize);
+
+impl VAddr {
+ /// Convert to `usize`
+ pub const fn as_usize(&self) -> usize {
+ self.0
+ }
+ /// Convert from `usize`
+ pub const fn from_usize(v: usize) -> Self {
+ VAddr(v)
+ }
+}
+
+impl fmt::Binary for VAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl fmt::Display for VAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl fmt::LowerHex for VAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl fmt::Octal for VAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl fmt::UpperHex for VAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
diff --git a/src/shared/segmentation.rs b/src/shared/segmentation.rs
new file mode 100644
index 0000000..7f895ae
--- /dev/null
+++ b/src/shared/segmentation.rs
@@ -0,0 +1,262 @@
+use core::fmt;
+
+use shared::descriptor;
+use shared::PrivilegeLevel;
+
+/// Specifies which element to load into a segment from
+/// descriptor tables (i.e., is a index to LDT or GDT table
+/// with some additional flags).
+///
+/// See Intel 3a, Section 3.4.2 "Segment Selectors"
+bitflags! {
+ #[repr(C, packed)]
+ pub flags SegmentSelector: u16 {
+ /// Requestor Privilege Level
+ const RPL_0 = 0b00,
+ const RPL_1 = 0b01,
+ const RPL_2 = 0b10,
+ const RPL_3 = 0b11,
+
+ /// Table Indicator (TI) 0 means GDT is used.
+ const TI_GDT = 0 << 3,
+ /// Table Indicator (TI) 1 means LDT is used.
+ const TI_LDT = 1 << 3,
+ }
+}
+
+/// Reload code segment register.
+/// Note this is special since we can not directly move
+/// to %cs. Instead we push the new segment selector
+/// and return value on the stack and use lretq
+/// to reload cs and continue at 1:.
+pub unsafe fn set_cs(sel: SegmentSelector) {
+
+ #[cfg(target_arch="x86")]
+ #[inline(always)]
+ unsafe fn inner(sel: SegmentSelector) {
+ asm!("pushl $0; \
+ pushl $$1f; \
+ lretl; \
+ 1:" :: "ri" (sel.bits() as usize) : "{rax}" "memory");
+ }
+
+ #[cfg(target_arch="x86_64")]
+ #[inline(always)]
+ unsafe fn inner(sel: SegmentSelector) {
+ asm!("pushq $0; \
+ leaq 1f(%rip), %rax; \
+ pushq %rax; \
+ lretq; \
+ 1:" :: "ri" (sel.bits() as usize) : "{rax}" "memory");
+ }
+
+ inner(sel)
+}
+
+
+impl SegmentSelector {
+ /// Create a new SegmentSelector
+ ///
+ /// # Arguments
+ /// * `index` index in GDT or LDT array.
+ ///
+ pub const fn new(index: u16, rpl: PrivilegeLevel) -> SegmentSelector {
+ SegmentSelector { bits: index << 3 | (rpl as u16) }
+ }
+
+ pub const fn from_raw(bits: u16) -> SegmentSelector {
+ SegmentSelector { bits: bits }
+ }
+}
+
+impl fmt::Display for SegmentSelector {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let r0 = match self.contains(RPL_0) {
+ false => "",
+ true => "Ring 0 segment selector.",
+ };
+ let r1 = match self.contains(RPL_1) {
+ false => "",
+ true => "Ring 1 segment selector.",
+ };
+ let r2 = match self.contains(RPL_2) {
+ false => "",
+ true => "Ring 2 segment selector.",
+ };
+ let r3 = match self.contains(RPL_3) {
+ false => "",
+ true => "Ring 3 segment selector.",
+ };
+ let tbl = match self.contains(TI_LDT) {
+ false => "GDT Table",
+ true => "LDT Table",
+ };
+
+ write!(f,
+ "Index {} in {}, {}{}{}{}",
+ self.bits >> 3,
+ tbl,
+ r0,
+ r1,
+ r2,
+ r3)
+ // write!(f, "Index")
+ }
+}
+
+
+/// Reload stack segment register.
+pub unsafe fn load_ss(sel: SegmentSelector) {
+ asm!("movw $0, %ss " :: "r" (sel) : "memory");
+}
+
+/// Reload data segment register.
+pub unsafe fn load_ds(sel: SegmentSelector) {
+ asm!("movw $0, %ds " :: "r" (sel) : "memory");
+}
+
+/// Reload es segment register.
+pub unsafe fn load_es(sel: SegmentSelector) {
+ asm!("movw $0, %es " :: "r" (sel) : "memory");
+}
+
+/// Reload fs segment register.
+pub unsafe fn load_fs(sel: SegmentSelector) {
+ asm!("movw $0, %fs " :: "r" (sel) : "memory");
+}
+
+/// Reload gs segment register.
+pub unsafe fn load_gs(sel: SegmentSelector) {
+ asm!("movw $0, %gs " :: "r" (sel) : "memory");
+}
+
+/// Returns the current value of the code segment register.
+pub fn cs() -> SegmentSelector {
+ let segment: u16;
+ unsafe { asm!("mov %cs, $0" : "=r" (segment) ) };
+ SegmentSelector::from_raw(segment)
+}
+
+
+bitflags! {
+ /// Data segment types. All are readable.
+ ///
+ /// See Table 3-1, "Code- and Data-Segment Types"
+ pub flags DataAccess: u8 {
+ /// Segment is writable
+ const DATA_WRITE = 1 << 1,
+ /// Segment grows down, for stack
+ const DATA_EXPAND_DOWN = 1 << 2,
+ }
+}
+
+bitflags! {
+ /// Code segment types. All are executable.
+ ///
+ /// See Table 3-1, "Code- and Data-Segment Types"
+ pub flags CodeAccess: u8 {
+ /// Segment is readable
+ const CODE_READ = 1 << 1,
+ /// Segment is callable from segment with fewer privileges.
+ const CODE_CONFORMING = 1 << 2,
+ }
+}
+
+/// Umbrella Segment Type.
+///
+/// See Table 3-1, "Code- and Data-Segment Types"
+#[repr(u8)]
+pub enum Type {
+ Data(DataAccess),
+ Code(CodeAccess),
+}
+
+impl Type {
+ pub fn pack(self) -> u8 {
+ match self {
+ Type::Data(d) => d.bits | 0b0_000,
+ Type::Code(c) => c.bits | 0b1_000,
+ }
+ }
+}
+
+
+/// Entry for GDT or LDT. Provides size and location of a segment.
+///
+/// See Intel 3a, Section 3.4.5 "Segment Descriptors", and Section 3.5.2
+/// "Segment Descriptor Tables in IA-32e Mode", especially Figure 3-8.
+#[derive(Copy, Clone, Debug)]
+#[repr(C, packed)]
+pub struct SegmentDescriptor {
+ limit1: u16,
+ base1: u16,
+ base2: u8,
+ access: descriptor::Flags,
+ limit2_flags: Flags,
+ base3: u8,
+}
+
+/// This is data-structure is a ugly mess thing so we provide some
+/// convenience function to program it.
+impl SegmentDescriptor {
+ pub const NULL: SegmentDescriptor = SegmentDescriptor {
+ base1: 0,
+ base2: 0,
+ base3: 0,
+ access: descriptor::Flags::BLANK,
+ limit1: 0,
+ limit2_flags: Flags::BLANK,
+ };
+
+ pub fn new(base: u32, limit: u32,
+ ty: Type, accessed: bool, dpl: PrivilegeLevel) -> SegmentDescriptor
+ {
+ let fine_grained = limit < 0x100000;
+ let (limit1, limit2) = if fine_grained {
+ ((limit & 0xFFFF) as u16, ((limit & 0xF0000) >> 16) as u8)
+ } else {
+ if ((limit - 0xFFF) & 0xFFF) > 0 {
+ panic!("bad segment limit for GDT entry");
+ }
+ (((limit & 0xFFFF000) >> 12) as u16, ((limit & 0xF0000000) >> 28) as u8)
+ };
+ let ty1 = descriptor::Type::SegmentDescriptor {
+ ty: ty,
+ accessed: accessed
+ };
+ SegmentDescriptor {
+ base1: base as u16,
+ base2: ((base as usize & 0xFF0000) >> 16) as u8,
+ base3: ((base as usize & 0xFF000000) >> 24) as u8,
+ access: descriptor::Flags::from_type(ty1)
+ | descriptor::Flags::from_priv(dpl),
+ limit1: limit1,
+ limit2_flags: FLAGS_DB
+ | if fine_grained { FLAGS_G } else { Flags::empty() }
+ | Flags::from_limit2(limit2),
+ }
+ }
+}
+
+bitflags! {
+ pub flags Flags: u8 {
+ /// Available for use by system software.
+ const FLAGS_AVL = 1 << 4,
+ /// 64-bit code segment (IA-32e mode only).
+ const FLAGS_L = 1 << 5,
+ /// Default operation size (0 = 16-bit segment, 1 = 32-bit segment).
+ const FLAGS_DB = 1 << 6,
+ /// Granularity (0 = limit in bytes, 1 = limt in 4 KiB Pages).
+ const FLAGS_G = 1 << 7,
+
+ }
+}
+
+impl Flags {
+ pub const BLANK: Flags = Flags { bits: 0 };
+
+ pub fn from_limit2(limit2: u8) -> Flags {
+ assert_eq!(limit2 & !0b111, 0);
+ Flags { bits: limit2 }
+ }
+}
diff --git a/src/shared/task.rs b/src/shared/task.rs
new file mode 100644
index 0000000..b87c032
--- /dev/null
+++ b/src/shared/task.rs
@@ -0,0 +1,9 @@
+//! Helpers to program the task state segment.
+//! See Intel 3a, Chapter 7
+
+pub use shared::segmentation;
+
+/// Load the task state register.
+pub unsafe fn load_tr(sel: segmentation::SegmentSelector) {
+ asm!("ltr $0" :: "r" (sel));
+}