aboutsummaryrefslogtreecommitdiff
path: root/src/segmentation.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/segmentation.rs')
-rw-r--r--src/segmentation.rs117
1 files changed, 75 insertions, 42 deletions
diff --git a/src/segmentation.rs b/src/segmentation.rs
index f91a6ec..ee73b8d 100644
--- a/src/segmentation.rs
+++ b/src/segmentation.rs
@@ -174,7 +174,7 @@ pub(crate) enum DescriptorType {
System64(SystemDescriptorTypes64),
System32(SystemDescriptorTypes32),
Data(DataSegmentType),
- Code(CodeSegmentType)
+ Code(CodeSegmentType),
}
/// Trait that defines the architecture specific functions for building various system segment descriptors
@@ -186,7 +186,7 @@ pub trait GateDescriptorBuilder<Size> {
fn trap_gate_descriptor(selector: SegmentSelector, offset: Size) -> Self;
}
-/// Trait to implement for building a task-gate (this descriptor is not implemented for 64-bit systems since
+/// 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 trait TaskGateDescriptorBuilder {
fn task_gate_descriptor(selector: SegmentSelector) -> Self;
@@ -229,22 +229,43 @@ pub struct DescriptorBuilder {
/// 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
-
+ 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, l: 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, l: false }
+ 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,
+ l: false,
+ }
}
-
+
pub(crate) fn set_type(mut self, typ: DescriptorType) -> DescriptorBuilder {
self.typ = Some(typ);
self
@@ -281,7 +302,7 @@ impl DescriptorBuilder {
}
/// 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
+ /// 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;
@@ -290,7 +311,6 @@ impl DescriptorBuilder {
}
impl GateDescriptorBuilder<u32> for DescriptorBuilder {
-
fn tss_descriptor(base: u64, limit: u64, available: bool) -> DescriptorBuilder {
let typ = match available {
true => DescriptorType::System32(SystemDescriptorTypes32::TssAvailable32),
@@ -301,37 +321,49 @@ impl GateDescriptorBuilder<u32> for DescriptorBuilder {
}
fn call_gate_descriptor(selector: SegmentSelector, offset: u32) -> DescriptorBuilder {
- DescriptorBuilder::with_selector_offset(selector, offset.into()).set_type(DescriptorType::System32(SystemDescriptorTypes32::CallGate32))
+ 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))
+ 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))
+ 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))
+ 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()
+ 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()
+ 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))
+ DescriptorBuilder::with_base_limit(base.into(), limit.into())
+ .set_type(DescriptorType::System32(SystemDescriptorTypes32::LDT))
}
}
@@ -341,18 +373,18 @@ impl BuildDescriptor<Descriptor> for DescriptorBuilder {
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::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);
@@ -361,7 +393,6 @@ impl BuildDescriptor<Descriptor> for DescriptorBuilder {
}
}
-
/// 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
@@ -373,13 +404,16 @@ pub struct Descriptor {
}
impl Descriptor {
-
pub const NULL: Descriptor = Descriptor { lower: 0, upper: 0 };
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));
+ 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();
@@ -416,7 +450,7 @@ impl Descriptor {
self.upper |= limit_last_four_bits << 16;
}
- /// Creates a new descriptor with selector and offset (for IDT Gate descriptors,
+ /// 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
@@ -432,8 +466,8 @@ impl Descriptor {
}
/// 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
+ /// 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
@@ -453,44 +487,43 @@ impl Descriptor {
}
/// 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
+ /// 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
+ /// 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,
+ /// 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;
+ /// 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);
}
}
-
/// Reload stack segment register.
pub unsafe fn load_ss(sel: SegmentSelector) {
asm!("movw $0, %ss " :: "r" (sel.bits()) : "memory");