fix: kernel/objects/endpoint: bug fix

This commit is contained in:
Paul Pan 2024-09-05 19:56:33 +08:00
parent 93dabb523b
commit 908822ae41
4 changed files with 45 additions and 28 deletions

View File

@ -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<TcbObject, EP_QUEUE_LINK_ID>,
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<irq>
* > 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);
}
}
pub fn irqs(&self) -> Option<usize> {
let irqs = self.cap().get().args[0];
(irqs != 0).then_some(irqs)
cap
}
fn set_irq(&mut self, irqs: usize) {
self.cap().get().args[0] |= 1 << irqs;
pub fn signals(&self) -> Option<usize> {
let signals = self.as_object().signals;
(signals != 0).then_some(signals)
}
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());

View File

@ -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),
};

View File

@ -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)
},

View File

@ -66,8 +66,6 @@ impl<T: LinkHelper<ID>, const ID: usize> Link<T, ID> {
}
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()
}