twizzler_abi/syscall/
thread_control.rs

1use num_enum::{FromPrimitive, IntoPrimitive};
2use twizzler_rt_abi::error::TwzError;
3
4use super::{convert_codes_to_result, twzerr, Syscall};
5use crate::{
6    arch::syscall::raw_syscall,
7    object::ObjID,
8    upcall::{UpcallFrame, UpcallTarget},
9};
10
11#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, FromPrimitive, IntoPrimitive)]
12#[repr(u64)]
13/// Possible Thread Control operations
14pub enum ThreadControl {
15    #[default]
16    /// Exit the thread. arg1 and arg2 should be code and location respectively, where code
17    /// contains a 64-bit value to write into *location, followed by the kernel performing a
18    /// thread-wake event on the memory word at location. If location is null, the write and
19    /// thread-wake do not occur.
20    Exit = 0,
21    /// Yield the thread's CPU time now. The actual effect of this is unspecified, but it acts as a
22    /// hint to the kernel that this thread does not need to run right now. The kernel, of course,
23    /// is free to ignore this hint.
24    Yield = 1,
25    /// Set thread's TLS pointer
26    SetTls = 2,
27    /// Get the thread's TLS pointer.
28    GetTls = 3,
29    /// Set the thread's upcall pointer (child threads in the same virtual address space will
30    /// inherit).
31    SetUpcall = 4,
32    /// Get the upcall pointer.
33    GetUpcall = 5,
34    /// Read a register from the thread's CPU state. The thread must be suspended.
35    ReadRegister = 6,
36    /// Write a value to a register in the thread's CPU state. The thread must be suspended.
37    WriteRegister = 7,
38    /// Send a user-defined async or sync event to the thread.
39    SendMessage = 8,
40    /// Change the thread's state. Allowed transitions are:
41    /// running -> suspended
42    /// suspended -> running
43    /// running -> exited
44    ChangeState = 9,
45    /// Set the Trap State for the thread.
46    SetTrapState = 10,
47    /// Get the Trap State for the thread.
48    GetTrapState = 11,
49    /// Set a thread's priority. Threads require special permission to increase their priority.
50    SetPriority = 12,
51    /// Get a thread's priority.
52    GetPriority = 13,
53    /// Set a thread's affinity.
54    SetAffinity = 14,
55    /// Get a thread's affinity.
56    GetAffinity = 15,
57    /// Resume from an upcall.
58    ResumeFromUpcall = 16,
59    /// Get the repr ID of the calling thread.
60    GetSelfId = 17,
61    /// Get the ID of the active security context.
62    GetActiveSctxId = 18,
63    /// Set the ID of the active security context.
64    SetActiveSctxId = 19,
65}
66
67/// Exit the thread. The code will be written to the [crate::thread::ThreadRepr] for the current
68/// thread as part of updating the status and code to indicate thread has exited.
69pub fn sys_thread_exit(code: u64) -> ! {
70    unsafe {
71        raw_syscall(Syscall::ThreadCtrl, &[ThreadControl::Exit as u64, code]);
72    }
73    unreachable!()
74}
75
76/// Yield the thread's CPU time now. The actual effect of this is unspecified, but it acts as a
77/// hint to the kernel that this thread does not need to run right now. The kernel, of course,
78/// is free to ignore this hint.
79pub fn sys_thread_yield() {
80    unsafe {
81        raw_syscall(Syscall::ThreadCtrl, &[ThreadControl::Yield as u64]);
82    }
83}
84
85/// Set the current kernel thread's TLS pointer. On x86_64, for example, this changes user's FS
86/// segment base to the supplies TLS value.
87pub fn sys_thread_settls(tls: u64) {
88    unsafe {
89        raw_syscall(Syscall::ThreadCtrl, &[ThreadControl::SetTls as u64, tls]);
90    }
91}
92
93/// Get the repr ID of the calling thread.
94pub fn sys_thread_self_id() -> ObjID {
95    let (hi, lo) = unsafe { raw_syscall(Syscall::ThreadCtrl, &[ThreadControl::GetSelfId as u64]) };
96    ObjID::from_parts([hi, lo])
97}
98
99/// Get the active security context ID for the calling thread.
100pub fn sys_thread_active_sctx_id() -> ObjID {
101    let (hi, lo) = unsafe {
102        raw_syscall(
103            Syscall::ThreadCtrl,
104            &[ThreadControl::GetActiveSctxId as u64],
105        )
106    };
107    ObjID::from_parts([hi, lo])
108}
109
110/// Get the active security context ID for the calling thread.
111pub fn sys_thread_set_active_sctx_id(id: ObjID) -> Result<(), TwzError> {
112    let (code, val) = unsafe {
113        raw_syscall(
114            Syscall::ThreadCtrl,
115            &[
116                ThreadControl::SetActiveSctxId as u64,
117                id.parts()[0],
118                id.parts()[1],
119            ],
120        )
121    };
122    convert_codes_to_result(code, val, |c, _| c != 0, |_, _| (), twzerr)
123}
124
125/// Set the upcall location for this thread.
126pub fn sys_thread_set_upcall(target: UpcallTarget) {
127    unsafe {
128        raw_syscall(
129            Syscall::ThreadCtrl,
130            &[
131                ThreadControl::SetUpcall as u64,
132                (&target as *const _) as usize as u64,
133            ],
134        );
135    }
136}
137
138/// Resume from an upcall, restoring registers. If you can
139/// resume yourself in userspace, this call is not necessary.
140///
141/// # Safety
142/// The frame argument must point to a valid upcall frame with
143/// a valid register state.
144pub unsafe fn sys_thread_resume_from_upcall(frame: &UpcallFrame) -> ! {
145    unsafe {
146        raw_syscall(
147            Syscall::ThreadCtrl,
148            &[
149                ThreadControl::ResumeFromUpcall as u64,
150                frame as *const _ as usize as u64,
151            ],
152        );
153        unreachable!()
154    }
155}
156
157pub fn sys_thread_ctrl(
158    target: Option<ObjID>,
159    cmd: ThreadControl,
160    arg0: usize,
161    arg1: usize,
162    arg2: usize,
163) -> (u64, u64) {
164    let target = target.unwrap_or(ObjID::new(0));
165    let ids = target.parts();
166    unsafe {
167        raw_syscall(
168            Syscall::ThreadCtrl,
169            &[
170                ids[0],
171                ids[1],
172                cmd as u64,
173                arg0 as u64,
174                arg1 as u64,
175                arg2 as u64,
176            ],
177        )
178    };
179    todo!("not ready yet!")
180}