@@ -9,6 +9,7 @@ use core::{cmp, fmt, mem};
99// imports for intra-doc links
1010#[ cfg( doc) ]
1111use crate :: registers:: segmentation:: { Segment , CS , SS } ;
12+ use crate :: structures:: tss:: InvalidIoMap ;
1213
1314#[ cfg( all( feature = "instructions" , target_arch = "x86_64" ) ) ]
1415use core:: sync:: atomic:: { AtomicU64 as EntryValue , Ordering } ;
@@ -439,10 +440,31 @@ impl Descriptor {
439440 /// being used.
440441 #[ inline]
441442 pub unsafe fn tss_segment_unchecked ( tss : * const TaskStateSegment ) -> Descriptor {
442- // TODO: Remove this with a call to a function that takes a method
443- // instead of a static reference.
444443 // SAFETY: if iomap_size is zero, there are no requirements to uphold.
445- unsafe { Self :: tss_segment_with_iomap ( & * tss, 0 ) }
444+ unsafe { Self :: tss_segment_raw ( tss, 0 ) }
445+ }
446+
447+ /// Creates a TSS system descriptor for the given TSS, setting up the IO permissions bitmap.
448+ pub fn tss_segment_with_iomap (
449+ tss : & ' static TaskStateSegment ,
450+ iomap : & ' static [ u8 ] ,
451+ ) -> Result < Descriptor , InvalidIoMap > {
452+ if iomap. len ( ) > 8193 {
453+ return Err ( InvalidIoMap :: TooLong { len : iomap. len ( ) } )
454+ }
455+
456+ let distance = iomap. as_ptr ( ) as usize - tss as * const _ as usize ;
457+ if distance > 0xdfff {
458+ return Err ( InvalidIoMap :: TooFarFromTss { distance } )
459+ }
460+
461+ let last_byte = * iomap. last ( ) . unwrap_or ( & 0xff ) ;
462+ if last_byte != 0xff {
463+ return Err ( InvalidIoMap :: InvalidTerminatingByte { byte : last_byte } )
464+ }
465+
466+ // SAFETY: all invariants checked above
467+ Ok ( unsafe { Self :: tss_segment_raw ( tss, iomap. len ( ) as u16 ) } )
446468 }
447469
448470 /// Creates a TSS system descriptor for the given TSS, setting up the IO permissions bitmap.
@@ -452,20 +474,20 @@ impl Descriptor {
452474 /// There must be a valid IO map at `(tss as *const u8).offset(tss.iomap_base)`
453475 /// of length `iomap_size`, with the terminating `0xFF` byte. Additionally, `iomap_base` must
454476 /// not exceed `0xDFFF`.
455- pub unsafe fn tss_segment_with_iomap (
456- tss : & ' static TaskStateSegment ,
477+ unsafe fn tss_segment_raw (
478+ tss : * const TaskStateSegment ,
457479 iomap_size : u16 ,
458480 ) -> Descriptor {
459481 use self :: DescriptorFlags as Flags ;
460482
461- let ptr = tss as * const _ as u64 ;
483+ let ptr = tss as u64 ;
462484
463485 let mut low = Flags :: PRESENT . bits ( ) ;
464486 // base
465487 low. set_bits ( 16 ..40 , ptr. get_bits ( 0 ..24 ) ) ;
466488 low. set_bits ( 56 ..64 , ptr. get_bits ( 24 ..32 ) ) ;
467489 // limit (the `-1` is needed since the bound is inclusive)
468- let iomap_limit = tss. iomap_base as u64 + iomap_size as u64 ;
490+ let iomap_limit = unsafe { ( * tss) . iomap_base } as u64 + iomap_size as u64 ;
469491 low. set_bits (
470492 0 ..16 ,
471493 cmp:: max ( mem:: size_of :: < TaskStateSegment > ( ) as u64 , iomap_limit) - 1 ,
0 commit comments