diff options
Diffstat (limited to 'src/segmentation.rs')
-rw-r--r-- | src/segmentation.rs | 117 |
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"); |