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 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<TcbObject, EP_QUEUE_LINK_ID>,
pub state: EndpointState,
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;
}
pub fn set_state(&mut self, state: EndpointState) {
self.as_object_mut().state = state;
match obj.queue.next().unwrap().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() {
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();
// 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();
// 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<usize> {
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<usize> {
@ -178,9 +218,14 @@ fn ipc_get_args(tcb: &TcbObject, idx: usize) -> SysResult<usize> {
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() {
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 {
badge: usize,
) -> SysResult {
// 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");
} 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(())
}

View File

@ -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> {
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)

View File

@ -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");

View File

@ -140,6 +140,12 @@ impl TryFrom<usize> for MessageInfo {
}
}
impl Into<usize> for MessageInfo {
fn into(self) -> usize {
self.0
}
}
/* ReplyInfo layout:
* > +---------+--------+--------+------------+-------+
* > | label | length | badged | transfered | error |
@ -150,6 +156,8 @@ impl TryFrom<usize> 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<usize> for ReplyInfo {
(info.label() != ReplyLabel::Invalid).then_ok(info, SysError::Invalid)
}
}
impl Into<usize> for ReplyInfo {
fn into(self) -> usize {
self.0
}
}