diff options
author | 2017-10-19 17:11:29 +0200 | |
---|---|---|
committer | 2017-10-19 17:11:29 +0200 | |
commit | 1e78c7f4b8e705cc6687191afa39090ecbe35dfd (patch) | |
tree | b61b02cc2611fedcf43e77c369ed77890faf4030 /src/bits64/segmentation.rs | |
parent | 8428a8d70a04534451f8ce858af5481b4d2f4211 (diff) | |
download | rust-x86-1e78c7f4b8e705cc6687191afa39090ecbe35dfd.tar.gz rust-x86-1e78c7f4b8e705cc6687191afa39090ecbe35dfd.tar.zst rust-x86-1e78c7f4b8e705cc6687191afa39090ecbe35dfd.zip |
Split up shared::segmentation into bits32::segmentation and bits64::segmentation and implement specifics of each architecture.
- Provide two functions new_memory and new_tss to comfortably create memory and TSS descriptors.
The x86-64 version of new_tss outputs an array of 2 descriptors to account for the upper bits of the TSS pointer address.
- Add a bitness parameter to the x86-64 version of new_memory to allow creating segments for 32-bit and 64-bit code.
- Fix a copy-pasta mistake in the x86 version of set_cs.
Diffstat (limited to 'src/bits64/segmentation.rs')
-rw-r--r-- | src/bits64/segmentation.rs | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/src/bits64/segmentation.rs b/src/bits64/segmentation.rs new file mode 100644 index 0000000..529efb9 --- /dev/null +++ b/src/bits64/segmentation.rs @@ -0,0 +1,56 @@ +use core::mem::size_of; + +use bits64::task::*; +use shared::descriptor; +use shared::PrivilegeLevel; +pub use shared::segmentation::*; + +/// Reload code segment register. +/// Note this is special since we can not directly move +/// to %cs. Instead we push the new segment selector +/// and return value on the stack and use lretq +/// to reload cs and continue at 1:. +pub unsafe fn set_cs(sel: SegmentSelector) { + asm!("pushq $0; \ + leaq 1f(%rip), %rax; \ + pushq %rax; \ + lretq; \ + 1:" :: "ri" (sel.bits() as usize) : "rax" "memory"); +} + +pub enum SegmentBitness { + Bits32, + Bits64, +} + +impl SegmentBitness { + pub fn pack(self) -> Flags { + match self { + SegmentBitness::Bits32 => FLAGS_DB, + SegmentBitness::Bits64 => FLAGS_L, + } + } +} + +impl SegmentDescriptor { + pub fn new_memory(base: u32, limit: u32, ty: Type, accessed: bool, dpl: PrivilegeLevel, bitness: SegmentBitness) -> SegmentDescriptor { + let ty1 = descriptor::Type::SegmentDescriptor { + ty: ty, + accessed: accessed, + }; + let flags = bitness.pack(); + let seg = SegmentDescriptor::memory_or_tss(base, limit, ty1, dpl, flags); + seg + } + + pub fn new_tss(tss: &TaskStateSegment, dpl: PrivilegeLevel) -> [SegmentDescriptor; 2] { + let tss_ptr = tss as *const TaskStateSegment; + let ty1 = descriptor::Type::SystemDescriptor { + size: true, + ty: descriptor::SystemType::TssAvailable, + }; + let seg1 = SegmentDescriptor::memory_or_tss(tss_ptr as u32, size_of::<TaskStateSegment>() as u32, ty1, dpl, Flags::empty()); + let seg2 = SegmentDescriptor::high(tss_ptr as u64); + [seg1, seg2] + } +} |