percore/
exceptions.rs

1// Copyright 2024 The percore Authors.
2// This project is dual-licensed under Apache 2.0 and MIT terms.
3// See LICENSE-APACHE and LICENSE-MIT for details.
4
5#[cfg(target_arch = "aarch64")]
6mod aarch64;
7#[cfg(target_arch = "aarch64")]
8use aarch64::{mask, restore};
9
10use core::marker::PhantomData;
11
12/// Runs the given function with exceptions masked.
13///
14/// Only IRQs, FIQs and SErrors can be masked. Synchronous exceptions cannot be masked and so may
15/// still occur.
16#[cfg(target_arch = "aarch64")]
17pub fn exception_free<T>(f: impl FnOnce(ExceptionFree<'_>) -> T) -> T {
18    // Mask all exceptions and save previous mask state.
19    let prev = mask();
20    // SAFETY: We just masked exceptions.
21    let token = unsafe { ExceptionFree::new() };
22
23    let result = f(token);
24
25    // SAFETY: `token` has been dropped by now, as its lifetime prevents `f` from storing it.
26    unsafe {
27        // Restore previous exception mask state.
28        restore(prev);
29    }
30
31    result
32}
33
34/// A token proving that exceptions are currently masked.
35///
36/// Note that synchronous exceptions cannot be masked and so may still occur.
37#[derive(Clone, Copy, Debug)]
38pub struct ExceptionFree<'cs> {
39    _private: PhantomData<&'cs ()>,
40}
41
42impl<'cs> ExceptionFree<'cs> {
43    /// Constructs a new instance of `ExceptionFree`, promising that exceptions will remain masked
44    /// for at least its lifetime.
45    ///
46    /// This usually should not be called directly; instead use [`exception_free`].
47    ///
48    /// # Safety
49    ///
50    /// `ExceptionFree` must only be constructed while exceptions are masked, and they must not be
51    /// unmasked until after it is dropped.
52    pub unsafe fn new() -> Self {
53        Self {
54            _private: PhantomData,
55        }
56    }
57}