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}, irq::{IRQ_MANAGER, IRQ_NUM},
trap::TrapContextOps, trap::TrapContextOps,
}; };
use core::sync::atomic::AtomicPtr;
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, syscall::*}; use uapi::{cap::ObjectType, syscall::*};
use utils::container_of_mut;
use utils::then::Then; use utils::then::Then;
use utils::{addr::*, array::*, linked_list::Link}; use utils::{addr::*, array::*, linked_list::Link};
@ -21,6 +23,7 @@ pub enum EndpointState {
pub struct EndpointObject { pub struct EndpointObject {
pub queue: Link<TcbObject, EP_QUEUE_LINK_ID>, pub queue: Link<TcbObject, EP_QUEUE_LINK_ID>,
pub signals: usize, pub signals: usize,
pub pending: usize,
} }
const_assert!(usize::BITS as usize >= IRQ_NUM); const_assert!(usize::BITS as usize >= IRQ_NUM);
@ -38,8 +41,8 @@ impl KernelObject for EndpointObject {
* > | [63:0] | * > | [63:0] |
* *
* in our implementation, EndpointCap layout: * in our implementation, EndpointCap layout:
* > args[0]: option<irq> * > args[0]: badge
* > args[1]: badge * > args[1]: none
* > ptr: base_ptr * > ptr: base_ptr
* > cap_type: cap_tag * > cap_type: cap_tag
*/ */
@ -48,34 +51,48 @@ pub type EndpointCap<'a> = Cap<'a, EndpointObject>;
impl<'a> EndpointCap<'a> { impl<'a> EndpointCap<'a> {
pub fn mint(ptr: PhysAddr, badge: usize) -> RawCap { 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<usize> { pub fn signals(&self) -> Option<usize> {
let irqs = self.cap().get().args[0]; let signals = self.as_object().signals;
(irqs != 0).then_some(irqs) (signals != 0).then_some(signals)
} }
fn set_irq(&mut self, irqs: usize) { fn set_signal(&mut self, signal: usize) {
self.cap().get().args[0] |= 1 << irqs; self.as_object_mut().signals |= 1 << signal;
} }
pub fn badge(&self) -> usize { pub fn badge(&self) -> usize {
self.cap().get().args[1] self.cap().get().args[0]
} }
pub fn signals(&self) -> usize { pub fn pendings(&self) -> usize {
self.as_object().signals self.as_object().pending
} }
fn set_signals(&mut self, signals: usize) { fn set_pendings(&mut self, pendings: usize) {
self.as_object_mut().signals = signals & self.irqs().unwrap_or(0); self.as_object_mut().pending = pendings & self.signals().unwrap_or(0);
} }
pub fn state(&self) -> EndpointState { pub fn state(&self) -> EndpointState {
let obj = self.as_object(); let obj = self.as_object();
if obj.signals > 0 { if obj.pending > 0 {
return EndpointState::Signal; return EndpointState::Signal;
} else if obj.queue.is_empty() { } else if obj.queue.is_empty() {
return EndpointState::Idle; return EndpointState::Idle;
@ -91,13 +108,13 @@ impl<'a> EndpointCap<'a> {
pub fn do_set_irq(&mut self, tcb: &TcbObject) -> SysResult { pub fn do_set_irq(&mut self, tcb: &TcbObject) -> SysResult {
let irq = tcb.trapframe.get_reg(REG_ARG_0); let irq = tcb.trapframe.get_reg(REG_ARG_0);
IRQ_MANAGER.lock().enable(irq, self.cte.clone()); IRQ_MANAGER.lock().enable(irq, self.cte.clone());
self.set_irq(irq); self.set_signal(irq);
Ok(()) Ok(())
} }
pub fn do_ack_irq(&mut self, tcb: &TcbObject) -> SysResult { pub fn do_ack_irq(&mut self, tcb: &TcbObject) -> SysResult {
let irq = tcb.trapframe.get_reg(REG_ARG_0); 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); IRQ_MANAGER.lock().complete(irq);
Ok(()) Ok(())
} }
@ -149,7 +166,7 @@ impl<'a> EndpointCap<'a> {
send.schedule_next(); send.schedule_next();
}, },
EndpointState::Signal => { 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 // 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 { 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(); let state = self.state();
self.set_signals(signals); self.set_pendings(signals);
let signals = self.signals(); // set_signals will filter out invalid signals let signals = self.pendings(); // set_signals will filter out invalid signals
if state == EndpointState::Recv && signals != 0 { if state == EndpointState::Recv && signals != 0 {
// do recv immediately // do recv immediately
self.set_signals(0); self.set_pendings(0);
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();
recv.set_state(ThreadState::Running); recv.set_state(ThreadState::Running);
recv.schedule_next(); recv.schedule_next();
do_signal(recv, signals)?; do_signal_reply(recv, signals)?;
} }
Ok(()) Ok(())
@ -189,8 +206,8 @@ impl Debug for EndpointCap<'_> {
f.debug_struct("EndpointCap") f.debug_struct("EndpointCap")
.field("ptr", &self.cap().get().ptr) .field("ptr", &self.cap().get().ptr)
.field("badge", &self.badge()) .field("badge", &self.badge())
.field("irqs", &self.irqs()) .field("irqs", &self.signals())
.field("signals", &self.signals()) .field("signals", &self.pendings())
.field("state", &self.state()) .field("state", &self.state())
.finish() .finish()
} }
@ -285,7 +302,7 @@ fn do_ipc(
Ok(()) 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); 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_REPLY_INFO, reply.into());

View File

@ -117,6 +117,7 @@ impl UntypedCap<'_> {
ObjectType::TCB => TcbCap::mint(addr), ObjectType::TCB => TcbCap::mint(addr),
ObjectType::Table => TableCap::mint(addr), ObjectType::Table => TableCap::mint(addr),
ObjectType::Frame => FrameCap::mint(addr, user_obj_bits, MapAttr::empty(), self.is_device()), ObjectType::Frame => FrameCap::mint(addr, user_obj_bits, MapAttr::empty(), self.is_device()),
ObjectType::Endpoint => EndpointCap::mint(addr, 0),
// TODO: other object types // TODO: other object types
_ => return Err(SysError::InvalidArgument), _ => return Err(SysError::InvalidArgument),
}; };

View File

@ -9,7 +9,7 @@ macro_rules! assert_length {
} }
}; };
($info:ident >= $len:expr) => { ($info:ident >= $len:expr) => {
if $info.length() >= $len { if $info.length() < $len {
return Err(SysError::InvalidArgument); return Err(SysError::InvalidArgument);
} }
}; };
@ -61,6 +61,7 @@ pub fn handle_syscall(tcb: &mut TcbObject) -> SysResult {
cap.do_set_irq(tcb) cap.do_set_irq(tcb)
}, },
Syscall::IrqAck => { Syscall::IrqAck => {
assert_length!(info, 3);
let mut cap = EndpointCap::try_from(cap)?; let mut cap = EndpointCap::try_from(cap)?;
cap.do_ack_irq(tcb) 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 { 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() self.prev.is_none() && self.next.is_none()
} }