mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
Compare commits
No commits in common. "908822ae41ffd541884302342ebdcf1054a33c45" and "d2a4b4899d696f85a14d794a8288d6a30bfe6437" have entirely different histories.
908822ae41
...
d2a4b4899d
@ -62,6 +62,7 @@ impl Debug for CapEntry {
|
|||||||
ObjectType::Table => write!(f, "{:?}", TableCap::try_from(self)),
|
ObjectType::Table => write!(f, "{:?}", TableCap::try_from(self)),
|
||||||
ObjectType::TCB => write!(f, "{:?}", TcbCap::try_from(self)),
|
ObjectType::TCB => write!(f, "{:?}", TcbCap::try_from(self)),
|
||||||
ObjectType::Untyped => write!(f, "{:?}", UntypedCap::try_from(self)),
|
ObjectType::Untyped => write!(f, "{:?}", UntypedCap::try_from(self)),
|
||||||
|
_ => write!(f, "UnknownCap"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,22 @@
|
|||||||
use crate::objects::*;
|
use crate::{objects::*, plat::trap::TrapContextOps};
|
||||||
use crate::plat::{
|
|
||||||
irq::{IRQ_MANAGER, IRQ_NUM},
|
|
||||||
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, fault::Fault, syscall::*};
|
||||||
use utils::container_of_mut;
|
|
||||||
use utils::then::Then;
|
|
||||||
use utils::{addr::*, array::*, linked_list::Link};
|
use utils::{addr::*, array::*, linked_list::Link};
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub enum EndpointState {
|
pub enum EndpointState {
|
||||||
Idle,
|
Idle,
|
||||||
Send,
|
Sending,
|
||||||
Recv,
|
Receiving,
|
||||||
Signal,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
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 state: EndpointState,
|
||||||
pub pending: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const_assert!(usize::BITS as usize >= IRQ_NUM);
|
|
||||||
const_assert!(core::mem::size_of::<EndpointObject>() <= ObjectType::Endpoint.size(0));
|
|
||||||
|
|
||||||
impl KernelObject for EndpointObject {
|
impl KernelObject for EndpointObject {
|
||||||
const OBJ_TYPE: ObjectType = ObjectType::Endpoint;
|
const OBJ_TYPE: ObjectType = ObjectType::Endpoint;
|
||||||
}
|
}
|
||||||
@ -51,154 +39,95 @@ 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 {
|
||||||
let cap = RawCap::new(badge, 0, ptr, ObjectType::Endpoint);
|
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 signals(&self) -> Option<usize> {
|
pub fn can_send(&self) -> bool {
|
||||||
let signals = self.as_object().signals;
|
self.cap().get().args[0] & 0x2 != 0
|
||||||
(signals != 0).then_some(signals)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_signal(&mut self, signal: usize) {
|
pub fn can_recv(&self) -> bool {
|
||||||
self.as_object_mut().signals |= 1 << signal;
|
self.cap().get().args[0] & 0x1 != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn badge(&self) -> usize {
|
pub fn badge(&self) -> usize {
|
||||||
self.cap().get().args[0]
|
self.cap().get().args[1]
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pendings(&self) -> usize {
|
|
||||||
self.as_object().pending
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_pendings(&mut self, pendings: usize) {
|
|
||||||
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();
|
self.as_object().state
|
||||||
|
|
||||||
if obj.pending > 0 {
|
|
||||||
return EndpointState::Signal;
|
|
||||||
} else if obj.queue.is_empty() {
|
|
||||||
return EndpointState::Idle;
|
|
||||||
}
|
|
||||||
|
|
||||||
match obj.queue.next().unwrap().state() {
|
|
||||||
ThreadState::Sending => EndpointState::Send,
|
|
||||||
ThreadState::Receiving => EndpointState::Recv,
|
|
||||||
_ => EndpointState::Idle,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_set_irq(&mut self, tcb: &TcbObject) -> SysResult {
|
pub fn set_state(&mut self, state: EndpointState) {
|
||||||
let irq = tcb.trapframe.get_reg(REG_ARG_0);
|
self.as_object_mut().state = state;
|
||||||
IRQ_MANAGER.lock().enable(irq, self.cte.clone());
|
|
||||||
self.set_signal(irq);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_ack_irq(&mut self, tcb: &TcbObject) -> SysResult {
|
pub fn do_send(&mut self, send: &mut TcbObject) -> SysResult<()> {
|
||||||
let irq = tcb.trapframe.get_reg(REG_ARG_0);
|
|
||||||
(self.signals().unwrap_or(0) & (1 << irq) != 0).else_err((), SysError::InvalidArgument)?;
|
|
||||||
IRQ_MANAGER.lock().complete(irq);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_send(&mut self, send: &mut TcbObject) -> SysResult {
|
|
||||||
match self.state() {
|
match self.state() {
|
||||||
EndpointState::Recv => {
|
EndpointState::Idle | EndpointState::Sending => {
|
||||||
debug_assert!(
|
send.set_state(ThreadState::Sending);
|
||||||
!self.as_object().queue.is_empty(),
|
send.set_badge(self.badge());
|
||||||
"[Endpoint] do_send: Receive endpoint queue must not be empty"
|
|
||||||
);
|
|
||||||
|
|
||||||
let badge = self.badge();
|
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 recv = self.as_object_mut().queue.next_mut().unwrap();
|
let recv = {
|
||||||
recv.ep_queue.detach();
|
let recv = self.as_object_mut().queue.next_mut().unwrap();
|
||||||
|
recv.ep_queue.detach();
|
||||||
|
|
||||||
do_ipc(send, send.get_message_info()?, recv, recv.get_message_info()?, badge)?;
|
// 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())?;
|
||||||
|
|
||||||
recv.set_state(ThreadState::Running);
|
recv.set_state(ThreadState::Running);
|
||||||
recv.schedule_next();
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_recv(&mut self, recv: &mut TcbObject) -> SysResult {
|
pub fn do_recv(&mut self, recv: &mut TcbObject) -> SysResult<()> {
|
||||||
match self.state() {
|
match self.state() {
|
||||||
EndpointState::Send => {
|
EndpointState::Idle | EndpointState::Receiving => {
|
||||||
debug_assert!(
|
recv.set_state(ThreadState::Receiving);
|
||||||
!self.as_object().queue.is_empty(),
|
|
||||||
"[Endpoint] do_recv: Send endpoint queue must not be empty"
|
|
||||||
);
|
|
||||||
|
|
||||||
let badge = self.badge();
|
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 send = self.as_object_mut().queue.next_mut().unwrap();
|
let send = {
|
||||||
send.ep_queue.detach();
|
let send = self.as_object_mut().queue.next_mut().unwrap();
|
||||||
|
send.ep_queue.detach();
|
||||||
|
|
||||||
do_ipc(send, send.get_message_info()?, recv, recv.get_message_info()?, badge)?;
|
// 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())?;
|
||||||
|
|
||||||
send.set_state(ThreadState::Running);
|
send.set_state(ThreadState::Running);
|
||||||
send.schedule_next();
|
send.schedule_next();
|
||||||
},
|
},
|
||||||
EndpointState::Signal => {
|
|
||||||
do_signal_reply(recv, self.pendings())?;
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
// 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_signal(&mut self, irq: usize) -> SysResult {
|
|
||||||
let signals = self.pendings() | (1 << irq);
|
|
||||||
let state = self.state();
|
|
||||||
|
|
||||||
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_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_reply(recv, signals)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for EndpointCap<'_> {
|
impl Debug for EndpointCap<'_> {
|
||||||
@ -206,19 +135,14 @@ 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.signals())
|
.field("can_send", &self.can_send())
|
||||||
.field("signals", &self.pendings())
|
.field("can_recv", &self.can_recv())
|
||||||
.field("state", &self.state())
|
.field("state", &self.state())
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_message(
|
fn copy_message(send: &mut TcbObject, send_msg: MessageInfo, recv: &mut TcbObject, recv_msg: MessageInfo) -> SysResult<()> {
|
||||||
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 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 recv_len = recv_msg.length() - if recv_msg.transfer_cap() { 2 } else { 0 };
|
||||||
let msg_len = min(send_len, recv_len);
|
let msg_len = min(send_len, recv_len);
|
||||||
@ -239,7 +163,7 @@ fn copy_message(
|
|||||||
recv.trapframe.set_reg(i, send.trapframe.get_reg(i));
|
recv.trapframe.set_reg(i, send.trapframe.get_reg(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(msg_len)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ipc_get_args(tcb: &TcbObject, idx: usize) -> SysResult<usize> {
|
fn ipc_get_args(tcb: &TcbObject, idx: usize) -> SysResult<usize> {
|
||||||
@ -254,14 +178,9 @@ fn ipc_get_args(tcb: &TcbObject, idx: usize) -> SysResult<usize> {
|
|||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transfer_cap(
|
fn transfer_cap(send: &mut TcbObject, send_msg: MessageInfo, recv: &mut TcbObject, recv_msg: MessageInfo) -> SysResult<()> {
|
||||||
send: &mut TcbObject,
|
|
||||||
send_msg: MessageInfo,
|
|
||||||
recv: &mut TcbObject,
|
|
||||||
recv_msg: MessageInfo,
|
|
||||||
) -> SysResult<bool> {
|
|
||||||
if !send_msg.transfer_cap() || !recv_msg.transfer_cap() {
|
if !send_msg.transfer_cap() || !recv_msg.transfer_cap() {
|
||||||
return Ok(false);
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let send_cspace = send.cspace()?;
|
let send_cspace = send.cspace()?;
|
||||||
@ -280,33 +199,24 @@ fn transfer_cap(
|
|||||||
dest.override_cap(send_cap.cap.get());
|
dest.override_cap(send_cap.cap.get());
|
||||||
send_cap.cap.replace(NullCap::mint());
|
send_cap.cap.replace(NullCap::mint());
|
||||||
|
|
||||||
Ok(true)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_ipc(
|
fn do_ipc_transfer(
|
||||||
send: &mut TcbObject,
|
send: &mut TcbObject,
|
||||||
send_msg: MessageInfo,
|
send_msg: MessageInfo,
|
||||||
recv: &mut TcbObject,
|
recv: &mut TcbObject,
|
||||||
recv_msg: MessageInfo,
|
recv_msg: MessageInfo,
|
||||||
badge: usize,
|
_badge: usize,
|
||||||
) -> SysResult {
|
) -> SysResult<()> {
|
||||||
// do normal transfer
|
if send.fault() == Fault::Null {
|
||||||
|
// do normal transfer
|
||||||
|
copy_message(send, send_msg, recv, recv_msg)?;
|
||||||
|
transfer_cap(send, send_msg, recv, recv_msg)?;
|
||||||
|
|
||||||
let length = copy_message(send, send_msg, recv, recv_msg)?;
|
todo!("do_ipc_transfer: normal transfer: uapi/reply");
|
||||||
let transfered = transfer_cap(send, send_msg, recv, recv_msg)?;
|
} else {
|
||||||
|
// do fault transfer
|
||||||
let reply = ReplyInfo::new(ReplyLabel::Message, length, true, transfered, SysError::Ok);
|
todo!("do_ipc_transfer: fault transfer");
|
||||||
recv.trapframe.set_reg(REG_REPLY_INFO, reply.into());
|
}
|
||||||
recv.trapframe.set_reg(REG_BADGE, badge);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
recv.trapframe.set_reg(REG_BADGE, signals);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ pub struct TcbObject {
|
|||||||
vspace: CapEntry,
|
vspace: CapEntry,
|
||||||
|
|
||||||
// endpoint
|
// endpoint
|
||||||
|
badge: usize,
|
||||||
buffer: CapEntry,
|
buffer: CapEntry,
|
||||||
fault: Fault,
|
fault: Fault,
|
||||||
|
|
||||||
@ -62,6 +63,7 @@ impl TcbObject {
|
|||||||
trapframe: TrapContext::default(),
|
trapframe: TrapContext::default(),
|
||||||
cspace: CapEntry::new(NullCap::mint()),
|
cspace: CapEntry::new(NullCap::mint()),
|
||||||
vspace: CapEntry::new(NullCap::mint()),
|
vspace: CapEntry::new(NullCap::mint()),
|
||||||
|
badge: 0,
|
||||||
buffer: CapEntry::new(NullCap::mint()),
|
buffer: CapEntry::new(NullCap::mint()),
|
||||||
fault: Fault::Null,
|
fault: Fault::Null,
|
||||||
state: ThreadState::Inactive,
|
state: ThreadState::Inactive,
|
||||||
@ -95,6 +97,14 @@ impl TcbObject {
|
|||||||
self.vspace = vspace;
|
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> {
|
pub fn buffer(&self) -> SysResult<FrameCap> {
|
||||||
FrameCap::try_from(&self.buffer)
|
FrameCap::try_from(&self.buffer)
|
||||||
}
|
}
|
||||||
@ -188,6 +198,7 @@ impl Debug for TcbCap<'_> {
|
|||||||
f.debug_struct("TcbCap")
|
f.debug_struct("TcbCap")
|
||||||
.field("cspace", &obj.cspace)
|
.field("cspace", &obj.cspace)
|
||||||
.field("vspace", &obj.vspace)
|
.field("vspace", &obj.vspace)
|
||||||
|
.field("badge", &obj.badge)
|
||||||
.field("buffer", &obj.buffer)
|
.field("buffer", &obj.buffer)
|
||||||
.field("fault", &obj.fault)
|
.field("fault", &obj.fault)
|
||||||
.field("state", &obj.state)
|
.field("state", &obj.state)
|
||||||
|
@ -117,7 +117,6 @@ 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),
|
||||||
};
|
};
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use super::utils::generate_driver;
|
use super::utils::generate_driver;
|
||||||
use crate::drivers::irq::IrqPlic;
|
use crate::drivers::irq::IrqPlic;
|
||||||
use crate::objects::*;
|
use crate::objects::*;
|
||||||
use log::{error, trace, warn};
|
use log::{error, warn};
|
||||||
use spin::{lazy::Lazy, Mutex};
|
use spin::{lazy::Lazy, Mutex};
|
||||||
|
|
||||||
pub const IRQ_NUM: usize = 32;
|
const IRQ_NUM: usize = 32;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub enum IrqState {
|
pub enum IrqState {
|
||||||
@ -50,6 +50,7 @@ pub fn set_irq_driver(driver: IrqDriver) {
|
|||||||
|
|
||||||
pub struct IrqManager {
|
pub struct IrqManager {
|
||||||
handler: [CapEntry; IRQ_NUM],
|
handler: [CapEntry; IRQ_NUM],
|
||||||
|
state: [IrqState; IRQ_NUM],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static IRQ_MANAGER: Lazy<Mutex<IrqManager>> = Lazy::new(|| Mutex::new(IrqManager::new()));
|
pub static IRQ_MANAGER: Lazy<Mutex<IrqManager>> = Lazy::new(|| Mutex::new(IrqManager::new()));
|
||||||
@ -58,31 +59,10 @@ impl IrqManager {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
handler: core::array::from_fn::<_, IRQ_NUM, _>(|_| CapEntry::new(NullCap::mint())),
|
handler: core::array::from_fn::<_, IRQ_NUM, _>(|_| CapEntry::new(NullCap::mint())),
|
||||||
|
state: [IrqState::Inactive; IRQ_NUM],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable(&mut self, irq: usize, cap: CapEntry) {
|
|
||||||
if irq >= IRQ_NUM {
|
|
||||||
error!("[IrqManager] Invalid IRQ number: {}", irq);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if NullCap::try_from(&self.handler[irq]).is_ok() {
|
|
||||||
self.handler[irq] = cap;
|
|
||||||
IRQ_DRIVER.lock().complete(irq);
|
|
||||||
IRQ_DRIVER.lock().enable(irq);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn complete(&mut self, irq: usize) {
|
|
||||||
if irq >= IRQ_NUM {
|
|
||||||
error!("[IrqManager] Invalid IRQ number: {}", irq);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IRQ_DRIVER.lock().complete(irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dispatch(&mut self) {
|
pub fn dispatch(&mut self) {
|
||||||
let irq = IRQ_DRIVER.lock().claim();
|
let irq = IRQ_DRIVER.lock().claim();
|
||||||
if irq.is_none() {
|
if irq.is_none() {
|
||||||
@ -90,16 +70,30 @@ impl IrqManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(irq) = irq
|
let irq = irq.unwrap();
|
||||||
&& irq < IRQ_NUM
|
if irq >= IRQ_NUM {
|
||||||
&& let Ok(mut cap) = EndpointCap::try_from(&self.handler[irq])
|
error!("[IrqManager] Invalid IRQ number: {}", irq);
|
||||||
{
|
IRQ_DRIVER.lock().disable(irq);
|
||||||
trace!("[IrqManager] Dispatching IRQ: {}", irq);
|
IRQ_DRIVER.lock().complete(irq);
|
||||||
cap.do_signal(irq).unwrap();
|
return;
|
||||||
} else {
|
|
||||||
warn!("[IrqManager] Received invalid IRQ: {:?}", irq);
|
|
||||||
IRQ_DRIVER.lock().disable(irq.unwrap());
|
|
||||||
IRQ_DRIVER.lock().complete(irq.unwrap());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match self.state[irq] {
|
||||||
|
IrqState::Inactive => {
|
||||||
|
warn!("[IrqManager] Received disabled IRQ: {}", irq);
|
||||||
|
IRQ_DRIVER.lock().disable(irq);
|
||||||
|
},
|
||||||
|
IrqState::Signal => {
|
||||||
|
// TODO: send signal via endpoint
|
||||||
|
warn!("[IrqManager] Undelivered IRQ: {}", irq);
|
||||||
|
IRQ_DRIVER.lock().disable(irq);
|
||||||
|
},
|
||||||
|
IrqState::Ipi => {
|
||||||
|
todo!("Kernel: NO SMP support now");
|
||||||
|
},
|
||||||
|
IrqState::Reserved => error!("[IrqManager] Received unhandled reserved IRQ: {}", irq),
|
||||||
|
}
|
||||||
|
|
||||||
|
IRQ_DRIVER.lock().complete(irq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,16 +3,11 @@ use log::trace;
|
|||||||
use uapi::{error::*, syscall::*};
|
use uapi::{error::*, syscall::*};
|
||||||
|
|
||||||
macro_rules! assert_length {
|
macro_rules! assert_length {
|
||||||
($info:ident, $len:expr) => {
|
($info:expr, $len:expr) => {
|
||||||
if $info.length() != $len {
|
if $info.length() != $len {
|
||||||
return Err(SysError::InvalidArgument);
|
return Err(SysError::InvalidArgument);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($info:ident >= $len:expr) => {
|
|
||||||
if $info.length() < $len {
|
|
||||||
return Err(SysError::InvalidArgument);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_syscall(tcb: &mut TcbObject) -> SysResult {
|
pub fn handle_syscall(tcb: &mut TcbObject) -> SysResult {
|
||||||
@ -34,37 +29,17 @@ pub fn handle_syscall(tcb: &mut TcbObject) -> SysResult {
|
|||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_length!(info >= 2);
|
let cspace = tcb.cspace()?;
|
||||||
|
|
||||||
// workaround ownership check
|
|
||||||
let tcb_cspace = unsafe { &mut *(tcb as *mut TcbObject) };
|
|
||||||
let cspace = tcb_cspace.cspace()?;
|
|
||||||
|
|
||||||
let cap_ptr = tcb.trapframe.get_reg(REG_CAP_PTR);
|
let cap_ptr = tcb.trapframe.get_reg(REG_CAP_PTR);
|
||||||
let cap = cspace.resolve_address_bits(cap_ptr, info.bits()).map_err(SysError::from)?;
|
let cap = cspace.resolve_address_bits(cap_ptr, info.bits()).map_err(SysError::from)?;
|
||||||
|
|
||||||
trace!("[Syscall] info={:?} cap={:?}", info, cap);
|
trace!("handle_syscall: info={:?} cap={:?}", info, cap);
|
||||||
|
|
||||||
match info.label() {
|
match info.label() {
|
||||||
// Endpoint
|
Syscall::InvokeNtfn => {
|
||||||
Syscall::EpSend => {
|
assert_length!(info, 2);
|
||||||
let mut cap = EndpointCap::try_from(cap)?;
|
unimplemented!("[Syscall] InvokeNtfn: {:?}", info.label());
|
||||||
cap.do_send(tcb)
|
|
||||||
},
|
},
|
||||||
Syscall::EpRecv => {
|
_ => unimplemented!("handle_syscall: {:?}, {:?}", info.label(), cap),
|
||||||
let mut cap = EndpointCap::try_from(cap)?;
|
|
||||||
cap.do_recv(tcb)
|
|
||||||
},
|
|
||||||
Syscall::IrqSet => {
|
|
||||||
assert_length!(info, 3);
|
|
||||||
let mut cap = EndpointCap::try_from(cap)?;
|
|
||||||
cap.do_set_irq(tcb)
|
|
||||||
},
|
|
||||||
Syscall::IrqAck => {
|
|
||||||
assert_length!(info, 3);
|
|
||||||
let mut cap = EndpointCap::try_from(cap)?;
|
|
||||||
cap.do_ack_irq(tcb)
|
|
||||||
},
|
|
||||||
_ => todo!("[Syscall] unhandled syscall: {:?}, {:?}", info.label(), cap),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,8 @@ 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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)]
|
||||||
pub enum ObjectType {
|
pub enum ObjectType {
|
||||||
Null = 0,
|
Null = 0,
|
||||||
CNode = 1,
|
CNode = 1,
|
||||||
TCB = 2,
|
TCB = 2,
|
||||||
Endpoint = 3,
|
Endpoint = 3,
|
||||||
Frame = 4,
|
Reply = 4,
|
||||||
Table = 5,
|
Notification = 5,
|
||||||
Untyped = 6,
|
Frame = 6,
|
||||||
|
Table = 7,
|
||||||
|
Interrupt = 8,
|
||||||
|
Untyped = 9,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ObjectType {
|
impl Default for ObjectType {
|
||||||
@ -16,9 +19,8 @@ impl Default for ObjectType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectType {
|
impl ObjectType {
|
||||||
const CNODE_BITS: usize = 5; // 32 bytes
|
const CNODE_BITS: usize = 6; // 48 bytes
|
||||||
const TCB_BITS: usize = 10; // 672 bytes
|
const TCB_BITS: usize = 10; // 672 bytes
|
||||||
const ENDPOINT_BITS: usize = 6; // 40 bytes
|
|
||||||
|
|
||||||
pub const fn size(&self, user_obj_bits: usize) -> usize {
|
pub const fn size(&self, user_obj_bits: usize) -> usize {
|
||||||
1 << self.bits(user_obj_bits)
|
1 << self.bits(user_obj_bits)
|
||||||
@ -30,9 +32,12 @@ impl ObjectType {
|
|||||||
ObjectType::Null => 0,
|
ObjectType::Null => 0,
|
||||||
ObjectType::CNode => Self::CNODE_BITS + user_obj_bits,
|
ObjectType::CNode => Self::CNODE_BITS + user_obj_bits,
|
||||||
ObjectType::TCB => Self::TCB_BITS,
|
ObjectType::TCB => Self::TCB_BITS,
|
||||||
ObjectType::Endpoint => Self::ENDPOINT_BITS,
|
ObjectType::Endpoint => 0, // TODO: fill it!
|
||||||
|
ObjectType::Reply => 0, // TODO: fill it!
|
||||||
|
ObjectType::Notification => 0, // TODO: fill it!
|
||||||
ObjectType::Frame => user_obj_bits,
|
ObjectType::Frame => user_obj_bits,
|
||||||
ObjectType::Table => user_obj_bits, // arch dependent page table size
|
ObjectType::Table => user_obj_bits, // arch dependent page table size
|
||||||
|
ObjectType::Interrupt => 0, // TODO: fill it!
|
||||||
ObjectType::Untyped => user_obj_bits,
|
ObjectType::Untyped => user_obj_bits,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)]
|
||||||
pub enum SysError {
|
pub enum SysError {
|
||||||
Ok,
|
Ok,
|
||||||
Invalid,
|
|
||||||
InvalidArgument,
|
InvalidArgument,
|
||||||
CapTypeMismatch, // Cap, Untyped
|
CapTypeMismatch, // Cap, Untyped
|
||||||
SlotNotEmpty, // Untyped
|
SlotNotEmpty, // Untyped
|
||||||
|
@ -8,20 +8,11 @@ pub enum Syscall {
|
|||||||
Invalid = 0,
|
Invalid = 0,
|
||||||
DebugPutChar = 1,
|
DebugPutChar = 1,
|
||||||
Yield = 2,
|
Yield = 2,
|
||||||
|
InvokeNtfn = 3,
|
||||||
// endpoint
|
// Send = 4,
|
||||||
EpSend = 3,
|
// Recv = 5,
|
||||||
EpRecv = 4,
|
// Call = 6,
|
||||||
IrqSet = 5,
|
// Reply = 7,
|
||||||
IrqAck = 6,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)]
|
|
||||||
pub enum ReplyLabel {
|
|
||||||
Invalid = 0,
|
|
||||||
Message = 1,
|
|
||||||
Signal = 2,
|
|
||||||
Fault = 3,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Syscall convention:
|
/* Syscall convention:
|
||||||
@ -36,16 +27,9 @@ pub enum ReplyLabel {
|
|||||||
* > > if info.transfer_cap { Arguments[-2] = cap_ptr; Arguments[-1] = n_bits; }
|
* > > if info.transfer_cap { Arguments[-2] = cap_ptr; Arguments[-1] = n_bits; }
|
||||||
* >
|
* >
|
||||||
* > Reply:
|
* > Reply:
|
||||||
* > > +----------+-------------------------+--------------+
|
* > TODO: figure out how vanilla seL4 handle reply
|
||||||
* > > | [a0] | REG_REPLY_INFO | ReplyInfo |
|
|
||||||
* > > | [a1] | REG_BADGE | Badge |
|
|
||||||
* > > | [a2..a7] | REG_ARG_0..=REG_ARG_MAX | Replied Data |
|
|
||||||
* > > | buffer | REG_ARG_MAX+1.. | Replied Data |
|
|
||||||
* > > +----------+-------------------------+--------------+
|
|
||||||
* > > length = (a0..).length(), extra data are stored on ipc buffer
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Call
|
|
||||||
pub const REG_MESSAGE_INFO: usize = 0;
|
pub const REG_MESSAGE_INFO: usize = 0;
|
||||||
pub const REG_CAP_PTR: usize = 1;
|
pub const REG_CAP_PTR: usize = 1;
|
||||||
pub const REG_ARG_0: usize = 2;
|
pub const REG_ARG_0: usize = 2;
|
||||||
@ -54,10 +38,6 @@ pub const REG_ARG_MAX: usize = 7;
|
|||||||
pub const LEN_ARG_OFFSET_CPTR: usize = 2;
|
pub const LEN_ARG_OFFSET_CPTR: usize = 2;
|
||||||
pub const LEN_ARG_OFFSET_BITS: usize = 1;
|
pub const LEN_ARG_OFFSET_BITS: usize = 1;
|
||||||
|
|
||||||
// Reply
|
|
||||||
pub const REG_REPLY_INFO: usize = 0;
|
|
||||||
pub const REG_BADGE: usize = 1;
|
|
||||||
|
|
||||||
/* MessageInfo layout:
|
/* MessageInfo layout:
|
||||||
* > +---------+--------+--------+--------------+
|
* > +---------+--------+--------+--------------+
|
||||||
* > | label | bits | length | transfer_cap |
|
* > | label | bits | length | transfer_cap |
|
||||||
@ -85,9 +65,9 @@ impl MessageInfo {
|
|||||||
const TRANSFER_CAP_OFFSET: usize = 0;
|
const TRANSFER_CAP_OFFSET: usize = 0;
|
||||||
|
|
||||||
pub fn new(label: Syscall, bits: usize, length: usize, transfer_cap: bool) -> Self {
|
pub fn new(label: Syscall, bits: usize, length: usize, transfer_cap: bool) -> Self {
|
||||||
let label = label.to_usize().unwrap();
|
let label = label.to_usize().unwrap_or(0);
|
||||||
let bits = bits - 1; // stored as n_bits - 1
|
let bits = bits - 1; // stored as n_bits - 1
|
||||||
let transfer_cap = if transfer_cap { 1 } else { 0 };
|
let transfer_cap = transfer_cap as usize;
|
||||||
|
|
||||||
assert!(label <= Self::LABEL_MASK);
|
assert!(label <= Self::LABEL_MASK);
|
||||||
assert!(bits <= Self::BITS_MASK);
|
assert!(bits <= Self::BITS_MASK);
|
||||||
@ -137,109 +117,6 @@ impl TryFrom<usize> for MessageInfo {
|
|||||||
|
|
||||||
fn try_from(value: usize) -> Result<Self, Self::Error> {
|
fn try_from(value: usize) -> Result<Self, Self::Error> {
|
||||||
let info = Self(value);
|
let info = Self(value);
|
||||||
(info.label() != Syscall::Invalid).then_ok(info, SysError::Invalid)
|
(info.label() != Syscall::Invalid).then_ok(info, SysError::InvalidArgument)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<usize> for MessageInfo {
|
|
||||||
fn into(self) -> usize {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ReplyInfo layout:
|
|
||||||
* > +---------+--------+--------+------------+-------+
|
|
||||||
* > | label | length | badged | transfered | error |
|
|
||||||
* > | [16:14] | [13:7] | [6] | [5] | [4:0] |
|
|
||||||
* > +---------+--------+--------+------------+-------+
|
|
||||||
* > label: reply label
|
|
||||||
* > length: args.len()
|
|
||||||
* > 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);
|
|
||||||
|
|
||||||
impl ReplyInfo {
|
|
||||||
const LABEL_MASK: usize = MASK!(16 - 14 + 1);
|
|
||||||
const LABEL_OFFSET: usize = 14;
|
|
||||||
|
|
||||||
const LENGTH_MASK: usize = MASK!(13 - 7 + 1);
|
|
||||||
const LENGTH_OFFSET: usize = 7;
|
|
||||||
|
|
||||||
const BADGED_MASK: usize = MASK!(1);
|
|
||||||
const BADGED_OFFSET: usize = 6;
|
|
||||||
|
|
||||||
const TRANSFERED_MASK: usize = MASK!(1);
|
|
||||||
const TRANSFERED_OFFSET: usize = 5;
|
|
||||||
|
|
||||||
const ERROR_MASK: usize = MASK!(4 - 0 + 1);
|
|
||||||
const ERROR_OFFSET: usize = 0;
|
|
||||||
|
|
||||||
pub fn new(label: ReplyLabel, length: usize, badged: bool, transfered: bool, error: SysError) -> Self {
|
|
||||||
let label = label.to_usize().unwrap();
|
|
||||||
let badged = if badged { 1 } else { 0 };
|
|
||||||
let transfered = if transfered { 1 } else { 0 };
|
|
||||||
let error = error.to_usize().unwrap();
|
|
||||||
|
|
||||||
assert!(label <= Self::LABEL_MASK);
|
|
||||||
assert!(length <= Self::LENGTH_MASK);
|
|
||||||
assert!(error <= Self::ERROR_MASK);
|
|
||||||
|
|
||||||
let info = ((label & Self::LABEL_MASK) << Self::LABEL_OFFSET)
|
|
||||||
| ((length & Self::LENGTH_MASK) << Self::LENGTH_OFFSET)
|
|
||||||
| ((badged & Self::BADGED_MASK) << Self::BADGED_OFFSET)
|
|
||||||
| ((transfered & Self::TRANSFERED_MASK) << Self::TRANSFERED_OFFSET)
|
|
||||||
| ((error & Self::ERROR_MASK) << Self::ERROR_OFFSET);
|
|
||||||
Self(info)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn label(&self) -> ReplyLabel {
|
|
||||||
ReplyLabel::from_usize((self.0 >> Self::LABEL_OFFSET) & Self::LABEL_MASK).unwrap_or(ReplyLabel::Invalid)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn length(&self) -> usize {
|
|
||||||
(self.0 >> Self::LENGTH_OFFSET) & Self::LENGTH_MASK
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn badged(&self) -> bool {
|
|
||||||
(self.0 >> Self::BADGED_OFFSET) & Self::BADGED_MASK != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transfered(&self) -> bool {
|
|
||||||
(self.0 >> Self::TRANSFERED_OFFSET) & Self::TRANSFERED_MASK != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn error(&self) -> SysError {
|
|
||||||
SysError::from_usize((self.0 >> Self::ERROR_OFFSET) & Self::ERROR_MASK).unwrap_or(SysError::Invalid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for ReplyInfo {
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
f.debug_struct("ReplyInfo")
|
|
||||||
.field("label", &self.label())
|
|
||||||
.field("length", &self.length())
|
|
||||||
.field("badged", &self.badged())
|
|
||||||
.field("transfered", &self.transfered())
|
|
||||||
.field("error", &self.error())
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<usize> for ReplyInfo {
|
|
||||||
type Error = SysError;
|
|
||||||
|
|
||||||
fn try_from(value: usize) -> Result<Self, Self::Error> {
|
|
||||||
let info = Self(value);
|
|
||||||
(info.label() != ReplyLabel::Invalid).then_ok(info, SysError::Invalid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<usize> for ReplyInfo {
|
|
||||||
fn into(self) -> usize {
|
|
||||||
self.0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user