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}