feat: kernel/objects/endpoint: add do_send, do_recv, do_signal

This commit is contained in:
Paul Pan 2024-09-04 15:50:39 +08:00
parent ecb0142b69
commit 46a8ff9691
4 changed files with 143 additions and 85 deletions

View File

@ -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 core::{cmp::min, fmt::Debug};
use tcb::{ThreadState, EP_QUEUE_LINK_ID}; 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}; use utils::{addr::*, array::*, linked_list::Link};
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq)]
pub enum EndpointState { pub enum EndpointState {
Idle, Idle,
Sending, Send,
Receiving, Recv,
Signal,
} }
#[repr(C)] #[repr(C)]
pub struct EndpointObject { pub struct EndpointObject {
pub queue: Link<TcbObject, EP_QUEUE_LINK_ID>, pub queue: Link<TcbObject, EP_QUEUE_LINK_ID>,
pub state: EndpointState, pub signals: usize,
} }
const_assert!(usize::BITS as usize >= IRQ_NUM);
impl KernelObject for EndpointObject { impl KernelObject for EndpointObject {
const OBJ_TYPE: ObjectType = ObjectType::Endpoint; const OBJ_TYPE: ObjectType = ObjectType::Endpoint;
} }
@ -54,80 +60,109 @@ impl<'a> EndpointCap<'a> {
self.cap().get().args[1] 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 { 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;
} }
pub fn set_state(&mut self, state: EndpointState) { match obj.queue.next().unwrap().state() {
self.as_object_mut().state = state; ThreadState::Sending => EndpointState::Send,
ThreadState::Receiving => EndpointState::Recv,
_ => EndpointState::Idle,
}
} }
pub fn do_send(&mut self, send: &mut TcbObject) -> SysResult<()> { pub fn do_send(&mut self, send: &mut TcbObject) -> SysResult {
match self.state() { match self.state() {
EndpointState::Idle | EndpointState::Sending => { EndpointState::Recv => {
send.set_state(ThreadState::Sending); debug_assert!(
send.set_badge(self.badge()); !self.as_object().queue.is_empty(),
"[Endpoint] do_send: Receive endpoint queue must not be empty"
);
self.set_state(EndpointState::Sending); let badge = self.badge();
self.as_object_mut().queue.append(send);
},
EndpointState::Receiving => {
assert!(!self.as_object().queue.is_empty(), "Receive endpoint queue must not be empty");
let recv = {
let recv = self.as_object_mut().queue.next_mut().unwrap(); let recv = self.as_object_mut().queue.next_mut().unwrap();
recv.ep_queue.detach(); recv.ep_queue.detach();
// SAFETY: `recv` is detached from the queue, no longer related to `self` do_ipc(send, send.get_message_info()?, recv, recv.get_message_info()?, badge)?;
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())?;
recv.set_state(ThreadState::Running); recv.set_state(ThreadState::Running);
recv.schedule_next(); 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(()) Ok(())
} }
pub fn do_recv(&mut self, recv: &mut TcbObject) -> SysResult<()> { pub fn do_recv(&mut self, recv: &mut TcbObject) -> SysResult {
match self.state() { match self.state() {
EndpointState::Idle | EndpointState::Receiving => { EndpointState::Send => {
recv.set_state(ThreadState::Receiving); debug_assert!(
!self.as_object().queue.is_empty(),
"[Endpoint] do_recv: Send endpoint queue must not be empty"
);
self.set_state(EndpointState::Receiving); let badge = self.badge();
self.as_object_mut().queue.append(recv);
},
EndpointState::Sending => {
assert!(!self.as_object().queue.is_empty(), "Send endpoint queue must not be empty");
let send = {
let send = self.as_object_mut().queue.next_mut().unwrap(); let send = self.as_object_mut().queue.next_mut().unwrap();
send.ep_queue.detach(); send.ep_queue.detach();
// SAFETY: `send` is detached from the queue, no longer related to `self` do_ipc(send, send.get_message_info()?, recv, recv.get_message_info()?, badge)?;
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())?;
send.set_state(ThreadState::Running); send.set_state(ThreadState::Running);
send.schedule_next(); 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(()) 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<'_> { 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<usize> {
let send_len = send_msg.length() - if send_msg.transfer_cap() { 2 } else { 0 }; 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 recv_len = recv_msg.length() - if recv_msg.transfer_cap() { 2 } else { 0 };
let msg_len = min(send_len, recv_len); 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)); recv.trapframe.set_reg(i, send.trapframe.get_reg(i));
} }
Ok(()) Ok(msg_len)
} }
fn ipc_get_args(tcb: &TcbObject, idx: usize) -> SysResult<usize> { fn ipc_get_args(tcb: &TcbObject, idx: usize) -> SysResult<usize> {
@ -178,9 +218,14 @@ fn ipc_get_args(tcb: &TcbObject, idx: usize) -> SysResult<usize> {
Ok(ret) 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<bool> {
if !send_msg.transfer_cap() || !recv_msg.transfer_cap() { if !send_msg.transfer_cap() || !recv_msg.transfer_cap() {
return Ok(()); return Ok(false);
} }
let send_cspace = send.cspace()?; 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()); dest.override_cap(send_cap.cap.get());
send_cap.cap.replace(NullCap::mint()); send_cap.cap.replace(NullCap::mint());
Ok(()) Ok(true)
} }
fn do_ipc_transfer( fn do_ipc(
send: &mut TcbObject, send: &mut TcbObject,
send_msg: MessageInfo, send_msg: MessageInfo,
recv: &mut TcbObject, recv: &mut TcbObject,
recv_msg: MessageInfo, recv_msg: MessageInfo,
_badge: usize, badge: usize,
) -> SysResult<()> { ) -> SysResult {
if send.fault() == Fault::Null {
// do normal transfer // do normal transfer
copy_message(send, send_msg, recv, recv_msg)?;
transfer_cap(send, send_msg, recv, recv_msg)?;
todo!("do_ipc_transfer: normal transfer: uapi/reply"); let length = copy_message(send, send_msg, recv, recv_msg)?;
} else { let transfered = transfer_cap(send, send_msg, recv, recv_msg)?;
// do fault transfer
todo!("do_ipc_transfer: fault transfer"); 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(())
} }

View File

@ -39,7 +39,6 @@ pub struct TcbObject {
vspace: CapEntry, vspace: CapEntry,
// endpoint // endpoint
badge: usize,
buffer: CapEntry, buffer: CapEntry,
fault: Fault, fault: Fault,
@ -63,7 +62,6 @@ impl TcbObject {
trapframe: TrapContext::default(), trapframe: TrapContext::default(),
cspace: CapEntry::new(NullCap::mint()), cspace: CapEntry::new(NullCap::mint()),
vspace: CapEntry::new(NullCap::mint()), vspace: CapEntry::new(NullCap::mint()),
badge: 0,
buffer: CapEntry::new(NullCap::mint()), buffer: CapEntry::new(NullCap::mint()),
fault: Fault::Null, fault: Fault::Null,
state: ThreadState::Inactive, state: ThreadState::Inactive,
@ -97,14 +95,6 @@ impl TcbObject {
self.vspace = vspace; 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> { pub fn buffer(&self) -> SysResult<FrameCap> {
FrameCap::try_from(&self.buffer) FrameCap::try_from(&self.buffer)
} }
@ -198,7 +188,6 @@ impl Debug for TcbCap<'_> {
f.debug_struct("TcbCap") f.debug_struct("TcbCap")
.field("cspace", &obj.cspace) .field("cspace", &obj.cspace)
.field("vspace", &obj.vspace) .field("vspace", &obj.vspace)
.field("badge", &obj.badge)
.field("buffer", &obj.buffer) .field("buffer", &obj.buffer)
.field("fault", &obj.fault) .field("fault", &obj.fault)
.field("state", &obj.state) .field("state", &obj.state)

View File

@ -1,10 +1,10 @@
use super::utils::generate_driver; use super::utils::generate_driver;
use crate::drivers::irq::IrqPlic; use crate::drivers::irq::IrqPlic;
use crate::objects::*; use crate::objects::*;
use log::{error, warn}; use log::{error, trace, warn};
use spin::{lazy::Lazy, Mutex}; use spin::{lazy::Lazy, Mutex};
const IRQ_NUM: usize = 32; pub const IRQ_NUM: usize = 32;
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq)]
pub enum IrqState { pub enum IrqState {
@ -84,9 +84,10 @@ impl IrqManager {
IRQ_DRIVER.lock().disable(irq); IRQ_DRIVER.lock().disable(irq);
}, },
IrqState::Signal => { IrqState::Signal => {
// TODO: send signal via endpoint trace!("[IrqManager] Dispatching IRQ: {}", irq);
warn!("[IrqManager] Undelivered IRQ: {}", irq); let mut cap = EndpointCap::try_from(&self.handler[irq]).unwrap();
IRQ_DRIVER.lock().disable(irq); cap.do_signal(irq).unwrap();
return;
}, },
IrqState::Ipi => { IrqState::Ipi => {
todo!("Kernel: NO SMP support now"); todo!("Kernel: NO SMP support now");

View File

@ -140,6 +140,12 @@ impl TryFrom<usize> for MessageInfo {
} }
} }
impl Into<usize> for MessageInfo {
fn into(self) -> usize {
self.0
}
}
/* ReplyInfo layout: /* ReplyInfo layout:
* > +---------+--------+--------+------------+-------+ * > +---------+--------+--------+------------+-------+
* > | label | length | badged | transfered | error | * > | label | length | badged | transfered | error |
@ -150,6 +156,8 @@ impl TryFrom<usize> for MessageInfo {
* > badged: if badged * > badged: if badged
* > transfered: if cap is transfered * > transfered: if cap is transfered
* > error: error code * > error: error code
* >
* > Fault / Signal: badged = false, REG_BADGE = fault detail/signal number
*/ */
pub struct ReplyInfo(usize); pub struct ReplyInfo(usize);
@ -228,3 +236,9 @@ impl TryFrom<usize> for ReplyInfo {
(info.label() != ReplyLabel::Invalid).then_ok(info, SysError::Invalid) (info.label() != ReplyLabel::Invalid).then_ok(info, SysError::Invalid)
} }
} }
impl Into<usize> for ReplyInfo {
fn into(self) -> usize {
self.0
}
}