diff options
author | 2018-04-20 19:32:18 -0700 | |
---|---|---|
committer | 2018-04-20 19:32:18 -0700 | |
commit | 1cee98a89ce51331dc21027b6c20615dd00947c2 (patch) | |
tree | 69df4f079e8bd3aa3fac2415b074680cc66ffeb4 | |
parent | a5d2a70541373d263443cfb4ba108c1a3a971070 (diff) | |
download | rust-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.toml | 2 | ||||
-rw-r--r-- | src/bits32/eflags.rs | 50 | ||||
-rw-r--r-- | src/bits32/irq.rs | 9 | ||||
-rw-r--r-- | src/bits32/segmentation.rs | 31 | ||||
-rw-r--r-- | src/bits64/irq.rs | 9 | ||||
-rw-r--r-- | src/bits64/mod.rs | 2 | ||||
-rw-r--r-- | src/bits64/paging.rs | 188 | ||||
-rw-r--r-- | src/bits64/rflags.rs | 50 | ||||
-rw-r--r-- | src/bits64/segmentation.rs | 47 | ||||
-rw-r--r-- | src/controlregs.rs | 86 | ||||
-rw-r--r-- | src/descriptor.rs | 194 | ||||
-rw-r--r-- | src/dtables.rs | 4 | ||||
-rw-r--r-- | src/irq.rs | 36 | ||||
-rw-r--r-- | src/lib.rs | 3 | ||||
-rw-r--r-- | src/segmentation.rs | 506 |
15 files changed, 575 insertions, 642 deletions
@@ -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 @@ -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. @@ -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) } |