twizzler_abi/
upcall.rs

1//! Functions for handling upcalls from the kernel.
2
3use twizzler_rt_abi::error::RawTwzError;
4
5pub use crate::arch::upcall::UpcallFrame;
6use crate::object::ObjID;
7
8/// Information about an exception.
9#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
10#[repr(C)]
11pub struct ExceptionInfo {
12    /// CPU-reported exception code.
13    pub code: u64,
14    /// Arch-specific additional info.
15    pub info: u64,
16}
17
18impl ExceptionInfo {
19    /// Construct new exception info.
20    pub fn new(code: u64, info: u64) -> Self {
21        Self { code, info }
22    }
23}
24
25/// Information about a memory access error to an object.
26#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
27#[repr(C)]
28pub struct ObjectMemoryFaultInfo {
29    /// Object ID of attempted access.
30    pub object_id: ObjID,
31    /// The kind of error.
32    pub error: ObjectMemoryError,
33    /// The kind of memory access that caused the error.
34    pub access: MemoryAccessKind,
35    /// The virtual address at which the error occurred.
36    pub addr: usize,
37}
38
39impl ObjectMemoryFaultInfo {
40    /// Construct a new upcall info for memory fault.
41    pub fn new(
42        object_id: ObjID,
43        error: ObjectMemoryError,
44        access: MemoryAccessKind,
45        addr: usize,
46    ) -> Self {
47        Self {
48            object_id,
49            error,
50            access,
51            addr,
52        }
53    }
54}
55
56/// Kinds of object memory errors.
57#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
58#[repr(u8)]
59pub enum ObjectMemoryError {
60    /// Tried to access an object's null page
61    NullPageAccess,
62    /// Tried to access outside of an object
63    OutOfBounds(usize),
64    /// Failed to satisfy fault due to backing storage failure
65    BackingFailed(RawTwzError),
66}
67
68/// Information about a non-object-related memory access violation.
69#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
70#[repr(C)]
71pub struct MemoryContextViolationInfo {
72    /// The virtual address that caused the exception.
73    pub address: u64,
74    /// The kind of memory access.
75    pub kind: MemoryAccessKind,
76}
77
78impl MemoryContextViolationInfo {
79    pub fn new(address: u64, kind: MemoryAccessKind) -> Self {
80        Self { address, kind }
81    }
82}
83
84/// Kinds of memory access.
85#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
86#[repr(u8)]
87pub enum MemoryAccessKind {
88    Read,
89    Write,
90    InstructionFetch,
91}
92
93/// Information about a non-object-related memory access violation.
94#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
95#[repr(C)]
96pub struct SecurityViolationInfo {
97    /// The virtual address that caused the violation.
98    pub address: u64,
99    /// The kind of memory access.
100    pub access_kind: MemoryAccessKind,
101}
102
103/// Possible upcall reasons and info.
104#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
105#[repr(C)]
106pub enum UpcallInfo {
107    Exception(ExceptionInfo),
108    ObjectMemoryFault(ObjectMemoryFaultInfo),
109    MemoryContextViolation(MemoryContextViolationInfo),
110    SecurityViolation(SecurityViolationInfo),
111}
112
113impl UpcallInfo {
114    /// The number of upcall info variants
115    pub const NR_UPCALLS: usize = 3;
116    /// Get the number associated with this variant
117    pub fn number(&self) -> usize {
118        match self {
119            UpcallInfo::Exception(_) => 0,
120            UpcallInfo::ObjectMemoryFault(_) => 1,
121            UpcallInfo::MemoryContextViolation(_) => 2,
122            UpcallInfo::SecurityViolation(_) => 3,
123        }
124    }
125}
126
127/// A collection of data about this upcall, and the [UpcallInfo] for this
128/// particular upcall.
129#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
130#[repr(C)]
131pub struct UpcallData {
132    /// Info for this upcall, including reason and elaboration data.
133    pub info: UpcallInfo,
134    /// Upcall flags
135    pub flags: UpcallHandlerFlags,
136    /// Source context
137    pub source_ctx: ObjID,
138    /// The thread ID for this thread.
139    pub thread_id: ObjID,
140}
141
142/// Information for handling an upcall, per-thread. By default, a thread starts with
143/// all these fields initialized to zero, and the mode set to [UpcallMode::Abort].
144#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
145#[repr(C)]
146pub struct UpcallTarget {
147    /// Address to jump to when handling via a call to the same context.
148    pub self_address: usize,
149    /// Address to jump to when handling via a call to supervisor context.
150    pub super_address: usize,
151    /// Address of supervisor stack to use, when switching to supervisor context.
152    pub super_stack: usize,
153    /// Size of the super stack.
154    pub super_stack_size: usize,
155    /// Value to use for stack pointer, when switching to supervisor context.
156    pub super_thread_ptr: usize,
157    /// Supervisor context to use, when switching to supervisor context.
158    pub super_ctx: ObjID,
159    /// Per-upcall options.
160    pub options: [UpcallOptions; UpcallInfo::NR_UPCALLS],
161}
162
163impl UpcallTarget {
164    /// Construct a new upcall target.
165    pub fn new(
166        self_address: Option<
167            unsafe extern "C-unwind" fn(*mut core::ffi::c_void, *const core::ffi::c_void) -> !,
168        >,
169        super_address: Option<
170            unsafe extern "C-unwind" fn(*mut core::ffi::c_void, *const core::ffi::c_void) -> !,
171        >,
172        super_stack: usize,
173        super_stack_size: usize,
174        super_thread_ptr: usize,
175        super_ctx: ObjID,
176        options: [UpcallOptions; UpcallInfo::NR_UPCALLS],
177    ) -> Self {
178        Self {
179            self_address: self_address.map(|addr| addr as usize).unwrap_or_default(),
180            super_address: super_address.map(|addr| addr as usize).unwrap_or_default(),
181            super_stack,
182            super_thread_ptr,
183            super_ctx,
184            options,
185            super_stack_size,
186        }
187    }
188}
189
190/// The exit code the kernel will use when killing a thread that cannot handle
191/// an upcall (e.g. the kernel fails to push the upcall stack frame, or the mode is set
192/// to [UpcallMode::Abort]).
193pub const UPCALL_EXIT_CODE: u64 = 127;
194
195bitflags::bitflags! {
196    /// Flags controlling upcall handling.
197#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
198pub struct UpcallFlags : u8 {
199    /// Whether or not to suspend the thread before handling (or aborting from) the upcall.
200    const SUSPEND = 1;
201}
202}
203
204bitflags::bitflags! {
205    /// Flags passed to the upcall handler in [UpcallData].
206#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
207pub struct UpcallHandlerFlags : u8 {
208    /// Whether or not to suspend the thread before handling (or aborting from) the upcall.
209    const SWITCHED_CONTEXT = 1;
210}
211}
212
213/// Possible modes for upcall handling.
214#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
215pub enum UpcallMode {
216    /// Handle this upcall by immediate abort. If the SUSPEND flag is set, the thread will
217    /// still abort when unsuspended.
218    Abort,
219    /// Handle this upcall by calling, without trying to transfer to supervisor context. Upcall
220    /// data, including frame data, will be placed on the current stack, and the thread pointer
221    /// is unchanged.
222    CallSelf,
223    /// Handle this upcall by calling into supervisor context. If the thread is already in
224    /// supervisor context, this acts like [UpcallMode::CallSelf]. Otherwise, the thread's stack
225    /// and thread pointer are updated to the super_stack and super_thread_pointer values in the
226    /// upcall target respectively, and the active security context is switched to the supervisor
227    /// context (super_ctx).
228    CallSuper,
229}
230
231/// Options for a single upcall.
232#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
233pub struct UpcallOptions {
234    /// Flags for the upcall.
235    pub flags: UpcallFlags,
236    /// The mode for the upcall.
237    pub mode: UpcallMode,
238}