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