From 0e66d8247aceb71288aea856378c6dabebfa4686 Mon Sep 17 00:00:00 2001 From: Restioson Date: Sat, 17 Oct 2020 09:30:42 +0200 Subject: [PATCH 01/16] Add ability to add iomap to TSS --- src/structures/gdt.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index e839fa6e..3c4d93e0 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -439,17 +439,33 @@ impl Descriptor { /// being used. #[inline] pub unsafe fn tss_segment_unchecked(tss: *const TaskStateSegment) -> Descriptor { + // TODO: Remove this with a call to a function that takes a method + // instead of a static reference. + // SAFETY: if iomap_size is zero, there are no requirements to uphold. + unsafe { Self::tss_segment_with_iomap(&*tss, 0) } + } + + /// Creates a TSS system descriptor for the given TSS, setting up the IO permissions bitmap. + /// + /// # Safety + /// + /// If `iomap_size` is greater than zero, there **must** be a valid IO map at `tss_ptr + iomap_base`. + /// The size of the IO map must correspond with the given `iomap_size`. + pub unsafe fn tss_segment_with_iomap(tss: &'static TaskStateSegment, iomap_size: u16) -> Descriptor { use self::DescriptorFlags as Flags; use core::mem::size_of; - let ptr = tss as u64; + let ptr = tss as *const _ as u64; let mut low = Flags::PRESENT.bits(); // base low.set_bits(16..40, ptr.get_bits(0..24)); low.set_bits(56..64, ptr.get_bits(24..32)); - // limit (the `-1` in needed since the bound is inclusive) - low.set_bits(0..16, (size_of::() - 1) as u64); + // limit (the `-1` is needed since the bound is inclusive) + low.set_bits( + 0..16, + (size_of::() + (tss.iomap_base + iomap_size) as usize - 1) as u64 + ); // type (0b1001 = available 64-bit tss) low.set_bits(40..44, 0b1001); From e17b928a5de67b2dc67fbe3fca9c83495ad2e5c8 Mon Sep 17 00:00:00 2001 From: Restioson Date: Sat, 17 Oct 2020 09:37:26 +0200 Subject: [PATCH 02/16] formatting --- src/structures/gdt.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index 3c4d93e0..47ffaa87 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -451,7 +451,10 @@ impl Descriptor { /// /// If `iomap_size` is greater than zero, there **must** be a valid IO map at `tss_ptr + iomap_base`. /// The size of the IO map must correspond with the given `iomap_size`. - pub unsafe fn tss_segment_with_iomap(tss: &'static TaskStateSegment, iomap_size: u16) -> Descriptor { + pub unsafe fn tss_segment_with_iomap( + tss: &'static TaskStateSegment, + iomap_size: u16, + ) -> Descriptor { use self::DescriptorFlags as Flags; use core::mem::size_of; @@ -464,7 +467,7 @@ impl Descriptor { // limit (the `-1` is needed since the bound is inclusive) low.set_bits( 0..16, - (size_of::() + (tss.iomap_base + iomap_size) as usize - 1) as u64 + (size_of::() + (tss.iomap_base + iomap_size) as usize - 1) as u64, ); // type (0b1001 = available 64-bit tss) low.set_bits(40..44, 0b1001); From 6cd1a9953dbfefeb91d33fff77fe992f6d6ecab8 Mon Sep 17 00:00:00 2001 From: Restioson Date: Sat, 17 Oct 2020 14:29:42 +0200 Subject: [PATCH 03/16] doc & iomap limit calculation --- src/structures/gdt.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index 47ffaa87..a5bb2a7b 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -5,7 +5,7 @@ use crate::structures::tss::TaskStateSegment; use crate::PrivilegeLevel; use bit_field::BitField; use bitflags::bitflags; -use core::fmt; +use core::{fmt, cmp, mem}; // imports for intra-doc links #[cfg(doc)] use crate::registers::segmentation::{Segment, CS, SS}; @@ -449,8 +449,8 @@ impl Descriptor { /// /// # Safety /// - /// If `iomap_size` is greater than zero, there **must** be a valid IO map at `tss_ptr + iomap_base`. - /// The size of the IO map must correspond with the given `iomap_size`. + /// There must be a valid IO map at `(tss as *const u8).offset(tss.iomap_base)` + /// of length `iomap_size` pub unsafe fn tss_segment_with_iomap( tss: &'static TaskStateSegment, iomap_size: u16, @@ -465,9 +465,10 @@ impl Descriptor { low.set_bits(16..40, ptr.get_bits(0..24)); low.set_bits(56..64, ptr.get_bits(24..32)); // limit (the `-1` is needed since the bound is inclusive) + let iomap_limit = tss.iomap_base as u64 + iomap_size as u64 - 1; low.set_bits( 0..16, - (size_of::() + (tss.iomap_base + iomap_size) as usize - 1) as u64, + cmp::max(mem::size_of::(), iomap_limit), ); // type (0b1001 = available 64-bit tss) low.set_bits(40..44, 0b1001); From d19a5ae1d8019dbcbd53626af61b77acfc0dce07 Mon Sep 17 00:00:00 2001 From: Restioson Date: Sat, 17 Oct 2020 14:33:21 +0200 Subject: [PATCH 04/16] missed a cast :( --- src/structures/gdt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index a5bb2a7b..4beec1ea 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -468,7 +468,7 @@ impl Descriptor { let iomap_limit = tss.iomap_base as u64 + iomap_size as u64 - 1; low.set_bits( 0..16, - cmp::max(mem::size_of::(), iomap_limit), + cmp::max(mem::size_of::() as u64, iomap_limit), ); // type (0b1001 = available 64-bit tss) low.set_bits(40..44, 0b1001); From 5a0ffc277afbb1ce2ce8753c375237c5f2778e30 Mon Sep 17 00:00:00 2001 From: Restioson Date: Sat, 17 Oct 2020 14:41:02 +0200 Subject: [PATCH 05/16] expand on safety requirements --- src/structures/gdt.rs | 3 ++- src/structures/tss.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index 4beec1ea..c33bf589 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -450,7 +450,8 @@ impl Descriptor { /// # Safety /// /// There must be a valid IO map at `(tss as *const u8).offset(tss.iomap_base)` - /// of length `iomap_size` + /// of length `iomap_size`, with the terminating `0xFF` byte. Additionally, `iomap_base` must + /// not exceed `0xDFFF`. pub unsafe fn tss_segment_with_iomap( tss: &'static TaskStateSegment, iomap_size: u16, diff --git a/src/structures/tss.rs b/src/structures/tss.rs index cbfeff47..c840dba7 100644 --- a/src/structures/tss.rs +++ b/src/structures/tss.rs @@ -19,7 +19,8 @@ pub struct TaskStateSegment { pub interrupt_stack_table: [VirtAddr; 7], reserved_3: u64, reserved_4: u16, - /// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base. + /// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base. It must not + /// exceed `0xDFFF`. pub iomap_base: u16, } From 2fef3bd0c5c705e19b5a87ce2cbe18107962d2ee Mon Sep 17 00:00:00 2001 From: Restioson Date: Sat, 17 Oct 2020 14:47:22 +0200 Subject: [PATCH 06/16] -1 after max --- src/structures/gdt.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index c33bf589..ca786a6f 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -457,7 +457,6 @@ impl Descriptor { iomap_size: u16, ) -> Descriptor { use self::DescriptorFlags as Flags; - use core::mem::size_of; let ptr = tss as *const _ as u64; @@ -466,10 +465,10 @@ impl Descriptor { low.set_bits(16..40, ptr.get_bits(0..24)); low.set_bits(56..64, ptr.get_bits(24..32)); // limit (the `-1` is needed since the bound is inclusive) - let iomap_limit = tss.iomap_base as u64 + iomap_size as u64 - 1; + let iomap_limit = tss.iomap_base as u64 + iomap_size as u64; low.set_bits( 0..16, - cmp::max(mem::size_of::() as u64, iomap_limit), + cmp::max(mem::size_of::() as u64, iomap_limit) - 1, ); // type (0b1001 = available 64-bit tss) low.set_bits(40..44, 0b1001); From 05c08286023f61cc68a27599ccb84453bb58b523 Mon Sep 17 00:00:00 2001 From: Restioson Date: Sat, 17 Oct 2020 14:47:56 +0200 Subject: [PATCH 07/16] fmt --- src/structures/gdt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index ca786a6f..3683d427 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -5,7 +5,7 @@ use crate::structures::tss::TaskStateSegment; use crate::PrivilegeLevel; use bit_field::BitField; use bitflags::bitflags; -use core::{fmt, cmp, mem}; +use core::{cmp, fmt, mem}; // imports for intra-doc links #[cfg(doc)] use crate::registers::segmentation::{Segment, CS, SS}; From f13551e53d54db815634c7eb68947b1105b8fb68 Mon Sep 17 00:00:00 2001 From: Restioson Date: Sat, 17 Oct 2020 15:15:24 +0200 Subject: [PATCH 08/16] slice for safety --- src/structures/gdt.rs | 36 +++++++++++++++++++++++++++++------- src/structures/tss.rs | 18 ++++++++++++++++++ 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index 3683d427..7db818ab 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -9,6 +9,7 @@ use core::{cmp, fmt, mem}; // imports for intra-doc links #[cfg(doc)] use crate::registers::segmentation::{Segment, CS, SS}; +use crate::structures::tss::InvalidIoMap; #[cfg(all(feature = "instructions", target_arch = "x86_64"))] use core::sync::atomic::{AtomicU64 as EntryValue, Ordering}; @@ -439,10 +440,31 @@ impl Descriptor { /// being used. #[inline] pub unsafe fn tss_segment_unchecked(tss: *const TaskStateSegment) -> Descriptor { - // TODO: Remove this with a call to a function that takes a method - // instead of a static reference. // SAFETY: if iomap_size is zero, there are no requirements to uphold. - unsafe { Self::tss_segment_with_iomap(&*tss, 0) } + unsafe { Self::tss_segment_raw(tss, 0) } + } + + /// Creates a TSS system descriptor for the given TSS, setting up the IO permissions bitmap. + pub fn tss_segment_with_iomap( + tss: &'static TaskStateSegment, + iomap: &'static [u8], + ) -> Result { + if iomap.len() > 8193 { + return Err(InvalidIoMap::TooLong { len: iomap.len() }) + } + + let distance = iomap.as_ptr() as usize - tss as *const _ as usize; + if distance > 0xdfff { + return Err(InvalidIoMap::TooFarFromTss { distance }) + } + + let last_byte = *iomap.last().unwrap_or(&0xff); + if last_byte != 0xff { + return Err(InvalidIoMap::InvalidTerminatingByte { byte: last_byte }) + } + + // SAFETY: all invariants checked above + Ok(unsafe { Self::tss_segment_raw(tss, iomap.len() as u16) }) } /// Creates a TSS system descriptor for the given TSS, setting up the IO permissions bitmap. @@ -452,20 +474,20 @@ impl Descriptor { /// There must be a valid IO map at `(tss as *const u8).offset(tss.iomap_base)` /// of length `iomap_size`, with the terminating `0xFF` byte. Additionally, `iomap_base` must /// not exceed `0xDFFF`. - pub unsafe fn tss_segment_with_iomap( - tss: &'static TaskStateSegment, + unsafe fn tss_segment_raw( + tss: *const TaskStateSegment, iomap_size: u16, ) -> Descriptor { use self::DescriptorFlags as Flags; - let ptr = tss as *const _ as u64; + let ptr = tss as u64; let mut low = Flags::PRESENT.bits(); // base low.set_bits(16..40, ptr.get_bits(0..24)); low.set_bits(56..64, ptr.get_bits(24..32)); // limit (the `-1` is needed since the bound is inclusive) - let iomap_limit = tss.iomap_base as u64 + iomap_size as u64; + let iomap_limit = unsafe { (*tss).iomap_base } as u64 + iomap_size as u64; low.set_bits( 0..16, cmp::max(mem::size_of::() as u64, iomap_limit) - 1, diff --git a/src/structures/tss.rs b/src/structures/tss.rs index c840dba7..7fc22d01 100644 --- a/src/structures/tss.rs +++ b/src/structures/tss.rs @@ -52,6 +52,24 @@ impl Default for TaskStateSegment { } } +/// The given IO permissions bitmap is invalid. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum InvalidIoMap { + /// The IO permissions bitmap is too far from the TSS. It must be within `0xdfff` bytes of the + /// start of the TSS. + TooFarFromTss { + distance: usize, + }, + /// The final byte of the IO permissions bitmap was not 0xff + InvalidTerminatingByte { + byte: u8, + }, + /// The IO permissions bitmap exceeds the maximum length (8193). + TooLong { + len: usize + }, +} + #[cfg(test)] mod tests { use super::*; From c03a90ab37e287b59df7f7cdf28498178a917dea Mon Sep 17 00:00:00 2001 From: Restioson Date: Sat, 17 Oct 2020 15:18:26 +0200 Subject: [PATCH 09/16] error if base =/= expected base --- src/structures/gdt.rs | 13 ++++++++++--- src/structures/tss.rs | 5 +++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index 7db818ab..d5d463dc 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -453,9 +453,9 @@ impl Descriptor { return Err(InvalidIoMap::TooLong { len: iomap.len() }) } - let distance = iomap.as_ptr() as usize - tss as *const _ as usize; - if distance > 0xdfff { - return Err(InvalidIoMap::TooFarFromTss { distance }) + let base = iomap.as_ptr() as usize - tss as *const _ as usize; + if base > 0xdfff { + return Err(InvalidIoMap::TooFarFromTss { distance: base }) } let last_byte = *iomap.last().unwrap_or(&0xff); @@ -463,6 +463,13 @@ impl Descriptor { return Err(InvalidIoMap::InvalidTerminatingByte { byte: last_byte }) } + if tss.iomap_base != base as u16 { + return Err(InvalidIoMap::InvalidBase { + expected: base as u16, + got: tss.iomap_base + }); + } + // SAFETY: all invariants checked above Ok(unsafe { Self::tss_segment_raw(tss, iomap.len() as u16) }) } diff --git a/src/structures/tss.rs b/src/structures/tss.rs index 7fc22d01..4c3b5d1e 100644 --- a/src/structures/tss.rs +++ b/src/structures/tss.rs @@ -68,6 +68,11 @@ pub enum InvalidIoMap { TooLong { len: usize }, + /// The `iomap_base` in the `TaskStateSegment` struct was not what was expected. + InvalidBase { + expected: u16, + got: u16, + } } #[cfg(test)] From a85c1e2032648f9933af29b485bbe39efc3559f9 Mon Sep 17 00:00:00 2001 From: Restioson Date: Sat, 17 Oct 2020 15:19:03 +0200 Subject: [PATCH 10/16] fmt (i always forget this...) --- src/structures/gdt.rs | 16 ++++++---------- src/structures/tss.rs | 17 ++++------------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index d5d463dc..0d0f81c3 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -1,7 +1,7 @@ //! Types for the Global Descriptor Table and segment selectors. pub use crate::registers::segmentation::SegmentSelector; -use crate::structures::tss::TaskStateSegment; +use crate::structures::tss::{InvalidIoMap, TaskStateSegment}; use crate::PrivilegeLevel; use bit_field::BitField; use bitflags::bitflags; @@ -9,7 +9,6 @@ use core::{cmp, fmt, mem}; // imports for intra-doc links #[cfg(doc)] use crate::registers::segmentation::{Segment, CS, SS}; -use crate::structures::tss::InvalidIoMap; #[cfg(all(feature = "instructions", target_arch = "x86_64"))] use core::sync::atomic::{AtomicU64 as EntryValue, Ordering}; @@ -450,23 +449,23 @@ impl Descriptor { iomap: &'static [u8], ) -> Result { if iomap.len() > 8193 { - return Err(InvalidIoMap::TooLong { len: iomap.len() }) + return Err(InvalidIoMap::TooLong { len: iomap.len() }); } let base = iomap.as_ptr() as usize - tss as *const _ as usize; if base > 0xdfff { - return Err(InvalidIoMap::TooFarFromTss { distance: base }) + return Err(InvalidIoMap::TooFarFromTss { distance: base }); } let last_byte = *iomap.last().unwrap_or(&0xff); if last_byte != 0xff { - return Err(InvalidIoMap::InvalidTerminatingByte { byte: last_byte }) + return Err(InvalidIoMap::InvalidTerminatingByte { byte: last_byte }); } if tss.iomap_base != base as u16 { return Err(InvalidIoMap::InvalidBase { expected: base as u16, - got: tss.iomap_base + got: tss.iomap_base, }); } @@ -481,10 +480,7 @@ impl Descriptor { /// There must be a valid IO map at `(tss as *const u8).offset(tss.iomap_base)` /// of length `iomap_size`, with the terminating `0xFF` byte. Additionally, `iomap_base` must /// not exceed `0xDFFF`. - unsafe fn tss_segment_raw( - tss: *const TaskStateSegment, - iomap_size: u16, - ) -> Descriptor { + unsafe fn tss_segment_raw(tss: *const TaskStateSegment, iomap_size: u16) -> Descriptor { use self::DescriptorFlags as Flags; let ptr = tss as u64; diff --git a/src/structures/tss.rs b/src/structures/tss.rs index 4c3b5d1e..ea298058 100644 --- a/src/structures/tss.rs +++ b/src/structures/tss.rs @@ -57,22 +57,13 @@ impl Default for TaskStateSegment { pub enum InvalidIoMap { /// The IO permissions bitmap is too far from the TSS. It must be within `0xdfff` bytes of the /// start of the TSS. - TooFarFromTss { - distance: usize, - }, + TooFarFromTss { distance: usize }, /// The final byte of the IO permissions bitmap was not 0xff - InvalidTerminatingByte { - byte: u8, - }, + InvalidTerminatingByte { byte: u8 }, /// The IO permissions bitmap exceeds the maximum length (8193). - TooLong { - len: usize - }, + TooLong { len: usize }, /// The `iomap_base` in the `TaskStateSegment` struct was not what was expected. - InvalidBase { - expected: u16, - got: u16, - } + InvalidBase { expected: u16, got: u16 }, } #[cfg(test)] From 9c30209c8b301ca6592fddb62a3bded8045231a7 Mon Sep 17 00:00:00 2001 From: Restioson Date: Sat, 17 Oct 2020 15:20:49 +0200 Subject: [PATCH 11/16] doc --- src/structures/tss.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/structures/tss.rs b/src/structures/tss.rs index ea298058..698a870f 100644 --- a/src/structures/tss.rs +++ b/src/structures/tss.rs @@ -57,13 +57,27 @@ impl Default for TaskStateSegment { pub enum InvalidIoMap { /// The IO permissions bitmap is too far from the TSS. It must be within `0xdfff` bytes of the /// start of the TSS. - TooFarFromTss { distance: usize }, + TooFarFromTss { + /// The distance of the IO permissions bitmap from the beginning of the TSS. + distance: usize + }, /// The final byte of the IO permissions bitmap was not 0xff - InvalidTerminatingByte { byte: u8 }, + InvalidTerminatingByte { + /// The byte found at the end of the IO permissions bitmap. + byte: u8 + }, /// The IO permissions bitmap exceeds the maximum length (8193). - TooLong { len: usize }, + TooLong { + /// The length of the IO permissions bitmap. + len: usize + }, /// The `iomap_base` in the `TaskStateSegment` struct was not what was expected. - InvalidBase { expected: u16, got: u16 }, + InvalidBase { + /// The expected `iomap_base` to be set in the `TaskStateSegment` struct. + expected: u16, + /// The actual `iomap_base` set in the `TaskStateSegment` struct. + got: u16 + }, } #[cfg(test)] From 7e49ece8d1589adfc371caf558508a6aea60eda1 Mon Sep 17 00:00:00 2001 From: Restioson Date: Sat, 17 Oct 2020 15:22:20 +0200 Subject: [PATCH 12/16] fmt --- src/structures/tss.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/structures/tss.rs b/src/structures/tss.rs index 698a870f..e5dd3ae5 100644 --- a/src/structures/tss.rs +++ b/src/structures/tss.rs @@ -59,24 +59,24 @@ pub enum InvalidIoMap { /// start of the TSS. TooFarFromTss { /// The distance of the IO permissions bitmap from the beginning of the TSS. - distance: usize + distance: usize, }, /// The final byte of the IO permissions bitmap was not 0xff InvalidTerminatingByte { /// The byte found at the end of the IO permissions bitmap. - byte: u8 + byte: u8, }, /// The IO permissions bitmap exceeds the maximum length (8193). TooLong { /// The length of the IO permissions bitmap. - len: usize + len: usize, }, /// The `iomap_base` in the `TaskStateSegment` struct was not what was expected. InvalidBase { /// The expected `iomap_base` to be set in the `TaskStateSegment` struct. expected: u16, /// The actual `iomap_base` set in the `TaskStateSegment` struct. - got: u16 + got: u16, }, } From cfa2083f16a6e1133fe9f4c8815c9a793d4a3f46 Mon Sep 17 00:00:00 2001 From: Restioson Date: Sat, 17 Oct 2020 15:57:35 +0200 Subject: [PATCH 13/16] handle iomap before tss --- src/structures/gdt.rs | 9 ++++++++- src/structures/tss.rs | 5 ++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index 0d0f81c3..630d2783 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -452,7 +452,14 @@ impl Descriptor { return Err(InvalidIoMap::TooLong { len: iomap.len() }); } - let base = iomap.as_ptr() as usize - tss as *const _ as usize; + let iomap_addr = iomap.as_ptr() as usize; + let tss_addr = tss as *const _ as usize; + + if tss_addr > iomap_addr { + return Err(InvalidIoMap::IoMapBeforeTss); + } + + let base = iomap_addr - tss_addr; if base > 0xdfff { return Err(InvalidIoMap::TooFarFromTss { distance: base }); } diff --git a/src/structures/tss.rs b/src/structures/tss.rs index e5dd3ae5..4dea64cd 100644 --- a/src/structures/tss.rs +++ b/src/structures/tss.rs @@ -55,8 +55,11 @@ impl Default for TaskStateSegment { /// The given IO permissions bitmap is invalid. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum InvalidIoMap { + /// The IO permissions bitmap is before the TSS. It must be located after the TSS. + IoMapBeforeTss, /// The IO permissions bitmap is too far from the TSS. It must be within `0xdfff` bytes of the - /// start of the TSS. + /// start of the TSS. Note that if the IO permissions bitmap is located before the TSS, then + /// `IoMapBeforeTss` will be returned instead. TooFarFromTss { /// The distance of the IO permissions bitmap from the beginning of the TSS. distance: usize, From 411b42b36936b5d7a3a66ae51e8d09139e0b6690 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Wed, 19 Mar 2025 19:57:58 +0100 Subject: [PATCH 14/16] use From instead of casts --- src/structures/gdt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index 630d2783..52a7e5c9 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -497,7 +497,7 @@ impl Descriptor { low.set_bits(16..40, ptr.get_bits(0..24)); low.set_bits(56..64, ptr.get_bits(24..32)); // limit (the `-1` is needed since the bound is inclusive) - let iomap_limit = unsafe { (*tss).iomap_base } as u64 + iomap_size as u64; + let iomap_limit = u64::from(unsafe { (*tss).iomap_base }) + u64::from(iomap_size); low.set_bits( 0..16, cmp::max(mem::size_of::() as u64, iomap_limit) - 1, From 66675311ae625b3e0c13978f6ba0452496449aff Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Wed, 19 Mar 2025 20:02:30 +0100 Subject: [PATCH 15/16] add Display impl for InvalidIoMap --- src/structures/tss.rs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/structures/tss.rs b/src/structures/tss.rs index 4dea64cd..f0174f3f 100644 --- a/src/structures/tss.rs +++ b/src/structures/tss.rs @@ -1,7 +1,10 @@ //! Provides a type for the task state segment structure. use crate::VirtAddr; -use core::mem::size_of; +use core::{ + fmt::{self, Display}, + mem::size_of, +}; /// In 64-bit mode the TSS holds information that is not /// directly related to the task-switch mechanism, @@ -83,6 +86,34 @@ pub enum InvalidIoMap { }, } +impl Display for InvalidIoMap { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + InvalidIoMap::IoMapBeforeTss => { + write!(f, "the IO permissions bitmap is before the TSS") + } + InvalidIoMap::TooFarFromTss { distance } => write!( + f, + "the IO permissions bitmap is too far from the TSS (distance {distance})" + ), + InvalidIoMap::InvalidTerminatingByte { byte } => write!( + f, + "The final byte of the IO permissions bitmap was not 0xff ({byte}" + ), + InvalidIoMap::TooLong { len } => { + write!( + f, + "The IO permissions bitmap exceeds the maximum length ({len} > 8193)" + ) + } + InvalidIoMap::InvalidBase { expected, got } => write!( + f, + "the `iomap_base` in the `TaskStateSegment` struct was not what was expected (expected {expected}, got {got})" + ), + } + } +} + #[cfg(test)] mod tests { use super::*; From 8e1d5f8791514e42cd8a7e246e7b51a099c08984 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Wed, 19 Mar 2025 20:07:50 +0100 Subject: [PATCH 16/16] add an example for Descriptor::tss_segment_with_iomap --- src/structures/gdt.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index 52a7e5c9..07b4093b 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -444,6 +444,27 @@ impl Descriptor { } /// Creates a TSS system descriptor for the given TSS, setting up the IO permissions bitmap. + /// + /// # Example + /// + /// ``` + /// use x86_64::structures::gdt::Descriptor; + /// use x86_64::structures::tss::TaskStateSegment; + /// + /// /// A helper that places some I/O map bytes behind a TSS. + /// #[repr(C)] + /// struct TssWithIOMap { + /// tss: TaskStateSegment, + /// iomap: [u8; 5], + /// } + /// + /// static TSS: TssWithIOMap = TssWithIOMap { + /// tss: TaskStateSegment::new(), + /// iomap: [0xff, 0xff, 0x00, 0x80, 0xff], + /// }; + /// + /// let tss = Descriptor::tss_segment_with_iomap(&TSS.tss, &TSS.iomap).unwrap(); + /// ``` pub fn tss_segment_with_iomap( tss: &'static TaskStateSegment, iomap: &'static [u8],