aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Gerd Zellweger <mail@gerdzellweger.com> 2018-04-26 19:20:36 -0700
committerGravatar Gerd Zellweger <mail@gerdzellweger.com> 2018-04-26 19:20:36 -0700
commit57a2bfac28ce1e62ce1051b9de731d81e1c25a8b (patch)
tree3d0f93200a5ad3c11cb685a4da9682b9c226c6a5
parent848ec0fae090dbc1657d02b436b8b887df519e90 (diff)
downloadrust-x86-57a2bfac28ce1e62ce1051b9de731d81e1c25a8b.tar.gz
rust-x86-57a2bfac28ce1e62ce1051b9de731d81e1c25a8b.tar.zst
rust-x86-57a2bfac28ce1e62ce1051b9de731d81e1c25a8b.zip
More segmentation refactoring.
Signed-off-by: Gerd Zellweger <mail@gerdzellweger.com>
-rw-r--r--src/bits16/segmentation.rs4
-rw-r--r--src/bits32/dtables.rs19
-rw-r--r--src/bits32/mod.rs1
-rw-r--r--src/bits32/segmentation.rs199
-rw-r--r--src/bits64/dtables.rs18
-rw-r--r--src/bits64/mod.rs1
-rw-r--r--src/bits64/segmentation.rs46
-rw-r--r--src/dtables.rs15
-rw-r--r--src/segmentation.rs226
9 files changed, 251 insertions, 278 deletions
diff --git a/src/bits16/segmentation.rs b/src/bits16/segmentation.rs
index 4e95a1d..516433d 100644
--- a/src/bits16/segmentation.rs
+++ b/src/bits16/segmentation.rs
@@ -2,13 +2,13 @@ use segmentation::{SegmentSelector, DescriptorBuilder, GateDescriptorBuilder, De
impl GateDescriptorBuilder<u16> for DescriptorBuilder {
- fn tss_descriptor(selector: SegmentSelector, offset: u16, available: bool) -> DescriptorBuilder {
+ fn tss_descriptor(base: u64, limit: u64, available: bool) -> DescriptorBuilder {
let typ = match available {
true => DescriptorType::System32(SystemDescriptorTypes32::TSSAvailable16),
false => DescriptorType::System32(SystemDescriptorTypes32::TSSBusy16),
};
- DescriptorBuilder::with_selector_offset(selector, offset.into()).set_type(typ)
+ DescriptorBuilder::with_base_limit(base, limit).set_type(typ)
}
fn call_gate_descriptor(selector: SegmentSelector, offset: u16) -> DescriptorBuilder {
diff --git a/src/bits32/dtables.rs b/src/bits32/dtables.rs
deleted file mode 100644
index 51596f8..0000000
--- a/src/bits32/dtables.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-//! Functions to load descriptor tables.
-use dtables::DescriptorTablePointer;
-use bits32::segmentation::Descriptor;
-
-/// Load GDT table with 32bit descriptors
-pub unsafe fn lgdt(gdt: &DescriptorTablePointer<Descriptor>) {
- asm!("lgdt ($0)" :: "r" (gdt) : "memory");
-}
-
-/// Load LDT table with 32bit descriptors.
-pub unsafe fn lldt(ldt: &DescriptorTablePointer<Descriptor>) {
- asm!("lldt ($0)" :: "r" (ldt) : "memory");
-}
-
-/// Load IDT table with 32bit descriptors.
-pub unsafe fn lidt(idt: &DescriptorTablePointer<Descriptor>) {
- asm!("lidt ($0)" :: "r" (idt) : "memory");
-}
-
diff --git a/src/bits32/mod.rs b/src/bits32/mod.rs
index 87a9d9c..e79b1e6 100644
--- a/src/bits32/mod.rs
+++ b/src/bits32/mod.rs
@@ -1,4 +1,3 @@
-pub mod dtables;
pub mod eflags;
pub mod segmentation;
pub mod task;
diff --git a/src/bits32/segmentation.rs b/src/bits32/segmentation.rs
index dc6da52..5114394 100644
--- a/src/bits32/segmentation.rs
+++ b/src/bits32/segmentation.rs
@@ -1,202 +1,5 @@
#[allow(unused_imports)]
use segmentation::{SegmentSelector};
-use segmentation::{DescriptorBuilder, DescriptorType, GateDescriptorBuilder, TaskGateDescriptorBuilder, SegmentDescriptorBuilder, LdtDescriptorBuilder, BuildDescriptor, SystemDescriptorTypes32, CodeSegmentType, DataSegmentType};
-use ::Ring;
-
-/// Entry for IDT, GDT or LDT. Provides size and location of a segment.
-///
-/// See Intel 3a, Section 3.4.5 "Segment Descriptors", and Section 3.5.2
-#[derive(Copy, Clone, Debug, Default)]
-#[repr(C, packed)]
-pub struct Descriptor {
- pub lower: u32,
- pub upper: u32,
-}
-
-impl Descriptor {
-
- pub(crate) fn apply_builder_settings(&mut self, builder: &DescriptorBuilder) {
- builder.dpl.map(|ring| self.set_dpl(ring));
- builder.base_limit.map(|(base, limit)| self.set_base_limit(base as u32, limit as u32));
- builder.selector_offset.map(|(selector, offset)| self.set_selector_offset(selector, offset as u32));
-
- if builder.present {
- self.set_p();
- }
- if builder.avl {
- self.set_avl();
- }
- if builder.db {
- self.set_db();
- }
- if builder.limit_granularity_4k {
- self.set_g();
- }
- }
-
- /// Create a new segment, TSS or LDT descriptor
- /// by setting the three base and two limit fields.
- pub fn set_base_limit(&mut self, base: u32, limit: u32) {
- // Clear the base and limit fields in Descriptor
- self.lower = 0;
- self.upper = self.upper & 0x00F0FF00;
-
- // Set the new base
- self.lower |= base << 16;
- self.upper |= (base >> 16) & 0xff;
- self.upper |= (base >> 24) << 24;
-
- // Set the new limit
- self.lower |= limit & 0xffff;
- let limit_last_four_bits = (limit >> 16) & 0x0f;
- self.upper |= limit_last_four_bits << 16;
- }
-
- /// Creates a new descriptor with selector and offset (for IDT Gate descriptors,
- /// e.g. Trap, Interrupts and Task gates)
- pub fn set_selector_offset(&mut self, selector: SegmentSelector, offset: u32) {
- // Clear the selector and offset
- self.lower = 0;
- self.upper = self.upper & 0x0000ffff;
-
- // Set selector
- self.lower |= (selector.bits() as u32) << 16;
-
- // Set offset
- self.lower |= offset & 0x0000ffff;
- self.upper |= offset & 0xffff0000;
- }
-
- /// Set the type of the descriptor (bits 8-11).
- /// Indicates the segment or gate type and specifies the kinds of access that can be made to the
- /// segment and the direction of growth. The interpretation of this field depends on whether the descriptor
- /// type flag specifies an application (code or data) descriptor or a system descriptor.
- pub fn set_type(&mut self, typ: u8) {
- self.upper &= !(0x0f << 8); // clear
- self.upper |= (typ as u32 & 0x0f) << 8;
- }
-
- /// Specifies whether the segment descriptor is for a system segment (S flag is clear) or a code or data segment (S flag is set).
- pub fn set_s(&mut self) {
- self.upper |= bit!(12);
- }
-
- /// Specifies the privilege level of the segment. The DPL is used to control access to the segment.
- pub fn set_dpl(&mut self, ring: Ring) {
- assert!(ring as u32 <= 0b11);
- self.upper &= !(0b11 << 13);
- self.upper |= (ring as u32) << 13;
- }
-
- /// Set Present bit.
- /// Indicates whether the segment is present in memory (set) or not present (clear).
- /// If this flag is clear, the processor generates a segment-not-present exception (#NP) when a segment selector
- /// that points to the segment descriptor is loaded into a segment register.
- pub fn set_p(&mut self) {
- self.upper |= bit!(15);
- }
-
- /// Set AVL bit. System software can use this bit to store information.
- pub fn set_avl(&mut self) {
- self.upper |= bit!(20);
- }
-
- /// Set L
- /// In IA-32e mode, bit 21 of the second doubleword of the segment descriptor indicates whether a
- /// code segment contains native 64-bit code. A value of 1 indicates instructions in this code
- /// segment are executed in 64-bit mode. A value of 0 indicates the instructions in this code segment
- /// are executed in compatibility mode. If L-bit is set, then D-bit must be cleared.
- pub fn set_l(&mut self) {
- self.upper |= bit!(21);
- }
-
- /// Set D/B.
- /// Performs different functions depending on whether the segment descriptor is an executable code segment,
- /// an expand-down data segment, or a stack segment.
- pub fn set_db(&mut self) {
- self.upper |= bit!(22);
- }
-
- /// Set G bit
- /// 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.
- pub fn set_g(&mut self) {
- self.upper |= bit!(23);
- }
-}
-
-impl GateDescriptorBuilder<u32> for DescriptorBuilder {
-
- fn tss_descriptor(selector: SegmentSelector, offset: u32, available: bool) -> DescriptorBuilder {
- let typ = match available {
- true => DescriptorType::System32(SystemDescriptorTypes32::TssAvailable32),
- false => DescriptorType::System32(SystemDescriptorTypes32::TssBusy32),
- };
-
- DescriptorBuilder::with_selector_offset(selector, offset.into()).set_type(typ)
- }
-
- fn call_gate_descriptor(selector: SegmentSelector, offset: u32) -> DescriptorBuilder {
- DescriptorBuilder::with_selector_offset(selector, offset.into()).set_type(DescriptorType::System32(SystemDescriptorTypes32::CallGate32))
- }
-
- fn interrupt_descriptor(selector: SegmentSelector, offset: u32) -> DescriptorBuilder {
- DescriptorBuilder::with_selector_offset(selector, offset.into()).set_type(DescriptorType::System32(SystemDescriptorTypes32::InterruptGate32))
- }
-
- fn trap_gate_descriptor(selector: SegmentSelector, offset: u32) -> DescriptorBuilder {
- DescriptorBuilder::with_selector_offset(selector, offset.into()).set_type(DescriptorType::System32(SystemDescriptorTypes32::TrapGate32))
- }
-}
-
-impl TaskGateDescriptorBuilder for DescriptorBuilder {
- fn task_gate_descriptor(selector: SegmentSelector) -> DescriptorBuilder {
- DescriptorBuilder::with_selector_offset(selector, 0).set_type(DescriptorType::System32(SystemDescriptorTypes32::TaskGate))
- }
-}
-
-impl SegmentDescriptorBuilder<u32> for DescriptorBuilder {
- fn code_descriptor(base: u32, limit: u32, cst: CodeSegmentType) -> DescriptorBuilder {
- DescriptorBuilder::with_base_limit(base.into(), limit.into()).set_type(DescriptorType::Code(cst)).db()
- }
-
- fn data_descriptor(base: u32, limit: u32, dst: DataSegmentType) -> DescriptorBuilder {
- DescriptorBuilder::with_base_limit(base.into(), limit.into()).set_type(DescriptorType::Data(dst)).db()
- }
-}
-
-impl LdtDescriptorBuilder<u32> for DescriptorBuilder {
- fn ldt_descriptor(base: u32, limit: u32) -> DescriptorBuilder {
- DescriptorBuilder::with_base_limit(base.into(), limit.into()).set_type(DescriptorType::System32(SystemDescriptorTypes32::LDT))
- }
-}
-
-impl BuildDescriptor<Descriptor> for DescriptorBuilder {
- fn finish(&self) -> Descriptor {
- let mut desc: Descriptor = Default::default();
- desc.apply_builder_settings(self);
-
- let typ = match self.typ {
- Some(DescriptorType::System64(_)) => panic!("You shall not use 64-bit types on 32-bit descriptor."),
- Some(DescriptorType::System32(typ)) => {
- typ as u8
- },
- Some(DescriptorType::Data(typ)) => {
- desc.set_s();
- typ as u8
- },
- Some(DescriptorType::Code(typ)) => {
- desc.set_s();
- typ as u8
- },
- None => unreachable!("Type not set, this is a library bug in x86."),
- };
- desc.set_type(typ);
-
- desc
- }
-}
/// Reload code segment register.
/// Note this is special since we can not directly move
@@ -204,7 +7,7 @@ impl BuildDescriptor<Descriptor> for DescriptorBuilder {
/// and return value on the stack and use lretl
/// to reload cs and continue at 1:.
#[cfg(target_arch="x86")]
-pub unsafe fn set_cs(sel: SegmentSelector) {
+pub unsafe fn load_cs(sel: SegmentSelector) {
asm!("pushl $0; \
pushl $$1f; \
lretl; \
diff --git a/src/bits64/dtables.rs b/src/bits64/dtables.rs
deleted file mode 100644
index 00fad0f..0000000
--- a/src/bits64/dtables.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-//! Functions to load descriptor tables.
-use dtables::DescriptorTablePointer;
-use bits64::segmentation::Descriptor;
-
-/// Load GDT table with 64-bits descriptors.
-pub unsafe fn lgdt(gdt: &DescriptorTablePointer<Descriptor>) {
- asm!("lgdt ($0)" :: "r" (gdt) : "memory");
-}
-
-/// Load LDT table with 64-bits descriptors.
-pub unsafe fn lldt(ldt: &DescriptorTablePointer<Descriptor>) {
- asm!("lldt ($0)" :: "r" (ldt) : "memory");
-}
-
-/// Load IDT table with 64-bits descriptors.
-pub unsafe fn lidt(idt: &DescriptorTablePointer<Descriptor>) {
- asm!("lidt ($0)" :: "r" (idt) : "memory");
-}
diff --git a/src/bits64/mod.rs b/src/bits64/mod.rs
index 7f8cdc3..72ea049 100644
--- a/src/bits64/mod.rs
+++ b/src/bits64/mod.rs
@@ -1,6 +1,5 @@
//! Data structures and functions used by IA-32e but not Protected Mode.
-pub mod dtables;
pub mod paging;
pub mod rflags;
pub mod segmentation;
diff --git a/src/bits64/segmentation.rs b/src/bits64/segmentation.rs
index 058bead..0c03780 100644
--- a/src/bits64/segmentation.rs
+++ b/src/bits64/segmentation.rs
@@ -1,7 +1,6 @@
#[allow(unused_imports)]
use segmentation::{SegmentSelector};
-use segmentation::{DescriptorBuilder, BuildDescriptor, DescriptorType, GateDescriptorBuilder, SegmentDescriptorBuilder, LdtDescriptorBuilder, CodeSegmentType, DataSegmentType, SystemDescriptorTypes64};
-use bits32::segmentation::Descriptor as Descriptor32;
+use segmentation::{DescriptorBuilder, BuildDescriptor, Descriptor, DescriptorType, GateDescriptorBuilder, LdtDescriptorBuilder, SystemDescriptorTypes64};
/// Entry for IDT, GDT or LDT.
///
@@ -9,13 +8,13 @@ use bits32::segmentation::Descriptor as Descriptor32;
/// "Segment Descriptor Tables in IA-32e Mode", especially Figure 3-8.
#[derive(Copy, Clone, Debug, Default)]
#[repr(C, packed)]
-pub struct Descriptor {
- desc32: Descriptor32,
+pub struct Descriptor64 {
+ desc32: Descriptor,
lower: u32,
upper: u32
}
-impl Descriptor {
+impl Descriptor64 {
pub(crate) fn apply_builder_settings(&mut self, builder: &DescriptorBuilder) {
self.desc32.apply_builder_settings(builder);
@@ -49,13 +48,13 @@ impl Descriptor {
impl GateDescriptorBuilder<u64> for DescriptorBuilder {
- fn tss_descriptor(selector: SegmentSelector, offset: u64, available: bool) -> DescriptorBuilder {
+ fn tss_descriptor(base: u64, limit: u64, available: bool) -> DescriptorBuilder {
let typ = match available {
true => DescriptorType::System64(SystemDescriptorTypes64::TssAvailable),
false => DescriptorType::System64(SystemDescriptorTypes64::TssBusy),
};
- DescriptorBuilder::with_selector_offset(selector, offset).set_type(typ)
+ DescriptorBuilder::with_base_limit(base, limit).set_type(typ)
}
fn call_gate_descriptor(selector: SegmentSelector, offset: u64) -> DescriptorBuilder {
@@ -71,46 +70,31 @@ impl GateDescriptorBuilder<u64> for DescriptorBuilder {
}
}
-impl SegmentDescriptorBuilder<u64> for DescriptorBuilder {
- fn code_descriptor(base: u64, limit: u64, cst: CodeSegmentType) -> DescriptorBuilder {
- DescriptorBuilder::with_base_limit(base, limit).set_type(DescriptorType::Code(cst)).db()
- }
-
- fn data_descriptor(base: u64, limit: u64, dst: DataSegmentType) -> DescriptorBuilder {
- DescriptorBuilder::with_base_limit(base, limit).set_type(DescriptorType::Data(dst)).db()
- }
-}
-
impl LdtDescriptorBuilder<u64> for DescriptorBuilder {
fn ldt_descriptor(base: u64, limit: u64) -> DescriptorBuilder {
DescriptorBuilder::with_base_limit(base, limit).set_type(DescriptorType::System64(SystemDescriptorTypes64::LDT))
}
}
-impl BuildDescriptor<Descriptor> for DescriptorBuilder {
- fn finish(&self) -> Descriptor {
- let mut desc: Descriptor = Default::default();
+impl BuildDescriptor<Descriptor64> for DescriptorBuilder {
+ fn finish(&self) -> Descriptor64 {
+ let mut desc: Descriptor64 = Default::default();
desc.apply_builder_settings(self);
- desc.desc32.set_l(); // 64-bit descriptor
let typ = match self.typ {
Some(DescriptorType::System64(typ)) => {
+ assert!(!self.l);
if typ == SystemDescriptorTypes64::LDT || typ == SystemDescriptorTypes64::TssAvailable || typ == SystemDescriptorTypes64::TssBusy {
assert!(!self.db);
}
typ as u8
},
- Some(DescriptorType::System32(_typ)) => panic!("You shall not use 32-bit types on 64-bit descriptors."),
- Some(DescriptorType::Data(typ)) => {
- desc.desc32.set_s();
- typ as u8
- },
- Some(DescriptorType::Code(typ)) => {
- desc.desc32.set_s();
- typ as u8
- },
+ Some(DescriptorType::System32(_typ)) => panic!("Can't build a 64-bit version of this type."),
+ Some(DescriptorType::Data(_typ)) => panic!("Can't build a 64-bit version of this type."),
+ Some(DescriptorType::Code(_typ)) => panic!("Can't build a 64-bit version of this type."),
None => unreachable!("Type not set, this is a library bug in x86."),
};
+
desc.desc32.set_type(typ);
desc
}
@@ -122,7 +106,7 @@ impl BuildDescriptor<Descriptor> for DescriptorBuilder {
/// and return value on the stack and use lretq
/// to reload cs and continue at 1:.
#[cfg(target_arch="x86_64")]
-pub unsafe fn set_cs(sel: SegmentSelector) {
+pub unsafe fn load_cs(sel: SegmentSelector) {
asm!("pushq $0; \
leaq 1f(%rip), %rax; \
pushq %rax; \
diff --git a/src/dtables.rs b/src/dtables.rs
index 19baa9a..43eb13b 100644
--- a/src/dtables.rs
+++ b/src/dtables.rs
@@ -31,3 +31,18 @@ impl<T> fmt::Debug for DescriptorTablePointer<T> {
unsafe { write!(f, "DescriptorTablePointer ({} {:?})", self.limit, self.base) }
}
}
+
+/// Load GDT table with 32bit descriptors
+pub unsafe fn lgdt<T>(gdt: &DescriptorTablePointer<T>) {
+ asm!("lgdt ($0)" :: "r" (gdt) : "memory");
+}
+
+/// Load LDT table with 32bit descriptors.
+pub unsafe fn lldt<T>(ldt: &DescriptorTablePointer<T>) {
+ asm!("lldt ($0)" :: "r" (ldt) : "memory");
+}
+
+/// Load IDT table with 32bit descriptors.
+pub unsafe fn lidt<T>(idt: &DescriptorTablePointer<T>) {
+ asm!("lidt ($0)" :: "r" (idt) : "memory");
+}
diff --git a/src/segmentation.rs b/src/segmentation.rs
index cf8843e..6f17c75 100644
--- a/src/segmentation.rs
+++ b/src/segmentation.rs
@@ -179,8 +179,8 @@ pub(crate) enum DescriptorType {
/// Trait that defines the architecture specific functions for building various system segment descriptors
/// which are available on all 16, 32, and 64 bits.
-pub(crate) trait GateDescriptorBuilder<Size> {
- fn tss_descriptor(selector: SegmentSelector, offset: Size, available: bool) -> Self;
+pub trait GateDescriptorBuilder<Size> {
+ fn tss_descriptor(base: u64, limit: u64, available: bool) -> Self;
fn call_gate_descriptor(selector: SegmentSelector, offset: Size) -> Self;
fn interrupt_descriptor(selector: SegmentSelector, offset: Size) -> Self;
fn trap_gate_descriptor(selector: SegmentSelector, offset: Size) -> Self;
@@ -188,23 +188,23 @@ pub(crate) trait GateDescriptorBuilder<Size> {
/// Trait to implement for building a task-gate (this descriptor is not implemented for 64-bit systems since
/// Hardware task switches are not supported in IA-32e mode.).
-pub(crate) trait TaskGateDescriptorBuilder {
+pub trait TaskGateDescriptorBuilder {
fn task_gate_descriptor(selector: SegmentSelector) -> Self;
}
/// Trait to define functions that build architecture specific code and data descriptors.
-pub(crate) trait SegmentDescriptorBuilder<Size> {
+pub trait SegmentDescriptorBuilder<Size> {
fn code_descriptor(base: Size, limit: Size, cst: CodeSegmentType) -> Self;
fn data_descriptor(base: Size, limit: Size, dst: DataSegmentType) -> Self;
}
/// Trait to define functions that build an architecture specific ldt descriptor.
/// There is no corresponding ldt descriptor type for 16 bit.
-pub(crate) trait LdtDescriptorBuilder<Size> {
+pub trait LdtDescriptorBuilder<Size> {
fn ldt_descriptor(base: Size, limit: Size) -> Self;
}
-pub(crate) trait BuildDescriptor<Descriptor> {
+pub trait BuildDescriptor<Descriptor> {
fn finish(&self) -> Descriptor;
}
@@ -228,18 +228,21 @@ pub struct DescriptorBuilder {
pub(crate) 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.
pub(crate) limit_granularity_4k: bool,
+ /// 64-bit code segment (IA-32e mode only)
+ pub(crate) l: bool
+
}
impl DescriptorBuilder {
/// Start building a new descriptor with a base and limit.
pub(crate) fn with_base_limit(base: u64, limit: u64) -> DescriptorBuilder {
- DescriptorBuilder { base_limit: Some((base, limit)), selector_offset: None, typ: None, dpl: None, present: false, avl: false, db: false, limit_granularity_4k: false }
+ DescriptorBuilder { base_limit: Some((base, limit)), selector_offset: None, typ: None, dpl: None, present: false, avl: false, db: false, limit_granularity_4k: false, l: false }
}
/// Start building a new descriptor with a segment selector and offset.
pub(crate) fn with_selector_offset(selector: SegmentSelector, offset: u64) -> DescriptorBuilder {
- DescriptorBuilder { base_limit: None, selector_offset: Some((selector, offset)), typ: None, dpl: None, present: false, avl: false, db: false, limit_granularity_4k: false }
+ DescriptorBuilder { base_limit: None, selector_offset: Some((selector, offset)), typ: None, dpl: None, present: false, avl: false, db: false, limit_granularity_4k: false, l: false }
}
pub(crate) fn set_type(mut self, typ: DescriptorType) -> DescriptorBuilder {
@@ -276,6 +279,213 @@ impl DescriptorBuilder {
self.db = true;
self
}
+
+ /// Set L bit if this descriptor is a 64-bit code segment.
+ /// In IA-32e mode, bit 21 of the second doubleword of the segment descriptor indicates whether a code segment
+ /// contains native 64-bit code. A value of 1 indicates instructions in this code segment are executed in 64-bit mode.
+ pub fn l(mut self) -> DescriptorBuilder {
+ self.l = true;
+ self
+ }
+}
+
+impl GateDescriptorBuilder<u32> for DescriptorBuilder {
+
+ fn tss_descriptor(base: u64, limit: u64, available: bool) -> DescriptorBuilder {
+ let typ = match available {
+ true => DescriptorType::System32(SystemDescriptorTypes32::TssAvailable32),
+ false => DescriptorType::System32(SystemDescriptorTypes32::TssBusy32),
+ };
+
+ DescriptorBuilder::with_base_limit(base.into(), limit.into()).set_type(typ)
+ }
+
+ fn call_gate_descriptor(selector: SegmentSelector, offset: u32) -> DescriptorBuilder {
+ DescriptorBuilder::with_selector_offset(selector, offset.into()).set_type(DescriptorType::System32(SystemDescriptorTypes32::CallGate32))
+ }
+
+ fn interrupt_descriptor(selector: SegmentSelector, offset: u32) -> DescriptorBuilder {
+ DescriptorBuilder::with_selector_offset(selector, offset.into()).set_type(DescriptorType::System32(SystemDescriptorTypes32::InterruptGate32))
+ }
+
+ fn trap_gate_descriptor(selector: SegmentSelector, offset: u32) -> DescriptorBuilder {
+ DescriptorBuilder::with_selector_offset(selector, offset.into()).set_type(DescriptorType::System32(SystemDescriptorTypes32::TrapGate32))
+ }
+}
+
+impl TaskGateDescriptorBuilder for DescriptorBuilder {
+ fn task_gate_descriptor(selector: SegmentSelector) -> DescriptorBuilder {
+ DescriptorBuilder::with_selector_offset(selector, 0).set_type(DescriptorType::System32(SystemDescriptorTypes32::TaskGate))
+ }
+}
+
+impl SegmentDescriptorBuilder<u32> for DescriptorBuilder {
+ fn code_descriptor(base: u32, limit: u32, cst: CodeSegmentType) -> DescriptorBuilder {
+ DescriptorBuilder::with_base_limit(base.into(), limit.into()).set_type(DescriptorType::Code(cst)).db()
+ }
+
+ fn data_descriptor(base: u32, limit: u32, dst: DataSegmentType) -> DescriptorBuilder {
+ DescriptorBuilder::with_base_limit(base.into(), limit.into()).set_type(DescriptorType::Data(dst)).db()
+ }
+}
+
+impl LdtDescriptorBuilder<u32> for DescriptorBuilder {
+ fn ldt_descriptor(base: u32, limit: u32) -> DescriptorBuilder {
+ DescriptorBuilder::with_base_limit(base.into(), limit.into()).set_type(DescriptorType::System32(SystemDescriptorTypes32::LDT))
+ }
+}
+
+impl BuildDescriptor<Descriptor> for DescriptorBuilder {
+ fn finish(&self) -> Descriptor {
+ let mut desc: Descriptor = Default::default();
+ desc.apply_builder_settings(self);
+
+ let typ = match self.typ {
+ Some(DescriptorType::System64(_)) => panic!("You shall not use 64-bit types on 32-bit descriptor."),
+ Some(DescriptorType::System32(typ)) => {
+ typ as u8
+ },
+ Some(DescriptorType::Data(typ)) => {
+ desc.set_s();
+ typ as u8
+ },
+ Some(DescriptorType::Code(typ)) => {
+ desc.set_s();
+ typ as u8
+ },
+ None => unreachable!("Type not set, this is a library bug in x86."),
+ };
+ desc.set_type(typ);
+
+ desc
+ }
+}
+
+
+/// Entry for IDT, GDT or LDT. Provides size and location of a segment.
+///
+/// See Intel 3a, Section 3.4.5 "Segment Descriptors", and Section 3.5.2
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C, packed)]
+pub struct Descriptor {
+ pub lower: u32,
+ pub upper: u32,
+}
+
+impl Descriptor {
+
+ pub(crate) fn apply_builder_settings(&mut self, builder: &DescriptorBuilder) {
+ builder.dpl.map(|ring| self.set_dpl(ring));
+ builder.base_limit.map(|(base, limit)| self.set_base_limit(base as u32, limit as u32));
+ builder.selector_offset.map(|(selector, offset)| self.set_selector_offset(selector, offset as u32));
+
+ if builder.present {
+ self.set_p();
+ }
+ if builder.avl {
+ self.set_avl();
+ }
+ if builder.db {
+ self.set_db();
+ }
+ if builder.limit_granularity_4k {
+ self.set_g();
+ }
+ if builder.l {
+ self.set_l();
+ }
+ }
+
+ /// Create a new segment, TSS or LDT descriptor
+ /// by setting the three base and two limit fields.
+ pub fn set_base_limit(&mut self, base: u32, limit: u32) {
+ // Clear the base and limit fields in Descriptor
+ self.lower = 0;
+ self.upper = self.upper & 0x00F0FF00;
+
+ // Set the new base
+ self.lower |= base << 16;
+ self.upper |= (base >> 16) & 0xff;
+ self.upper |= (base >> 24) << 24;
+
+ // Set the new limit
+ self.lower |= limit & 0xffff;
+ let limit_last_four_bits = (limit >> 16) & 0x0f;
+ self.upper |= limit_last_four_bits << 16;
+ }
+
+ /// Creates a new descriptor with selector and offset (for IDT Gate descriptors,
+ /// e.g. Trap, Interrupts and Task gates)
+ pub fn set_selector_offset(&mut self, selector: SegmentSelector, offset: u32) {
+ // Clear the selector and offset
+ self.lower = 0;
+ self.upper = self.upper & 0x0000ffff;
+
+ // Set selector
+ self.lower |= (selector.bits() as u32) << 16;
+
+ // Set offset
+ self.lower |= offset & 0x0000ffff;
+ self.upper |= offset & 0xffff0000;
+ }
+
+ /// Set the type of the descriptor (bits 8-11).
+ /// Indicates the segment or gate type and specifies the kinds of access that can be made to the
+ /// segment and the direction of growth. The interpretation of this field depends on whether the descriptor
+ /// type flag specifies an application (code or data) descriptor or a system descriptor.
+ pub fn set_type(&mut self, typ: u8) {
+ self.upper &= !(0x0f << 8); // clear
+ self.upper |= (typ as u32 & 0x0f) << 8;
+ }
+
+ /// Specifies whether the segment descriptor is for a system segment (S flag is clear) or a code or data segment (S flag is set).
+ pub fn set_s(&mut self) {
+ self.upper |= bit!(12);
+ }
+
+ /// Specifies the privilege level of the segment. The DPL is used to control access to the segment.
+ pub fn set_dpl(&mut self, ring: Ring) {
+ assert!(ring as u32 <= 0b11);
+ self.upper &= !(0b11 << 13);
+ self.upper |= (ring as u32) << 13;
+ }
+
+ /// Set Present bit.
+ /// Indicates whether the segment is present in memory (set) or not present (clear).
+ /// If this flag is clear, the processor generates a segment-not-present exception (#NP) when a segment selector
+ /// that points to the segment descriptor is loaded into a segment register.
+ pub fn set_p(&mut self) {
+ self.upper |= bit!(15);
+ }
+
+ /// Set AVL bit. System software can use this bit to store information.
+ pub fn set_avl(&mut self) {
+ self.upper |= bit!(20);
+ }
+
+ /// Set L
+ /// In IA-32e mode, bit 21 of the second doubleword of the segment descriptor indicates whether a
+ /// code segment contains native 64-bit code. A value of 1 indicates instructions in this code
+ /// segment are executed in 64-bit mode. A value of 0 indicates the instructions in this code segment
+ /// are executed in compatibility mode. If L-bit is set, then D-bit must be cleared.
+ pub fn set_l(&mut self) {
+ self.upper |= bit!(21);
+ }
+
+ /// Set D/B.
+ /// Performs different functions depending on whether the segment descriptor is an executable code segment,
+ /// an expand-down data segment, or a stack segment.
+ pub fn set_db(&mut self) {
+ self.upper |= bit!(22);
+ }
+
+ /// Set G bit
+ /// 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.
+ pub fn set_g(&mut self) {
+ self.upper |= bit!(23);
+ }
}