aboutsummaryrefslogtreecommitdiff
path: root/src/shared/segmentation.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/segmentation.rs')
-rw-r--r--src/shared/segmentation.rs127
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 }
+ }
+}