aboutsummaryrefslogtreecommitdiff
path: root/src/bits64/segmentation.rs
diff options
context:
space:
mode:
authorGravatar Colin Finck <mail@colinfinck.de> 2017-10-19 17:11:29 +0200
committerGravatar Colin Finck <mail@colinfinck.de> 2017-10-19 17:11:29 +0200
commit1e78c7f4b8e705cc6687191afa39090ecbe35dfd (patch)
treeb61b02cc2611fedcf43e77c369ed77890faf4030 /src/bits64/segmentation.rs
parent8428a8d70a04534451f8ce858af5481b4d2f4211 (diff)
downloadrust-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.rs56
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]
+ }
+}