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")] 6 mod aarch64; 7 #[cfg(target_arch = "aarch64")] 8 use aarch64::{mask, restore}; 9 10 use 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")] exception_free<T>(f: impl FnOnce(ExceptionFree<'_>) -> T) -> T17pub 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)] 38 pub struct ExceptionFree<'cs> { 39 _private: PhantomData<&'cs ()>, 40 } 41 42 impl<'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. new() -> Self52 pub unsafe fn new() -> Self { 53 Self { 54 _private: PhantomData, 55 } 56 } 57 } 58