Compare commits

...

6 Commits

10 changed files with 375 additions and 148 deletions

View File

@ -62,7 +62,6 @@ 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"),
} }
} }
} }

View File

@ -1,22 +1,34 @@
use crate::{objects::*, plat::trap::TrapContextOps}; use crate::objects::*;
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, fault::Fault, syscall::*}; use uapi::{cap::ObjectType, 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,
Sending, Send,
Receiving, Recv,
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 state: EndpointState, pub signals: usize,
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;
} }
@ -39,95 +51,154 @@ 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(badge, 0, 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 can_send(&self) -> bool { cap
self.cap().get().args[0] & 0x2 != 0
} }
pub fn can_recv(&self) -> bool { pub fn signals(&self) -> Option<usize> {
self.cap().get().args[0] & 0x1 != 0 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 { pub fn badge(&self) -> usize {
self.cap().get().args[1] self.cap().get().args[0]
}
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 {
self.as_object().state let obj = self.as_object();
if obj.pending > 0 {
return EndpointState::Signal;
} else if obj.queue.is_empty() {
return EndpointState::Idle;
} }
pub fn set_state(&mut self, state: EndpointState) { match obj.queue.next().unwrap().state() {
self.as_object_mut().state = state; ThreadState::Sending => EndpointState::Send,
ThreadState::Receiving => EndpointState::Recv,
_ => EndpointState::Idle,
}
} }
pub fn do_send(&mut self, send: &mut TcbObject) -> SysResult<()> { 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_signal(irq);
Ok(())
}
pub fn do_ack_irq(&mut self, tcb: &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::Idle | EndpointState::Sending => { EndpointState::Recv => {
send.set_state(ThreadState::Sending); debug_assert!(
send.set_badge(self.badge()); !self.as_object().queue.is_empty(),
"[Endpoint] do_send: Receive endpoint queue must not be empty"
);
self.set_state(EndpointState::Sending); let badge = self.badge();
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 = {
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();
// SAFETY: `recv` is detached from the queue, no longer related to `self` do_ipc(send, send.get_message_info()?, recv, recv.get_message_info()?, badge)?;
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::Idle | EndpointState::Receiving => { EndpointState::Send => {
recv.set_state(ThreadState::Receiving); debug_assert!(
!self.as_object().queue.is_empty(),
"[Endpoint] do_recv: Send endpoint queue must not be empty"
);
self.set_state(EndpointState::Receiving); let badge = self.badge();
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 = {
let send = self.as_object_mut().queue.next_mut().unwrap(); let send = self.as_object_mut().queue.next_mut().unwrap();
send.ep_queue.detach(); send.ep_queue.detach();
// SAFETY: `send` is detached from the queue, no longer related to `self` do_ipc(send, send.get_message_info()?, recv, recv.get_message_info()?, badge)?;
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<'_> {
@ -135,14 +206,19 @@ 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("can_send", &self.can_send()) .field("irqs", &self.signals())
.field("can_recv", &self.can_recv()) .field("signals", &self.pendings())
.field("state", &self.state()) .field("state", &self.state())
.finish() .finish()
} }
} }
fn copy_message(send: &mut TcbObject, send_msg: MessageInfo, recv: &mut TcbObject, recv_msg: MessageInfo) -> SysResult<()> { fn copy_message(
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);
@ -163,7 +239,7 @@ fn copy_message(send: &mut TcbObject, send_msg: MessageInfo, recv: &mut TcbObjec
recv.trapframe.set_reg(i, send.trapframe.get_reg(i)); recv.trapframe.set_reg(i, send.trapframe.get_reg(i));
} }
Ok(()) Ok(msg_len)
} }
fn ipc_get_args(tcb: &TcbObject, idx: usize) -> SysResult<usize> { fn ipc_get_args(tcb: &TcbObject, idx: usize) -> SysResult<usize> {
@ -178,9 +254,14 @@ fn ipc_get_args(tcb: &TcbObject, idx: usize) -> SysResult<usize> {
Ok(ret) Ok(ret)
} }
fn transfer_cap(send: &mut TcbObject, send_msg: MessageInfo, recv: &mut TcbObject, recv_msg: MessageInfo) -> SysResult<()> { fn transfer_cap(
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(()); return Ok(false);
} }
let send_cspace = send.cspace()?; let send_cspace = send.cspace()?;
@ -199,24 +280,33 @@ fn transfer_cap(send: &mut TcbObject, send_msg: MessageInfo, recv: &mut TcbObjec
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(()) Ok(true)
} }
fn do_ipc_transfer( fn do_ipc(
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 {
if send.fault() == Fault::Null {
// do normal transfer // do normal transfer
copy_message(send, send_msg, recv, recv_msg)?;
transfer_cap(send, send_msg, recv, recv_msg)?;
todo!("do_ipc_transfer: normal transfer: uapi/reply"); let length = copy_message(send, send_msg, recv, recv_msg)?;
} else { let transfered = transfer_cap(send, send_msg, recv, recv_msg)?;
// do fault transfer
todo!("do_ipc_transfer: fault transfer"); let reply = ReplyInfo::new(ReplyLabel::Message, length, true, transfered, SysError::Ok);
} 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(())
} }

View File

@ -39,7 +39,6 @@ pub struct TcbObject {
vspace: CapEntry, vspace: CapEntry,
// endpoint // endpoint
badge: usize,
buffer: CapEntry, buffer: CapEntry,
fault: Fault, fault: Fault,
@ -63,7 +62,6 @@ 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,
@ -97,14 +95,6 @@ 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)
} }
@ -198,7 +188,6 @@ 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)

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

@ -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, warn}; use log::{error, trace, warn};
use spin::{lazy::Lazy, Mutex}; use spin::{lazy::Lazy, Mutex};
const IRQ_NUM: usize = 32; pub const IRQ_NUM: usize = 32;
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq)]
pub enum IrqState { pub enum IrqState {
@ -50,7 +50,6 @@ 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()));
@ -59,10 +58,31 @@ 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() {
@ -70,30 +90,16 @@ impl IrqManager {
return; return;
} }
let irq = irq.unwrap(); if let Some(irq) = irq
if irq >= IRQ_NUM { && irq < IRQ_NUM
error!("[IrqManager] Invalid IRQ number: {}", irq); && let Ok(mut cap) = EndpointCap::try_from(&self.handler[irq])
IRQ_DRIVER.lock().disable(irq); {
IRQ_DRIVER.lock().complete(irq); trace!("[IrqManager] Dispatching IRQ: {}", irq);
return; cap.do_signal(irq).unwrap();
} 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);
} }
} }

