From 2cb9d3e154dca47610891c79a40015ca17bb9686 Mon Sep 17 00:00:00 2001 From: mental Date: Sat, 2 Jan 2021 21:12:51 +0200 Subject: [PATCH 1/3] feat(idt): add unsafe const `set_handler_{fn|addr}_unchecked` methods --- src/lib.rs | 1 + src/structures/idt.rs | 40 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) 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..4a0839122 100644 --- a/src/structures/idt.rs +++ b/src/structures/idt.rs @@ -9,7 +9,7 @@ //! Provides types for the Interrupt Descriptor Table and its entries. -use crate::{structures::DescriptorTablePointer, PrivilegeLevel, VirtAddr}; +use crate::{structures::{DescriptorTablePointer, gdt::SegmentSelector}, PrivilegeLevel, VirtAddr}; use bit_field::BitField; use bitflags::bitflags; use core::fmt; @@ -611,14 +611,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_unchecked(addr, segmentation::cs()) } + } + #[inline] + const unsafe fn set_handler_addr_unchecked( + &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.gdt_selector = segmentation::cs().0; + self.gdt_selector = cs_segment.0; + + // Note: we can't use `self.options.set_present` due to the underlying + // `set_bit` call being non-const... and that cant be const since + // `BitField` is a trait and traits cant have const associated methods. + *(&mut self.options.0) |= 1 << 15; - self.options.set_present(true); &mut self.options } } @@ -638,6 +651,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_unchecked( + &mut self, + handler: $h, + cs_segment: SegmentSelector, + ) -> &mut EntryOptions { + self.set_handler_addr_unchecked(handler as u64, cs_segment) + } + } } }; } From 82bb94ed4d02a688240ac88cbe80d318a9f87096 Mon Sep 17 00:00:00 2001 From: mental Date: Sat, 2 Jan 2021 21:19:41 +0200 Subject: [PATCH 2/3] cargo fmt --- src/structures/idt.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/structures/idt.rs b/src/structures/idt.rs index 4a0839122..a3c3e1ceb 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, gdt::SegmentSelector}, PrivilegeLevel, VirtAddr}; +use crate::{ + structures::{gdt::SegmentSelector, DescriptorTablePointer}, + PrivilegeLevel, VirtAddr, +}; use bit_field::BitField; use bitflags::bitflags; use core::fmt; From b6504861b2875bbd52f0a3b2575e966197216cd3 Mon Sep 17 00:00:00 2001 From: mental Date: Sun, 3 Jan 2021 15:53:23 +0200 Subject: [PATCH 3/3] Apply suggested changes --- src/structures/idt.rs | 58 ++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/src/structures/idt.rs b/src/structures/idt.rs index a3c3e1ceb..3f761f4d9 100644 --- a/src/structures/idt.rs +++ b/src/structures/idt.rs @@ -615,27 +615,26 @@ impl Entry { 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_unchecked(addr, segmentation::cs()) } + unsafe { self.set_handler_addr_with_segment(addr, segmentation::cs()) } } - #[inline] - const unsafe fn set_handler_addr_unchecked( - &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.gdt_selector = cs_segment.0; - - // Note: we can't use `self.options.set_present` due to the underlying - // `set_bit` call being non-const... and that cant be const since - // `BitField` is a trait and traits cant have const associated methods. - *(&mut self.options.0) |= 1 << 15; - - &mut self.options + 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.gdt_selector = cs_segment.0; + + self.options.set_present(true); + + &mut self.options + } } } @@ -667,12 +666,12 @@ macro_rules! impl_set_handler_fn { /// The function returns a mutable reference to the entry's options that allows /// further customization. #[inline] - pub unsafe fn set_handler_fn_unchecked( + pub unsafe fn set_handler_fn_with_segment( &mut self, handler: $h, cs_segment: SegmentSelector, ) -> &mut EntryOptions { - self.set_handler_addr_unchecked(handler as u64, cs_segment) + self.set_handler_addr_with_segment(handler as u64, cs_segment) } } } @@ -697,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,