use core::mem::MaybeUninit;
use moa_uapi::{
channel::{ChanHandle, ChannelFlags, ConnId, ConnInfo, MsgInfo, RcvId, ReplyRecvArgs},
error::{
ERR_CHANNEL_CLOSED, ERR_CLIENT_GONE, ERR_FAULT, ERR_INVAL, ERR_NO_RESOURCE, ERR_NOT_FOUND,
ERR_PERM, ERR_TIMEOUT,
},
sysnr::{
SYSNR_CHANNEL_CLOSE, SYSNR_CHANNEL_CREATE, SYSNR_CONNECT_INFO, SYSNR_CONNECT_REJECT,
SYSNR_MSG_INFO, SYSNR_MSG_READ, SYSNR_MSG_WRITE, SYSNR_RECV, SYSNR_REPLY_RECV,
SYSNR_REPLYV,
},
types::{IoVec, Timeout},
};
pub type Result<T> = core::result::Result<T, ChannelError>;
define_syscall_error! {
pub enum ChannelError {
Perm = ERR_PERM,
NotFound = ERR_NOT_FOUND,
Inval = ERR_INVAL,
NoResource = ERR_NO_RESOURCE,
Fault = ERR_FAULT,
Timeout = ERR_TIMEOUT,
ChannelClosed = ERR_CHANNEL_CLOSED,
ClientGone = ERR_CLIENT_GONE,
}
}
pub fn channel_create(flags: ChannelFlags, pulse_depth: u32) -> Result<ChanHandle> {
let ret = unsafe {
super::arch::syscall2(SYSNR_CHANNEL_CREATE, flags.bits() as usize, pulse_depth as usize)
};
if ret < 0 { Err(ChannelError::from_raw(ret)) } else { Ok(ChanHandle::from_raw(ret as u32)) }
}
pub fn channel_close(chan: ChanHandle) -> Result<()> {
let ret = unsafe { super::arch::syscall1(SYSNR_CHANNEL_CLOSE, chan.raw() as usize) };
if ret < 0 { Err(ChannelError::from_raw(ret)) } else { Ok(()) }
}
pub fn recv(
chan: ChanHandle,
iov: &mut [IoVec],
timeout: Timeout,
info: Option<&mut MsgInfo>,
) -> Result<RcvId> {
let info_ptr = match info {
Some(p) => p as *mut MsgInfo as usize,
None => 0,
};
let ret = unsafe {
super::arch::syscall5(
SYSNR_RECV,
chan.raw() as usize,
iov.as_mut_ptr() as usize,
iov.len(),
timeout.raw() as usize,
info_ptr,
)
};
if ret < 0 { Err(ChannelError::from_raw(ret)) } else { Ok(RcvId::from_raw(ret as usize)) }
}
pub fn replyv(rcvid: RcvId, status: u32, iov: &[IoVec]) -> Result<()> {
let ret = unsafe {
super::arch::syscall4(
SYSNR_REPLYV,
rcvid.raw(),
status as usize,
iov.as_ptr() as usize,
iov.len(),
)
};
if ret < 0 { Err(ChannelError::from_raw(ret)) } else { Ok(()) }
}
pub fn reply_recv(
chan: ChanHandle,
rcvid: RcvId,
status: u32,
reply_iov: &[IoVec],
recv_iov: &mut [IoVec],
timeout: Timeout,
info: Option<&mut MsgInfo>,
) -> Result<RcvId> {
let args = ReplyRecvArgs {
chan,
rcvid,
status,
reply_iov: reply_iov.as_ptr(),
reply_parts: reply_iov.len() as u32,
recv_iov: recv_iov.as_mut_ptr(),
recv_parts: recv_iov.len() as u32,
timeout,
info: match info {
Some(p) => p as *mut MsgInfo,
None => core::ptr::null_mut(),
},
};
let ret = unsafe { super::arch::syscall1(SYSNR_REPLY_RECV, &raw const args as usize) };
if ret < 0 { Err(ChannelError::from_raw(ret)) } else { Ok(RcvId::from_raw(ret as usize)) }
}
pub fn msg_read(rcvid: RcvId, offset: usize, buf: &mut [u8]) -> Result<usize> {
let ret = unsafe {
super::arch::syscall4(
SYSNR_MSG_READ,
rcvid.raw(),
buf.as_mut_ptr() as usize,
offset,
buf.len(),
)
};
if ret < 0 { Err(ChannelError::from_raw(ret)) } else { Ok(ret as usize) }
}
pub fn msg_write(rcvid: RcvId, offset: usize, data: &[u8]) -> Result<usize> {
let ret = unsafe {
super::arch::syscall4(
SYSNR_MSG_WRITE,
rcvid.raw(),
data.as_ptr() as usize,
offset,
data.len(),
)
};
if ret < 0 { Err(ChannelError::from_raw(ret)) } else { Ok(ret as usize) }
}
pub fn msg_info(rcvid: RcvId) -> Result<MsgInfo> {
let mut info = MaybeUninit::<MsgInfo>::uninit();
let ret =
unsafe { super::arch::syscall2(SYSNR_MSG_INFO, rcvid.raw(), info.as_mut_ptr() as usize) };
if ret < 0 { Err(ChannelError::from_raw(ret)) } else { Ok(unsafe { info.assume_init() }) }
}
pub fn connect_info(connid: ConnId) -> Result<ConnInfo> {
let mut info = MaybeUninit::<ConnInfo>::uninit();
let ret = unsafe {
super::arch::syscall2(SYSNR_CONNECT_INFO, connid.raw() as usize, info.as_mut_ptr() as usize)
};
if ret < 0 { Err(ChannelError::from_raw(ret)) } else { Ok(unsafe { info.assume_init() }) }
}
pub fn connect_reject(connid: ConnId) -> Result<()> {
let ret = unsafe { super::arch::syscall1(SYSNR_CONNECT_REJECT, connid.raw() as usize) };
if ret < 0 { Err(ChannelError::from_raw(ret)) } else { Ok(()) }
}