mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
fix: kernel/objects/endpoint: bug fix
This commit is contained in:
parent
93dabb523b
commit
908822ae41
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
cap
|
||||
}
|
||||
|
||||
pub fn irqs(&self) -> Option<usize> {
|
||||
let irqs = self.cap().get().args[0];
|
||||
(irqs != 0).then_some(irqs)
|
||||
pub fn signals(&self) -> Option<usize> {
|
||||
let signals = self.as_object().signals;
|
||||
(signals != 0).then_some(signals)
|
||||
}
|
||||
|
||||
fn set_irq(&mut self, irqs: usize) {
|
||||
self.cap().get().args[0] |= 1 << irqs;
|
||||
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());
|
||||
|
@ -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),
|
||||
};
|
||||
|
@ -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)
|
||||
},
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user