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},
|
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());
|
||||||
|
@ -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),
|
||||||
};
|
};
|
||||||
|
@ -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)
|
||||||
},
|
},
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user