diff --git a/src/lib.rs b/src/lib.rs index 360acf1a8..95d7a5886 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ #![cfg_attr(feature = "const_fn", feature(const_mut_refs))] #![cfg_attr(feature = "const_fn", feature(const_fn_fn_ptr_basics))] #![cfg_attr(feature = "const_fn", feature(const_in_array_repeat_expressions))] +#![cfg_attr(feature = "const_fn", feature(const_raw_ptr_to_usize_cast))] #![cfg_attr(feature = "inline_asm", feature(asm))] #![cfg_attr(feature = "abi_x86_interrupt", feature(abi_x86_interrupt))] #![warn(missing_docs)] diff --git a/src/structures/idt.rs b/src/structures/idt.rs index dd605f20a..3f761f4d9 100644 --- a/src/structures/idt.rs +++ b/src/structures/idt.rs @@ -9,7 +9,10 @@ //! Provides types for the Interrupt Descriptor Table and its entries. -use crate::{structures::DescriptorTablePointer, PrivilegeLevel, VirtAddr}; +use crate::{ + structures::{gdt::SegmentSelector, DescriptorTablePointer}, + PrivilegeLevel, VirtAddr, +}; use bit_field::BitField; use bitflags::bitflags; use core::fmt; @@ -611,15 +614,27 @@ impl Entry { #[inline] fn set_handler_addr(&mut self, addr: u64) -> &mut EntryOptions { use crate::instructions::segmentation; + // SAFETY: CS segment is loaded directly from the register, so it's valid. + unsafe { self.set_handler_addr_with_segment(addr, segmentation::cs()) } + } + + const_fn! { + #[inline] + unsafe fn set_handler_addr_with_segment( + &mut self, + addr: u64, + cs_segment: SegmentSelector, + ) -> &mut EntryOptions { + self.pointer_low = addr as u16; + self.pointer_middle = (addr >> 16) as u16; + self.pointer_high = (addr >> 32) as u32; - self.pointer_low = addr as u16; - self.pointer_middle = (addr >> 16) as u16; - self.pointer_high = (addr >> 32) as u32; + self.gdt_selector = cs_segment.0; - self.gdt_selector = segmentation::cs().0; + self.options.set_present(true); - self.options.set_present(true); - &mut self.options + &mut self.options + } } } @@ -638,6 +653,27 @@ macro_rules! impl_set_handler_fn { pub fn set_handler_fn(&mut self, handler: $h) -> &mut EntryOptions { self.set_handler_addr(handler as u64) } + + const_fn! { + /// Set the handler function for the IDT entry and sets the present bit. + /// + /// # Safety + /// + /// For the code selector field, this function uses the code segment selector that + /// is passed in through the arguments, the user must take care to ensure that it is + /// valid. + /// + /// The function returns a mutable reference to the entry's options that allows + /// further customization. + #[inline] + pub unsafe fn set_handler_fn_with_segment( + &mut self, + handler: $h, + cs_segment: SegmentSelector, + ) -> &mut EntryOptions { + self.set_handler_addr_with_segment(handler as u64, cs_segment) + } + } } }; } @@ -660,11 +696,18 @@ impl EntryOptions { EntryOptions(0b1110_0000_0000) } - /// Set or reset the preset bit. - #[inline] - pub fn set_present(&mut self, present: bool) -> &mut Self { - self.0.set_bit(15, present); - self + const_fn! { + /// Set or reset the preset bit. + #[inline] + pub fn set_present(&mut self, present: bool) -> &mut Self { + if present { + self.0 |= 1 << 15; + } else { + self.0 &= !(1 << 15); + } + + self + } } /// Let the CPU disable hardware interrupts when the handler is invoked. By default,