View File

@ -3,11 +3,16 @@ use log::trace;
use uapi::{error::*, syscall::*}; use uapi::{error::*, syscall::*};
macro_rules! assert_length { macro_rules! assert_length {
($info:expr, $len:expr) => { ($info:ident, $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 {
@ -29,17 +34,37 @@ pub fn handle_syscall(tcb: &mut TcbObject) -> SysResult {
_ => (), _ => (),
}; };
let cspace = tcb.cspace()?; assert_length!(info >= 2);
// 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!("handle_syscall: info={:?} cap={:?}", info, cap); trace!("[Syscall] info={:?} cap={:?}", info, cap);
match info.label() { match info.label() {
Syscall::InvokeNtfn => { // Endpoint
assert_length!(info, 2); Syscall::EpSend => {
unimplemented!("[Syscall] InvokeNtfn: {:?}", info.label()); let mut cap = EndpointCap::try_from(cap)?;
cap.do_send(tcb)
}, },
_ => unimplemented!("handle_syscall: {:?}, {:?}", info.label(), cap), Syscall::EpRecv => {
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),
} }
} }

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()
} }

View File

@ -4,12 +4,9 @@ pub enum ObjectType {
CNode = 1, CNode = 1,
TCB = 2, TCB = 2,
Endpoint = 3, Endpoint = 3,
Reply = 4, Frame = 4,
Notification = 5, Table = 5,
Frame = 6, Untyped = 6,
Table = 7,
Interrupt = 8,
Untyped = 9,
} }
impl Default for ObjectType { impl Default for ObjectType {
@ -19,8 +16,9 @@ impl Default for ObjectType {
} }
impl ObjectType { impl ObjectType {
const CNODE_BITS: usize = 6; // 48 bytes const CNODE_BITS: usize = 5; // 32 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)
@ -32,12 +30,9 @@ 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 => 0, // TODO: fill it! ObjectType::Endpoint => Self::ENDPOINT_BITS,
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,
} }
} }

View File

@ -1,6 +1,7 @@
#[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

View File

@ -8,11 +8,20 @@ pub enum Syscall {
Invalid = 0, Invalid = 0,
DebugPutChar = 1, DebugPutChar = 1,
Yield = 2, Yield = 2,
InvokeNtfn = 3,
// Send = 4, // endpoint
// Recv = 5, EpSend = 3,
// Call = 6, EpRecv = 4,
// Reply = 7, IrqSet = 5,
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:
@ -27,9 +36,16 @@ pub enum Syscall {
* > > 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;
@ -38,6 +54,10 @@ 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 |
@ -65,9 +85,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_or(0); let label = label.to_usize().unwrap();
let bits = bits - 1; // stored as n_bits - 1 let bits = bits - 1; // stored as n_bits - 1
let transfer_cap = transfer_cap as usize; let transfer_cap = if transfer_cap { 1 } else { 0 };
assert!(label <= Self::LABEL_MASK); assert!(label <= Self::LABEL_MASK);
assert!(bits <= Self::BITS_MASK); assert!(bits <= Self::BITS_MASK);
@ -117,6 +137,109 @@ 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::InvalidArgument) (info.label() != Syscall::Invalid).then_ok(info, SysError::Invalid)
}
}
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
} }
} }