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_get_upcall() -> Result<UpcallTarget, TwzError> {
147 let mut target = MaybeUninit::<UpcallTarget>::uninit();
148 let (code, val) = unsafe {
149 raw_syscall(
150 Syscall::ThreadCtrl,
151 &[
152 0,
153 0,
154 ThreadControl::GetUpcall as u64,
155 target.as_mut_ptr() as usize as u64,
156 ],
157 )
158 };
159 convert_codes_to_result(
160 code,
161 val,
162 |c, _| c != 0,
163 |_, _| unsafe { target.assume_init() },
164 twzerr,
165 )
166}
167
168pub fn sys_thread_set_upcall(target: UpcallTarget) -> Result<(), TwzError> {
170 let (code, val) = unsafe {
171 raw_syscall(
172 Syscall::ThreadCtrl,
173 &[
174 0,
175 0,
176 ThreadControl::SetUpcall as u64,
177 (&target as *const _) as usize as u64,
178 ],
179 )
180 };
181 convert_codes_to_result(code, val, |c, _| c != 0, |_, _| (), twzerr)
182}
183
184pub unsafe fn sys_thread_resume_from_upcall(frame: &UpcallFrame, flags: ResumeFlags) -> ! {
191 unsafe {
192 raw_syscall(
193 Syscall::ThreadCtrl,
194 &[
195 0,
196 0,
197 ThreadControl::ResumeFromUpcall as u64,
198 frame as *const _ as usize as u64,
199 flags.bits(),
200 ],
201 );
202 unreachable!()
203 }
204}
205
206pub fn sys_thread_gettls() -> u64 {
208 let (tls, _) =
209 unsafe { raw_syscall(Syscall::ThreadCtrl, &[0, 0, ThreadControl::GetTls as u64]) };
210 tls
211}
212
213pub fn sys_thread_read_registers(target: ObjID) -> Result<ArchRegisters, TwzError> {
215 let mut regs = MaybeUninit::zeroed();
216 let (code, val) = unsafe {
217 raw_syscall(
218 Syscall::ThreadCtrl,
219 &[
220 target.parts()[0],
221 target.parts()[1],
222 ThreadControl::ReadRegisters as u64,
223 regs.as_mut_ptr() as usize as u64,
224 ],
225 )
226 };
227 convert_codes_to_result(
228 code,
229 val,
230 |c, _| c != 0,
231 move |_, _| unsafe { regs.assume_init() },
232 twzerr,
233 )
234}
235
236pub fn sys_thread_write_registers(target: ObjID, regs: &ArchRegisters) -> Result<(), TwzError> {
238 let (code, val) = unsafe {
239 raw_syscall(
240 Syscall::ThreadCtrl,
241 &[
242 target.parts()[0],
243 target.parts()[1],
244 ThreadControl::WriteRegisters as u64,
245 regs as *const _ as usize as u64,
246 ],
247 )
248 };
249 convert_codes_to_result(code, val, |c, _| c != 0, |_, _| (), twzerr)
250}
251
252pub fn sys_thread_send_message(target: ObjID, message: u64, flags: u64) -> Result<(), TwzError> {
254 let (code, val) = unsafe {
255 raw_syscall(
256 Syscall::ThreadCtrl,
257 &[
258 target.parts()[0],
259 target.parts()[1],
260 ThreadControl::SendMessage as u64,
261 message,
262 flags,
263 ],
264 )
265 };
266 convert_codes_to_result(code, val, |c, _| c != 0, |_, _| (), twzerr)
267}
268
269pub fn sys_thread_change_state(
271 target: ObjID,
272 new_state: ExecutionState,
273) -> Result<ExecutionState, TwzError> {
274 let (code, val) = unsafe {
275 raw_syscall(
276 Syscall::ThreadCtrl,
277 &[
278 target.parts()[0],
279 target.parts()[1],
280 ThreadControl::ChangeState as u64,
281 new_state.to_status(),
282 ],
283 )
284 };
285 convert_codes_to_result(
286 code,
287 val,
288 |c, _| c != 0,
289 |_, v| ExecutionState::from_status(v),
290 twzerr,
291 )
292}
293
294pub fn sys_thread_set_trap_state(target: ObjID, trap_state: u64) -> Result<(), TwzError> {
296 let (code, val) = unsafe {
297 raw_syscall(
298 Syscall::ThreadCtrl,
299 &[
300 target.parts()[0],
301 target.parts()[1],
302 ThreadControl::SetTrapState as u64,
303 trap_state,
304 ],
305 )
306 };
307 convert_codes_to_result(code, val, |c, _| c != 0, |_, _| (), twzerr)
308}
309
310pub fn sys_thread_get_trap_state(target: ObjID) -> Result<u64, TwzError> {
312 let (code, val) = unsafe {
313 raw_syscall(
314 Syscall::ThreadCtrl,
315 &[
316 target.parts()[0],
317 target.parts()[1],
318 ThreadControl::GetTrapState as u64,
319 ],
320 )
321 };
322 convert_codes_to_result(code, val, |c, _| c != 0, |_, v| v, twzerr)
323}
324
325pub fn sys_thread_set_trace_events(target: ObjID, events: u64) -> Result<(), TwzError> {
327 let (code, val) = unsafe {
328 raw_syscall(
329 Syscall::ThreadCtrl,
330 &[
331 target.parts()[0],
332 target.parts()[1],
333 ThreadControl::SetTraceEvents as u64,
334 events,
335 ],
336 )
337 };
338 convert_codes_to_result(code, val, |c, _| c != 0, |_, _| (), twzerr)
339}
340
341pub fn sys_thread_get_trace_events(target: ObjID) -> Result<u64, TwzError> {
343 let (code, val) = unsafe {
344 raw_syscall(
345 Syscall::ThreadCtrl,
346 &[
347 target.parts()[0],
348 target.parts()[1],
349 ThreadControl::GetTraceEvents as u64,
350 ],
351 )
352 };
353 convert_codes_to_result(code, val, |c, _| c != 0, |_, v| v, twzerr)
354}
355
356pub const PERTHREAD_TRACE_GEN_SAMPLE: u64 = 1;
357
358pub fn sys_thread_ctrl(
359 target: Option<ObjID>,
360 cmd: ThreadControl,
361 arg0: usize,
362 arg1: usize,
363 arg2: usize,
364) -> (u64, u64) {
365 let target = target.unwrap_or(ObjID::new(0));
366 let ids = target.parts();
367 unsafe {
368 raw_syscall(
369 Syscall::ThreadCtrl,
370 &[
371 ids[0],
372 ids[1],
373 cmd as u64,
374 arg0 as u64,
375 arg1 as u64,
376 arg2 as u64,
377 ],
378 )
379 };
380 todo!("not ready yet!")
381}