Skip to content

Commit 66b11eb

Browse files
toku-sa-nphil-opp
andauthored
feat(idt): make it available in the stable Rust (#271)
This PR makes the `idt` module available for use in the stable Rust with the `instructions` feature. Especially, this PR - exposes `Entry::set_handler_addr` as an unsafe method. This is the only way for the users of this crate who build it with the stable Rust to set the addresses of the interrupt or exception handlers. - defines the handler function types as `()` if the `abi_x86_interrupt` feature is not enabled. These types are only used with the `abi_x86_interrupt` feature. Co-authored-by: Philipp Oppermann <[email protected]>
1 parent e5c202c commit 66b11eb

File tree

2 files changed

+64
-5
lines changed

2 files changed

+64
-5
lines changed

src/structures/idt.rs

+64-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@
88
// except according to those terms.
99

1010
//! Provides types for the Interrupt Descriptor Table and its entries.
11+
//!
12+
//! # For the builds without the `abi_x86_interrupt` feature
13+
//! The following types are opaque and non-constructable instead of function pointers.
14+
//!
15+
//! - [`DivergingHandlerFunc`]
16+
//! - [`DivergingHandlerFuncWithErrCode`]
17+
//! - [`HandlerFunc`]
18+
//! - [`HandlerFuncWithErrCode`]
19+
//! - [`PageFaultHandlerFunc`]
20+
//!
21+
//! These types are defined for the compatibility with the Nightly Rust build.
1122
1223
use crate::{PrivilegeLevel, VirtAddr};
1324
use bit_field::BitField;
@@ -593,17 +604,56 @@ impl<T> PartialEq for Entry<T> {
593604
}
594605

595606
/// A handler function for an interrupt or an exception without error code.
607+
///
608+
/// This type alias is only usable with the `abi_x86_interrupt` feature enabled.
609+
#[cfg(feature = "abi_x86_interrupt")]
596610
pub type HandlerFunc = extern "x86-interrupt" fn(InterruptStackFrame);
611+
/// This type is not usable without the `abi_x86_interrupt` feature.
612+
#[cfg(not(feature = "abi_x86_interrupt"))]
613+
#[derive(Copy, Clone, Debug)]
614+
pub struct HandlerFunc(());
615+
597616
/// A handler function for an exception that pushes an error code.
617+
///
618+
/// This type alias is only usable with the `abi_x86_interrupt` feature enabled.
619+
#[cfg(feature = "abi_x86_interrupt")]
598620
pub type HandlerFuncWithErrCode = extern "x86-interrupt" fn(InterruptStackFrame, error_code: u64);
621+
/// This type is not usable without the `abi_x86_interrupt` feature.
622+
#[cfg(not(feature = "abi_x86_interrupt"))]
623+
#[derive(Copy, Clone, Debug)]
624+
pub struct HandlerFuncWithErrCode(());
625+
599626
/// A page fault handler function that pushes a page fault error code.
627+
///
628+
/// This type alias is only usable with the `abi_x86_interrupt` feature enabled.
629+
#[cfg(feature = "abi_x86_interrupt")]
600630
pub type PageFaultHandlerFunc =
601631
extern "x86-interrupt" fn(InterruptStackFrame, error_code: PageFaultErrorCode);
632+
/// This type is not usable without the `abi_x86_interrupt` feature.
633+
#[cfg(not(feature = "abi_x86_interrupt"))]
634+
#[derive(Copy, Clone, Debug)]
635+
pub struct PageFaultHandlerFunc(());
636+
602637
/// A handler function that must not return, e.g. for a machine check exception.
638+
///
639+
/// This type alias is only usable with the `abi_x86_interrupt` feature enabled.
640+
#[cfg(feature = "abi_x86_interrupt")]
603641
pub type DivergingHandlerFunc = extern "x86-interrupt" fn(InterruptStackFrame) -> !;
642+
/// This type is not usable without the `abi_x86_interrupt` feature.
643+
#[cfg(not(feature = "abi_x86_interrupt"))]
644+
#[derive(Copy, Clone, Debug)]
645+
pub struct DivergingHandlerFunc(());
646+
604647
/// A handler function with an error code that must not return, e.g. for a double fault exception.
648+
///
649+
/// This type alias is only usable with the `abi_x86_interrupt` feature enabled.
650+
#[cfg(feature = "abi_x86_interrupt")]
605651
pub type DivergingHandlerFuncWithErrCode =
606652
extern "x86-interrupt" fn(InterruptStackFrame, error_code: u64) -> !;
653+
/// This type is not usable without the `abi_x86_interrupt` feature.
654+
#[cfg(not(feature = "abi_x86_interrupt"))]
655+
#[derive(Copy, Clone, Debug)]
656+
pub struct DivergingHandlerFuncWithErrCode(());
607657

608658
impl<F> Entry<F> {
609659
/// Creates a non-present IDT entry (but sets the must-be-one bits).
@@ -627,11 +677,18 @@ impl<F> Entry<F> {
627677
///
628678
/// The function returns a mutable reference to the entry's options that allows
629679
/// further customization.
680+
///
681+
/// # Safety
682+
///
683+
/// The caller must ensure that `addr` is the address of a valid interrupt handler function,
684+
/// and the signature of such a function is correct for the entry type.
630685
#[cfg(feature = "instructions")]
631686
#[inline]
632-
fn set_handler_addr(&mut self, addr: u64) -> &mut EntryOptions {
687+
pub unsafe fn set_handler_addr(&mut self, addr: VirtAddr) -> &mut EntryOptions {
633688
use crate::instructions::segmentation::{Segment, CS};
634689

690+
let addr = addr.as_u64();
691+
635692
self.pointer_low = addr as u16;
636693
self.pointer_middle = (addr >> 16) as u16;
637694
self.pointer_high = (addr >> 32) as u32;
@@ -652,7 +709,7 @@ impl<F> Entry<F> {
652709

653710
macro_rules! impl_set_handler_fn {
654711
($h:ty) => {
655-
#[cfg(feature = "instructions")]
712+
#[cfg(all(feature = "instructions", feature = "abi_x86_interrupt"))]
656713
impl Entry<$h> {
657714
/// Set the handler function for the IDT entry and sets the present bit.
658715
///
@@ -661,9 +718,13 @@ macro_rules! impl_set_handler_fn {
661718
///
662719
/// The function returns a mutable reference to the entry's options that allows
663720
/// further customization.
721+
///
722+
/// This method is only usable with the `abi_x86_interrupt` feature enabled. Without it, the
723+
/// unsafe [`Entry::set_handler_addr`] method has to be used instead.
664724
#[inline]
665725
pub fn set_handler_fn(&mut self, handler: $h) -> &mut EntryOptions {
666-
self.set_handler_addr(handler as u64)
726+
let handler = VirtAddr::new(handler as u64);
727+
unsafe { self.set_handler_addr(handler) }
667728
}
668729
}
669730
};

src/structures/mod.rs

-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ use crate::VirtAddr;
44

55
pub mod gdt;
66

7-
// idt needs `feature(abi_x86_interrupt)`, which is not available on stable rust
8-
#[cfg(feature = "abi_x86_interrupt")]
97
pub mod idt;
108

119
pub mod paging;

0 commit comments

Comments
 (0)