@@ -18,6 +18,8 @@ use core::ops::Bound::{Excluded, Included, Unbounded};
18
18
use core:: ops:: { Deref , Index , IndexMut , RangeBounds } ;
19
19
use volatile:: Volatile ;
20
20
21
+ use super :: gdt:: SegmentSelector ;
22
+
21
23
/// An Interrupt Descriptor Table with 256 entries.
22
24
///
23
25
/// The first 32 entries are used for CPU exceptions. These entries can be either accessed through
@@ -557,13 +559,11 @@ impl IndexMut<usize> for InterruptDescriptorTable {
557
559
558
560
/// An Interrupt Descriptor Table entry.
559
561
///
560
- /// The generic parameter can either be `HandlerFunc` or `HandlerFuncWithErrCode`, depending
561
- /// on the interrupt vector.
562
+ /// The generic parameter is some [`InterruptFn`], depending on the interrupt vector.
562
563
#[ derive( Clone , Copy ) ]
563
564
#[ repr( C ) ]
564
565
pub struct Entry < F > {
565
566
pointer_low : u16 ,
566
- gdt_selector : u16 ,
567
567
options : EntryOptions ,
568
568
pointer_middle : u16 ,
569
569
pointer_high : u32 ,
@@ -575,7 +575,6 @@ impl<T> fmt::Debug for Entry<T> {
575
575
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
576
576
f. debug_struct ( "Entry" )
577
577
. field ( "handler_addr" , & format_args ! ( "{:#x}" , self . handler_addr( ) ) )
578
- . field ( "gdt_selector" , & self . gdt_selector )
579
578
. field ( "options" , & self . options )
580
579
. finish ( )
581
580
}
@@ -584,7 +583,6 @@ impl<T> fmt::Debug for Entry<T> {
584
583
impl < T > PartialEq for Entry < T > {
585
584
fn eq ( & self , other : & Self ) -> bool {
586
585
self . pointer_low == other. pointer_low
587
- && self . gdt_selector == other. gdt_selector
588
586
&& self . options == other. options
589
587
&& self . pointer_middle == other. pointer_middle
590
588
&& self . pointer_high == other. pointer_high
@@ -610,7 +608,6 @@ impl<F> Entry<F> {
610
608
#[ inline]
611
609
pub const fn missing ( ) -> Self {
612
610
Entry {
613
- gdt_selector : 0 ,
614
611
pointer_low : 0 ,
615
612
pointer_middle : 0 ,
616
613
pointer_high : 0 ,
@@ -620,93 +617,121 @@ impl<F> Entry<F> {
620
617
}
621
618
}
622
619
623
- /// Set the handler address for the IDT entry and sets the present bit.
624
- ///
625
- /// For the code selector field, this function uses the code segment selector currently
626
- /// active in the CPU.
620
+ #[ inline]
621
+ fn handler_addr ( & self ) -> u64 {
622
+ self . pointer_low as u64
623
+ | ( self . pointer_middle as u64 ) << 16
624
+ | ( self . pointer_high as u64 ) << 32
625
+ }
626
+ }
627
+
628
+ #[ cfg( feature = "instructions" ) ]
629
+ impl < F : InterruptFn > Entry < F > {
630
+ /// Sets the handler function for the IDT entry and sets the following defaults:
631
+ /// - The code selector is the code segment currently active in the CPU
632
+ /// - The present bit is set
633
+ /// - Interrupts are disabled on handler invocation
634
+ /// - The privilege level (DPL) is [`PrivilegeLevel::Ring0`]
635
+ /// - No IST is configured (existing stack will be used)
627
636
///
628
637
/// The function returns a mutable reference to the entry's options that allows
629
638
/// further customization.
630
- #[ cfg( feature = "instructions" ) ]
631
- #[ inline]
632
- fn set_handler_addr ( & mut self , addr : u64 ) -> & mut EntryOptions {
639
+ pub fn set_handler_fn ( & mut self , handler : F ) -> & mut EntryOptions {
633
640
use crate :: instructions:: segmentation;
634
641
642
+ let addr = handler. addr ( ) . as_u64 ( ) ;
635
643
self . pointer_low = addr as u16 ;
636
644
self . pointer_middle = ( addr >> 16 ) as u16 ;
637
645
self . pointer_high = ( addr >> 32 ) as u32 ;
638
646
639
- self . gdt_selector = segmentation:: cs ( ) . 0 ;
640
-
647
+ self . options = EntryOptions :: minimal ( ) ;
648
+ // SAFETY: The current CS is a valid, long-mode code segment.
649
+ unsafe { self . options . set_code_selector ( segmentation:: cs ( ) ) } ;
641
650
self . options . set_present ( true ) ;
642
651
& mut self . options
643
652
}
653
+ }
644
654
645
- #[ inline]
646
- fn handler_addr ( & self ) -> u64 {
647
- self . pointer_low as u64
648
- | ( self . pointer_middle as u64 ) << 16
649
- | ( self . pointer_high as u64 ) << 32
650
- }
655
+ /// A trait for function pointers that can be used as interrupt handlers
656
+ pub trait InterruptFn {
657
+ /// The virtual address of this function pointer
658
+ fn addr ( self ) -> VirtAddr ;
651
659
}
652
660
653
- macro_rules! impl_set_handler_fn {
661
+ macro_rules! impl_interrupt_fn {
654
662
( $h: ty) => {
655
- #[ cfg( feature = "instructions" ) ]
656
- impl Entry <$h> {
657
- /// Set the handler function for the IDT entry and sets the present bit.
658
- ///
659
- /// For the code selector field, this function uses the code segment selector currently
660
- /// active in the CPU.
661
- ///
662
- /// The function returns a mutable reference to the entry's options that allows
663
- /// further customization.
664
- #[ inline]
665
- pub fn set_handler_fn( & mut self , handler: $h) -> & mut EntryOptions {
666
- self . set_handler_addr( handler as u64 )
663
+ #[ cfg( target_pointer_width = "64" ) ]
664
+ impl InterruptFn for $h {
665
+ fn addr( self ) -> VirtAddr {
666
+ VirtAddr :: from_ptr( self as * const ( ) )
667
667
}
668
668
}
669
669
} ;
670
670
}
671
671
672
- impl_set_handler_fn ! ( HandlerFunc ) ;
673
- impl_set_handler_fn ! ( HandlerFuncWithErrCode ) ;
674
- impl_set_handler_fn ! ( PageFaultHandlerFunc ) ;
675
- impl_set_handler_fn ! ( DivergingHandlerFunc ) ;
676
- impl_set_handler_fn ! ( DivergingHandlerFuncWithErrCode ) ;
672
+ impl_interrupt_fn ! ( HandlerFunc ) ;
673
+ impl_interrupt_fn ! ( HandlerFuncWithErrCode ) ;
674
+ impl_interrupt_fn ! ( PageFaultHandlerFunc ) ;
675
+ impl_interrupt_fn ! ( DivergingHandlerFunc ) ;
676
+ impl_interrupt_fn ! ( DivergingHandlerFuncWithErrCode ) ;
677
677
678
- /// Represents the options field of an IDT entry.
679
- #[ repr( transparent ) ]
678
+ /// Represents the 4 non-offset bytes of an IDT entry.
679
+ #[ repr( C ) ]
680
680
#[ derive( Clone , Copy , PartialEq ) ]
681
- pub struct EntryOptions ( u16 ) ;
681
+ pub struct EntryOptions {
682
+ cs : SegmentSelector ,
683
+ bits : u16 ,
684
+ }
682
685
683
686
impl fmt:: Debug for EntryOptions {
684
687
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
685
- f. debug_tuple ( "EntryOptions" )
686
- . field ( & format_args ! ( "{:#06x}" , self . 0 ) )
688
+ f. debug_struct ( "EntryOptions" )
689
+ . field ( "code_selector" , & self . cs )
690
+ . field ( "stack_index" , & self . stack_index ( ) )
691
+ . field ( "type" , & format_args ! ( "{:#04b}" , self . bits. get_bits( 8 ..12 ) ) )
692
+ . field ( "privilege_level" , & self . privilege_level ( ) )
693
+ . field ( "present" , & self . present ( ) )
687
694
. finish ( )
688
695
}
689
696
}
690
697
691
698
impl EntryOptions {
692
- /// Creates a minimal options field with all the must-be-one bits set.
699
+ /// Creates a minimal options field with all the must-be-one bits set. This
700
+ /// means the CS selector, IST, and DPL field are all 0.
693
701
#[ inline]
694
702
const fn minimal ( ) -> Self {
695
- EntryOptions ( 0b1110_0000_0000 )
703
+ EntryOptions {
704
+ cs : SegmentSelector ( 0 ) ,
705
+ bits : 0b1110_0000_0000 , // Default to a 64-bit Interrupt Gate
706
+ }
707
+ }
708
+
709
+ /// Set the code segment that will be used by this interrupt.
710
+ ///
711
+ /// ## Safety
712
+ /// This function is unsafe because the caller must ensure that the passed
713
+ /// segment selector points to a valid, long-mode code segment.
714
+ pub unsafe fn set_code_selector ( & mut self , cs : SegmentSelector ) -> & mut Self {
715
+ self . cs = cs;
716
+ self
696
717
}
697
718
698
719
/// Set or reset the preset bit.
699
720
#[ inline]
700
721
pub fn set_present ( & mut self , present : bool ) -> & mut Self {
701
- self . 0 . set_bit ( 15 , present) ;
722
+ self . bits . set_bit ( 15 , present) ;
702
723
self
703
724
}
704
725
726
+ fn present ( & self ) -> bool {
727
+ self . bits . get_bit ( 15 )
728
+ }
729
+
705
730
/// Let the CPU disable hardware interrupts when the handler is invoked. By default,
706
731
/// interrupts are disabled on handler invocation.
707
732
#[ inline]
708
733
pub fn disable_interrupts ( & mut self , disable : bool ) -> & mut Self {
709
- self . 0 . set_bit ( 8 , !disable) ;
734
+ self . bits . set_bit ( 8 , !disable) ;
710
735
self
711
736
}
712
737
@@ -716,10 +741,14 @@ impl EntryOptions {
716
741
/// This function panics for a DPL > 3.
717
742
#[ inline]
718
743
pub fn set_privilege_level ( & mut self , dpl : PrivilegeLevel ) -> & mut Self {
719
- self . 0 . set_bits ( 13 ..15 , dpl as u16 ) ;
744
+ self . bits . set_bits ( 13 ..15 , dpl as u16 ) ;
720
745
self
721
746
}
722
747
748
+ fn privilege_level ( & self ) -> PrivilegeLevel {
749
+ PrivilegeLevel :: from_u16 ( self . bits . get_bits ( 13 ..15 ) )
750
+ }
751
+
723
752
/// Assigns a Interrupt Stack Table (IST) stack to this handler. The CPU will then always
724
753
/// switch to the specified stack before the handler is invoked. This allows kernels to
725
754
/// recover from corrupt stack pointers (e.g., on kernel stack overflow).
@@ -736,9 +765,13 @@ impl EntryOptions {
736
765
pub unsafe fn set_stack_index ( & mut self , index : u16 ) -> & mut Self {
737
766
// The hardware IST index starts at 1, but our software IST index
738
767
// starts at 0. Therefore we need to add 1 here.
739
- self . 0 . set_bits ( 0 ..3 , index + 1 ) ;
768
+ self . bits . set_bits ( 0 ..3 , index + 1 ) ;
740
769
self
741
770
}
771
+
772
+ fn stack_index ( & self ) -> u16 {
773
+ self . bits . get_bits ( 0 ..3 ) - 1
774
+ }
742
775
}
743
776
744
777
/// Wrapper type for the interrupt stack frame pushed by the CPU.
@@ -874,8 +907,7 @@ mod test {
874
907
875
908
foo ( Entry :: < HandlerFuncWithErrCode > {
876
909
pointer_low : 0 ,
877
- gdt_selector : 0 ,
878
- options : EntryOptions ( 0 ) ,
910
+ options : EntryOptions :: minimal ( ) ,
879
911
pointer_middle : 0 ,
880
912
pointer_high : 0 ,
881
913
reserved : 0 ,
0 commit comments