aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Gerd Zellweger <mail@gerdzellweger.com> 2018-04-20 19:32:18 -0700
committerGravatar Gerd Zellweger <mail@gerdzellweger.com> 2018-04-20 19:32:18 -0700
commit1cee98a89ce51331dc21027b6c20615dd00947c2 (patch)
tree69df4f079e8bd3aa3fac2415b074680cc66ffeb4
parenta5d2a70541373d263443cfb4ba108c1a3a971070 (diff)
downloadrust-x86-1cee98a89ce51331dc21027b6c20615dd00947c2.tar.gz
rust-x86-1cee98a89ce51331dc21027b6c20615dd00947c2.tar.zst
rust-x86-1cee98a89ce51331dc21027b6c20615dd00947c2.zip
Major rewrite for the segmentation mess.
Signed-off-by: Gerd Zellweger <mail@gerdzellweger.com>
-rw-r--r--Cargo.toml2
-rw-r--r--src/bits32/eflags.rs50
-rw-r--r--src/bits32/irq.rs9
-rw-r--r--src/bits32/segmentation.rs31
-rw-r--r--src/bits64/irq.rs9
-rw-r--r--src/bits64/mod.rs2
-rw-r--r--src/bits64/paging.rs188
-rw-r--r--src/bits64/rflags.rs50
-rw-r--r--src/bits64/segmentation.rs47
-rw-r--r--src/controlregs.rs86
-rw-r--r--src/descriptor.rs194
-rw-r--r--src/dtables.rs4
-rw-r--r--src/irq.rs36
-rw-r--r--src/lib.rs3
-rw-r--r--src/segmentation.rs506
15 files changed, 575 insertions, 642 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 31a5e72..1224313 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -38,7 +38,7 @@ csv = { version = "0.14.3", optional = true }
serde_json = { version = "0.6.0", optional = true }
[dependencies]
-bitflags = "0.7"
+bitflags = "*"
raw-cpuid = "2.*"
[dependencies.phf]
diff --git a/src/bits32/eflags.rs b/src/bits32/eflags.rs
index 4daa917..1b1591c 100644
--- a/src/bits32/eflags.rs
+++ b/src/bits32/eflags.rs
@@ -1,63 +1,63 @@
//! Processor state stored in the EFLAGS register.
-use ::PrivilegeLevel;
+use ::Ring;
/// The EFLAGS register.
bitflags! {
- pub flags EFlags: u32 {
+ pub struct EFlags: u32 {
/// ID Flag (ID)
- const FLAGS_ID = 1 << 21,
+ const FLAGS_ID = 1 << 21;
/// Virtual Interrupt Pending (VIP)
- const FLAGS_VIP = 1 << 20,
+ const FLAGS_VIP = 1 << 20;
/// Virtual Interrupt Flag (VIF)
- const FLAGS_VIF = 1 << 19,
+ const FLAGS_VIF = 1 << 19;
/// Alignment Check (AC)
- const FLAGS_AC = 1 << 18,
+ const FLAGS_AC = 1 << 18;
/// Virtual-8086 Mode (VM)
- const FLAGS_VM = 1 << 17,
+ const FLAGS_VM = 1 << 17;
/// Resume Flag (RF)
- const FLAGS_RF = 1 << 16,
+ const FLAGS_RF = 1 << 16;
/// Nested Task (NT)
- const FLAGS_NT = 1 << 14,
+ const FLAGS_NT = 1 << 14;
/// I/O Privilege Level (IOPL) 0
- const FLAGS_IOPL0 = 0b00 << 12,
+ const FLAGS_IOPL0 = 0b00 << 12;
/// I/O Privilege Level (IOPL) 1
- const FLAGS_IOPL1 = 0b01 << 12,
+ const FLAGS_IOPL1 = 0b01 << 12;
/// I/O Privilege Level (IOPL) 2
- const FLAGS_IOPL2 = 0b10 << 12,
+ const FLAGS_IOPL2 = 0b10 << 12;
/// I/O Privilege Level (IOPL) 3
- const FLAGS_IOPL3 = 0b11 << 12,
+ const FLAGS_IOPL3 = 0b11 << 12;
/// Overflow Flag (OF)
- const FLAGS_OF = 1 << 11,
+ const FLAGS_OF = 1 << 11;
/// Direction Flag (DF)
- const FLAGS_DF = 1 << 10,
+ const FLAGS_DF = 1 << 10;
/// Interrupt Enable Flag (IF)
- const FLAGS_IF = 1 << 9,
+ const FLAGS_IF = 1 << 9;
/// Trap Flag (TF)
- const FLAGS_TF = 1 << 8,
+ const FLAGS_TF = 1 << 8;
/// Sign Flag (SF)
- const FLAGS_SF = 1 << 7,
+ const FLAGS_SF = 1 << 7;
/// Zero Flag (ZF)
- const FLAGS_ZF = 1 << 6,
+ const FLAGS_ZF = 1 << 6;
/// Auxiliary Carry Flag (AF)
- const FLAGS_AF = 1 << 4,
+ const FLAGS_AF = 1 << 4;
/// Parity Flag (PF)
- const FLAGS_PF = 1 << 2,
+ const FLAGS_PF = 1 << 2;
/// Bit 1 is always 1.
- const FLAGS_A1 = 1 << 1,
+ const FLAGS_A1 = 1 << 1;
/// Carry Flag (CF)
- const FLAGS_CF = 1 << 0,
+ const FLAGS_CF = 1 << 0;
}
}
impl EFlags {
/// Creates a new Flags entry. Ensures bit 1 is set.
pub const fn new() -> EFlags {
- FLAGS_A1
+ EFlags::FLAGS_A1
}
/// Creates a new Flags with the given I/O privilege level.
- pub const fn from_priv(iopl: PrivilegeLevel) -> EFlags {
+ pub const fn from_priv(iopl: Ring) -> EFlags {
EFlags { bits: (iopl as u32) << 12 }
}
}
diff --git a/src/bits32/irq.rs b/src/bits32/irq.rs
index 7affeb5..bc385ee 100644
--- a/src/bits32/irq.rs
+++ b/src/bits32/irq.rs
@@ -1,8 +1,8 @@
//! Interrupt description and set-up code.
-
+/*
use ::descriptor::*;
use ::paging::VAddr;
-use ::PrivilegeLevel;
+use ::Ring;
/// An interrupt gate or trap gate descriptor.
///
@@ -17,7 +17,7 @@ pub struct IdtEntry {
/// This must always be zero.
pub reserved: u8,
/// flags.
- pub flags: Flags,
+ pub struct: Flags,
/// The upper 16 bits of ISR.
pub offset_hi: u16
}
@@ -39,7 +39,7 @@ impl IdtEntry {
/// 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 {
+ dpl: Ring, 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,
@@ -55,3 +55,4 @@ impl IdtEntry {
}
}
}
+*/ \ No newline at end of file
diff --git a/src/bits32/segmentation.rs b/src/bits32/segmentation.rs
index 6f0fec8..5327d5e 100644
--- a/src/bits32/segmentation.rs
+++ b/src/bits32/segmentation.rs
@@ -1,10 +1,5 @@
-use core::mem::size_of;
-
-use ::descriptor;
-use ::PrivilegeLevel;
-pub use ::segmentation::*;
-
-use bits32::task::*;
+#[allow(unused_imports)]
+use segmentation::SegmentSelector;
/// Reload code segment register.
/// Note this is special since we can not directly move
@@ -18,25 +13,3 @@ pub unsafe fn set_cs(sel: SegmentSelector) {
lretl; \
1:" :: "ri" (sel.bits() as u32) : "memory");
}
-
-impl SegmentDescriptor {
- pub fn new_memory32(base: u32, limit: u32, ty: Type, accessed: bool, dpl: PrivilegeLevel) -> SegmentDescriptor {
- let ty1 = descriptor::Type::SegmentDescriptor {
- ty: ty,
- accessed: accessed,
- };
- let flags = FLAGS_DB;
- let seg = SegmentDescriptor::memory_or_tss(base, limit, ty1, dpl, flags);
- seg
- }
-
- pub fn new_tss32(tss: &TaskStateSegment, dpl: PrivilegeLevel) -> SegmentDescriptor {
- let tss_ptr = tss as *const TaskStateSegment;
- let ty1 = descriptor::Type::SystemDescriptor {
- size: true,
- ty: descriptor::SystemType::TssAvailable,
- };
- let seg = SegmentDescriptor::memory_or_tss(tss_ptr as u32, size_of::<TaskStateSegment>() as u32, ty1, dpl, Flags::empty());
- seg
- }
-}
diff --git a/src/bits64/irq.rs b/src/bits64/irq.rs
index 50d205d..da2e3c4 100644
--- a/src/bits64/irq.rs
+++ b/src/bits64/irq.rs
@@ -1,7 +1,7 @@
//! Interrupt description and set-up code.
-
+/*
use ::segmentation::SegmentSelector;
-use PrivilegeLevel;
+use Ring;
use descriptor::*;
use paging::VAddr;
@@ -21,7 +21,7 @@ pub struct IdtEntry {
/// This must always be zero.
pub ist_index: u8,
/// Flags.
- pub flags: Flags,
+ pub struct: Flags,
/// The upper 48 bits of ISR (the last 16 bits must be zero).
pub base_hi: u64,
/// Must be zero.
@@ -67,7 +67,7 @@ impl IdtEntry {
pub fn new(
handler: VAddr,
gdt_code_selector: SegmentSelector,
- dpl: PrivilegeLevel,
+ dpl: Ring,
ty: Type,
ist_index: u8,
) -> IdtEntry {
@@ -83,3 +83,4 @@ impl IdtEntry {
}
}
+*/ \ No newline at end of file
diff --git a/src/bits64/mod.rs b/src/bits64/mod.rs
index 0458745..2c4a776 100644
--- a/src/bits64/mod.rs
+++ b/src/bits64/mod.rs
@@ -1,7 +1,7 @@
//! Data structures and functions used by IA-32e but not Protected Mode.
macro_rules! check_flag {
- ($doc:meta, $fun:ident, $flag:ident) => (
+ ($doc:meta, $fun:ident, $flag:expr) => (
#[$doc]
pub fn $fun(&self) -> bool {
self.contains($flag)
diff --git a/src/bits64/paging.rs b/src/bits64/paging.rs
index 0fda00e..ee30f79 100644
--- a/src/bits64/paging.rs
+++ b/src/bits64/paging.rs
@@ -99,26 +99,26 @@ pub fn pt_index(addr: VAddr) -> u64 {
/// PML4 Entry bits description.
bitflags! {
- pub flags PML4Entry: u64 {
+ pub struct PML4Entry: u64 {
/// Present; must be 1 to reference a page-directory-pointer table
- const PML4_P = bit!(0),
+ const P = bit!(0);
/// Read/write; if 0, writes may not be allowed to the 512-GByte region
/// controlled by this entry (see Section 4.6)
- const PML4_RW = bit!(1),
+ const RW = bit!(1);
/// User/supervisor; if 0, user-mode accesses are not allowed
/// to the 512-GByte region controlled by this entry.
- const PML4_US = bit!(2),
+ const US = bit!(2);
/// Page-level write-through; indirectly determines the memory type used to
/// access the page-directory-pointer table referenced by this entry.
- const PML4_PWT = bit!(3),
+ const PWT = bit!(3);
/// Page-level cache disable; indirectly determines the memory type used to
/// access the page-directory-pointer table referenced by this entry.
- const PML4_PCD = bit!(4),
+ const PCD = bit!(4);
/// Accessed; indicates whether this entry has been used for linear-address translation.
- const PML4_A = bit!(5),
+ const A = bit!(5);
/// If IA32_EFER.NXE = 1, execute-disable
/// If 1, instruction fetches are not allowed from the 512-GByte region.
- const PML4_XD = bit!(63),
+ const XD = bit!(63);
}
}
@@ -141,51 +141,51 @@ impl PML4Entry {
PAddr::from_u64(self.bits & ADDRESS_MASK)
}
- check_flag!(doc = "Is page present?", is_present, PML4_P);
+ check_flag!(doc = "Is page present?", is_present, PML4Entry::P);
check_flag!(doc = "Read/write; if 0, writes may not be allowed to the 512-GByte region, controlled by this entry (see Section 4.6)",
- is_writeable, PML4_RW);
+ is_writeable, PML4Entry::RW);
check_flag!(doc = "User/supervisor; if 0, user-mode accesses are not allowed to the 512-GByte region controlled by this entry.",
- is_user_mode_allowed, PML4_US);
+ is_user_mode_allowed, PML4Entry::US);
check_flag!(doc = "Page-level write-through; indirectly determines the memory type used to access the page-directory-pointer table referenced by this entry.",
- is_page_write_through, PML4_PWT);
+ is_page_write_through, PML4Entry::PWT);
check_flag!(doc = "Page-level cache disable; indirectly determines the memory type used to access the page-directory-pointer table referenced by this entry.",
- is_page_level_cache_disabled, PML4_PCD);
+ is_page_level_cache_disabled, PML4Entry::PCD);
check_flag!(doc = "Accessed; indicates whether this entry has been used for linear-address translation.",
- is_accessed, PML4_A);
+ is_accessed, PML4Entry::A);
check_flag!(doc = "If IA32_EFER.NXE = 1, execute-disable. If 1, instruction fetches are not allowed from the 512-GByte region.",
- is_instruction_fetching_disabled, PML4_XD);
+ is_instruction_fetching_disabled, PML4Entry::XD);
}
/// PDPT Entry bits description.
bitflags! {
- pub flags PDPTEntry: u64 {
+ pub struct PDPTEntry: u64 {
/// Present; must be 1 to map a 1-GByte page or reference a page directory.
- const PDPT_P = bit!(0),
+ const P = bit!(0);
/// Read/write; if 0, writes may not be allowed to the 1-GByte region controlled by this entry
- const PDPT_RW = bit!(1),
+ const RW = bit!(1);
/// User/supervisor; user-mode accesses are not allowed to the 1-GByte region controlled by this entry.
- const PDPT_US = bit!(2),
+ const US = bit!(2);
/// Page-level write-through.
- const PDPT_PWT = bit!(3),
+ const PWT = bit!(3);
/// Page-level cache disable.
- const PDPT_PCD = bit!(4),
- /// Accessed; if PDPT_PS set indicates whether software has accessed the 1-GByte page
+ const PCD = bit!(4);
+ /// Accessed; if PS set indicates whether software has accessed the 1-GByte page
/// else indicates whether this entry has been used for linear-address translation
- const PDPT_A = bit!(5),
- /// Dirty; if PDPT_PS indicates whether software has written to the 1-GByte page referenced by this entry.
+ const A = bit!(5);
+ /// Dirty; if PS indicates whether software has written to the 1-GByte page referenced by this entry.
/// else ignored.
- const PDPT_D = bit!(6),
+ const D = bit!(6);
/// Page size; if set this entry maps a 1-GByte page; otherwise, this entry references a page directory.
- /// if not PDPT_PS this is ignored.
- const PDPT_PS = bit!(7),
- /// Global; if PDPT_PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise
- /// if not PDPT_PS this is ignored.
- const PDPT_G = bit!(8),
+ /// if not PS this is ignored.
+ const PS = bit!(7);
+ /// Global; if PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise
+ /// if not PS this is ignored.
+ const G = bit!(8);
/// Indirectly determines the memory type used to access the 1-GByte page referenced by this entry.
- const PDPT_PAT = bit!(12),
+ const PAT = bit!(12);
/// If IA32_EFER.NXE = 1, execute-disable
/// If 1, instruction fetches are not allowed from the 512-GByte region.
- const PDPT_XD = bit!(63),
+ const XD = bit!(63);
}
}
@@ -207,53 +207,53 @@ impl PDPTEntry {
PAddr::from_u64(self.bits & ADDRESS_MASK)
}
- check_flag!(doc = "Is page present?", is_present, PDPT_P);
+ check_flag!(doc = "Is page present?", is_present, PDPTEntry::P);
check_flag!(doc = "Read/write; if 0, writes may not be allowed to the 1-GByte region controlled by this entry.",
- is_writeable, PDPT_RW);
+ is_writeable, PDPTEntry::RW);
check_flag!(doc = "User/supervisor; user-mode accesses are not allowed to the 1-GByte region controlled by this entry.",
- is_user_mode_allowed, PDPT_US);
+ is_user_mode_allowed, PDPTEntry::US);
check_flag!(doc = "Page-level write-through.",
- is_page_write_through, PDPT_PWT);
+ is_page_write_through, PDPTEntry::PWT);
check_flag!(doc = "Page-level cache disable.",
- is_page_level_cache_disabled, PDPT_PCD);
+ is_page_level_cache_disabled, PDPTEntry::PCD);
check_flag!(doc = "Accessed; indicates whether this entry has been used for linear-address translation.",
- is_accessed, PDPT_A);
- check_flag!(doc = "Indirectly determines the memory type used to access the 1-GByte page referenced by this entry. if not PDPT_PS this is ignored.",
- is_pat, PDPT_PAT);
+ is_accessed, PDPTEntry::A);
+ check_flag!(doc = "Indirectly determines the memory type used to access the 1-GByte page referenced by this entry. if not PS this is ignored.",
+ is_pat, PDPTEntry::PAT);
check_flag!(doc = "If IA32_EFER.NXE = 1, execute-disable. If 1, instruction fetches are not allowed from the 512-GByte region.",
- is_instruction_fetching_disabled, PDPT_XD);
+ is_instruction_fetching_disabled, PDPTEntry::XD);
}
/// PD Entry bits description.
bitflags! {
- pub flags PDEntry: u64 {
+ pub struct PDEntry: u64 {
/// Present; must be 1 to map a 2-MByte page or reference a page table.
- const PD_P = bit!(0),
+ const P = bit!(0);
/// Read/write; if 0, writes may not be allowed to the 2-MByte region controlled by this entry
- const PD_RW = bit!(1),
+ const RW = bit!(1);
/// User/supervisor; user-mode accesses are not allowed to the 2-MByte region controlled by this entry.
- const PD_US = bit!(2),
+ const US = bit!(2);
/// Page-level write-through.
- const PD_PWT = bit!(3),
+ const PWT = bit!(3);
/// Page-level cache disable.
- const PD_PCD = bit!(4),
- /// Accessed; if PD_PS set indicates whether software has accessed the 2-MByte page
+ const PCD = bit!(4);
+ /// Accessed; if PS set indicates whether software has accessed the 2-MByte page
/// else indicates whether this entry has been used for linear-address translation
- const PD_A = bit!(5),
- /// Dirty; if PD_PS indicates whether software has written to the 2-MByte page referenced by this entry.
+ const A = bit!(5);
+ /// Dirty; if PS indicates whether software has written to the 2-MByte page referenced by this entry.
/// else ignored.
- const PD_D = bit!(6),
+ const D = bit!(6);
/// Page size; if set this entry maps a 2-MByte page; otherwise, this entry references a page directory.
- const PD_PS = bit!(7),
- /// Global; if PD_PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise
- /// if not PD_PS this is ignored.
- const PD_G = bit!(8),
+ const PS = bit!(7);
+ /// Global; if PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise
+ /// if not PS this is ignored.
+ const G = bit!(8);
/// Indirectly determines the memory type used to access the 2-MByte page referenced by this entry.
- /// if not PD_PS this is ignored.
- const PD_PAT = bit!(12),
+ /// if not PS this is ignored.
+ const PAT = bit!(12);
/// If IA32_EFER.NXE = 1, execute-disable
/// If 1, instruction fetches are not allowed from the 512-GByte region.
- const PD_XD = bit!(63),
+ const XD = bit!(63);
}
}
@@ -276,51 +276,51 @@ impl PDEntry {
}
check_flag!(doc = "Present; must be 1 to map a 2-MByte page or reference a page table.",
- is_present, PD_P);
+ is_present, PDEntry::P);
check_flag!(doc = "Read/write; if 0, writes may not be allowed to the 2-MByte region controlled by this entry",
- is_writeable, PD_RW);
+ is_writeable, PDEntry::RW);
check_flag!(doc = "User/supervisor; user-mode accesses are not allowed to the 2-MByte region controlled by this entry.",
- is_user_mode_allowed, PD_US);
+ is_user_mode_allowed, PDEntry::US);
check_flag!(doc = "Page-level write-through.",
- is_page_write_through, PD_PWT);
+ is_page_write_through, PDEntry::PWT);
check_flag!(doc = "Page-level cache disable.",
- is_page_level_cache_disabled, PD_PCD);
- check_flag!(doc = "Accessed; if PD_PS set indicates whether software has accessed the 2-MByte page else indicates whether this entry has been used for linear-address translation.",
- is_accessed, PD_A);
- check_flag!(doc = "Dirty; if PD_PS set indicates whether software has written to the 2-MByte page referenced by this entry else ignored.",
- is_dirty, PD_D);
+ is_page_level_cache_disabled, PDEntry::PCD);
+ check_flag!(doc = "Accessed; if PS set indicates whether software has accessed the 2-MByte page else indicates whether this entry has been used for linear-address translation.",
+ is_accessed, PDEntry::A);
+ check_flag!(doc = "Dirty; if PS set indicates whether software has written to the 2-MByte page referenced by this entry else ignored.",
+ is_dirty, PDEntry::D);
check_flag!(doc = "Page size; if set this entry maps a 2-MByte page; otherwise, this entry references a page directory.",
- is_page, PD_PS);
- check_flag!(doc = "Global; if PD_PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise if not PD_PS this is ignored.",
- is_global, PD_G);
- check_flag!(doc = "Indirectly determines the memory type used to access the 2-MByte page referenced by this entry. if not PD_PS this is ignored.",
- is_pat, PD_PAT);
+ is_page, PDEntry::PS);
+ check_flag!(doc = "Global; if PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise if not PS this is ignored.",
+ is_global, PDEntry::G);
+ check_flag!(doc = "Indirectly determines the memory type used to access the 2-MByte page referenced by this entry. if not PS this is ignored.",
+ is_pat, PDEntry::PAT);
check_flag!(doc = "If IA32_EFER.NXE = 1, execute-disable. If 1, instruction fetches are not allowed from the 2-Mbyte region.",
- is_instruction_fetching_disabled, PD_XD);
+ is_instruction_fetching_disabled, PDEntry::XD);
}
/// PT Entry bits description.
bitflags! {
- pub flags PTEntry: u64 {
+ pub struct PTEntry: u64 {
/// Present; must be 1 to map a 4-KByte page.
- const PT_P = bit!(0),
+ const P = bit!(0);
/// Read/write; if 0, writes may not be allowed to the 4-KByte region controlled by this entry
- const PT_RW = bit!(1),
+ const RW = bit!(1);
/// User/supervisor; user-mode accesses are not allowed to the 4-KByte region controlled by this entry.
- const PT_US = bit!(2),
+ const US = bit!(2);
/// Page-level write-through.
- const PT_PWT = bit!(3),
+ const PWT = bit!(3);
/// Page-level cache disable.
- const PT_PCD = bit!(4),
+ const PCD = bit!(4);
/// Accessed; indicates whether software has accessed the 4-KByte page
- const PT_A = bit!(5),
+ const A = bit!(5);
/// Dirty; indicates whether software has written to the 4-KByte page referenced by this entry.
- const PT_D = bit!(6),
+ const D = bit!(6);
/// Global; if CR4.PGE = 1, determines whether the translation is global (see Section 4.10); ignored otherwise
- const PT_G = bit!(8),
+ const G = bit!(8);
/// If IA32_EFER.NXE = 1, execute-disable
/// If 1, instruction fetches are not allowed from the 512-GByte region.
- const PT_XD = bit!(63),
+ const XD = bit!(63);
}
}
@@ -344,21 +344,21 @@ impl PTEntry {
}
check_flag!(doc = "Present; must be 1 to map a 4-KByte page or reference a page table.",
- is_present, PT_P);
+ is_present, PTEntry::P);
check_flag!(doc = "Read/write; if 0, writes may not be allowed to the 4-KByte region controlled by this entry",
- is_writeable, PT_RW);
+ is_writeable, PTEntry::RW);
check_flag!(doc = "User/supervisor; user-mode accesses are not allowed to the 4-KByte region controlled by this entry.",
- is_user_mode_allowed, PT_US);
+ is_user_mode_allowed, PTEntry::US);
check_flag!(doc = "Page-level write-through.",
- is_page_write_through, PT_PWT);
+ is_page_write_through, PTEntry::PWT);
check_flag!(doc = "Page-level cache disable.",
- is_page_level_cache_disabled, PT_PCD);
- check_flag!(doc = "Accessed; if PT_PS set indicates whether software has accessed the 4-KByte page else indicates whether this entry has been used for linear-address translation.",
- is_accessed, PT_A);
+ is_page_level_cache_disabled, PTEntry::PCD);
+ check_flag!(doc = "Accessed; if PS set indicates whether software has accessed the 4-KByte page else indicates whether this entry has been used for linear-address translation.",
+ is_accessed, PTEntry::A);
check_flag!(doc = "Dirty; if PD_PS set indicates whether software has written to the 4-KByte page referenced by this entry else ignored.",
- is_dirty, PT_D);
- check_flag!(doc = "Global; if PT_PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise if not PT_PS this is ignored.",
- is_global, PT_G);
+ is_dirty, PTEntry::D);
+ check_flag!(doc = "Global; if PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise if not PS this is ignored.",
+ is_global, PTEntry::G);
check_flag!(doc = "If IA32_EFER.NXE = 1, execute-disable. If 1, instruction fetches are not allowed from the 4-KByte region.",
- is_instruction_fetching_disabled, PT_XD);
+ is_instruction_fetching_disabled, PTEntry::XD);
}
diff --git a/src/bits64/rflags.rs b/src/bits64/rflags.rs
index 937d3d3..6301420 100644
--- a/src/bits64/rflags.rs
+++ b/src/bits64/rflags.rs
@@ -4,65 +4,65 @@
//! The upper 32 bits of RFLAGS register is reserved.
//! The lower 32 bits of RFLAGS is the same as EFLAGS.
-use ::PrivilegeLevel;
+use ::Ring;
/// The RFLAGS register.
/// This is duplicated code from bits32 eflags.rs.
bitflags! {
- pub flags RFlags: u64 {
+ pub struct RFlags: u64 {
/// ID Flag (ID)
- const FLAGS_ID = 1 << 21,
+ const FLAGS_ID = 1 << 21;
/// Virtual Interrupt Pending (VIP)
- const FLAGS_VIP = 1 << 20,
+ const FLAGS_VIP = 1 << 20;
/// Virtual Interrupt Flag (VIF)
- const FLAGS_VIF = 1 << 19,
+ const FLAGS_VIF = 1 << 19;
/// Alignment Check (AC)
- const FLAGS_AC = 1 << 18,
+ const FLAGS_AC = 1 << 18;
/// Virtual-8086 Mode (VM)
- const FLAGS_VM = 1 << 17,
+ const FLAGS_VM = 1 << 17;
/// Resume Flag (RF)
- const FLAGS_RF = 1 << 16,
+ const FLAGS_RF = 1 << 16;
/// Nested Task (NT)
- const FLAGS_NT = 1 << 14,
+ const FLAGS_NT = 1 << 14;
/// I/O Privilege Level (IOPL) 0
- const FLAGS_IOPL0 = 0b00 << 12,
+ const FLAGS_IOPL0 = 0b00 << 12;
/// I/O Privilege Level (IOPL) 1
- const FLAGS_IOPL1 = 0b01 << 12,
+ const FLAGS_IOPL1 = 0b01 << 12;
/// I/O Privilege Level (IOPL) 2
- const FLAGS_IOPL2 = 0b10 << 12,
+ const FLAGS_IOPL2 = 0b10 << 12;
/// I/O Privilege Level (IOPL) 3
- const FLAGS_IOPL3 = 0b11 << 12,
+ const FLAGS_IOPL3 = 0b11 << 12;
/// Overflow Flag (OF)
- const FLAGS_OF = 1 << 11,
+ const FLAGS_OF = 1 << 11;
/// Direction Flag (DF)
- const FLAGS_DF = 1 << 10,
+ const FLAGS_DF = 1 << 10;
/// Interrupt Enable Flag (IF)
- const FLAGS_IF = 1 << 9,
+ const FLAGS_IF = 1 << 9;
/// Trap Flag (TF)
- const FLAGS_TF = 1 << 8,
+ const FLAGS_TF = 1 << 8;
/// Sign Flag (SF)
- const FLAGS_SF = 1 << 7,
+ const FLAGS_SF = 1 << 7;
/// Zero Flag (ZF)
- const FLAGS_ZF = 1 << 6,
+ const FLAGS_ZF = 1 << 6;
/// Auxiliary Carry Flag (AF)
- const FLAGS_AF = 1 << 4,
+ const FLAGS_AF = 1 << 4;
/// Parity Flag (PF)
- const FLAGS_PF = 1 << 2,
+ const FLAGS_PF = 1 << 2;
/// Bit 1 is always 1.
- const FLAGS_A1 = 1 << 1,
+ const FLAGS_A1 = 1 << 1;
/// Carry Flag (CF)
- const FLAGS_CF = 1 << 0,
+ const FLAGS_CF = 1 << 0;
}
}
impl RFlags {
/// Creates a new Flags entry. Ensures bit 1 is set.
pub const fn new() -> RFlags {
- FLAGS_A1
+ RFlags::FLAGS_A1
}
/// Creates a new Flags with the given I/O privilege level.
- pub const fn from_priv(iopl: PrivilegeLevel) -> RFlags {
+ pub const fn from_priv(iopl: Ring) -> RFlags {
RFlags { bits: (iopl as u64) << 12 }
}
}
diff --git a/src/bits64/segmentation.rs b/src/bits64/segmentation.rs
index 4c440e9..f43828a 100644
--- a/src/bits64/segmentation.rs
+++ b/src/bits64/segmentation.rs
@@ -1,16 +1,12 @@
-use core::mem::size_of;
-
-use ::descriptor;
-use ::PrivilegeLevel;
-pub use ::segmentation::*;
-use bits64::task::*;
+#[allow(unused_imports)]
+use segmentation::SegmentSelector;
/// 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:.
-#[cfg(target_arch="x86-64")]
+#[cfg(target_arch="x86_64")]
pub unsafe fn set_cs(sel: SegmentSelector) {
asm!("pushq $0; \
leaq 1f(%rip), %rax; \
@@ -18,40 +14,3 @@ pub unsafe fn set_cs(sel: SegmentSelector) {
lretq; \
1:" :: "ri" (sel.bits() as usize) : "rax" "memory");
}
-
-pub enum SegmentBitness {
- Bits32,
- Bits64,
-}
-
-impl SegmentBitness {
- pub fn pack(self) -> Flags {
- match self {
- SegmentBitness::Bits32 => FLAGS_DB,
- SegmentBitness::Bits64 => FLAGS_L,
- }
- }
-}
-
-impl SegmentDescriptor {
- pub fn new_memory64(base: u32, limit: u32, ty: Type, accessed: bool, dpl: PrivilegeLevel, bitness: SegmentBitness) -> SegmentDescriptor {
- let ty1 = descriptor::Type::SegmentDescriptor {
- ty: ty,
- accessed: accessed,
- };
- let flags = bitness.pack();
- let seg = SegmentDescriptor::memory_or_tss(base, limit, ty1, dpl, flags);
- seg
- }
-
- pub fn new_tss64(tss: &TaskStateSegment, dpl: PrivilegeLevel) -> [SegmentDescriptor; 2] {
- let tss_ptr = tss as *const TaskStateSegment;
- let ty1 = descriptor::Type::SystemDescriptor {
- size: true,
- ty: descriptor::SystemType::TssAvailable,
- };
- let seg1 = SegmentDescriptor::memory_or_tss(tss_ptr as u32, size_of::<TaskStateSegment>() as u32, ty1, dpl, Flags::empty());
- let seg2 = SegmentDescriptor::high(tss_ptr as u64);
- [seg1, seg2]
- }
-}
diff --git a/src/controlregs.rs b/src/controlregs.rs
index 1a1f6a3..3e611e1 100644
--- a/src/controlregs.rs
+++ b/src/controlregs.rs
@@ -2,57 +2,57 @@
//! See Intel Vol. 3a Section 2.5, especially Figure 2-7.
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,
+ pub struct 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_PROTECTION_KEY = 1 << 22,
- 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_FSGSBASE = 1 << 16,
- const CR4_ENABLE_SMX = 1 << 14,
- const CR4_ENABLE_VMX = 1 << 13,
- const CR4_ENABLE_UMIP = 1 << 11,
- 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,
+ pub struct Cr4: usize {
+ const CR4_ENABLE_PROTECTION_KEY = 1 << 22;
+ 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_FSGSBASE = 1 << 16;
+ const CR4_ENABLE_SMX = 1 << 14;
+ const CR4_ENABLE_VMX = 1 << 13;
+ const CR4_ENABLE_UMIP = 1 << 11;
+ 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;
}
}
bitflags! {
- pub flags Xcr0: u64 {
- const XCR0_PKRU_STATE = 1 << 9,
- const XCR0_HI16_ZMM_STATE = 1 << 7,
- const XCR0_ZMM_HI256_STATE = 1 << 6,
- const XCR0_OPMASK_STATE = 1 << 5,
- const XCR0_BNDCSR_STATE = 1 << 4,
- const XCR0_BNDREG_STATE = 1 << 3,
- const XCR0_AVX_STATE = 1 << 2,
- const XCR0_SSE_STATE = 1 << 1,
- const XCR0_FPU_MMX_STATE = 1 << 0,
+ pub struct Xcr0: u64 {
+ const XCR0_PKRU_STATE = 1 << 9;
+ const XCR0_HI16_ZMM_STATE = 1 << 7;
+ const XCR0_ZMM_HI256_STATE = 1 << 6;
+ const XCR0_OPMASK_STATE = 1 << 5;
+ const XCR0_BNDCSR_STATE = 1 << 4;
+ const XCR0_BNDREG_STATE = 1 << 3;
+ const XCR0_AVX_STATE = 1 << 2;
+ const XCR0_SSE_STATE = 1 << 1;
+ const XCR0_FPU_MMX_STATE = 1 << 0;
}
}
diff --git a/src/descriptor.rs b/src/descriptor.rs
deleted file mode 100644
index aff4f0e..0000000
--- a/src/descriptor.rs
+++ /dev/null
@@ -1,194 +0,0 @@
-//! Fields which are common to all segment-section and gate descriptors
-
-use ::PrivilegeLevel;
-use ::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_SEG.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_C_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_CODE.bits,
- /// Code Execute-Only, accessed
- const FLAGS_TYPE_SEG_C_EOA = FLAGS_TYPE_CODE.bits
- | FLAGS_TYPE_SEG_ACCESSED.bits,
- /// Code Execute/Read
- const FLAGS_TYPE_SEG_C_ER = FLAGS_TYPE_CODE.bits
- | FLAGS_TYPE_SEG_C_READ.bits,
- /// Code Execute/Read, accessed
- const FLAGS_TYPE_SEG_C_ERA = FLAGS_TYPE_CODE.bits
- | FLAGS_TYPE_SEG_C_READ.bits
- | FLAGS_TYPE_SEG_ACCESSED.bits,
- /// Code Execute-Only, conforming
- const FLAGS_TYPE_SEG_C_EOC = FLAGS_TYPE_CODE.bits
- | FLAGS_TYPE_SEG_C_CONFORMING.bits,
- /// Code Execute-Only, conforming, accessed
- const FLAGS_TYPE_SEG_C_EOCA = FLAGS_TYPE_CODE.bits
- | FLAGS_TYPE_SEG_C_CONFORMING.bits
- | FLAGS_TYPE_SEG_ACCESSED.bits,
- /// Code Execute/Read, conforming
- const FLAGS_TYPE_SEG_C_ERC = FLAGS_TYPE_CODE.bits
- | FLAGS_TYPE_SEG_C_READ.bits
- | FLAGS_TYPE_SEG_C_CONFORMING.bits,
- /// Code Execute/Read, conforming, accessed
- const FLAGS_TYPE_SEG_C_ERCA = FLAGS_TYPE_CODE.bits
- | FLAGS_TYPE_SEG_C_READ.bits
- | FLAGS_TYPE_SEG_C_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/dtables.rs b/src/dtables.rs
index 5f2b17a..97395d6 100644
--- a/src/dtables.rs
+++ b/src/dtables.rs
@@ -3,7 +3,6 @@
use core::fmt;
use core::mem::size_of;
-use current::irq::IdtEntry;
use segmentation::SegmentDescriptor;
/// A struct describing a pointer to a descriptor table (GDT / IDT).
@@ -45,8 +44,9 @@ pub unsafe fn lgdt(gdt: &DescriptorTablePointer<SegmentDescriptor>) {
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");
}
+*/ \ No newline at end of file
diff --git a/src/irq.rs b/src/irq.rs
index f93491d..68d675c 100644
--- a/src/irq.rs
+++ b/src/irq.rs
@@ -185,46 +185,46 @@ pub static EXCEPTIONS: [InterruptDescription; 21] = [
bitflags!{
// Taken from Intel Manual Section 4.7 Page-Fault Exceptions.
- pub flags PageFaultError: u32 {
+ pub struct 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),
+ 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),
+ 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),
+ 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),
+ 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),
+ 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),
+ 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) {
+ let p = match self.contains(PageFaultError::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) {
+ let wr = match self.contains(PageFaultError::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) {
+ let us = match self.contains(PageFaultError::PFAULT_ERROR_US) {
false => {
"The access causing the fault originated when the processor was executing in \
supervisor mode."
@@ -234,11 +234,11 @@ impl fmt::Display for PageFaultError {
mode."
}
};
- let rsvd = match self.contains(PFAULT_ERROR_RSVD) {
+ let rsvd = match self.contains(PageFaultError::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) {
+ let id = match self.contains(PageFaultError::PFAULT_ERROR_ID) {
false => "The fault was not caused by an instruction fetch.",
true => "The fault was caused by an instruction fetch.",
};
@@ -249,12 +249,12 @@ impl fmt::Display for PageFaultError {
#[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);
+ assert!(PageFaultError::PFAULT_ERROR_PK.bits() == 0b100000);
+ assert!(PageFaultError::PFAULT_ERROR_ID.bits() == 0b10000);
+ assert!(PageFaultError::PFAULT_ERROR_RSVD.bits() == 0b1000);
+ assert!(PageFaultError::PFAULT_ERROR_US.bits() == 0b100);
+ assert!(PageFaultError::PFAULT_ERROR_WR.bits() == 0b10);
+ assert!(PageFaultError::PFAULT_ERROR_P.bits() == 0b1);
}
/// Enable Interrupts.
diff --git a/src/lib.rs b/src/lib.rs
index 7768244..1d93883 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -22,7 +22,6 @@ pub mod bits32;
pub mod bits64;
pub mod controlregs;
-pub mod descriptor;
pub mod dtables;
pub mod io;
pub mod irq;
@@ -55,7 +54,7 @@ mod std {
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
-pub enum PrivilegeLevel {
+pub enum Ring {
Ring0 = 0,
Ring1 = 1,
Ring2 = 2,
diff --git a/src/segmentation.rs b/src/segmentation.rs
index 7672d4a..e919a8b 100644
--- a/src/segmentation.rs
+++ b/src/segmentation.rs
@@ -1,7 +1,6 @@
use core::fmt;
-use ::descriptor;
-use ::PrivilegeLevel;
+use Ring;
/// Specifies which element to load into a segment from
/// descriptor tables (i.e., is a index to LDT or GDT table
@@ -9,18 +8,17 @@ use ::PrivilegeLevel;
///
/// See Intel 3a, Section 3.4.2 "Segment Selectors"
bitflags! {
- #[repr(C, packed)]
- pub flags SegmentSelector: u16 {
+ pub struct SegmentSelector: u16 {
/// Requestor Privilege Level
- const RPL_0 = 0b00,
- const RPL_1 = 0b01,
- const RPL_2 = 0b10,
- const RPL_3 = 0b11,
+ 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 << 2,
+ const TI_GDT = 0 << 2;
/// Table Indicator (TI) 1 means LDT is used.
- const TI_LDT = 1 << 2,
+ const TI_LDT = 1 << 2;
}
}
@@ -28,12 +26,15 @@ 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) }
+ /// * `index` - index in GDT or LDT array.
+ /// * `rpl` - Requested privilege level of the selector
+ pub const fn new(index: u16, rpl: Ring) -> SegmentSelector {
+ SegmentSelector {
+ bits: index << 3 | (rpl as u16),
+ }
}
+ /// Make a new segment selector from a untyped u16 value.
pub const fn from_raw(bits: u16) -> SegmentSelector {
SegmentSelector { bits: bits }
}
@@ -41,203 +42,396 @@ impl SegmentSelector {
impl fmt::Display for SegmentSelector {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let r0 = match self.contains(RPL_0) {
+ let r0 = match self.contains(SegmentSelector::RPL_0) {
false => "",
true => "Ring 0 segment selector.",
};
- let r1 = match self.contains(RPL_1) {
+ let r1 = match self.contains(SegmentSelector::RPL_1) {
false => "",
true => "Ring 1 segment selector.",
};
- let r2 = match self.contains(RPL_2) {
+ let r2 = match self.contains(SegmentSelector::RPL_2) {
false => "",
true => "Ring 2 segment selector.",
};
- let r3 = match self.contains(RPL_3) {
+ let r3 = match self.contains(SegmentSelector::RPL_3) {
false => "",
true => "Ring 3 segment selector.",
};
- let tbl = match self.contains(TI_LDT) {
+ let tbl = match self.contains(SegmentSelector::TI_LDT) {
false => "GDT Table",
true => "LDT Table",
};
- write!(f,
- "Index {} in {}, {}{}{}{}",
- self.bits >> 3,
- tbl,
- r0,
- r1,
- r2,
- r3)
- // write!(f, "Index")
+ write!(
+ f,
+ "Index {} in {}, {}{}{}{}",
+ self.bits >> 3,
+ tbl,
+ r0,
+ r1,
+ r2,
+ r3
+ )
}
}
+/// 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,
+ type_access: u8,
+ limit2_flags: u8,
+ base3: u8,
+}
-/// Reload stack segment register.
-pub unsafe fn load_ss(sel: SegmentSelector) {
- asm!("movw $0, %ss " :: "r" (sel.bits()) : "memory");
+#[repr(u8)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum DataSegmentType {
+ /// Data Read-Only
+ ReadOnly = 0b0000,
+ /// Data Read-Only, accessed
+ ReadOnlyAccessed = 0b0001,
+ /// Data Read/Write
+ ReadWrite = 0b0010,
+ /// Data Read/Write, accessed
+ ReadWriteAccessed = 0b0011,
+ /// Data Read-Only, expand-down
+ ReadExpand = 0b0100,
+ /// Data Read-Only, expand-down, accessed
+ ReadExpandAccessed = 0b0101,
+ /// Data Read/Write, expand-down
+ ReadWriteExpand = 0b0110,
+ /// Data Read/Write, expand-down, accessed
+ ReadWriteExpandAccessed = 0b0111,
}
-/// Reload data segment register.
-pub unsafe fn load_ds(sel: SegmentSelector) {
- asm!("movw $0, %ds " :: "r" (sel.bits()) : "memory");
+#[repr(u8)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum CodeSegmentType {
+ /// Code Execute-Only
+ Execute = 0b1000,
+ /// Code Execute-Only, accessed
+ ExecuteAccessed = 0b1001,
+ /// Code Execute/Read
+ ExecuteRead = 0b1010,
+ /// Code Execute/Read, accessed
+ ExecuteReadAccessed = 0b1011,
+ /// Code Execute-Only, conforming
+ ExecuteConforming = 0b1100,
+ /// Code Execute-Only, conforming, accessed
+ ExecuteConformingAccessed = 0b1101,
+ /// Code Execute/Read, conforming
+ ExecuteReadConforming = 0b1110,
+ /// Code Execute/Read, conforming, accessed
+ ExecuteReadConformingAccessed = 0b1111,
}
-/// Reload es segment register.
-pub unsafe fn load_es(sel: SegmentSelector) {
- asm!("movw $0, %es " :: "r" (sel.bits()) : "memory");
+/// System-Segment and Gate-Descriptor Types 32-bit mode
+#[repr(u8)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+enum SystemDescriptor32 {
+ //Reserved0 = 0b0000,
+ TSSAvailable16 = 0b0001,
+ LDT = 0b0010,
+ TSSBusy16 = 0b0011,
+ CallGate16 = 0b0100,
+ TaskGate = 0b0101,
+ InterruptGate16 = 0b0110,
+ TrapGate16 = 0b0111,
+ //Reserved1 = 0b1000,
+ TssAvailable32 = 0b1001,
+ //Reserved2 = 0b1010,
+ TssBusy32 = 0b1011,
+ CallGate32 = 0b1100,
+ //Reserved3 = 0b1101,
+ InterruptGate32 = 0b1110,
+ TrapGate32 = 0b1111,
}
-/// Reload fs segment register.
-pub unsafe fn load_fs(sel: SegmentSelector) {
- asm!("movw $0, %fs " :: "r" (sel.bits()) : "memory");
+/// System-Segment and Gate-Descriptor Types 64-bit mode
+#[repr(u8)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+enum SystemDescriptor64 {
+ //Reserved0 = 0b0000,
+ //Reserved1 = 0b0001,
+ LDT = 0b0010,
+ //Reserved = 0b0011,
+ //Reserved = 0b0100,
+ //Reserved = 0b0101,
+ //Reserved = 0b0110,
+ //Reserved = 0b0111,
+ //Reserved = 0b1000,
+ TssAvailable64 = 0b1001,
+ //Reserved = 0b1010,
+ TssBusy64 = 0b1011,
+ CallGate64 = 0b1100,
+ //Reserved = 0b1101,
+ InterruptGate64 = 0b1110,
+ TrapGate64 = 0b1111,
}
-/// Reload gs segment register.
-pub unsafe fn load_gs(sel: SegmentSelector) {
- asm!("movw $0, %gs " :: "r" (sel.bits()) : "memory");
+#[derive(Debug, Eq, PartialEq)]
+pub enum SystemMode {
+ Mode16,
+ Mode32,
+ Mode64,
}
-/// 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)
+/// Makes building descriptors easier (hopefully).
+pub struct DescriptorBuilder {
+ /// What privilege level the descriptor is for.
+ mode: SystemMode,
+
+ /// Defines the location of byte 0 of the segment within the 4-GByte linear address space.
+ base: u32,
+ /// The size of the range covered by the segment. Really a 20bit value.
+ limit: u32,
+
+ /// The type of the segment if we have a data segment.
+ dst: Option<DataSegmentType>,
+ /// The type of the segment if we have a code segment.
+ cst: Option<CodeSegmentType>,
+ /// The type of the segment if we have a system segment in 32bit mode.
+ system_type32: Option<SystemDescriptor32>,
+ /// The type of the segment if we have a system segment in 64bit mode.
+ system_type64: Option<SystemDescriptor64>,
+
+ /// Specifies the privilege level of the segment. The privilege level can range from 0 to 3, with 0 being the most privileged level.
+ dpl: Option<Ring>,
+ /// Indicates whether the segment is present in memory (set) or not present (clear).
+ present: bool,
+ /// Available for use by system software
+ avl: bool,
+ /// Performs different functions depending on whether the segment descriptor is an executable code segment, an expand-down data segment, or a stack segment.
+ db: bool,
+ /// Determines the scaling of the segment limit field. When the granularity flag is clear, the segment limit is interpreted in byte units; when flag is set, the segment limit is interpreted in 4-KByte units.
+ limit_granularity_4k: bool,
}
+impl DescriptorBuilder {
+ pub fn new(mode: SystemMode) -> DescriptorBuilder {
+ DescriptorBuilder {
+ base: 0,
+ limit: 0,
+ mode: mode,
+ dst: None,
+ cst: None,
+ system_type32: None,
+ system_type64: None,
+ dpl: None,
+ present: false,
+ db: false,
+ avl: false,
+ limit_granularity_4k: false,
+ }
+ }
-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,
+ /// Set a base for the descriptor.
+ pub fn base(mut self, base: u32) -> DescriptorBuilder {
+ self.base = base;
+ self
}
-}
-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,
+ /// Set the limit for the descriptor.
+ pub fn limit(mut self, limit: u32) -> DescriptorBuilder {
+ self.limit = limit;
+ self
}
-}
-/// Umbrella Segment Type.
-///
-/// See Table 3-1, "Code- and Data-Segment Types"
-#[repr(u8)]
-pub enum Type {
- Data(DataAccess),
- Code(CodeAccess),
-}
+ /// The segment limit is interpreted in 4-KByte units if this is set.
+ pub fn limit_granularity_4kb(mut self) -> DescriptorBuilder {
+ self.limit_granularity_4k = true;
+ self
+ }
-impl Type {
- pub fn pack(self) -> u8 {
- match self {
- Type::Data(d) => d.bits | 0b10_000,
- Type::Code(c) => c.bits | 0b11_000,
+ /// Indicates whether the segment is present in memory (set) or not present (clear).
+ pub fn present(mut self) -> DescriptorBuilder {
+ self.present = true;
+ self
+ }
+
+ /// Specifies the privilege level of the segment.
+ pub fn dpl(mut self, dpl: Ring) -> DescriptorBuilder {
+ self.dpl = Some(dpl);
+ self
+ }
+
+ /// Toggle the AVL bit.
+ pub fn avl(mut self) -> DescriptorBuilder {
+ self.avl = true;
+ self
+ }
+
+ /// Make a ldt descriptor.
+ pub fn ldt_descriptor(mut self) -> DescriptorBuilder {
+ match self.mode {
+ SystemMode::Mode16 => self.system_type32 = Some(SystemDescriptor32::LDT),
+ SystemMode::Mode32 => self.system_type32 = Some(SystemDescriptor32::LDT),
+ SystemMode::Mode64 => self.system_type64 = Some(SystemDescriptor64::LDT),
}
+ self
+ }
+
+ /// Make a tss descriptor.
+ pub fn tss_descriptor(mut self, available: bool) -> DescriptorBuilder {
+ match (available, &self.mode) {
+ (true, SystemMode::Mode16) => self.system_type32 = Some(SystemDescriptor32::TSSAvailable16),
+ (true, SystemMode::Mode32) => self.system_type32 = Some(SystemDescriptor32::TssAvailable32),
+ (true, SystemMode::Mode64) => self.system_type64 = Some(SystemDescriptor64::TssAvailable64),
+ (false, SystemMode::Mode16) => self.system_type32 = Some(SystemDescriptor32::TSSBusy16),
+ (false, SystemMode::Mode32) => self.system_type32 = Some(SystemDescriptor32::TssBusy32),
+ (false, SystemMode::Mode64) => self.system_type64 = Some(SystemDescriptor64::TssBusy64),
+ }
+ self
}
-}
+ /// Make a call gate descriptor.
+ pub fn call_gate_descriptor(mut self) -> DescriptorBuilder {
+ match self.mode {
+ SystemMode::Mode16 => self.system_type32 = Some(SystemDescriptor32::CallGate16),
+ SystemMode::Mode32 => self.system_type32 = Some(SystemDescriptor32::CallGate32),
+ SystemMode::Mode64 => self.system_type64 = Some(SystemDescriptor64::CallGate64),
+ }
+ self
+ }
-/// 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,
-}
+ /// Make an interrupt descriptor.
+ pub fn interrupt_descriptor(mut self) -> DescriptorBuilder {
+ match self.mode {
+ SystemMode::Mode16 => self.system_type32 = Some(SystemDescriptor32::InterruptGate16),
+ SystemMode::Mode32 => self.system_type32 = Some(SystemDescriptor32::InterruptGate32),
+ SystemMode::Mode64 => self.system_type64 = Some(SystemDescriptor64::InterruptGate64),
+ }
+ self
+ }
+
+ /// Make a trap gate descriptor
+ pub fn trap_gate_descriptor(mut self) -> DescriptorBuilder {
+ match self.mode {
+ SystemMode::Mode16 => self.system_type32 = Some(SystemDescriptor32::TrapGate16),
+ SystemMode::Mode32 => self.system_type32 = Some(SystemDescriptor32::TrapGate32),
+ SystemMode::Mode64 => self.system_type64 = Some(SystemDescriptor64::TrapGate64),
+ }
+ self
+ }
+ /// Make a task gate descriptor. Note: This call will panic if mode is not 32bit!
+ pub fn task_gate_descriptor(mut self) -> DescriptorBuilder {
+ match self.mode {
+ SystemMode::Mode32 => self.system_type32 = Some(SystemDescriptor32::TaskGate),
+ _ => panic!("Can't build a taskgate for {:?}", self.mode)
+ }
+ self
+ }
-/// This data-structure is an ugly mess thing so we provide some
-/// convenience function to program it.
-impl SegmentDescriptor {
- pub const NULL: SegmentDescriptor = SegmentDescriptor {
- limit1: 0,
- base1: 0,
- base2: 0,
- access: descriptor::Flags::BLANK,
- limit2_flags: Flags::BLANK,
- base3: 0,
- };
-
- /// Outputs a memory or TSS descriptor.
- /// For a TSS descriptor on x86-64, you also need a high descriptor as second entry (see below).
- pub(crate) fn memory_or_tss(base: u32, limit: u32, ty: descriptor::Type, dpl: PrivilegeLevel, flags: Flags) -> 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)
- };
- SegmentDescriptor {
- limit1: limit1,
- base1: base as u16,
- base2: ((base as usize & 0xFF0000) >> 16) as u8,
- access: descriptor::Flags::from_type(ty)
- | descriptor::Flags::from_priv(dpl)
- | descriptor::FLAGS_PRESENT,
- limit2_flags: if fine_grained { Flags::empty() } else { FLAGS_G }
- | flags
- | Flags::from_limit2(limit2),
- base3: ((base as usize & 0xFF000000) >> 24) as u8,
+ // Make a code segment descriptor.
+ pub fn new_code_descriptor(mut self, cst: CodeSegmentType) -> DescriptorBuilder {
+ self.cst = Some(cst);
+ if self.mode == SystemMode::Mode32 {
+ // Not sure it's always ok to do this here but the manual says:
+ // This flag should always be set to 1 for 32-bit code and data segments and to 0 for 16-bit code and data segments.
+ self.db = true;
}
+ self
}
- /// Outputs a descriptor containing the high 32 bits of a memory address.
- /// Serves as the second entry for descriptors that consume 2 table entries in x86-64.
- pub(crate) const fn high(address: u64) -> SegmentDescriptor {
- SegmentDescriptor {
- limit1: (address >> 32) as u16,
- base1: (address >> 48) as u16,
+ // Make a data segment descriptor.
+ pub fn new_data_descriptor(mut self, dst: DataSegmentType) -> DescriptorBuilder {
+ self.dst = Some(dst);
+ if self.mode == SystemMode::Mode32 {
+ // Not sure it's always ok to do this here but the manual says:
+ // This flag should always be set to 1 for 32-bit code and data segments and to 0 for 16-bit code and data segments.
+ self.db = true;
+ }
+ self
+ }
+
+ // Build the final segment descriptor.
+ pub fn finish(&self) -> SegmentDescriptor {
+ let mut sd = SegmentDescriptor {
+ limit1: 0,
+ base1: 0,
base2: 0,
- access: descriptor::Flags::BLANK,
- limit2_flags: Flags::BLANK,
+ type_access: 0,
+ limit2_flags: 0,
base3: 0,
+ };
+
+ // Set base
+ sd.base1 = self.base as u16;
+ sd.base2 = (self.base >> 16) as u8;
+ sd.base3 = (self.base >> 24) as u8;
+
+ // Set limit
+ sd.limit1 = self.limit as u16;
+ sd.limit2_flags = (sd.limit2_flags & 0xf0) | (((self.limit >> 16) as u8) & 0x0f);
+
+ // Set Type and S
+ // s_bit specifies whether the segment descriptor is for a system segment (S flag is clear) or a code or data segment (S flag is set).
+ let s_bit = 1 << 4;
+ match (self.dst, self.cst, self.system_type32, self.system_type64) {
+ (Some(typ), None, None, None) => sd.type_access = (sd.type_access & 0xf0) | s_bit | (typ as u8 & 0x0f),
+ (None, Some(typ), None, None) => sd.type_access = (sd.type_access & 0xf0) | s_bit | (typ as u8 & 0x0f),
+ (None, None, Some(typ), None) => sd.type_access = (sd.type_access & 0xf0) | (typ as u8 & 0x0f),
+ (None, None, None, Some(typ)) => sd.type_access = (sd.type_access & 0xf0) | (typ as u8 & 0x0f),
+ (None, None, None, None) => {/* do nothing */},
+ _ => panic!("Trying to build a segment descriptor that is multiple types is not possible."),
}
+
+ // Set DPL
+ self.dpl.map(|ring| {
+ sd.type_access |= (ring as u8) << 5;
+ });
+ // Set P
+ sd.type_access |= (self.present as u8) << 7;
+ // Set AVL
+ sd.limit2_flags |= (self.avl as u8) << 4;
+ // Set L
+ sd.limit2_flags |= ((self.mode == SystemMode::Mode64) as u8) << 5;
+ // Set D/B
+ sd.limit2_flags |= (self.db as u8) << 6;
+ // Set G
+ sd.limit2_flags |= (self.limit_granularity_4k as u8) << 7;
+
+ sd
}
}
-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 = limit in 4 KiB Pages).
- const FLAGS_G = 1 << 7,
+/// Reload stack segment register.
+pub unsafe fn load_ss(sel: SegmentSelector) {
+ asm!("movw $0, %ss " :: "r" (sel.bits()) : "memory");
+}
- }
+/// Reload data segment register.
+pub unsafe fn load_ds(sel: SegmentSelector) {
+ asm!("movw $0, %ds " :: "r" (sel.bits()) : "memory");
}
-impl Flags {
- pub const BLANK: Flags = Flags { bits: 0 };
+/// Reload es segment register.
+pub unsafe fn load_es(sel: SegmentSelector) {
+ asm!("movw $0, %es " :: "r" (sel.bits()) : "memory");
+}
- pub fn from_limit2(limit2: u8) -> Flags {
- assert_eq!(limit2 & !0b1111, 0);
- Flags { bits: limit2 }
- }
+/// Reload fs segment register.
+pub unsafe fn load_fs(sel: SegmentSelector) {
+ asm!("movw $0, %fs " :: "r" (sel.bits()) : "memory");
+}
+
+/// Reload gs segment register.
+pub unsafe fn load_gs(sel: SegmentSelector) {
+ asm!("movw $0, %gs " :: "r" (sel.bits()) : "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)
}