diff --git a/kernel/src/objects/endpoint.rs b/kernel/src/objects/endpoint.rs index 982fddd..16e507b 100644 --- a/kernel/src/objects/endpoint.rs +++ b/kernel/src/objects/endpoint.rs @@ -1,22 +1,28 @@ -use crate::{objects::*, plat::trap::TrapContextOps}; +use crate::{ + objects::*, + plat::{irq::IRQ_NUM, trap::TrapContextOps}, +}; use core::{cmp::min, fmt::Debug}; use tcb::{ThreadState, EP_QUEUE_LINK_ID}; -use uapi::{cap::ObjectType, fault::Fault, syscall::*}; +use uapi::{cap::ObjectType, syscall::*}; use utils::{addr::*, array::*, linked_list::Link}; #[derive(Debug, Copy, Clone, PartialEq)] pub enum EndpointState { Idle, - Sending, - Receiving, + Send, + Recv, + Signal, } #[repr(C)] pub struct EndpointObject { - pub queue: Link, - pub state: EndpointState, + pub queue: Link, + pub signals: usize, } +const_assert!(usize::BITS as usize >= IRQ_NUM); + impl KernelObject for EndpointObject { const OBJ_TYPE: ObjectType = ObjectType::Endpoint; } @@ -54,80 +60,109 @@ impl<'a> EndpointCap<'a> { self.cap().get().args[1] } + pub fn signals(&self) -> usize { + self.as_object().signals + } + + pub fn set_signals(&mut self, signals: usize) { + self.as_object_mut().signals = signals; + } + pub fn state(&self) -> EndpointState { - self.as_object().state + let obj = self.as_object(); + + if obj.signals > 0 { + return EndpointState::Signal; + } else if obj.queue.is_empty() { + return EndpointState::Idle; + } + + match obj.queue.next().unwrap().state() { + ThreadState::Sending => EndpointState::Send, + ThreadState::Receiving => EndpointState::Recv, + _ => EndpointState::Idle, + } } - pub fn set_state(&mut self, state: EndpointState) { - self.as_object_mut().state = state; - } - - pub fn do_send(&mut self, send: &mut TcbObject) -> SysResult<()> { + pub fn do_send(&mut self, send: &mut TcbObject) -> SysResult { match self.state() { - EndpointState::Idle | EndpointState::Sending => { - send.set_state(ThreadState::Sending); - send.set_badge(self.badge()); + EndpointState::Recv => { + debug_assert!( + !self.as_object().queue.is_empty(), + "[Endpoint] do_send: Receive endpoint queue must not be empty" + ); - self.set_state(EndpointState::Sending); - self.as_object_mut().queue.append(send); - }, - EndpointState::Receiving => { - assert!(!self.as_object().queue.is_empty(), "Receive endpoint queue must not be empty"); + let badge = self.badge(); - let recv = { - let recv = self.as_object_mut().queue.next_mut().unwrap(); - recv.ep_queue.detach(); + let recv = self.as_object_mut().queue.next_mut().unwrap(); + recv.ep_queue.detach(); - // SAFETY: `recv` is detached from the queue, no longer related to `self` - unsafe { &mut *(recv as *mut TcbObject) } - }; - - if self.as_object().queue.is_empty() { - self.set_state(EndpointState::Idle); - } - - do_ipc_transfer(send, send.get_message_info()?, recv, recv.get_message_info()?, self.badge())?; + do_ipc(send, send.get_message_info()?, recv, recv.get_message_info()?, badge)?; recv.set_state(ThreadState::Running); recv.schedule_next(); }, + _ => { + // no thread wants to recv msg, block sender and append it to queue + send.set_state(ThreadState::Sending); + self.as_object_mut().queue.append(send); + }, }; Ok(()) } - pub fn do_recv(&mut self, recv: &mut TcbObject) -> SysResult<()> { + pub fn do_recv(&mut self, recv: &mut TcbObject) -> SysResult { match self.state() { - EndpointState::Idle | EndpointState::Receiving => { - recv.set_state(ThreadState::Receiving); + EndpointState::Send => { + debug_assert!( + !self.as_object().queue.is_empty(), + "[Endpoint] do_recv: Send endpoint queue must not be empty" + ); - self.set_state(EndpointState::Receiving); - self.as_object_mut().queue.append(recv); - }, - EndpointState::Sending => { - assert!(!self.as_object().queue.is_empty(), "Send endpoint queue must not be empty"); + let badge = self.badge(); - let send = { - let send = self.as_object_mut().queue.next_mut().unwrap(); - send.ep_queue.detach(); + let send = self.as_object_mut().queue.next_mut().unwrap(); + send.ep_queue.detach(); - // SAFETY: `send` is detached from the queue, no longer related to `self` - unsafe { &mut *(send as *mut TcbObject) } - }; - - if self.as_object().queue.is_empty() { - self.set_state(EndpointState::Idle); - } - - do_ipc_transfer(send, send.get_message_info()?, recv, recv.get_message_info()?, self.badge())?; + do_ipc(send, send.get_message_info()?, recv, recv.get_message_info()?, badge)?; send.set_state(ThreadState::Running); send.schedule_next(); }, + EndpointState::Signal => { + do_signal(recv, self.signals())?; + }, + _ => { + // no thread sent msg or no signal happens, block receiver and append it to queue + recv.set_state(ThreadState::Receiving); + self.as_object_mut().queue.append(recv); + }, }; Ok(()) } + + pub fn do_signal(&mut self, irq: usize) -> SysResult { + let signals = self.signals() | (1 << irq); + let state = self.state(); + + self.set_signals(signals); + + if state == EndpointState::Recv { + // do recv immediately + self.set_signals(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)?; + } + + Ok(()) + } } impl Debug for EndpointCap<'_> { @@ -142,7 +177,12 @@ impl Debug for EndpointCap<'_> { } } -fn copy_message(send: &mut TcbObject, send_msg: MessageInfo, recv: &mut TcbObject, recv_msg: MessageInfo) -> SysResult<()> { +fn copy_message( + send: &mut TcbObject, + send_msg: MessageInfo, + recv: &mut TcbObject, + recv_msg: MessageInfo, +) -> SysResult { let send_len = send_msg.length() - if send_msg.transfer_cap() { 2 } else { 0 }; let recv_len = recv_msg.length() - if recv_msg.transfer_cap() { 2 } else { 0 }; let msg_len = min(send_len, recv_len); @@ -163,7 +203,7 @@ fn copy_message(send: &mut TcbObject, send_msg: MessageInfo, recv: &mut TcbObjec recv.trapframe.set_reg(i, send.trapframe.get_reg(i)); } - Ok(()) + Ok(msg_len) } fn ipc_get_args(tcb: &TcbObject, idx: usize) -> SysResult { @@ -178,9 +218,14 @@ fn ipc_get_args(tcb: &TcbObject, idx: usize) -> SysResult { Ok(ret) } -fn transfer_cap(send: &mut TcbObject, send_msg: MessageInfo, recv: &mut TcbObject, recv_msg: MessageInfo) -> SysResult<()> { +fn transfer_cap( + send: &mut TcbObject, + send_msg: MessageInfo, + recv: &mut TcbObject, + recv_msg: MessageInfo, +) -> SysResult { if !send_msg.transfer_cap() || !recv_msg.transfer_cap() { - return Ok(()); + return Ok(false); } let send_cspace = send.cspace()?; @@ -199,24 +244,33 @@ fn transfer_cap(send: &mut TcbObject, send_msg: MessageInfo, recv: &mut TcbObjec dest.override_cap(send_cap.cap.get()); send_cap.cap.replace(NullCap::mint()); - Ok(()) + Ok(true) } -fn do_ipc_transfer( +fn do_ipc( send: &mut TcbObject, send_msg: MessageInfo, recv: &mut TcbObject, recv_msg: MessageInfo, - _badge: usize, -) -> SysResult<()> { - if send.fault() == Fault::Null { - // do normal transfer - copy_message(send, send_msg, recv, recv_msg)?; - transfer_cap(send, send_msg, recv, recv_msg)?; + badge: usize, +) -> SysResult { + // do normal transfer - todo!("do_ipc_transfer: normal transfer: uapi/reply"); - } else { - // do fault transfer - todo!("do_ipc_transfer: fault transfer"); - } + let length = copy_message(send, send_msg, recv, recv_msg)?; + let transfered = transfer_cap(send, send_msg, recv, recv_msg)?; + + let reply = ReplyInfo::new(ReplyLabel::Message, length, true, transfered, SysError::Ok); + recv.trapframe.set_reg(REG_REPLY_INFO, reply.into()); + recv.trapframe.set_reg(REG_BADGE, badge); + + Ok(()) +} + +fn do_signal(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()); + recv.trapframe.set_reg(REG_BADGE, signals); + + Ok(()) } diff --git a/kernel/src/objects/tcb.rs b/kernel/src/objects/tcb.rs index 18162ab..1aa6f89 100644 --- a/kernel/src/objects/tcb.rs +++ b/kernel/src/objects/tcb.rs @@ -39,7 +39,6 @@ pub struct TcbObject { vspace: CapEntry, // endpoint - badge: usize, buffer: CapEntry, fault: Fault, @@ -63,7 +62,6 @@ impl TcbObject { trapframe: TrapContext::default(), cspace: CapEntry::new(NullCap::mint()), vspace: CapEntry::new(NullCap::mint()), - badge: 0, buffer: CapEntry::new(NullCap::mint()), fault: Fault::Null, state: ThreadState::Inactive, @@ -97,14 +95,6 @@ impl TcbObject { self.vspace = vspace; } - pub fn badge(&self) -> usize { - self.badge - } - - pub fn set_badge(&mut self, badge: usize) { - self.badge = badge; - } - pub fn buffer(&self) -> SysResult { FrameCap::try_from(&self.buffer) } @@ -198,7 +188,6 @@ impl Debug for TcbCap<'_> { f.debug_struct("TcbCap") .field("cspace", &obj.cspace) .field("vspace", &obj.vspace) - .field("badge", &obj.badge) .field("buffer", &obj.buffer) .field("fault", &obj.fault) .field("state", &obj.state) diff --git a/kernel/src/plat/irq.rs b/kernel/src/plat/irq.rs index acd80fd..b330467 100644 --- a/kernel/src/plat/irq.rs +++ b/kernel/src/plat/irq.rs @@ -1,10 +1,10 @@ use super::utils::generate_driver; use crate::drivers::irq::IrqPlic; use crate::objects::*; -use log::{error, warn}; +use log::{error, trace, warn}; use spin::{lazy::Lazy, Mutex}; -const IRQ_NUM: usize = 32; +pub const IRQ_NUM: usize = 32; #[derive(Debug, Copy, Clone, PartialEq)] pub enum IrqState { @@ -84,9 +84,10 @@ impl IrqManager { IRQ_DRIVER.lock().disable(irq); }, IrqState::Signal => { - // TODO: send signal via endpoint - warn!("[IrqManager] Undelivered IRQ: {}", irq); - IRQ_DRIVER.lock().disable(irq); + trace!("[IrqManager] Dispatching IRQ: {}", irq); + let mut cap = EndpointCap::try_from(&self.handler[irq]).unwrap(); + cap.do_signal(irq).unwrap(); + return; }, IrqState::Ipi => { todo!("Kernel: NO SMP support now"); diff --git a/uapi/src/syscall.rs b/uapi/src/syscall.rs index ef677e9..8d530c6 100644 --- a/uapi/src/syscall.rs +++ b/uapi/src/syscall.rs @@ -140,6 +140,12 @@ impl TryFrom for MessageInfo { } } +impl Into for MessageInfo { + fn into(self) -> usize { + self.0 + } +} + /* ReplyInfo layout: * > +---------+--------+--------+------------+-------+ * > | label | length | badged | transfered | error | @@ -150,6 +156,8 @@ impl TryFrom for MessageInfo { * > badged: if badged * > transfered: if cap is transfered * > error: error code + * > + * > Fault / Signal: badged = false, REG_BADGE = fault detail/signal number */ pub struct ReplyInfo(usize); @@ -228,3 +236,9 @@ impl TryFrom for ReplyInfo { (info.label() != ReplyLabel::Invalid).then_ok(info, SysError::Invalid) } } + +impl Into for ReplyInfo { + fn into(self) -> usize { + self.0 + } +}