diff options
Diffstat (limited to 'src/shared/segmentation.rs')
-rw-r--r-- | src/shared/segmentation.rs | 127 |
1 files changed, 127 insertions, 0 deletions
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 } + } +} |