twizzler_abi/syscall/
spawn.rs

1use bitflags::bitflags;
2use twizzler_rt_abi::Result;
3
4use super::{convert_codes_to_result, twzerr, Syscall};
5use crate::{arch::syscall::raw_syscall, object::ObjID, upcall::UpcallTarget};
6bitflags! {
7    /// Flags to pass to [sys_spawn].
8    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
9    pub struct ThreadSpawnFlags: u32 {
10    }
11}
12
13#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
14#[repr(C)]
15pub enum UpcallTargetSpawnOption {
16    /// Set all sync event handlers to abort by default. Entry addresses will be zero, and upcalls
17    /// will not be issued.
18    DefaultAbort,
19    /// Inherit the upcall target entry address. All supervisor fields are cleared.
20    Inherit,
21    /// Set the upcall target directly. The following conditions must be met:
22    ///   1. The super_ctx field holds the ID of the current thread's active context (prevents priv
23    ///      escalation).
24    ///   2. The super_entry_address is at most r-x, and at least --x in the super_ctx.
25    ///   3. The super_thread_pointer is exactly rw- in the super_ctx.
26    ///   4. The super_stack_pointer is exactly rw- in the super_ctx.
27    SetTo(UpcallTarget),
28}
29
30#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
31#[repr(C)]
32/// Arguments to pass to [sys_spawn].
33pub struct ThreadSpawnArgs {
34    pub entry: usize,
35    pub stack_base: usize,
36    pub stack_size: usize,
37    pub tls: usize,
38    pub arg: usize,
39    pub flags: ThreadSpawnFlags,
40    pub vm_context_handle: Option<ObjID>,
41    pub upcall_target: UpcallTargetSpawnOption,
42}
43
44impl ThreadSpawnArgs {
45    /// Construct a new ThreadSpawnArgs. If vm_context_handle is Some(handle), then spawn the thread
46    /// in the VM context defined by handle. Otherwise spawn it in the same VM context as the
47    /// spawner.
48    #[warn(clippy::too_many_arguments)]
49    pub fn new(
50        entry: usize,
51        stack_base: usize,
52        stack_size: usize,
53        tls: usize,
54        arg: usize,
55        flags: ThreadSpawnFlags,
56        vm_context_handle: Option<ObjID>,
57        upcall_target: UpcallTargetSpawnOption,
58    ) -> Self {
59        Self {
60            entry,
61            stack_base,
62            stack_size,
63            tls,
64            arg,
65            flags,
66            vm_context_handle,
67            upcall_target,
68        }
69    }
70}
71
72/// Spawn a new thread, returning the ObjID of the thread's handle or an error.
73/// # Safety
74/// The caller must ensure that the [ThreadSpawnArgs] has sane values.
75pub unsafe fn sys_spawn(args: ThreadSpawnArgs) -> Result<ObjID> {
76    let (code, val) = raw_syscall(Syscall::Spawn, &[&args as *const ThreadSpawnArgs as u64]);
77    convert_codes_to_result(
78        code,
79        val,
80        |c, _| c == 0,
81        |x, y| crate::object::ObjID::from_parts([x, y]),
82        twzerr,
83    )
84}