Nothing to see here, move along meow
1use crate::cap::cnode;
2use crate::cap::object::ObjectTag;
3use crate::cap::pool::POOL;
4use crate::cap::table::Rights;
5use crate::error::KernelError;
6use crate::proc::PROCESSES;
7use crate::proc::context::CpuContext;
8use crate::syscall::{SyscallResult, try_syscall};
9use crate::types::{Pid, Priority};
10use lancer_core::header::NONE_SENTINEL;
11use lancer_core::object_layout::SchedContextObject;
12
13pub fn sys_sched_attach(ctx: &mut CpuContext) {
14 let sched_addr = ctx.rdi;
15 let target_pid_raw = try_syscall!(ctx, super::u32_from_reg(ctx.rsi));
16 let pid = crate::arch::syscall::current_pid();
17
18 let target_pid = match Pid::try_new(target_pid_raw) {
19 Some(p) => p,
20 None => {
21 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
22 return;
23 }
24 };
25
26 let mut ptable = PROCESSES.lock();
27 let cap = {
28 let pool = POOL.lock_after(&ptable);
29 try_syscall!(
30 ctx,
31 cnode::resolve_caller_validate(
32 pid,
33 sched_addr,
34 ObjectTag::SchedContext,
35 Rights::WRITE,
36 &ptable,
37 &pool
38 )
39 )
40 };
41
42 if target_pid != pid {
43 let pool = POOL.lock_after(&ptable);
44 let has_proc_cap = {
45 let (cnode_id, cnode_gen, _, _, _) =
46 try_syscall!(ctx, cnode::cnode_coords(pid, &ptable));
47 let mut found = false;
48 let _ = cnode::walk_cnode_slots(&pool, cnode_id, cnode_gen, |slot| {
49 if let crate::cap::table::CapSlot::Active(cap) = slot
50 && cap.tag() == ObjectTag::Process
51 && cap.rights().contains(Rights::WRITE)
52 && pool
53 .read_as::<lancer_core::object_layout::ProcessObject>(
54 cap.phys(),
55 cap.generation(),
56 )
57 .ok()
58 .and_then(|p| Pid::try_new(p.pid))
59 .is_some_and(|p| p == target_pid)
60 {
61 found = true;
62 }
63 });
64 found
65 };
66 if !has_proc_cap {
67 ctx.rax = SyscallResult::error(KernelError::PermissionDenied).raw();
68 return;
69 }
70 }
71
72 let priority = {
73 let mut pool = POOL.lock_after(&ptable);
74 match pool.write_as::<SchedContextObject>(cap.phys(), cap.generation()) {
75 Ok(sc) => {
76 let old_attached = Pid::try_new(sc.attached_pid);
77 match old_attached {
78 Some(old_pid) if old_pid != target_pid => {
79 if old_pid != pid {
80 ctx.rax = SyscallResult::error(KernelError::PermissionDenied).raw();
81 return;
82 }
83 if let Some(old_proc) = ptable.get_mut(old_pid) {
84 old_proc.detach_sched_context();
85 }
86 }
87 _ => {}
88 }
89 sc.attached_pid = target_pid.raw();
90 let now_us = crate::wcet::tsc::cycles_to_ns(crate::wcet::tsc::read_tsc()) / 1000;
91 sc.remaining_us = sc.budget_us;
92 sc.replenish_at = now_us.saturating_add(sc.period_us);
93 Priority::new(sc.priority)
94 }
95 Err(e) => {
96 ctx.rax = SyscallResult::error(e).raw();
97 return;
98 }
99 }
100 };
101
102 ctx.rax = match ptable.get_mut(target_pid) {
103 Some(target) => {
104 let old_sc = target.sched_context();
105 target.attach_sched_context(cap.phys(), cap.generation(), priority);
106
107 if let Some((old_id, old_gen)) = old_sc {
108 let mut pool = POOL.lock_after(&ptable);
109 if let Ok(sc) = pool.write_as::<SchedContextObject>(old_id, old_gen) {
110 sc.attached_pid = NONE_SENTINEL;
111 }
112 }
113 SyscallResult::ok().raw()
114 }
115 None => SyscallResult::error(KernelError::InvalidObject).raw(),
116 };
117}
118
119pub fn sys_sched_configure(ctx: &mut CpuContext) {
120 let sched_addr = ctx.rdi;
121 let budget_us = ctx.rsi;
122 let period_us = ctx.rdx;
123 let priority_raw = try_syscall!(ctx, super::u8_from_reg(ctx.r10));
124 let pid = crate::arch::syscall::current_pid();
125
126 const MIN_PERIOD_US: u64 = 1_000;
127 const MAX_PERIOD_US: u64 = 3_600_000_000;
128
129 let priority = match Priority::new_user(priority_raw) {
130 Some(p) => p,
131 None => {
132 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
133 return;
134 }
135 };
136
137 if budget_us == 0
138 || period_us < MIN_PERIOD_US
139 || budget_us > period_us
140 || period_us > MAX_PERIOD_US
141 {
142 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
143 return;
144 }
145
146 let ptable = PROCESSES.lock();
147 let cap = {
148 let pool = POOL.lock_after(&ptable);
149 try_syscall!(
150 ctx,
151 cnode::resolve_caller_validate(
152 pid,
153 sched_addr,
154 ObjectTag::SchedContext,
155 Rights::WRITE,
156 &ptable,
157 &pool,
158 )
159 )
160 };
161
162 let mut pool = POOL.lock_after(&ptable);
163 ctx.rax = match pool.write_as::<SchedContextObject>(cap.phys(), cap.generation()) {
164 Ok(sc) => {
165 sc.budget_us = budget_us;
166 sc.period_us = period_us;
167 sc.remaining_us = budget_us;
168 sc.priority = priority.raw();
169 SyscallResult::ok().raw()
170 }
171 Err(e) => SyscallResult::error(e).raw(),
172 };
173}
174
175pub fn sys_sched_yield(ctx: &mut CpuContext) {
176 ctx.rax = SyscallResult::ok().raw();
177 crate::sched::schedule(ctx);
178}