use core::convert::{TryFrom, TryInto};
#[cfg(feature = "processes-as-threads")]
pub use crate::arch::ProcessArgsAsThread;
use crate::{
CID, CpuID, Error, MemoryAddress, MemoryFlags, MemoryMessage, MemoryRange, MemorySize, MemoryType,
Message, MessageEnvelope, MessageSender, PID, ProcessArgs, ProcessInit, Result, SID, ScalarMessage,
SysCallResult, TID, ThreadInit, pid_from_usize,
};
#[derive(Debug, PartialEq)]
pub enum SysCall {
MapMemory(
Option<MemoryAddress>,
Option<MemoryAddress>,
MemorySize,
MemoryFlags,
),
UnmapMemory(MemoryRange),
SetMemRegion(
PID,
MemoryType,
MemoryAddress,
usize,
),
IncreaseHeap(usize , MemoryFlags),
DecreaseHeap(usize ),
UpdateMemoryFlags(
MemoryRange,
MemoryFlags,
Option<PID>,
),
Yield,
WaitEvent,
ReceiveMessage(SID),
TryReceiveMessage(SID),
ReturnToParent(PID, CpuID),
ClaimInterrupt(
usize,
MemoryAddress,
Option<MemoryAddress>,
),
FreeInterrupt(usize ),
SwitchTo(PID, usize ),
ReadyThreads(PID),
CreateServerWithAddress(SID ),
Connect(SID ),
TryConnect(SID ),
SendMessage(CID, Message),
TrySendMessage(CID, Message),
ReturnMemory(
MessageSender,
MemoryRange,
Option<MemorySize>,
Option<MemorySize>,
),
ReturnScalar1(MessageSender, usize),
ReturnScalar2(MessageSender, usize, usize),
CreateThread(ThreadInit),
CreateProcess(ProcessInit),
TerminateProcess(u32),
Shutdown,
CreateServer,
CreateServerId,
ConnectForProcess(PID, SID),
GetThreadId,
GetProcessId,
DestroyServer(SID),
Disconnect(CID),
JoinThread(TID),
SetExceptionHandler(usize , usize ),
AdjustProcessLimit(
usize,
usize,
usize,
),
#[cfg(feature = "v2p")]
VirtToPhys(usize ),
ReturnScalar5(MessageSender, usize, usize, usize, usize, usize),
ReplyAndReceiveNext(
MessageSender,
usize,
usize,
usize,
usize,
usize,
usize,
),
#[cfg(feature = "v2p")]
VirtToPhysPid(PID , usize ),
#[cfg(feature = "swap")]
RegisterSwapper(u32, u32, u32, u32, usize, usize),
#[cfg(feature = "swap")]
SwapOp(usize, usize, usize, usize, usize, usize, usize),
#[cfg(feature = "raw-trng")]
RawTrng(usize, usize, usize, usize, usize, usize, usize),
PlatformSpecific(usize, usize, usize, usize, usize, usize, usize),
Invalid(usize, usize, usize, usize, usize, usize, usize),
}
pub enum SysCallNumber {
Invalid = 0,
MapMemory = 2,
Yield = 3,
ReturnToParent = 4,
ClaimInterrupt = 5,
FreeInterrupt = 6,
SwitchTo = 7,
ReadyThreads = 8,
WaitEvent = 9,
IncreaseHeap = 10,
DecreaseHeap = 11,
UpdateMemoryFlags = 12,
SetMemRegion = 13,
CreateServerWithAddress = 14,
ReceiveMessage = 15,
SendMessage = 16,
Connect = 17,
CreateThread = 18,
UnmapMemory = 19,
ReturnMemory = 20,
CreateProcess = 21,
TerminateProcess = 22,
Shutdown = 23,
TrySendMessage = 24,
TryConnect = 25,
ReturnScalar1 = 26,
ReturnScalar2 = 27,
TryReceiveMessage = 28,
CreateServer = 29,
ConnectForProcess = 30,
CreateServerId = 31,
GetThreadId = 32,
GetProcessId = 33,
DestroyServer = 34,
Disconnect = 35,
JoinThread = 36,
SetExceptionHandler = 37,
AdjustProcessLimit = 38,
#[cfg(feature = "v2p")]
VirtToPhys = 39,
ReturnScalar5 = 40,
ReplyAndReceiveNext = 41,
#[cfg(feature = "v2p")]
VirtToPhysPid = 42,
#[cfg(feature = "swap")]
RegisterSwapper = 43,
#[cfg(feature = "swap")]
SwapOp = 44,
#[cfg(feature = "raw-trng")]
RawTrng = 45,
PlatformSpecific = 46,
}
impl SysCallNumber {
pub fn from(val: usize) -> SysCallNumber {
use SysCallNumber::*;
match val {
2 => MapMemory,
3 => Yield,
4 => ReturnToParent,
5 => ClaimInterrupt,
6 => FreeInterrupt,
7 => SwitchTo,
8 => ReadyThreads,
9 => WaitEvent,
10 => IncreaseHeap,
11 => DecreaseHeap,
12 => UpdateMemoryFlags,
13 => SetMemRegion,
14 => CreateServerWithAddress,
15 => ReceiveMessage,
16 => SendMessage,
17 => Connect,
18 => CreateThread,
19 => UnmapMemory,
20 => ReturnMemory,
21 => CreateProcess,
22 => TerminateProcess,
23 => Shutdown,
24 => TrySendMessage,
25 => TryConnect,
26 => ReturnScalar1,
27 => ReturnScalar2,
28 => TryReceiveMessage,
29 => CreateServer,
30 => ConnectForProcess,
31 => CreateServerId,
32 => GetThreadId,
33 => GetProcessId,
34 => DestroyServer,
35 => Disconnect,
36 => JoinThread,
37 => SetExceptionHandler,
38 => AdjustProcessLimit,
#[cfg(feature = "v2p")]
39 => VirtToPhys,
40 => ReturnScalar5,
41 => ReplyAndReceiveNext,
#[cfg(feature = "v2p")]
42 => VirtToPhysPid,
#[cfg(feature = "swap")]
43 => RegisterSwapper,
#[cfg(feature = "swap")]
44 => SwapOp,
#[cfg(feature = "raw-trng")]
45 => RawTrng,
46 => PlatformSpecific,
_ => Invalid,
}
}
}
impl SysCall {
fn add_opcode(opcode: SysCallNumber, args: [usize; 7]) -> [usize; 8] {
[opcode as usize, args[0], args[1], args[2], args[3], args[4], args[5], args[6]]
}
pub fn as_args(&self) -> [usize; 8] {
use core::mem;
assert!(
mem::size_of::<SysCall>() == mem::size_of::<usize>() * 8,
"SysCall is not the expected size (expected {}, got {})",
mem::size_of::<usize>() * 8,
mem::size_of::<SysCall>()
);
match self {
SysCall::MapMemory(a1, a2, a3, a4) => [
SysCallNumber::MapMemory as usize,
a1.map(|x| x.get()).unwrap_or_default(),
a2.map(|x| x.get()).unwrap_or_default(),
a3.get(),
a4.bits(),
0,
0,
0,
],
SysCall::UnmapMemory(range) => {
[SysCallNumber::UnmapMemory as usize, range.as_ptr() as usize, range.len(), 0, 0, 0, 0, 0]
}
SysCall::Yield => [SysCallNumber::Yield as usize, 0, 0, 0, 0, 0, 0, 0],
SysCall::WaitEvent => [SysCallNumber::WaitEvent as usize, 0, 0, 0, 0, 0, 0, 0],
SysCall::ReceiveMessage(sid) => {
let s = sid.to_u32();
[SysCallNumber::ReceiveMessage as usize, s.0 as _, s.1 as _, s.2 as _, s.3 as _, 0, 0, 0]
}
SysCall::TryReceiveMessage(sid) => {
let s = sid.to_u32();
[SysCallNumber::TryReceiveMessage as usize, s.0 as _, s.1 as _, s.2 as _, s.3 as _, 0, 0, 0]
}
SysCall::ConnectForProcess(pid, sid) => {
let s = sid.to_u32();
[
SysCallNumber::ConnectForProcess as usize,
pid.get() as _,
s.0 as _,
s.1 as _,
s.2 as _,
s.3 as _,
0,
0,
]
}
SysCall::CreateServerId => [SysCallNumber::CreateServerId as usize, 0, 0, 0, 0, 0, 0, 0],
SysCall::ReturnToParent(a1, a2) => {
[SysCallNumber::ReturnToParent as usize, a1.get() as usize, *a2, 0, 0, 0, 0, 0]
}
SysCall::ClaimInterrupt(a1, a2, a3) => [
SysCallNumber::ClaimInterrupt as usize,
*a1,
a2.get(),
a3.map(|x| x.get()).unwrap_or_default(),
0,
0,
0,
0,
],
SysCall::FreeInterrupt(a1) => [SysCallNumber::FreeInterrupt as usize, *a1, 0, 0, 0, 0, 0, 0],
SysCall::SwitchTo(a1, a2) => {
[SysCallNumber::SwitchTo as usize, a1.get() as usize, *a2, 0, 0, 0, 0, 0]
}
SysCall::ReadyThreads(a1) => {
[SysCallNumber::ReadyThreads as usize, a1.get() as usize, 0, 0, 0, 0, 0, 0]
}
SysCall::IncreaseHeap(a1, a2) => {
[SysCallNumber::IncreaseHeap as usize, *a1, a2.bits(), 0, 0, 0, 0, 0]
}
SysCall::DecreaseHeap(a1) => [SysCallNumber::DecreaseHeap as usize, *a1, 0, 0, 0, 0, 0, 0],
SysCall::UpdateMemoryFlags(a1, a2, a3) => [
SysCallNumber::UpdateMemoryFlags as usize,
a1.as_mut_ptr() as usize,
a1.len(),
a2.bits(),
a3.map(|m| m.get() as usize).unwrap_or(0),
0,
0,
0,
],
SysCall::SetMemRegion(a1, a2, a3, a4) => [
SysCallNumber::SetMemRegion as usize,
a1.get() as usize,
*a2 as usize,
a3.get(),
*a4,
0,
0,
0,
],
SysCall::CreateServerWithAddress(sid) => {
let s = sid.to_u32();
[
SysCallNumber::CreateServerWithAddress as usize,
s.0 as _,
s.1 as _,
s.2 as _,
s.3 as _,
0,
0,
0,
]
}
SysCall::CreateServer => [SysCallNumber::CreateServer as usize, 0, 0, 0, 0, 0, 0, 0],
SysCall::Connect(sid) => {
let s = sid.to_u32();
[SysCallNumber::Connect as usize, s.0 as _, s.1 as _, s.2 as _, s.3 as _, 0, 0, 0]
}
SysCall::SendMessage(a1, ref a2) => match a2 {
Message::MutableBorrow(mm) | Message::Borrow(mm) | Message::Move(mm) => [
SysCallNumber::SendMessage as usize,
*a1 as usize,
a2.message_type(),
mm.id,
mm.buf.as_ptr() as usize,
mm.buf.len(),
mm.offset.map(|x| x.get()).unwrap_or(0),
mm.valid.map(|x| x.get()).unwrap_or(0),
],
Message::Scalar(sc) | Message::BlockingScalar(sc) => [
SysCallNumber::SendMessage as usize,
*a1 as usize,
a2.message_type(),
sc.id,
sc.arg1,
sc.arg2,
sc.arg3,
sc.arg4,
],
},
SysCall::ReturnMemory(sender, buf, offset, valid) => [
SysCallNumber::ReturnMemory as usize,
sender.to_usize(),
buf.as_ptr() as usize,
buf.len(),
offset.map(|o| o.get()).unwrap_or_default(),
valid.map(|v| v.get()).unwrap_or_default(),
0,
0,
],
SysCall::ReplyAndReceiveNext(sender, arg0, arg1, arg2, arg3, arg4, return_type) => [
SysCallNumber::ReplyAndReceiveNext as usize,
sender.to_usize(),
*arg0,
*arg1,
*arg2,
*arg3,
*arg4,
*return_type,
],
SysCall::CreateThread(init) => {
crate::arch::thread_to_args(SysCallNumber::CreateThread as usize, init)
}
SysCall::CreateProcess(init) => Self::add_opcode(SysCallNumber::CreateProcess, init.into()),
SysCall::TerminateProcess(exit_code) => {
[SysCallNumber::TerminateProcess as usize, *exit_code as usize, 0, 0, 0, 0, 0, 0]
}
SysCall::Shutdown => [SysCallNumber::Shutdown as usize, 0, 0, 0, 0, 0, 0, 0],
SysCall::TryConnect(sid) => {
let s = sid.to_u32();
[SysCallNumber::TryConnect as usize, s.0 as _, s.1 as _, s.2 as _, s.3 as _, 0, 0, 0]
}
SysCall::TrySendMessage(a1, ref a2) => match a2 {
Message::MutableBorrow(mm) | Message::Borrow(mm) | Message::Move(mm) => [
SysCallNumber::TrySendMessage as usize,
*a1 as usize,
a2.message_type(),
mm.id,
mm.buf.as_ptr() as usize,
mm.buf.len(),
mm.offset.map(|x| x.get()).unwrap_or(0),
mm.valid.map(|x| x.get()).unwrap_or(0),
],
Message::Scalar(sc) | Message::BlockingScalar(sc) => [
SysCallNumber::TrySendMessage as usize,
*a1 as usize,
a2.message_type(),
sc.id,
sc.arg1,
sc.arg2,
sc.arg3,
sc.arg4,
],
},
SysCall::ReturnScalar1(sender, arg1) => {
[SysCallNumber::ReturnScalar1 as usize, sender.to_usize(), *arg1, 0, 0, 0, 0, 0]
}
SysCall::ReturnScalar2(sender, arg1, arg2) => {
[SysCallNumber::ReturnScalar2 as usize, sender.to_usize(), *arg1, *arg2, 0, 0, 0, 0]
}
SysCall::GetThreadId => [SysCallNumber::GetThreadId as usize, 0, 0, 0, 0, 0, 0, 0],
SysCall::GetProcessId => [SysCallNumber::GetProcessId as usize, 0, 0, 0, 0, 0, 0, 0],
SysCall::DestroyServer(sid) => {
let s = sid.to_u32();
[SysCallNumber::DestroyServer as usize, s.0 as _, s.1 as _, s.2 as _, s.3 as _, 0, 0, 0]
}
SysCall::Disconnect(cid) => [SysCallNumber::Disconnect as usize, *cid as usize, 0, 0, 0, 0, 0, 0],
SysCall::JoinThread(tid) => [SysCallNumber::JoinThread as usize, *tid, 0, 0, 0, 0, 0, 0],
SysCall::SetExceptionHandler(pc, sp) => {
[SysCallNumber::SetExceptionHandler as usize, *pc, *sp, 0, 0, 0, 0, 0]
}
SysCall::AdjustProcessLimit(index, current, new) => {
[SysCallNumber::AdjustProcessLimit as usize, *index, *current, *new, 0, 0, 0, 0]
}
#[cfg(feature = "v2p")]
SysCall::VirtToPhys(vaddr) => [SysCallNumber::VirtToPhys as usize, *vaddr, 0, 0, 0, 0, 0, 0],
SysCall::ReturnScalar5(sender, arg1, arg2, arg3, arg4, arg5) => [
SysCallNumber::ReturnScalar5 as usize,
sender.to_usize(),
*arg1,
*arg2,
*arg3,
*arg4,
*arg5,
0,
],
#[cfg(feature = "v2p")]
SysCall::VirtToPhysPid(pid, vaddr) => {
[SysCallNumber::VirtToPhysPid as usize, pid.get() as usize, *vaddr, 0, 0, 0, 0, 0]
}
#[cfg(feature = "swap")]
SysCall::RegisterSwapper(s0, s1, s2, s3, handler, state) => [
SysCallNumber::RegisterSwapper as usize,
*s0 as usize,
*s1 as usize,
*s2 as usize,
*s3 as usize,
*handler,
*state,
0,
],
#[cfg(feature = "swap")]
SysCall::SwapOp(a1, a2, a3, a4, a5, a6, a7) => {
[SysCallNumber::SwapOp as usize, *a1, *a2, *a3, *a4, *a5, *a6, *a7]
}
#[cfg(feature = "raw-trng")]
SysCall::RawTrng(a1, a2, a3, a4, a5, a6, a7) => {
[SysCallNumber::RawTrng as usize, *a1, *a2, *a3, *a4, *a5, *a6, *a7]
}
SysCall::PlatformSpecific(a1, a2, a3, a4, a5, a6, a7) => {
[SysCallNumber::PlatformSpecific as usize, *a1, *a2, *a3, *a4, *a5, *a6, *a7]
}
SysCall::Invalid(a1, a2, a3, a4, a5, a6, a7) => {
[SysCallNumber::Invalid as usize, *a1, *a2, *a3, *a4, *a5, *a6, *a7]
}
}
}
#[allow(clippy::too_many_arguments)]
pub fn from_args(
a0: usize,
a1: usize,
a2: usize,
a3: usize,
a4: usize,
a5: usize,
a6: usize,
a7: usize,
) -> core::result::Result<Self, Error> {
Ok(match SysCallNumber::from(a0) {
SysCallNumber::MapMemory => SysCall::MapMemory(
MemoryAddress::new(a1),
MemoryAddress::new(a2),
MemoryAddress::new(a3).ok_or(Error::InvalidSyscall)?,
crate::MemoryFlags::from_bits(a4).ok_or(Error::InvalidSyscall)?,
),
SysCallNumber::UnmapMemory => {
SysCall::UnmapMemory(unsafe { MemoryRange::new(a1, a2).or(Err(Error::InvalidSyscall)) }?)
}
SysCallNumber::Yield => SysCall::Yield,
SysCallNumber::WaitEvent => SysCall::WaitEvent,
SysCallNumber::ReceiveMessage => {
SysCall::ReceiveMessage(SID::from_u32(a1 as _, a2 as _, a3 as _, a4 as _))
}
SysCallNumber::TryReceiveMessage => {
SysCall::TryReceiveMessage(SID::from_u32(a1 as _, a2 as _, a3 as _, a4 as _))
}
SysCallNumber::ReturnToParent => SysCall::ReturnToParent(pid_from_usize(a1)?, a2),
SysCallNumber::ClaimInterrupt => SysCall::ClaimInterrupt(
a1,
MemoryAddress::new(a2).ok_or(Error::InvalidSyscall)?,
MemoryAddress::new(a3),
),
SysCallNumber::FreeInterrupt => SysCall::FreeInterrupt(a1),
SysCallNumber::SwitchTo => SysCall::SwitchTo(pid_from_usize(a1)?, a2),
SysCallNumber::ReadyThreads => SysCall::ReadyThreads(pid_from_usize(a1)?),
SysCallNumber::IncreaseHeap => {
SysCall::IncreaseHeap(a1, crate::MemoryFlags::from_bits(a2).ok_or(Error::InvalidSyscall)?)
}
SysCallNumber::DecreaseHeap => SysCall::DecreaseHeap(a1),
SysCallNumber::UpdateMemoryFlags => SysCall::UpdateMemoryFlags(
unsafe { MemoryRange::new(a1, a2) }?,
crate::MemoryFlags::from_bits(a3).ok_or(Error::InvalidSyscall)?,
PID::new(a4 as _),
),
SysCallNumber::SetMemRegion => SysCall::SetMemRegion(
pid_from_usize(a1)?,
MemoryType::from(a2),
MemoryAddress::new(a3).ok_or(Error::InvalidSyscall)?,
a4,
),
SysCallNumber::CreateServerWithAddress => {
SysCall::CreateServerWithAddress(SID::from_u32(a1 as _, a2 as _, a3 as _, a4 as _))
}
SysCallNumber::CreateServer => SysCall::CreateServer,
SysCallNumber::Connect => SysCall::Connect(SID::from_u32(a1 as _, a2 as _, a3 as _, a4 as _)),
SysCallNumber::SendMessage => Message::try_from((a2, a3, a4, a5, a6, a7))
.map(|m| SysCall::SendMessage(a1.try_into().unwrap(), m))
.unwrap_or_else(|_| SysCall::Invalid(a1, a2, a3, a4, a5, a6, a7)),
SysCallNumber::ReturnMemory => SysCall::ReturnMemory(
MessageSender::from_usize(a1),
unsafe { MemoryRange::new(a2, a3) }?,
MemorySize::new(a4),
MemorySize::new(a5),
),
SysCallNumber::ReplyAndReceiveNext => {
SysCall::ReplyAndReceiveNext(MessageSender::from_usize(a1), a2, a3, a4, a5, a6, a7)
}
SysCallNumber::CreateThread => {
SysCall::CreateThread(crate::arch::args_to_thread(a1, a2, a3, a4, a5, a6, a7)?)
}
SysCallNumber::CreateProcess => SysCall::CreateProcess([a1, a2, a3, a4, a5, a6, a7].try_into()?),
SysCallNumber::TerminateProcess => SysCall::TerminateProcess(a1 as u32),
SysCallNumber::Shutdown => SysCall::Shutdown,
SysCallNumber::TryConnect => {
SysCall::TryConnect(SID::from_u32(a1 as _, a2 as _, a3 as _, a4 as _))
}
SysCallNumber::TrySendMessage => match a2 {
1 => SysCall::TrySendMessage(
a1 as u32,
Message::MutableBorrow(MemoryMessage {
id: a3,
buf: unsafe { MemoryRange::new(a4, a5) }?,
offset: MemoryAddress::new(a6),
valid: MemorySize::new(a7),
}),
),
2 => SysCall::TrySendMessage(
a1 as u32,
Message::Borrow(MemoryMessage {
id: a3,
buf: unsafe { MemoryRange::new(a4, a5) }?,
offset: MemoryAddress::new(a6),
valid: MemorySize::new(a7),
}),
),
3 => SysCall::TrySendMessage(
a1 as u32,
Message::Move(MemoryMessage {
id: a3,
buf: unsafe { MemoryRange::new(a4, a5) }?,
offset: MemoryAddress::new(a6),
valid: MemorySize::new(a7),
}),
),
4 => SysCall::TrySendMessage(
a1 as u32,
Message::Scalar(ScalarMessage { id: a3, arg1: a4, arg2: a5, arg3: a6, arg4: a7 }),
),
5 => SysCall::TrySendMessage(
a1.try_into().unwrap(),
Message::BlockingScalar(ScalarMessage { id: a3, arg1: a4, arg2: a5, arg3: a6, arg4: a7 }),
),
_ => SysCall::Invalid(a1, a2, a3, a4, a5, a6, a7),
},
SysCallNumber::ReturnScalar1 => SysCall::ReturnScalar1(MessageSender::from_usize(a1), a2),
SysCallNumber::ReturnScalar2 => SysCall::ReturnScalar2(MessageSender::from_usize(a1), a2, a3),
SysCallNumber::ConnectForProcess => SysCall::ConnectForProcess(
PID::new(a1 as _).ok_or(Error::InvalidSyscall)?,
SID::from_u32(a2 as _, a3 as _, a4 as _, a5 as _),
),
SysCallNumber::CreateServerId => SysCall::CreateServerId,
SysCallNumber::GetThreadId => SysCall::GetThreadId,
SysCallNumber::GetProcessId => SysCall::GetProcessId,
SysCallNumber::DestroyServer => {
SysCall::DestroyServer(SID::from_u32(a1 as _, a2 as _, a3 as _, a4 as _))
}
SysCallNumber::Disconnect => SysCall::Disconnect(a1 as _),
SysCallNumber::JoinThread => SysCall::JoinThread(a1 as _),
SysCallNumber::SetExceptionHandler => SysCall::SetExceptionHandler(a1 as _, a2 as _),
SysCallNumber::AdjustProcessLimit => SysCall::AdjustProcessLimit(a1, a2, a3),
#[cfg(feature = "v2p")]
SysCallNumber::VirtToPhys => SysCall::VirtToPhys(a1 as _),
#[cfg(feature = "v2p")]
SysCallNumber::VirtToPhysPid => SysCall::VirtToPhysPid(pid_from_usize(a1)?, a2 as _),
SysCallNumber::ReturnScalar5 => {
SysCall::ReturnScalar5(MessageSender::from_usize(a1), a2, a3, a4, a5, a6)
}
#[cfg(feature = "swap")]
SysCallNumber::RegisterSwapper => {
SysCall::RegisterSwapper(a1 as u32, a2 as u32, a3 as u32, a4 as u32, a5 as usize, a6 as usize)
}
#[cfg(feature = "swap")]
SysCallNumber::SwapOp => SysCall::SwapOp(a1, a2, a3, a4, a5, a6, a7),
#[cfg(feature = "raw-trng")]
SysCallNumber::RawTrng => SysCall::RawTrng(a1, a2, a3, a4, a5, a6, a7),
SysCallNumber::PlatformSpecific => SysCall::PlatformSpecific(a1, a2, a3, a4, a5, a6, a7),
SysCallNumber::Invalid => SysCall::Invalid(a1, a2, a3, a4, a5, a6, a7),
})
}
pub fn has_memory(&self) -> bool {
match self {
SysCall::TrySendMessage(_, msg) | SysCall::SendMessage(_, msg) => {
matches!(msg, Message::Move(_) | Message::Borrow(_) | Message::MutableBorrow(_))
}
SysCall::ReturnMemory(_, _, _, _) => true,
SysCall::ReplyAndReceiveNext(_, _, _, _, _, _, usize::MAX) => true,
_ => false,
}
}
pub fn is_move(&self) -> bool {
match self {
SysCall::TrySendMessage(_, msg) | SysCall::SendMessage(_, msg) => {
matches!(msg, Message::Move(_))
}
_ => false,
}
}
pub fn is_borrow(&self) -> bool {
match self {
SysCall::TrySendMessage(_, msg) | SysCall::SendMessage(_, msg) => {
matches!(msg, Message::Borrow(_))
}
_ => false,
}
}
pub fn is_mutableborrow(&self) -> bool {
match self {
SysCall::TrySendMessage(_, msg) | SysCall::SendMessage(_, msg) => {
matches!(msg, Message::MutableBorrow(_))
}
_ => false,
}
}
pub fn is_return_memory(&self) -> bool {
matches!(self, SysCall::ReturnMemory(..) | SysCall::ReplyAndReceiveNext(_, _, _, _, _, _, usize::MAX))
}
pub fn memory(&self) -> Option<MemoryRange> {
match self {
SysCall::TrySendMessage(_, msg) | SysCall::SendMessage(_, msg) => match msg {
Message::Move(memory_message)
| Message::Borrow(memory_message)
| Message::MutableBorrow(memory_message) => Some(memory_message.buf),
_ => None,
},
SysCall::ReturnMemory(_, range, _, _) => Some(*range),
SysCall::ReplyAndReceiveNext(_, _, a1, a2, _, _, usize::MAX) => unsafe {
MemoryRange::new(*a1, *a2).ok()
},
_ => None,
}
}
pub unsafe fn replace_memory(&mut self, new: MemoryRange) {
match self {
SysCall::TrySendMessage(_, msg) | SysCall::SendMessage(_, msg) => match msg {
Message::Move(memory_message)
| Message::Borrow(memory_message)
| Message::MutableBorrow(memory_message) => memory_message.buf = new,
_ => (),
},
SysCall::ReturnMemory(_, range, _, _) => *range = new,
SysCall::ReplyAndReceiveNext(_, _, a1, a2, _, _, usize::MAX) => {
*a1 = new.addr.get();
*a2 = new.size.get();
}
_ => (),
}
}
pub fn can_call_from_interrupt(&self) -> bool {
if let SysCall::TrySendMessage(_cid, msg) = self {
return !msg.is_blocking();
}
#[cfg(feature = "swap")]
if let SysCall::SwapOp(_, _, _, _, _, _, _) = self {
return true;
}
matches!(
self,
SysCall::TryConnect(_)
| SysCall::FreeInterrupt(_)
| SysCall::ClaimInterrupt(_, _, _)
| SysCall::TryReceiveMessage(_)
| SysCall::ReturnToParent(_, _)
| SysCall::ReturnScalar5(_, _, _, _, _, _)
| SysCall::ReturnScalar2(_, _, _)
| SysCall::ReturnScalar1(_, _)
| SysCall::ReturnMemory(_, _, _, _)
)
}
}
pub fn map_memory(
phys: Option<MemoryAddress>,
virt: Option<MemoryAddress>,
size: usize,
flags: MemoryFlags,
) -> core::result::Result<MemoryRange, Error> {
crate::arch::map_memory_pre(&phys, &virt, size, flags)?;
let result =
rsyscall(SysCall::MapMemory(phys, virt, MemorySize::new(size).ok_or(Error::InvalidSyscall)?, flags))?;
if let Result::MemoryRange(range) = result {
Ok(crate::arch::map_memory_post(phys, virt, size, flags, range)?)
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn unmap_memory(range: MemoryRange) -> core::result::Result<(), Error> {
crate::arch::unmap_memory_pre(&range)?;
let result = rsyscall(SysCall::UnmapMemory(range))?;
if let crate::Result::Ok = result {
crate::arch::unmap_memory_post(range)?;
Ok(())
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn update_memory_flags(range: MemoryRange, flags: MemoryFlags) -> core::result::Result<Result, Error> {
let result = rsyscall(SysCall::UpdateMemoryFlags(range, flags, None))?;
if let Result::Ok = result {
Ok(Result::Ok)
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn return_memory(sender: MessageSender, mem: MemoryRange) -> core::result::Result<(), Error> {
let result = rsyscall(SysCall::ReturnMemory(sender, mem, None, None))?;
if let crate::Result::Ok = result {
Ok(())
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn return_memory_offset(
sender: MessageSender,
mem: MemoryRange,
offset: Option<MemorySize>,
) -> core::result::Result<(), Error> {
let result = rsyscall(SysCall::ReturnMemory(sender, mem, offset, None))?;
if let crate::Result::Ok = result {
Ok(())
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn return_memory_offset_valid(
sender: MessageSender,
mem: MemoryRange,
offset: Option<MemorySize>,
valid: Option<MemorySize>,
) -> core::result::Result<(), Error> {
let result = rsyscall(SysCall::ReturnMemory(sender, mem, offset, valid))?;
if let crate::Result::Ok = result {
Ok(())
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn return_scalar(sender: MessageSender, val: usize) -> core::result::Result<(), Error> {
let result = rsyscall(SysCall::ReturnScalar1(sender, val))?;
if let crate::Result::Ok = result {
Ok(())
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn return_scalar2(sender: MessageSender, val1: usize, val2: usize) -> core::result::Result<(), Error> {
let result = rsyscall(SysCall::ReturnScalar2(sender, val1, val2))?;
if let crate::Result::Ok = result {
Ok(())
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn return_scalar5(
sender: MessageSender,
val1: usize,
val2: usize,
val3: usize,
val4: usize,
val5: usize,
) -> core::result::Result<(), Error> {
let result = rsyscall(SysCall::ReturnScalar5(sender, val1, val2, val3, val4, val5))?;
if let crate::Result::Ok = result {
Ok(())
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn claim_interrupt(
irq_no: usize,
callback: fn(irq_no: usize, arg: *mut usize),
arg: *mut usize,
) -> core::result::Result<(), Error> {
let result = rsyscall(SysCall::ClaimInterrupt(
irq_no,
MemoryAddress::new(callback as *mut usize as usize).ok_or(Error::InvalidSyscall)?,
MemoryAddress::new(arg as *mut usize as usize),
))?;
if let crate::Result::Ok = result {
Ok(())
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn create_server_with_address(name_bytes: &[u8; 16]) -> core::result::Result<SID, Error> {
let sid = SID::from_bytes(name_bytes).ok_or(Error::InvalidString)?;
let result = rsyscall(SysCall::CreateServerWithAddress(sid))?;
if let Result::NewServerID(sid, _cid) = result {
Ok(sid)
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn create_server_with_sid(sid: SID) -> core::result::Result<SID, Error> {
let result = rsyscall(SysCall::CreateServerWithAddress(sid))?;
if let Result::NewServerID(sid, _cid) = result {
Ok(sid)
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn create_server() -> core::result::Result<SID, Error> {
let result = rsyscall(SysCall::CreateServer)?;
if let Result::NewServerID(sid, _cid) = result {
Ok(sid)
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn create_server_id() -> core::result::Result<SID, Error> {
let result = rsyscall(SysCall::CreateServerId)?;
if let Result::ServerID(sid) = result {
Ok(sid)
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn connect(server: SID) -> core::result::Result<CID, Error> {
let result = rsyscall(SysCall::Connect(server))?;
if let Result::ConnectionID(cid) = result {
Ok(cid)
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn try_connect(server: SID) -> core::result::Result<CID, Error> {
let result = rsyscall(SysCall::TryConnect(server))?;
if let Result::ConnectionID(cid) = result {
Ok(cid)
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn receive_message(server: SID) -> core::result::Result<MessageEnvelope, Error> {
let result = rsyscall(SysCall::ReceiveMessage(server)).expect("Couldn't call ReceiveMessage");
if let Result::MessageEnvelope(envelope) = result {
Ok(envelope)
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn try_receive_message(server: SID) -> core::result::Result<Option<MessageEnvelope>, Error> {
let result = rsyscall(SysCall::TryReceiveMessage(server)).expect("Couldn't call ReceiveMessage");
if let Result::MessageEnvelope(envelope) = result {
Ok(Some(envelope))
} else if result == Result::None {
Ok(None)
} else if let Result::Error(e) = result {
Err(e)
} else {
Err(Error::InternalError)
}
}
pub fn try_send_message(connection: CID, message: Message) -> core::result::Result<Result, Error> {
let result = rsyscall(SysCall::TrySendMessage(connection, message));
match result {
Ok(Result::Ok) => Ok(Result::Ok),
Ok(Result::Scalar1(a)) => Ok(Result::Scalar1(a)),
Ok(Result::Scalar2(a, b)) => Ok(Result::Scalar2(a, b)),
Ok(Result::Scalar5(a, b, c, d, e)) => Ok(Result::Scalar5(a, b, c, d, e)),
Ok(Result::MemoryReturned(offset, valid)) => Ok(Result::MemoryReturned(offset, valid)),
Ok(Result::MessageEnvelope(msg)) => Ok(Result::MessageEnvelope(msg)),
Err(e) => Err(e),
v => panic!("Unexpected return value: {:?}", v),
}
}
pub fn connect_for_process(pid: PID, sid: SID) -> core::result::Result<Result, Error> {
let result = rsyscall(SysCall::ConnectForProcess(pid, sid));
match result {
Ok(Result::ConnectionID(cid)) => Ok(Result::ConnectionID(cid)),
Err(e) => Err(e),
v => panic!("Unexpected return value: {:?}", v),
}
}
pub fn send_message(connection: CID, message: Message) -> core::result::Result<Result, Error> {
let result = rsyscall(SysCall::SendMessage(connection, message));
match result {
Ok(Result::Ok) => Ok(Result::Ok),
Ok(Result::Scalar1(a)) => Ok(Result::Scalar1(a)),
Ok(Result::Scalar2(a, b)) => Ok(Result::Scalar2(a, b)),
Ok(Result::Scalar5(a, b, c, d, e)) => Ok(Result::Scalar5(a, b, c, d, e)),
Ok(Result::MemoryReturned(offset, valid)) => Ok(Result::MemoryReturned(offset, valid)),
Err(e) => Err(e),
v => panic!("Unexpected return value: {:?}", v),
}
}
pub fn terminate_process(exit_code: u32) -> ! {
rsyscall(SysCall::TerminateProcess(exit_code)).expect("terminate_process returned an error");
panic!("process didn't terminate");
}
pub fn yield_slice() { rsyscall(SysCall::Yield).ok(); }
pub fn wait_event() { rsyscall(SysCall::WaitEvent).ok(); }
#[deprecated(since = "0.2.0", note = "Please use create_thread_n() or create_thread()")]
pub fn create_thread_simple<T, U>(
f: fn(T) -> U,
arg: T,
) -> core::result::Result<crate::arch::WaitHandle<U>, Error>
where
T: Send + 'static,
U: Send + 'static,
{
let thread_info = crate::arch::create_thread_simple_pre(&f, &arg)?;
rsyscall(SysCall::CreateThread(thread_info)).and_then(|result| {
if let Result::ThreadID(thread_id) = result {
crate::arch::create_thread_simple_post(f, arg, thread_id)
} else {
Err(Error::InternalError)
}
})
}
pub fn create_thread_0<T>(f: fn() -> T) -> core::result::Result<crate::arch::WaitHandle<T>, Error>
where
T: Send + 'static,
{
let thread_info = crate::arch::create_thread_0_pre(&f)?;
rsyscall(SysCall::CreateThread(thread_info)).and_then(|result| {
if let Result::ThreadID(thread_id) = result {
crate::arch::create_thread_0_post(f, thread_id)
} else {
Err(Error::InternalError)
}
})
}
pub fn create_thread_1<T>(
f: fn(usize) -> T,
arg1: usize,
) -> core::result::Result<crate::arch::WaitHandle<T>, Error>
where
T: Send + 'static,
{
let thread_info = crate::arch::create_thread_1_pre(&f, &arg1)?;
rsyscall(SysCall::CreateThread(thread_info)).and_then(|result| {
if let Result::ThreadID(thread_id) = result {
crate::arch::create_thread_1_post(f, arg1, thread_id)
} else {
Err(Error::InternalError)
}
})
}
pub fn create_thread_2<T>(
f: fn(usize, usize) -> T,
arg1: usize,
arg2: usize,
) -> core::result::Result<crate::arch::WaitHandle<T>, Error>
where
T: Send + 'static,
{
let thread_info = crate::arch::create_thread_2_pre(&f, &arg1, &arg2)?;
rsyscall(SysCall::CreateThread(thread_info)).and_then(|result| {
if let Result::ThreadID(thread_id) = result {
crate::arch::create_thread_2_post(f, arg1, arg2, thread_id)
} else {
Err(Error::InternalError)
}
})
}
pub fn create_thread_3<T>(
f: fn(usize, usize, usize) -> T,
arg1: usize,
arg2: usize,
arg3: usize,
) -> core::result::Result<crate::arch::WaitHandle<T>, Error>
where
T: Send + 'static,
{
let thread_info = crate::arch::create_thread_3_pre(&f, &arg1, &arg2, &arg3)?;
rsyscall(SysCall::CreateThread(thread_info)).and_then(|result| {
if let Result::ThreadID(thread_id) = result {
crate::arch::create_thread_3_post(f, arg1, arg2, arg3, thread_id)
} else {
Err(Error::InternalError)
}
})
}
pub fn create_thread_4<T>(
f: fn(usize, usize, usize, usize) -> T,
arg1: usize,
arg2: usize,
arg3: usize,
arg4: usize,
) -> core::result::Result<crate::arch::WaitHandle<T>, Error>
where
T: Send + 'static,
{
let thread_info = crate::arch::create_thread_4_pre(&f, &arg1, &arg2, &arg3, &arg4)?;
rsyscall(SysCall::CreateThread(thread_info)).and_then(|result| {
if let Result::ThreadID(thread_id) = result {
crate::arch::create_thread_4_post(f, arg1, arg2, arg3, arg4, thread_id)
} else {
Err(Error::InternalError)
}
})
}
pub fn create_thread<F, T>(f: F) -> core::result::Result<crate::arch::WaitHandle<T>, Error>
where
F: FnOnce() -> T,
F: Send + 'static,
T: Send + 'static,
{
let thread_info = crate::arch::create_thread_pre(&f)?;
rsyscall(SysCall::CreateThread(thread_info)).and_then(|result| {
if let Result::ThreadID(thread_id) = result {
crate::arch::create_thread_post(f, thread_id)
} else {
Err(Error::InternalError)
}
})
}
pub fn wait_thread<T>(joiner: crate::arch::WaitHandle<T>) -> SysCallResult {
crate::arch::wait_thread(joiner)
}
#[cfg(feature = "processes-as-threads")]
pub fn create_process_as_thread<F>(
args: ProcessArgsAsThread<F>,
) -> core::result::Result<crate::arch::ProcessHandleAsThread, Error>
where
F: FnOnce() + Send + 'static,
{
let process_init = crate::arch::create_process_pre_as_thread(&args)?;
rsyscall(SysCall::CreateProcess(process_init)).and_then(|result| {
if let Result::NewProcess(startup) = result {
crate::arch::create_process_post_as_thread(args, process_init, startup)
} else {
Err(Error::InternalError)
}
})
}
#[cfg(feature = "processes-as-threads")]
pub fn wait_process_as_thread(joiner: crate::arch::ProcessHandleAsThread) -> SysCallResult {
crate::arch::wait_process_as_thread(joiner)
}
pub fn create_process(args: ProcessArgs) -> core::result::Result<crate::arch::ProcessHandle, Error> {
let process_init = crate::arch::create_process_pre(&args)?;
rsyscall(SysCall::CreateProcess(process_init)).and_then(|result| {
if let Result::NewProcess(startup) = result {
crate::arch::create_process_post(args, process_init, startup)
} else {
Err(Error::InternalError)
}
})
}
pub fn wait_process(joiner: crate::arch::ProcessHandle) -> SysCallResult { crate::arch::wait_process(joiner) }
pub fn current_pid() -> core::result::Result<PID, Error> {
rsyscall(SysCall::GetProcessId).and_then(|result| {
if let Result::ProcessID(pid) = result { Ok(pid) } else { Err(Error::InternalError) }
})
}
pub fn current_tid() -> core::result::Result<TID, Error> {
rsyscall(SysCall::GetThreadId).and_then(|result| {
if let Result::ThreadID(tid) = result { Ok(tid) } else { Err(Error::InternalError) }
})
}
pub fn destroy_server(sid: SID) -> core::result::Result<(), Error> {
rsyscall(SysCall::DestroyServer(sid))
.and_then(|result| if let Result::Ok = result { Ok(()) } else { Err(Error::InternalError) })
}
pub unsafe fn disconnect(cid: CID) -> core::result::Result<(), Error> {
rsyscall(SysCall::Disconnect(cid))
.and_then(|result| if let Result::Ok = result { Ok(()) } else { Err(Error::InternalError) })
}
pub fn join_thread(tid: TID) -> core::result::Result<usize, Error> {
rsyscall(SysCall::JoinThread(tid)).and_then(|result| {
if let Result::Scalar1(val) = result {
Ok(val)
} else if let Result::Error(Error::ThreadNotAvailable) = result {
Err(Error::ThreadNotAvailable)
} else {
Err(Error::InternalError)
}
})
}
pub fn reply_and_receive_next(
server: SID,
msg: &mut Option<MessageEnvelope>,
) -> core::result::Result<(), crate::Error> {
reply_and_receive_next_legacy(server, msg, &mut 0)
}
pub fn reply_and_receive_next_legacy(
server: SID,
msg: &mut Option<MessageEnvelope>,
return_type: &mut usize,
) -> core::result::Result<(), crate::Error> {
let mut rt = *return_type;
*return_type = 0;
if let Some(envelope) = msg.take() {
if !envelope.body.is_blocking() {
*msg = Some(receive_message(server)?);
return Ok(());
}
let args = if let Some(mem) = envelope.body.memory_message() {
rt = usize::MAX;
mem.to_usize()
} else if let Some(scalar) = envelope.body.scalar_message() {
scalar.to_usize()
} else {
panic!("unrecognized message type")
};
let sender = envelope.sender;
core::mem::forget(envelope);
let call = SysCall::ReplyAndReceiveNext(sender, args[0], args[1], args[2], args[3], args[4], rt);
match rsyscall(call) {
Ok(crate::Result::MessageEnvelope(envelope)) => {
*msg = Some(envelope);
Ok(())
}
Ok(crate::Result::Error(e)) => Err(e),
_ => Err(crate::Error::InternalError),
}
} else {
*msg = Some(receive_message(server)?);
Ok(())
}
}
#[cfg(feature = "v2p")]
pub fn virt_to_phys(va: usize) -> core::result::Result<usize, Error> {
rsyscall(SysCall::VirtToPhys(va))
.and_then(|result| if let Result::Scalar1(pa) = result { Ok(pa) } else { Err(Error::BadAddress) })
}
#[cfg(feature = "v2p")]
pub fn virt_to_phys_pid(pid: PID, va: usize) -> core::result::Result<usize, Error> {
rsyscall(SysCall::VirtToPhysPid(pid, va))
.and_then(|result| if let Result::Scalar1(pa) = result { Ok(pa) } else { Err(Error::BadAddress) })
}
pub fn increase_heap(bytes: usize, flags: MemoryFlags) -> core::result::Result<MemoryRange, ()> {
let res = crate::arch::syscall(SysCall::IncreaseHeap(bytes, flags));
if let Ok(Result::MemoryRange(range)) = res {
return Ok(range);
}
Err(())
}
pub fn rsyscall(call: SysCall) -> SysCallResult { crate::arch::syscall(call) }