1use core::mem::MaybeUninit;
2
3use num_enum::{FromPrimitive, IntoPrimitive};
4use twizzler_rt_abi::error::TwzError;
5
6use super::{convert_codes_to_result, twzerr, Syscall};
7use crate::{
8 arch::{syscall::raw_syscall, ArchRegisters},
9 object::ObjID,
10 thread::ExecutionState,
11 upcall::{ResumeFlags, UpcallFrame, UpcallTarget},
12};
13
14#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, FromPrimitive, IntoPrimitive)]
15#[repr(u64)]
16pub enum ThreadControl {
18 #[default]
19 Exit = 0,
24 Yield = 1,
28 SetTls = 2,
30 GetTls = 3,
32 SetUpcall = 4,
35 GetUpcall = 5,
37 ReadRegisters = 6,
39 WriteRegisters = 7,
41 SendMessage = 8,
43 ChangeState = 9,
48 SetTrapState = 10,
50 GetTrapState = 11,
52 SetPriority = 12,
54 GetPriority = 13,
56 SetAffinity = 14,
58 GetAffinity = 15,
60 ResumeFromUpcall = 16,
62 GetSelfId = 17,
64 GetActiveSctxId = 18,
66 SetActiveSctxId = 19,
68 SetTraceEvents = 20,
70 GetTraceEvents = 21,
72}
73
74pub fn sys_thread_exit(code: u64) -> ! {
77 unsafe {
78 raw_syscall(
79 Syscall::ThreadCtrl,
80 &[0, 0, ThreadControl::Exit as u64, code],
81 );
82 }
83 unreachable!()
84}
85
86pub fn sys_thread_yield() {
90 unsafe {
91 raw_syscall(Syscall::ThreadCtrl, &[0, 0, ThreadControl::Yield as u64]);
92 }
93}
94
95pub fn sys_thread_settls(tls: u64) {
98 unsafe {
99 raw_syscall(
100 Syscall::ThreadCtrl,
101 &[0, 0, ThreadControl::SetTls as u64, tls],
102 );
103 }
104}
105
106pub fn sys_thread_self_id() -> ObjID {
108 let (hi, lo) = unsafe {
109 raw_syscall(
110 Syscall::ThreadCtrl,
111 &[0, 0, ThreadControl::GetSelfId as u64],
112 )
113 };
114 ObjID::from_parts([hi, lo])
115}
116
117pub fn sys_thread_active_sctx_id() -> ObjID {
119 let (hi, lo) = unsafe {
120 raw_syscall(
121 Syscall::ThreadCtrl,
122 &[0, 0, ThreadControl::GetActiveSctxId as u64],
123 )
124 };
125 ObjID::from_parts([hi, lo])
126}
127
128pub fn sys_thread_set_active_sctx_id(id: ObjID) -> Result<(), TwzError> {
130 let (code, val) = unsafe {
131 raw_syscall(
132 Syscall::ThreadCtrl,
133 &[
134 0,
135 0,
136 ThreadControl::SetActiveSctxId as u64,
137 id.parts()[0],
138 id.parts()[1],
139 ],
140 )
141 };
142 convert_codes_to_result(code, val, |c, _| c != 0, |_, _| (), twzerr)
143}
144
145pub fn sys_thread_set_upcall(target: UpcallTarget) {
147 unsafe {
148 raw_syscall(
149 Syscall::ThreadCtrl,
150 &[
151 0,
152 0,
153 ThreadControl::SetUpcall as u64,
154 (&target as *const _) as usize as u64,
155 ],
156 );
157 }
158}
159
160pub unsafe fn sys_thread_resume_from_upcall(frame: &UpcallFrame, flags: ResumeFlags) -> ! {
167 unsafe {
168 raw_syscall(
169 Syscall::ThreadCtrl,
170 &[
171 0,
172 0,
173 ThreadControl::ResumeFromUpcall as u64,
174 frame as *const _ as usize as u64,
175 flags.bits(),
176 ],
177 );
178 unreachable!()
179 }
180}
181
182pub fn sys_thread_gettls() -> u64 {
184 let (tls, _) =
185 unsafe { raw_syscall(Syscall::ThreadCtrl, &[0, 0, ThreadControl::GetTls as u64]) };
186 tls
187}
188
189pub fn sys_thread_read_registers(target: ObjID) -> Result<ArchRegisters, TwzError> {
191 let mut regs = MaybeUninit::zeroed();
192 let (code, val) = unsafe {
193 raw_syscall(
194 Syscall::ThreadCtrl,
195 &[
196 target.parts()[0],
197 target.parts()[1],
198 ThreadControl::ReadRegisters as u64,
199 regs.as_mut_ptr() as usize as u64,
200 ],
201 )
202 };
203 convert_codes_to_result(
204 code,
205 val,
206 |c, _| c != 0,
207 move |_, _| unsafe { regs.assume_init() },
208 twzerr,
209 )
210}
211
212pub fn sys_thread_write_registers(target: ObjID, regs: &ArchRegisters) -> Result<(), TwzError> {
214 let (code, val) = unsafe {
215 raw_syscall(
216 Syscall::ThreadCtrl,
217 &[
218 target.parts()[0],
219 target.parts()[1],
220 ThreadControl::WriteRegisters as u64,
221 regs as *const _ as usize as u64,
222 ],
223 )
224 };
225 convert_codes_to_result(code, val, |c, _| c != 0, |_, _| (), twzerr)
226}
227
228pub fn sys_thread_send_message(target: ObjID, message: u64, flags: u64) -> Result<(), TwzError> {
230 let (code, val) = unsafe {
231 raw_syscall(
232 Syscall::ThreadCtrl,
233 &[
234 target.parts()[0],
235 target.parts()[1],
236 ThreadControl::SendMessage as u64,
237 message,
238 flags,
239 ],
240 )
241 };
242 convert_codes_to_result(code, val, |c, _| c != 0, |_, _| (), twzerr)
243}
244
245pub fn sys_thread_change_state(
247 target: ObjID,
248 new_state: ExecutionState,
249) -> Result<ExecutionState, TwzError> {
250 let (code, val) = unsafe {
251 raw_syscall(
252 Syscall::ThreadCtrl,
253 &[
254 target.parts()[0],
255 target.parts()[1],
256 ThreadControl::ChangeState as u64,
257 new_state.to_status(),
258 ],
259 )
260 };
261 convert_codes_to_result(
262 code,
263 val,
264 |c, _| c != 0,
265 |_, v| ExecutionState::from_status(v),
266 twzerr,
267 )
268}
269
270pub fn sys_thread_set_trap_state(target: ObjID, trap_state: u64) -> Result<(), TwzError> {
272 let (code, val) = unsafe {
273 raw_syscall(
274 Syscall::ThreadCtrl,
275 &[
276 target.parts()[0],
277 target.parts()[1],
278 ThreadControl::SetTrapState as u64,
279 trap_state,
280 ],
281 )
282 };
283 convert_codes_to_result(code, val, |c, _| c != 0, |_, _| (), twzerr)
284}
285
286pub fn sys_thread_get_trap_state(target: ObjID) -> Result<u64, TwzError> {
288 let (code, val) = unsafe {
289 raw_syscall(
290 Syscall::ThreadCtrl,
291 &[
292 target.parts()[0],
293 target.parts()[1],
294 ThreadControl::GetTrapState as u64,
295 ],
296 )
297 };
298 convert_codes_to_result(code, val, |c, _| c != 0, |_, v| v, twzerr)
299}
300
301pub fn sys_thread_set_trace_events(target: ObjID, events: u64) -> Result<(), TwzError> {
303 let (code, val) = unsafe {
304 raw_syscall(
305 Syscall::ThreadCtrl,
306 &[
307 target.parts()[0],
308 target.parts()[1],
309 ThreadControl::SetTraceEvents as u64,
310 events,
311 ],
312 )
313 };
314 convert_codes_to_result(code, val, |c, _| c != 0, |_, _| (), twzerr)
315}
316
317pub fn sys_thread_get_trace_events(target: ObjID) -> Result<u64, TwzError> {
319 let (code, val) = unsafe {
320 raw_syscall(
321 Syscall::ThreadCtrl,
322 &[
323 target.parts()[0],
324 target.parts()[1],
325 ThreadControl::GetTraceEvents as u64,
326 ],
327 )
328 };
329 convert_codes_to_result(code, val, |c, _| c != 0, |_, v| v, twzerr)
330}
331
332pub const PERTHREAD_TRACE_GEN_SAMPLE: u64 = 1;
333
334pub fn sys_thread_ctrl(
335 target: Option<ObjID>,
336 cmd: ThreadControl,
337 arg0: usize,
338 arg1: usize,
339 arg2: usize,
340) -> (u64, u64) {
341 let target = target.unwrap_or(ObjID::new(0));
342 let ids = target.parts();
343 unsafe {
344 raw_syscall(
345 Syscall::ThreadCtrl,
346 &[
347 ids[0],
348 ids[1],
349 cmd as u64,
350 arg0 as u64,
351 arg1 as u64,
352 arg2 as u64,
353 ],
354 )
355 };
356 todo!("not ready yet!")
357}