aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bits32/mod.rs79
-rw-r--r--src/bits64/mod.rs1
-rw-r--r--src/bits64/segmentation.rs92
-rw-r--r--src/bits64/task.rs2
-rw-r--r--src/shared/descriptor.rs85
-rw-r--r--src/shared/dtables.rs44
-rw-r--r--src/shared/segmentation.rs127
7 files changed, 253 insertions, 177 deletions
diff --git a/src/bits32/mod.rs b/src/bits32/mod.rs
index 13aa20e..ac872d7 100644
--- a/src/bits32/mod.rs
+++ b/src/bits32/mod.rs
@@ -3,64 +3,7 @@
pub mod irq;
pub mod task;
-pub use shared::{
- Flags,
- PrivilegeLevel,
-};
-pub use self::irq::IdtEntry;
-
-use core::mem::size_of;
-
-bitflags! {
- pub flags GdtAccess: u8 {
- const Accessed = 1 << 0,
- const Writable = 1 << 1,
- const Direction = 1 << 2,
- const Executable = 1 << 3,
- const NotTss = 1 << 4,
- }
-}
-
-#[derive(Copy, Clone, Debug)]
-#[repr(C, packed)]
-pub struct GdtEntry {
- limit: u16,
- base1: u16,
- base2: u8,
- access: u8,
- flags: u8,
- base3: u8,
-}
-
-impl GdtEntry {
- pub const NULL: GdtEntry = GdtEntry {
- base1: 0,
- base2: 0,
- base3: 0,
- access: 0,
- limit: 0,
- flags: 0
- };
-
- pub fn new(base: *const (), limit: usize, access: GdtAccess, dpl: PrivilegeLevel) -> GdtEntry {
- let (limit, flags) = if limit < 0x100000 {
- ((limit & 0xFFFF) as u16, ((limit & 0xF0000) >> 16) as u8 | 0x40u8)
- } else {
- if ((limit - 0xFFF) & 0xFFF) > 0 {
- panic!("bad segment limit for GDT entry");
- }
- (((limit & 0xFFFF000) >> 12) as u16, ((limit & 0xF0000000) >> 28) as u8 | 0xC0u8)
- };
- GdtEntry {
- base1: base as u16,
- base2: ((base as usize & 0xFF0000) >> 16) as u8,
- base3: ((base as usize & 0xFF000000) >> 24) as u8,
- access: access.bits() | ((dpl as u8) << 5) | 0x80,
- limit: limit,
- flags: flags
- }
- }
-}
+pub use shared::Flags;
#[inline(always)]
pub fn get_flags() -> Flags {
@@ -77,26 +20,6 @@ pub unsafe fn set_flags(val: Flags) {
}
#[inline(always)]
-pub unsafe fn set_gdt(gdt: &[GdtEntry]) {
- #[repr(C, packed)]
- struct GDTR {
- limit: u16,
- ptr: *const GdtEntry,
- }
- asm!("lgdtl $0" :: "*m"(&GDTR { ptr: gdt.as_ptr(), limit: (gdt.len()*size_of::<GdtEntry>() - 1) as u16 }) :: "volatile");
-}
-
-#[inline(always)]
-pub unsafe fn set_idt(idt: &[IdtEntry]) {
- #[repr(C, packed)]
- struct IDTR {
- limit: u16,
- ptr: *const IdtEntry,
- }
- asm!("lidtl $0" :: "*m"(&IDTR { ptr: idt.as_ptr(), limit: idt.len() as u16 * 8 }) :: "volatile");
-}
-
-#[inline(always)]
pub unsafe fn stack_jmp(stack: *mut (), ip: *const ()) -> ! {
asm!("mov esp, $0; jmp $1" :: "rg"(stack), "r"(ip) :: "volatile", "intel");
loop { }
diff --git a/src/bits64/mod.rs b/src/bits64/mod.rs
index 9e5994a..413d3cf 100644
--- a/src/bits64/mod.rs
+++ b/src/bits64/mod.rs
@@ -35,7 +35,6 @@ pub mod time;
pub mod irq;
pub mod rflags;
pub mod paging;
-pub mod segmentation;
pub mod task;
pub mod syscall;
pub mod sgx;
diff --git a/src/bits64/segmentation.rs b/src/bits64/segmentation.rs
deleted file mode 100644
index 4f12358..0000000
--- a/src/bits64/segmentation.rs
+++ /dev/null
@@ -1,92 +0,0 @@
-//! Program x86 segmentation hardware.
-
-/// Entry for GDT or LDT. Provides size and location of a segment.
-bitflags! {
- pub flags SegmentDescriptor: u64 {
- /// Descriptor type (0 = system; 1 = code or data).
- const DESC_S = 1 << (32+12),
- /// Descriptor privilege level 0.
- const DESC_DPL0 = 0b00 << (32+13),
- /// Descriptor privilege level 1.
- const DESC_DPL1 = 0b01 << (32+13),
- /// Descriptor privilege level 2.
- const DESC_DPL2 = 0b10 << (32+13),
- /// Descriptor privilege level 3.
- const DESC_DPL3 = 0b11 << (32+13),
- /// Descriptor is Present.
- const DESC_P = 1 << (32+15),
- /// Available for use by system software.
- const DESC_AVL = 1 << (32+20),
- /// 64-bit code segment (IA-32e mode only).
- const DESC_L = 1 << (32+21),
- /// Default operation size (0 = 16-bit segment, 1 = 32-bit segment)
- const DESC_DB = 1 << (32+22),
- /// Granularity.
- const DESC_G = 1 << (32+23),
-
- // System-Segment and Gate-Descriptor Types for IA32e mode.
- // When the S (descriptor type) flag in a segment descriptor is clear,
- // the descriptor type is a system descriptor.
-
- const TYPE_SYS_LDT = 0b0010 << (32+8),
- const TYPE_SYS_TSS_AVAILABLE = 0b1001 << (32+8),
- const TYPE_SYS_TSS_BUSY = 0b1011 << (32+8),
- const TYPE_SYS_CALL_GATE = 0b1100 << (32+8),
- const TYPE_SYS_INTERRUPT_GATE = 0b1110 << (32+8),
- const TYPE_SYS_TRAP_GATE = 0b1111 << (32+8),
-
- // Code- and Data-Segment Descriptor Types.
- // When the S (descriptor type) flag in a segment descriptor is set,
- // the descriptor is for either a code or a data segment.
-
- /// Data Read-Only
- const TYPE_D_RO = 0b0000 << (32+8),
- /// Data Read-Only, accessed
- const TYPE_D_ROA = 0b0001 << (32+8),
- /// Data Read/Write
- const TYPE_D_RW = 0b0010 << (32+8),
- /// Data Read/Write, accessed
- const TYPE_D_RWA = 0b0011 << (32+8),
- /// Data Read-Only, expand-down
- const TYPE_D_ROEXD = 0b0100 << (32+8),
- /// Data Read-Only, expand-down, accessed
- const TYPE_D_ROEXDA = 0b0101 << (32+8),
- /// Data Read/Write, expand-down
- const TYPE_D_RWEXD = 0b0110 << (32+8),
- /// Data Read/Write, expand-down, accessed
- const TYPE_D_RWEXDA = 0b0111 << (32+8),
-
- /// Code Execute-Only
- const TYPE_C_EO = 0b1000 << (32+8),
- /// Code Execute-Only, accessed
- const TYPE_C_EOA = 0b1001 << (32+8),
- /// Code Execute/Read
- const TYPE_C_ER = 0b1010 << (32+8),
- /// Code Execute/Read, accessed
- const TYPE_C_ERA = 0b1011 << (32+8),
- /// Code Execute-Only, conforming
- const TYPE_C_EOC = 0b1100 << (32+8),
- /// Code Execute-Only, conforming, accessed
- const TYPE_C_EOCA = 0b1101 << (32+8),
- /// Code Execute/Read, conforming
- const TYPE_C_ERC = 0b1110 << (32+8),
- /// Code Execute/Read, conforming, accessed
- const TYPE_C_ERCA = 0b1111 << (32+8),
- }
-}
-
-/// This is data-structure is a ugly mess thing so we provide some
-/// convenience function to program it.
-impl SegmentDescriptor {
- pub fn new(base: u32, limit: u32) -> SegmentDescriptor {
- let base_low: u64 = base as u64 & 0xffffff;
- let base_high: u64 = (base as u64 >> 24) & 0xff;
-
- let limit_low: u64 = limit as u64 & 0xffff;
- let limit_high: u64 = (limit as u64 & (0b1111 << 16)) >> 16;
-
- SegmentDescriptor {
- bits: limit_low | base_low << 16 | limit_high << (32 + 16) | base_high << (32 + 24),
- }
- }
-}
diff --git a/src/bits64/task.rs b/src/bits64/task.rs
index da3093c..1d98bad 100644
--- a/src/bits64/task.rs
+++ b/src/bits64/task.rs
@@ -1,7 +1,7 @@
//! Helpers to program the task state segment.
//! See Intel 3a, Chapter 7, Section 7
-use super::segmentation;
+use shared::segmentation;
pub type TaskStateDescriptorLow = segmentation::SegmentDescriptor;
pub type TaskStateDescriptorHigh = u64;
diff --git a/src/shared/descriptor.rs b/src/shared/descriptor.rs
index 201d8cc..32abb79 100644
--- a/src/shared/descriptor.rs
+++ b/src/shared/descriptor.rs
@@ -1,6 +1,7 @@
//! Fields which are common to all segment-section and gate descriptors
use shared::PrivilegeLevel;
+use shared::segmentation;
/// System-Segment and Gate-Descriptor Types for IA32e mode. When the `S`
/// (descriptor type) flag in a segment descriptor is clear, the descriptor type
@@ -24,6 +25,7 @@ pub enum SystemType {
/// 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
@@ -31,6 +33,10 @@ pub enum Type {
size: bool,
ty: SystemType
},
+ SegmentDescriptor {
+ ty: segmentation::Type,
+ accessed: bool
+ }
}
impl Type {
@@ -38,6 +44,8 @@ impl Type {
match self {
Type::SystemDescriptor { size, ty } =>
(size as u8) << 3 | (ty as u8) | FLAGS_TYPE_SYS.bits,
+ Type::SegmentDescriptor { ty, accessed } =>
+ (accessed as u8) | ty.pack() | FLAGS_TYPE_SYS.bits,
}
}
}
@@ -59,6 +67,7 @@ bitflags!{
// 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,
@@ -81,6 +90,82 @@ bitflags!{
const FLAGS_TYPE_SYS_NATIVE_CALL_GATE = 0b0_1100,
const FLAGS_TYPE_SYS_NATIVE_INTERRUPT_GATE = 0b0_1110,
const FLAGS_TYPE_SYS_NATIVE_TRAP_GATE = 0b0_1111,
+
+ // Code- and Data-Segment Descriptor Types.
+ // When the S (descriptor type) flag in a segment descriptor is set,
+ // the descriptor is for either a code or a data segment.
+
+ /// Data or code, accessed
+ const FLAGS_TYPE_SEG_ACCESSED = 0b1_0001,
+
+ const FLAGS_TYPE_DATA = 0b1_0000,
+ const FLAGS_TYPE_CODE = 0b1_1000,
+
+ // Data => permissions
+ const FLAGS_TYPE_SEG_D_WRITE = 0b1_0010,
+ const FLAGS_TYPE_SEG_D_EXPAND_DOWN = 0b1_0100,
+
+ // Code => permissions
+ const FLAGS_TYPE_SEG_C_READ = 0b1_0010,
+ const FLAGS_TYPE_SEG_D_CONFORMING = 0b1_0100,
+
+ /// Data Read-Only
+ const FLAGS_TYPE_SEG_D_RO = FLAGS_TYPE_DATA.bits,
+ /// Data Read-Only, accessed
+ const FLAGS_TYPE_SEG_D_ROA = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_ACCESSED.bits,
+ /// Data Read/Write
+ const FLAGS_TYPE_SEG_D_RW = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_D_WRITE.bits,
+ /// Data Read/Write, accessed
+ const FLAGS_TYPE_SEG_D_RWA = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_D_WRITE.bits
+ | FLAGS_TYPE_SEG_ACCESSED.bits,
+ /// Data Read-Only, expand-down
+ const FLAGS_TYPE_SEG_D_ROEXD = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_D_EXPAND_DOWN.bits,
+ /// Data Read-Only, expand-down, accessed
+ const FLAGS_TYPE_SEG_D_ROEXDA = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_D_EXPAND_DOWN.bits
+ | FLAGS_TYPE_SEG_ACCESSED.bits,
+ /// Data Read/Write, expand-down
+ const FLAGS_TYPE_SEG_D_RWEXD = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_D_WRITE.bits
+ | FLAGS_TYPE_SEG_D_EXPAND_DOWN.bits,
+ /// Data Read/Write, expand-down, accessed
+ const FLAGS_TYPE_SEG_D_RWEXDA = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_D_WRITE.bits
+ | FLAGS_TYPE_SEG_D_EXPAND_DOWN.bits
+ | FLAGS_TYPE_SEG_ACCESSED.bits,
+
+ /// Code Execute-Only
+ const FLAGS_TYPE_SEG_C_EO = FLAGS_TYPE_DATA.bits,
+ /// Code Execute-Only, accessed
+ const FLAGS_TYPE_SEG_C_EOA = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_ACCESSED.bits,
+ /// Code Execute/Read
+ const FLAGS_TYPE_SEG_C_ER = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_C_READ.bits,
+ /// Code Execute/Read, accessed
+ const FLAGS_TYPE_SEG_C_ERA = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_C_READ.bits
+ | FLAGS_TYPE_SEG_ACCESSED.bits,
+ /// Code Execute-Only, conforming
+ const FLAGS_TYPE_SEG_C_EOC = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_D_CONFORMING.bits,
+ /// Code Execute-Only, conforming, accessed
+ const FLAGS_TYPE_SEG_C_EOCA = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_D_CONFORMING.bits
+ | FLAGS_TYPE_SEG_ACCESSED.bits,
+ /// Code Execute/Read, conforming
+ const FLAGS_TYPE_SEG_C_ERC = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_C_READ.bits
+ | FLAGS_TYPE_SEG_D_CONFORMING.bits,
+ /// Code Execute/Read, conforming, accessed
+ const FLAGS_TYPE_SEG_C_ERCA = FLAGS_TYPE_DATA.bits
+ | FLAGS_TYPE_SEG_C_READ.bits
+ | FLAGS_TYPE_SEG_D_CONFORMING.bits
+ | FLAGS_TYPE_SEG_ACCESSED.bits,
}
}
diff --git a/src/shared/dtables.rs b/src/shared/dtables.rs
index d2e3413..c5337fb 100644
--- a/src/shared/dtables.rs
+++ b/src/shared/dtables.rs
@@ -1,27 +1,61 @@
//! Functions and data-structures to load descriptor tables.
+use core::mem::size_of;
+
+use current::irq::IdtEntry;
+use shared::segmentation::SegmentDescriptor;
+
/// A struct describing a pointer to a descriptor table (GDT / IDT).
/// This is in a format suitable for giving to 'lgdt' or 'lidt'.
#[derive(Debug)]
#[repr(C, packed)]
-pub struct DescriptorTablePointer {
+pub struct DescriptorTablePointer<Entry> {
/// Size of the DT.
pub limit: u16,
/// Pointer to the memory region containing the DT.
- pub base: u64,
+ pub base: *const Entry,
}
+impl<T> DescriptorTablePointer<T> {
+ fn new(slice: &[T]) -> Self {
+ let len = slice.len() * size_of::<T>();
+ assert!(len < 0x10000);
+ DescriptorTablePointer {
+ base: slice.as_ptr(),
+ limit: len as u16,
+ }
+ }
+}
+
+impl DescriptorTablePointer<SegmentDescriptor> {
+ pub fn new_gdtp(gdt: &[SegmentDescriptor]) -> Self {
+ let mut p = Self::new(gdt);
+ p.limit -= 1;
+ p
+ }
+ pub fn new_ldtp(ldt: &[SegmentDescriptor]) -> Self {
+ Self::new(ldt)
+ }
+}
+
+impl DescriptorTablePointer<IdtEntry> {
+ pub fn new_idtp(idt: &[IdtEntry]) -> Self {
+ Self::new(idt)
+ }
+}
+
+
/// Load GDT table.
-pub unsafe fn lgdt(gdt: &DescriptorTablePointer) {
+pub unsafe fn lgdt(gdt: &DescriptorTablePointer<SegmentDescriptor>) {
asm!("lgdt ($0)" :: "r" (gdt) : "memory");
}
/// Load LDT table.
-pub unsafe fn lldt(ldt: &DescriptorTablePointer) {
+pub unsafe fn lldt(ldt: &DescriptorTablePointer<SegmentDescriptor>) {
asm!("lldt ($0)" :: "r" (ldt) : "memory");
}
/// Load IDT table.
-pub unsafe fn lidt(idt: &DescriptorTablePointer) {
+pub unsafe fn lidt(idt: &DescriptorTablePointer<IdtEntry>) {
asm!("lidt ($0)" :: "r" (idt) : "memory");
}
diff --git a/src/shared/segmentation.rs b/src/shared/segmentation.rs
index f4dc194..7f895ae 100644
--- a/src/shared/segmentation.rs
+++ b/src/shared/segmentation.rs
@@ -1,10 +1,13 @@
use core::fmt;
+use shared::descriptor;
use shared::PrivilegeLevel;
/// Specifies which element to load into a segment from
/// descriptor tables (i.e., is a index to LDT or GDT table
/// with some additional flags).
+///
+/// See Intel 3a, Section 3.4.2 "Segment Selectors"
bitflags! {
#[repr(C, packed)]
pub flags SegmentSelector: u16 {
@@ -133,3 +136,127 @@ pub fn cs() -> SegmentSelector {
unsafe { asm!("mov %cs, $0" : "=r" (segment) ) };
SegmentSelector::from_raw(segment)
}
+
+
+bitflags! {
+ /// Data segment types. All are readable.
+ ///
+ /// See Table 3-1, "Code- and Data-Segment Types"
+ pub flags DataAccess: u8 {
+ /// Segment is writable
+ const DATA_WRITE = 1 << 1,
+ /// Segment grows down, for stack
+ const DATA_EXPAND_DOWN = 1 << 2,
+ }
+}
+
+bitflags! {
+ /// Code segment types. All are executable.
+ ///
+ /// See Table 3-1, "Code- and Data-Segment Types"
+ pub flags CodeAccess: u8 {
+ /// Segment is readable
+ const CODE_READ = 1 << 1,
+ /// Segment is callable from segment with fewer privileges.
+ const CODE_CONFORMING = 1 << 2,
+ }
+}
+
+/// Umbrella Segment Type.
+///
+/// See Table 3-1, "Code- and Data-Segment Types"
+#[repr(u8)]
+pub enum Type {
+ Data(DataAccess),
+ Code(CodeAccess),
+}
+
+impl Type {
+ pub fn pack(self) -> u8 {
+ match self {
+ Type::Data(d) => d.bits | 0b0_000,
+ Type::Code(c) => c.bits | 0b1_000,
+ }
+ }
+}
+
+
+/// Entry for GDT or LDT. Provides size and location of a segment.
+///
+/// See Intel 3a, Section 3.4.5 "Segment Descriptors", and Section 3.5.2
+/// "Segment Descriptor Tables in IA-32e Mode", especially Figure 3-8.
+#[derive(Copy, Clone, Debug)]
+#[repr(C, packed)]
+pub struct SegmentDescriptor {
+ limit1: u16,
+ base1: u16,
+ base2: u8,
+ access: descriptor::Flags,
+ limit2_flags: Flags,
+ base3: u8,
+}
+
+/// This is data-structure is a ugly mess thing so we provide some
+/// convenience function to program it.
+impl SegmentDescriptor {
+ pub const NULL: SegmentDescriptor = SegmentDescriptor {
+ base1: 0,
+ base2: 0,
+ base3: 0,
+ access: descriptor::Flags::BLANK,
+ limit1: 0,
+ limit2_flags: Flags::BLANK,
+ };
+
+ pub fn new(base: u32, limit: u32,
+ ty: Type, accessed: bool, dpl: PrivilegeLevel) -> SegmentDescriptor
+ {
+ let fine_grained = limit < 0x100000;
+ let (limit1, limit2) = if fine_grained {
+ ((limit & 0xFFFF) as u16, ((limit & 0xF0000) >> 16) as u8)
+ } else {
+ if ((limit - 0xFFF) & 0xFFF) > 0 {
+ panic!("bad segment limit for GDT entry");
+ }
+ (((limit & 0xFFFF000) >> 12) as u16, ((limit & 0xF0000000) >> 28) as u8)
+ };
+ let ty1 = descriptor::Type::SegmentDescriptor {
+ ty: ty,
+ accessed: accessed
+ };
+ SegmentDescriptor {
+ base1: base as u16,
+ base2: ((base as usize & 0xFF0000) >> 16) as u8,
+ base3: ((base as usize & 0xFF000000) >> 24) as u8,
+ access: descriptor::Flags::from_type(ty1)
+ | descriptor::Flags::from_priv(dpl),
+ limit1: limit1,
+ limit2_flags: FLAGS_DB
+ | if fine_grained { FLAGS_G } else { Flags::empty() }
+ | Flags::from_limit2(limit2),
+ }
+ }
+}
+
+bitflags! {
+ pub flags Flags: u8 {
+ /// Available for use by system software.
+ const FLAGS_AVL = 1 << 4,
+ /// 64-bit code segment (IA-32e mode only).
+ const FLAGS_L = 1 << 5,
+ /// Default operation size (0 = 16-bit segment, 1 = 32-bit segment).
+ const FLAGS_DB = 1 << 6,
+ /// Granularity (0 = limit in bytes, 1 = limt in 4 KiB Pages).
+ const FLAGS_G = 1 << 7,
+
+ }
+}
+
+impl Flags {
+ pub const BLANK: Flags = Flags { bits: 0 };
+
+ pub fn from_limit2(limit2: u8) -> Flags {
+ assert_eq!(limit2 & !0b111, 0);
+ Flags { bits: limit2 }
+ }
+}