Nothing to see here, move along meow
1use crate::arch::x86_64::idt::{
2 ERROR_VECTOR, IPI_FUNC_CALL_VECTOR, IPI_HALT_VECTOR, IPI_RESCHEDULE_VECTOR,
3 IPI_TLB_SHOOTDOWN_VECTOR, IrqVector, SPURIOUS_VECTOR, TIMER_VECTOR,
4};
5use crate::cap::cnode;
6use crate::cap::object::{IoPort, IrqSource, ObjectTag, PortRange};
7use crate::cap::pool::POOL;
8use crate::cap::table::Rights;
9use crate::error::KernelError;
10use crate::irq;
11use crate::proc::PROCESSES;
12use crate::proc::context::CpuContext;
13use crate::syscall::{SyscallResult, try_syscall};
14use crate::types::Pid;
15use lancer_core::object_layout::IrqHandlerObject;
16
17pub(crate) fn is_reserved_vector(v: IrqVector) -> bool {
18 matches!(
19 v.raw(),
20 TIMER_VECTOR_RAW
21 | ERROR_VECTOR_RAW
22 | SPURIOUS_VECTOR_RAW
23 | IPI_RESCHEDULE_RAW
24 | IPI_TLB_SHOOTDOWN_RAW
25 | IPI_HALT_RAW
26 | IPI_FUNC_CALL_RAW
27 )
28}
29
30const TIMER_VECTOR_RAW: u8 = TIMER_VECTOR.raw();
31const ERROR_VECTOR_RAW: u8 = ERROR_VECTOR.raw();
32const SPURIOUS_VECTOR_RAW: u8 = SPURIOUS_VECTOR.raw();
33const IPI_RESCHEDULE_RAW: u8 = IPI_RESCHEDULE_VECTOR.raw();
34const IPI_TLB_SHOOTDOWN_RAW: u8 = IPI_TLB_SHOOTDOWN_VECTOR.raw();
35const IPI_HALT_RAW: u8 = IPI_HALT_VECTOR.raw();
36const IPI_FUNC_CALL_RAW: u8 = IPI_FUNC_CALL_VECTOR.raw();
37
38fn decode_irq_source(obj: &IrqHandlerObject) -> IrqSource {
39 match obj.source_kind {
40 1 => IrqSource::Msix {
41 device_table_idx: obj.source_data as u8,
42 entry_idx: (obj.source_data >> 8) as u16,
43 },
44 _ => IrqSource::Ioapic {
45 gsi: crate::arch::ioapic::Gsi::new(obj.source_data),
46 },
47 }
48}
49
50fn port_range_from_obj(obj: &IrqHandlerObject) -> Option<PortRange> {
51 PortRange::new(obj.port_base, obj.port_count)
52}
53
54pub fn sys_irq_bind(ctx: &mut CpuContext) {
55 let irq_cap_addr = ctx.rdi;
56 let notif_cap_addr = ctx.rsi;
57 let bit =
58 match crate::types::NotificationBit::new(try_syscall!(ctx, super::u8_from_reg(ctx.rdx))) {
59 Some(b) => b,
60 None => {
61 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
62 return;
63 }
64 };
65 let pid = crate::arch::syscall::current_pid();
66
67 let ptable = PROCESSES.lock();
68 let pool = POOL.lock_after(&ptable);
69
70 let irq_cap = try_syscall!(
71 ctx,
72 cnode::resolve_caller_validate(
73 pid,
74 irq_cap_addr,
75 ObjectTag::IrqHandler,
76 Rights::WRITE,
77 &ptable,
78 &pool
79 )
80 );
81
82 let (vector, source) =
83 match pool.read_as::<IrqHandlerObject>(irq_cap.phys(), irq_cap.generation()) {
84 Ok(h) => match IrqVector::try_new(h.vector) {
85 Some(v) => (v, decode_irq_source(h)),
86 None => {
87 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
88 return;
89 }
90 },
91 Err(e) => {
92 ctx.rax = SyscallResult::error(e).raw();
93 return;
94 }
95 };
96
97 let notif_cap = try_syscall!(
98 ctx,
99 cnode::resolve_caller_validate(
100 pid,
101 notif_cap_addr,
102 ObjectTag::Notification,
103 Rights::WRITE,
104 &ptable,
105 &pool
106 )
107 );
108
109 let notif_id = notif_cap.phys();
110 let notif_gen = notif_cap.generation();
111
112 drop(pool);
113 drop(ptable);
114
115 ctx.rax = match irq::bind(vector, source, notif_id, notif_gen, bit) {
116 Ok(()) => SyscallResult::ok().raw(),
117 Err(e) => SyscallResult::error(e).raw(),
118 };
119}
120
121pub fn sys_irq_ack(ctx: &mut CpuContext) {
122 let irq_cap_addr = ctx.rdi;
123 let pid = crate::arch::syscall::current_pid();
124
125 let ptable = PROCESSES.lock();
126 let irq_cap = {
127 let pool = POOL.lock_after(&ptable);
128 try_syscall!(
129 ctx,
130 cnode::resolve_caller_validate(
131 pid,
132 irq_cap_addr,
133 ObjectTag::IrqHandler,
134 Rights::WRITE,
135 &ptable,
136 &pool
137 )
138 )
139 };
140
141 let source = {
142 let pool = POOL.lock_after(&ptable);
143 match pool.read_as::<IrqHandlerObject>(irq_cap.phys(), irq_cap.generation()) {
144 Ok(h) => decode_irq_source(h),
145 Err(e) => {
146 ctx.rax = SyscallResult::error(e).raw();
147 return;
148 }
149 }
150 };
151
152 drop(ptable);
153
154 match source {
155 IrqSource::Ioapic { gsi } => crate::arch::ioapic::unmask_irq(gsi),
156 IrqSource::Msix {
157 device_table_idx,
158 entry_idx,
159 } => {
160 let _ = crate::pci::msix::unmask_entry(device_table_idx, entry_idx);
161 }
162 }
163
164 ctx.rax = SyscallResult::ok().raw();
165}
166
167pub fn sys_io_in8(ctx: &mut CpuContext) {
168 let irq_cap_addr = ctx.rdi;
169 let port = IoPort::new(try_syscall!(ctx, super::u16_from_reg(ctx.rsi)));
170 let pid = crate::arch::syscall::current_pid();
171
172 let ptable = PROCESSES.lock();
173 let irq_cap = {
174 let pool = POOL.lock_after(&ptable);
175 try_syscall!(
176 ctx,
177 cnode::resolve_caller_validate(
178 pid,
179 irq_cap_addr,
180 ObjectTag::IrqHandler,
181 Rights::READ,
182 &ptable,
183 &pool
184 )
185 )
186 };
187
188 {
189 let pool = POOL.lock_after(&ptable);
190 match pool.read_as::<IrqHandlerObject>(irq_cap.phys(), irq_cap.generation()) {
191 Ok(h) => match port_range_from_obj(h) {
192 Some(pr) if pr.contains(port) => {}
193 _ => {
194 ctx.rax = SyscallResult::error(KernelError::PermissionDenied).raw();
195 return;
196 }
197 },
198 Err(e) => {
199 ctx.rax = SyscallResult::error(e).raw();
200 return;
201 }
202 }
203 }
204
205 drop(ptable);
206
207 let val: u8 = unsafe { x86_64::instructions::port::Port::new(port.raw()).read() };
208 ctx.rax = SyscallResult::success(val as u64).raw();
209}
210
211pub fn sys_io_out8(ctx: &mut CpuContext) {
212 let irq_cap_addr = ctx.rdi;
213 let port = IoPort::new(try_syscall!(ctx, super::u16_from_reg(ctx.rsi)));
214 let val = try_syscall!(ctx, super::u8_from_reg(ctx.rdx));
215 let pid = crate::arch::syscall::current_pid();
216
217 let ptable = PROCESSES.lock();
218 let irq_cap = {
219 let pool = POOL.lock_after(&ptable);
220 try_syscall!(
221 ctx,
222 cnode::resolve_caller_validate(
223 pid,
224 irq_cap_addr,
225 ObjectTag::IrqHandler,
226 Rights::WRITE,
227 &ptable,
228 &pool
229 )
230 )
231 };
232
233 {
234 let pool = POOL.lock_after(&ptable);
235 match pool.read_as::<IrqHandlerObject>(irq_cap.phys(), irq_cap.generation()) {
236 Ok(h) => match port_range_from_obj(h) {
237 Some(pr) if pr.contains(port) => {}
238 _ => {
239 ctx.rax = SyscallResult::error(KernelError::PermissionDenied).raw();
240 return;
241 }
242 },
243 Err(e) => {
244 ctx.rax = SyscallResult::error(e).raw();
245 return;
246 }
247 }
248 }
249
250 drop(ptable);
251
252 unsafe { x86_64::instructions::port::Port::new(port.raw()).write(val) };
253 ctx.rax = SyscallResult::ok().raw();
254}
255
256pub fn sys_irq_configure(ctx: &mut CpuContext) {
257 let pid = crate::arch::syscall::current_pid();
258
259 if pid != Pid::new(0) {
260 ctx.rax = SyscallResult::error(KernelError::PermissionDenied).raw();
261 return;
262 }
263
264 let irq_addr = ctx.rdi;
265 let gsi = crate::arch::ioapic::Gsi::new(try_syscall!(ctx, super::u32_from_reg(ctx.rsi)));
266 let vector = match IrqVector::try_new(try_syscall!(ctx, super::u8_from_reg(ctx.rdx))) {
267 Some(v) => v,
268 None => {
269 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
270 return;
271 }
272 };
273 let port_base = try_syscall!(ctx, super::u16_from_reg(ctx.r10));
274 let port_count = try_syscall!(ctx, super::u16_from_reg(ctx.r8));
275
276 if is_reserved_vector(vector) {
277 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
278 return;
279 }
280
281 let _port_range = match PortRange::new(port_base, port_count) {
282 Some(pr) => pr,
283 None => {
284 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw();
285 return;
286 }
287 };
288
289 let ptable = PROCESSES.lock();
290 let cap = {
291 let pool = POOL.lock_after(&ptable);
292 try_syscall!(
293 ctx,
294 cnode::resolve_caller_validate(
295 pid,
296 irq_addr,
297 ObjectTag::IrqHandler,
298 Rights::WRITE,
299 &ptable,
300 &pool,
301 )
302 )
303 };
304
305 let mut pool = POOL.lock_after(&ptable);
306 ctx.rax = match pool.write_as::<IrqHandlerObject>(cap.phys(), cap.generation()) {
307 Ok(h) => {
308 h.vector = vector.raw();
309 h.source_kind = 0;
310 h.source_data = gsi.raw();
311 h.port_base = port_base;
312 h.port_count = port_count;
313 SyscallResult::ok().raw()
314 }
315 Err(e) => SyscallResult::error(e).raw(),
316 };
317}