diff --git a/kernel/src/objects/endpoint.rs b/kernel/src/objects/endpoint.rs index 083d82f..5e9a67d 100644 --- a/kernel/src/objects/endpoint.rs +++ b/kernel/src/objects/endpoint.rs @@ -3,9 +3,11 @@ use crate::plat::{ irq::{IRQ_MANAGER, IRQ_NUM}, trap::TrapContextOps, }; +use core::sync::atomic::AtomicPtr; use core::{cmp::min, fmt::Debug}; use tcb::{ThreadState, EP_QUEUE_LINK_ID}; use uapi::{cap::ObjectType, syscall::*}; +use utils::container_of_mut; use utils::then::Then; use utils::{addr::*, array::*, linked_list::Link}; @@ -21,6 +23,7 @@ pub enum EndpointState { pub struct EndpointObject { pub queue: Link, pub signals: usize, + pub pending: usize, } const_assert!(usize::BITS as usize >= IRQ_NUM); @@ -38,8 +41,8 @@ impl KernelObject for EndpointObject { * > | [63:0] | * * in our implementation, EndpointCap layout: - * > args[0]: option - * > args[1]: badge + * > args[0]: badge + * > args[1]: none * > ptr: base_ptr * > cap_type: cap_tag */ @@ -48,34 +51,48 @@ pub type EndpointCap<'a> = Cap<'a, EndpointObject>; impl<'a> EndpointCap<'a> { pub fn mint(ptr: PhysAddr, badge: usize) -> RawCap { - RawCap::new(0, badge, ptr, ObjectType::Endpoint) + let cap = RawCap::new(badge, 0, ptr, ObjectType::Endpoint); + + { + let cte = CapEntry::new(cap); + let mut ep = EndpointCap::try_from(&cte).unwrap(); + let obj = ep.as_object_mut(); + + unsafe { + let head = Some(AtomicPtr::new(container_of_mut!(&obj.queue, TcbObject, ep_queue))); + obj.queue.set_next(&head); + obj.queue.set_prev(&head); + } + } + + cap } - pub fn irqs(&self) -> Option { - let irqs = self.cap().get().args[0]; - (irqs != 0).then_some(irqs) + pub fn signals(&self) -> Option { + let signals = self.as_object().signals; + (signals != 0).then_some(signals) } - fn set_irq(&mut self, irqs: usize) { - self.cap().get().args[0] |= 1 << irqs; + fn set_signal(&mut self, signal: usize) { + self.as_object_mut().signals |= 1 << signal; } pub fn badge(&self) -> usize { - self.cap().get().args[1] + self.cap().get().args[0] } - pub fn signals(&self) -> usize { - self.as_object().signals + pub fn pendings(&self) -> usize { + self.as_object().pending } - fn set_signals(&mut self, signals: usize) { - self.as_object_mut().signals = signals & self.irqs().unwrap_or(0); + fn set_pendings(&mut self, pendings: usize) { + self.as_object_mut().pending = pendings & self.signals().unwrap_or(0); } pub fn state(&self) -> EndpointState { let obj = self.as_object(); - if obj.signals > 0 { + if obj.pending > 0 { return EndpointState::Signal; } else if obj.queue.is_empty() { return EndpointState::Idle; @@ -91,13 +108,13 @@ impl<'a> EndpointCap<'a> { pub fn do_set_irq(&mut self, tcb: &TcbObject) -> SysResult { let irq = tcb.trapframe.get_reg(REG_ARG_0); IRQ_MANAGER.lock().enable(irq, self.cte.clone()); - self.set_irq(irq); + self.set_signal(irq); Ok(()) } pub fn do_ack_irq(&mut self, tcb: &TcbObject) -> SysResult { let irq = tcb.trapframe.get_reg(REG_ARG_0); - (self.irqs().unwrap_or(0) & (1 << irq) != 0).else_err((), SysError::InvalidArgument)?; + (self.signals().unwrap_or(0) & (1 << irq) != 0).else_err((), SysError::InvalidArgument)?; IRQ_MANAGER.lock().complete(irq); Ok(()) } @@ -149,7 +166,7 @@ impl<'a> EndpointCap<'a> { send.schedule_next(); }, EndpointState::Signal => { - do_signal(recv, self.signals())?; + do_signal_reply(recv, self.pendings())?; }, _ => { // no thread sent msg or no signal happens, block receiver and append it to queue @@ -162,22 +179,22 @@ impl<'a> EndpointCap<'a> { } pub fn do_signal(&mut self, irq: usize) -> SysResult { - let signals = self.signals() | (1 << irq); + let signals = self.pendings() | (1 << irq); let state = self.state(); - self.set_signals(signals); - let signals = self.signals(); // set_signals will filter out invalid signals + self.set_pendings(signals); + let signals = self.pendings(); // set_signals will filter out invalid signals if state == EndpointState::Recv && signals != 0 { // do recv immediately - self.set_signals(0); + self.set_pendings(0); let recv = self.as_object_mut().queue.next_mut().unwrap(); recv.ep_queue.detach(); recv.set_state(ThreadState::Running); recv.schedule_next(); - do_signal(recv, signals)?; + do_signal_reply(recv, signals)?; } Ok(()) @@ -189,8 +206,8 @@ impl Debug for EndpointCap<'_> { f.debug_struct("EndpointCap") .field("ptr", &self.cap().get().ptr) .field("badge", &self.badge()) - .field("irqs", &self.irqs()) - .field("signals", &self.signals()) + .field("irqs", &self.signals()) + .field("signals", &self.pendings()) .field("state", &self.state()) .finish() } @@ -285,7 +302,7 @@ fn do_ipc( Ok(()) } -fn do_signal(recv: &mut TcbObject, signals: usize) -> SysResult { +fn do_signal_reply(recv: &mut TcbObject, signals: usize) -> SysResult { let reply = ReplyInfo::new(ReplyLabel::Signal, 2, false, false, SysError::Ok); recv.trapframe.set_reg(REG_REPLY_INFO, reply.into()); diff --git a/kernel/src/objects/untyped.rs b/kernel/src/objects/untyped.rs index 121b9b7..6a38c5a 100644 --- a/kernel/src/objects/untyped.rs +++ b/kernel/src/objects/untyped.rs @@ -117,6 +117,7 @@ impl UntypedCap<'_> { ObjectType::TCB => TcbCap::mint(addr), ObjectType::Table => TableCap::mint(addr), ObjectType::Frame => FrameCap::mint(addr, user_obj_bits, MapAttr::empty(), self.is_device()), + ObjectType::Endpoint => EndpointCap::mint(addr, 0), // TODO: other object types _ => return Err(SysError::InvalidArgument), }; diff --git a/kernel/src/syscall.rs b/kernel/src/syscall.rs index 3fce133..b59d140 100644 --- a/kernel/src/syscall.rs +++ b/kernel/src/syscall.rs @@ -9,7 +9,7 @@ macro_rules! assert_length { } }; ($info:ident >= $len:expr) => { - if $info.length() >= $len { + if $info.length() < $len { return Err(SysError::InvalidArgument); } }; @@ -61,6 +61,7 @@ pub fn handle_syscall(tcb: &mut TcbObject) -> SysResult { cap.do_set_irq(tcb) }, Syscall::IrqAck => { + assert_length!(info, 3); let mut cap = EndpointCap::try_from(cap)?; cap.do_ack_irq(tcb) }, diff --git a/lib/utils/src/linked_list.rs b/lib/utils/src/linked_list.rs index 93e81d4..963106c 100644 --- a/lib/utils/src/linked_list.rs +++ b/lib/utils/src/linked_list.rs @@ -66,8 +66,6 @@ impl, const ID: usize> Link { } pub fn is_empty(&self) -> bool { - debug_assert!(!(self.prev.is_none() && self.next.is_some())); - debug_assert!(!(self.prev.is_some() && self.next.is_none())); self.prev.is_none() && self.next.is_none() }