diff options
author | 2016-06-29 16:19:18 -0700 | |
---|---|---|
committer | 2016-07-01 14:50:24 -0700 | |
commit | c37a7b580d528f0a4d0721702ddd645a357a405d (patch) | |
tree | 4cc74350de6782a702f002d3545378ba4d96c182 | |
parent | 7234146529386a0d59817055c847b5e906ab605c (diff) | |
download | rust-x86-c37a7b580d528f0a4d0721702ddd645a357a405d.tar.gz rust-x86-c37a7b580d528f0a4d0721702ddd645a357a405d.tar.zst rust-x86-c37a7b580d528f0a4d0721702ddd645a357a405d.zip |
Combine Interface: SegmentSelector; libcpu: permissions parameter
-rw-r--r-- | src/bits64/segmentation.rs | 116 | ||||
-rw-r--r-- | src/bits64/task.rs | 5 | ||||
-rw-r--r-- | src/shared/mod.rs | 55 | ||||
-rw-r--r-- | src/shared/segmentation.rs | 135 |
4 files changed, 142 insertions, 169 deletions
diff --git a/src/bits64/segmentation.rs b/src/bits64/segmentation.rs index e46b333..4f12358 100644 --- a/src/bits64/segmentation.rs +++ b/src/bits64/segmentation.rs @@ -1,76 +1,5 @@ //! Program x86 segmentation hardware. -use core::fmt; - -/// Specifies which element to load into a segment from -/// descriptor tables (i.e., is a index to LDT or GDT table -/// with some additional flags). -bitflags! { - pub flags SegmentSelector: u16 { - /// Requestor Privilege Level - const RPL_0 = 0b00, - const RPL_1 = 0b01, - const RPL_2 = 0b10, - const RPL_3 = 0b11, - - /// Table Indicator (TI) 0 means GDT is used. - const TI_GDT = 0 << 3, - /// Table Indicator (TI) 1 means LDT is used. - const TI_LDT = 1 << 3, - } -} - -impl SegmentSelector { - /// Create a new SegmentSelector - /// - /// # Arguments - /// * `index` index in GDT or LDT array. - /// - pub fn new(index: u16) -> SegmentSelector { - SegmentSelector { bits: index << 3 } - } - - pub fn from_raw(bits: u16) -> SegmentSelector { - SegmentSelector { bits: bits } - } -} - -impl fmt::Display for SegmentSelector { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let r0 = match self.contains(RPL_0) { - false => "", - true => "Ring 0 segment selector.", - }; - let r1 = match self.contains(RPL_1) { - false => "", - true => "Ring 1 segment selector.", - }; - let r2 = match self.contains(RPL_2) { - false => "", - true => "Ring 2 segment selector.", - }; - let r3 = match self.contains(RPL_3) { - false => "", - true => "Ring 3 segment selector.", - }; - let tbl = match self.contains(TI_LDT) { - false => "GDT Table", - true => "LDT Table", - }; - - write!(f, - "Index {} in {}, {}{}{}{}", - self.bits >> 3, - tbl, - r0, - r1, - r2, - r3) - // write!(f, "Index") - } -} - - /// Entry for GDT or LDT. Provides size and location of a segment. bitflags! { pub flags SegmentDescriptor: u64 { @@ -161,48 +90,3 @@ impl SegmentDescriptor { } } } - -/// Reload stack segment register. -pub unsafe fn load_ss(sel: SegmentSelector) { - asm!("movw $0, %ss " :: "r" (sel) : "memory"); -} - -/// Reload data segment register. -pub unsafe fn load_ds(sel: SegmentSelector) { - asm!("movw $0, %ds " :: "r" (sel) : "memory"); -} - -/// Reload es segment register. -pub unsafe fn load_es(sel: SegmentSelector) { - asm!("movw $0, %es " :: "r" (sel) : "memory"); -} - -/// Reload fs segment register. -pub unsafe fn load_fs(sel: SegmentSelector) { - asm!("movw $0, %fs " :: "r" (sel) : "memory"); -} - -/// Reload gs segment register. -pub unsafe fn load_gs(sel: SegmentSelector) { - asm!("movw $0, %gs " :: "r" (sel) : "memory"); -} - -/// Reload code segment register. -/// Note this is special since we can not directly move -/// to %cs. Instead we push the new segment selector -/// and return value on the stack and use lretq -/// to reload cs and continue at 1:. -pub unsafe fn load_cs(sel: SegmentSelector) { - asm!("pushq $0 - lea 1f(%rip), %rax - pushq %rax - lretq - 1:" :: "r" (sel.bits() as u64) : "{rax}" "memory"); -} - -/// Returns the current value of the code segment register. -pub fn cs() -> SegmentSelector { - let segment: u16; - unsafe { asm!("mov %cs, $0" : "=r" (segment) ) }; - SegmentSelector::from_raw(segment) -} diff --git a/src/bits64/task.rs b/src/bits64/task.rs index 97d3341..fff00fe 100644 --- a/src/bits64/task.rs +++ b/src/bits64/task.rs @@ -1,6 +1,9 @@ //! Helpers to program the task state segment. -use super::segmentation; +mod segmentation { + pub use shared::segmentation::*; + pub use super::super::segmentation::*; +} pub type TaskStateDescriptorLow = segmentation::SegmentDescriptor; pub type TaskStateDescriptorHigh = u64; diff --git a/src/shared/mod.rs b/src/shared/mod.rs index 977dcf4..f110934 100644 --- a/src/shared/mod.rs +++ b/src/shared/mod.rs @@ -6,6 +6,9 @@ pub mod dtables; pub mod io; pub mod irq; pub mod paging; +pub mod segmentation; + +use self::segmentation::SegmentSelector; bitflags! { pub flags Flags: usize { @@ -133,64 +136,12 @@ pub enum PrivilegeLevel { Ring3 = 3, } -#[derive(Copy, Clone, PartialEq, Eq)] -#[repr(C, packed)] -pub struct SegmentSelector { - data: u16 -} - -impl SegmentSelector { - #[inline(always)] - pub fn new(index: u16, rpl: PrivilegeLevel) -> SegmentSelector { - SegmentSelector { - data: index << 3 | rpl as u16 - } - } - - pub fn bits(&self) -> u16 { - self.data - } -} - #[inline(always)] pub unsafe fn set_tr(selector: SegmentSelector) { asm!("ltr $0" :: "r"(selector.bits()) :: "volatile", "intel"); } #[inline(always)] -pub unsafe fn set_ss(selector: SegmentSelector) { - asm!("mov ss, $0" :: "r"(selector.bits()) :: "volatile", "intel"); -} - -#[inline(always)] -pub unsafe fn set_ds(selector: SegmentSelector) { - asm!("mov ds, $0" :: "r"(selector.bits()) :: "volatile", "intel"); -} - -#[inline(always)] -pub unsafe fn set_es(selector: SegmentSelector) { - asm!("mov es, $0" :: "r"(selector.bits()) :: "volatile", "intel"); -} - -#[inline(always)] -pub unsafe fn set_gs(selector: SegmentSelector) { - asm!("mov gs, $0" :: "r"(selector.bits()) :: "volatile", "intel"); -} - -#[inline(always)] -pub unsafe fn set_fs(selector: SegmentSelector) { - asm!("mov fs, $0" :: "r"(selector.bits()) :: "volatile", "intel"); -} - -#[inline(always)] -pub unsafe fn set_cs(selector: SegmentSelector) { - asm!("push $0; - push $$1f - lret; - 1:" :: "ri"(selector.bits() as usize) :: "volatile"); -} - -#[inline(always)] pub unsafe fn halt() { asm!("hlt" :::: "volatile", "intel"); } diff --git a/src/shared/segmentation.rs b/src/shared/segmentation.rs new file mode 100644 index 0000000..f4dc194 --- /dev/null +++ b/src/shared/segmentation.rs @@ -0,0 +1,135 @@ +use core::fmt; + +use shared::PrivilegeLevel; + +/// Specifies which element to load into a segment from +/// descriptor tables (i.e., is a index to LDT or GDT table +/// with some additional flags). +bitflags! { + #[repr(C, packed)] + pub flags SegmentSelector: u16 { + /// Requestor Privilege Level + const RPL_0 = 0b00, + const RPL_1 = 0b01, + const RPL_2 = 0b10, + const RPL_3 = 0b11, + + /// Table Indicator (TI) 0 means GDT is used. + const TI_GDT = 0 << 3, + /// Table Indicator (TI) 1 means LDT is used. + const TI_LDT = 1 << 3, + } +} + +/// Reload code segment register. +/// Note this is special since we can not directly move +/// to %cs. Instead we push the new segment selector +/// and return value on the stack and use lretq +/// to reload cs and continue at 1:. +pub unsafe fn set_cs(sel: SegmentSelector) { + + #[cfg(target_arch="x86")] + #[inline(always)] + unsafe fn inner(sel: SegmentSelector) { + asm!("pushl $0; \ + pushl $$1f; \ + lretl; \ + 1:" :: "ri" (sel.bits() as usize) : "{rax}" "memory"); + } + + #[cfg(target_arch="x86_64")] + #[inline(always)] + unsafe fn inner(sel: SegmentSelector) { + asm!("pushq $0; \ + leaq 1f(%rip), %rax; \ + pushq %rax; \ + lretq; \ + 1:" :: "ri" (sel.bits() as usize) : "{rax}" "memory"); + } + + inner(sel) +} + + +impl SegmentSelector { + /// Create a new SegmentSelector + /// + /// # Arguments + /// * `index` index in GDT or LDT array. + /// + pub const fn new(index: u16, rpl: PrivilegeLevel) -> SegmentSelector { + SegmentSelector { bits: index << 3 | (rpl as u16) } + } + + pub const fn from_raw(bits: u16) -> SegmentSelector { + SegmentSelector { bits: bits } + } +} + +impl fmt::Display for SegmentSelector { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let r0 = match self.contains(RPL_0) { + false => "", + true => "Ring 0 segment selector.", + }; + let r1 = match self.contains(RPL_1) { + false => "", + true => "Ring 1 segment selector.", + }; + let r2 = match self.contains(RPL_2) { + false => "", + true => "Ring 2 segment selector.", + }; + let r3 = match self.contains(RPL_3) { + false => "", + true => "Ring 3 segment selector.", + }; + let tbl = match self.contains(TI_LDT) { + false => "GDT Table", + true => "LDT Table", + }; + + write!(f, + "Index {} in {}, {}{}{}{}", + self.bits >> 3, + tbl, + r0, + r1, + r2, + r3) + // write!(f, "Index") + } +} + + +/// Reload stack segment register. +pub unsafe fn load_ss(sel: SegmentSelector) { + asm!("movw $0, %ss " :: "r" (sel) : "memory"); +} + +/// Reload data segment register. +pub unsafe fn load_ds(sel: SegmentSelector) { + asm!("movw $0, %ds " :: "r" (sel) : "memory"); +} + +/// Reload es segment register. +pub unsafe fn load_es(sel: SegmentSelector) { + asm!("movw $0, %es " :: "r" (sel) : "memory"); +} + +/// Reload fs segment register. +pub unsafe fn load_fs(sel: SegmentSelector) { + asm!("movw $0, %fs " :: "r" (sel) : "memory"); +} + +/// Reload gs segment register. +pub unsafe fn load_gs(sel: SegmentSelector) { + asm!("movw $0, %gs " :: "r" (sel) : "memory"); +} + +/// Returns the current value of the code segment register. +pub fn cs() -> SegmentSelector { + let segment: u16; + unsafe { asm!("mov %cs, $0" : "=r" (segment) ) }; + SegmentSelector::from_raw(segment) +} |