Skip to main content

catalejo_sys/exception/
action.rs

1//! Construction of fixed-ABI immutable exception actions.
2
3use core::{
4    mem::{self, MaybeUninit},
5    num::NonZero,
6};
7
8use crate::ffi::binding;
9
10/// A complete architectural recovery policy.
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum Action {
13    /// Leave the exception to native Linux handling.
14    None,
15
16    /// Replace the saved userspace instruction pointer.
17    Ip(
18        /// The nonzero userspace instruction address restored on recovery.
19        NonZero<usize>,
20    ),
21
22    /// Retry the faulting instruction.
23    Retry,
24}
25
26impl Action {
27    /// Encode the immutable kernel ABI value.
28    #[inline]
29    pub const fn encode(self) -> binding::mirilla_except_action {
30        let mut target_storage = MaybeUninit::<binding::mirilla_except_action>::zeroed();
31
32        let target_base = target_storage.as_mut_ptr().cast::<u8>();
33        let target_tag = target_base
34            .wrapping_add(mem::offset_of!(binding::mirilla_except_action, tag))
35            .cast::<u16>();
36
37        match self {
38            Self::None => {
39                // SAFETY: The field offset locates the complete tag within live zeroed storage.
40                unsafe {
41                    target_tag.write(binding::MIRILLA_EXCEPT_ACTION_NONE as u16);
42                }
43            }
44            Self::Ip(target_address) => {
45                let address = target_address.get() as binding::virtual_address_t;
46
47                let ip = binding::mirilla_except_action_ip_context { address };
48
49                let action_context = binding::mirilla_except_action_context { ip };
50
51                let target_context = target_base
52                    .wrapping_add(mem::offset_of!(binding::mirilla_except_action, context))
53                    .cast::<binding::mirilla_except_action_context>();
54
55                // SAFETY: The field offset locates the complete context within live zeroed
56                // storage. The tag written below selects its initialized union member.
57                unsafe { target_context.write(action_context) };
58
59                // SAFETY: The field offset locates the complete tag within live zeroed storage.
60                unsafe {
61                    target_tag.write(binding::MIRILLA_EXCEPT_ACTION_IP as u16);
62                }
63            }
64            Self::Retry => {
65                // SAFETY: The field offset locates the complete tag within live zeroed storage.
66                unsafe {
67                    target_tag.write(binding::MIRILLA_EXCEPT_ACTION_RETRY as u16);
68                }
69            }
70        }
71
72        // SAFETY: The buffer began fully zeroed and every semantic action writes its valid tag.
73        unsafe { target_storage.assume_init() }
74    }
75}