use crate::arch;
use crate::arch::process::Process as ArchProcess;
use crate::irq::interrupt_claim;
use crate::mem::{MemoryManager, PAGE_SIZE};
use crate::server::{SenderID, WaitingMessage};
use crate::services::SystemServices;
use xous_kernel::*;
static mut SWITCHTO_CALLER: Option<(PID, TID)> = None;
#[derive(PartialEq)]
enum ExecutionType {
Blocking,
NonBlocking,
}
#[cfg(baremetal)]
pub fn reset_switchto_caller() {
unsafe { SWITCHTO_CALLER = None };
}
fn retry_syscall(pid: PID, tid: TID) -> SysCallResult {
if cfg!(baremetal) {
arch::process::Process::with_current_mut(|p| p.retry_instruction(tid))?;
do_yield(pid, tid)
} else {
Ok(xous_kernel::Result::RetryCall)
}
}
fn do_yield(_pid: PID, tid: TID) -> SysCallResult {
if !cfg!(baremetal) {
return Ok(xous_kernel::Result::Ok);
}
let (parent_pid, parent_ctx) = unsafe {
SWITCHTO_CALLER
.take()
.expect("yielded when no parent context was present")
};
SystemServices::with_mut(|ss| {
ss.activate_process_thread(tid, parent_pid, parent_ctx, true)
.map(|_| Ok(xous_kernel::Result::ResumeProcess))
.unwrap_or(Err(xous_kernel::Error::ProcessNotFound))
})
}
fn send_message(pid: PID, tid: TID, cid: CID, message: Message) -> SysCallResult {
SystemServices::with_mut(|ss| {
let sidx = ss
.sidx_from_cid(cid)
.ok_or(xous_kernel::Error::ServerNotFound)?;
let server_pid = ss
.server_from_sidx(sidx)
.expect("server couldn't be located")
.pid;
let client_address = match &message {
Message::Scalar(_) | Message::BlockingScalar(_) => None,
Message::Move(msg) | Message::MutableBorrow(msg) | Message::Borrow(msg) => {
MemoryAddress::new(msg.buf.as_ptr() as _)
}
};
let blocking = message.is_blocking();
let message = match message {
Message::Scalar(_) | Message::BlockingScalar(_) => message,
Message::Move(msg) => {
let new_virt = ss.send_memory(
msg.buf.as_mut_ptr() as *mut usize,
server_pid,
core::ptr::null_mut(),
msg.buf.len(),
)?;
Message::Move(MemoryMessage {
id: msg.id,
buf: unsafe { MemoryRange::new(new_virt as usize, msg.buf.len()) }?,
offset: msg.offset,
valid: msg.valid,
})
}
Message::MutableBorrow(msg) => {
let new_virt = ss.lend_memory(
msg.buf.as_mut_ptr() as *mut usize,
server_pid,
core::ptr::null_mut(),
msg.buf.len(),
true,
)?;
Message::MutableBorrow(MemoryMessage {
id: msg.id,
buf: unsafe { MemoryRange::new(new_virt as usize, msg.buf.len()) }?,
offset: msg.offset,
valid: msg.valid,
})
}
Message::Borrow(msg) => {
let new_virt = ss.lend_memory(
msg.buf.as_mut_ptr() as *mut usize,
server_pid,
core::ptr::null_mut(),
msg.buf.len(),
false,
)?;
Message::Borrow(MemoryMessage {
id: msg.id,
buf: unsafe { MemoryRange::new(new_virt as usize, msg.buf.len()) }?,
offset: msg.offset,
valid: msg.valid,
})
}
};
let server = ss
.server_from_sidx_mut(sidx)
.expect("server couldn't be located");
if let Some(server_tid) = server.take_available_thread() {
let sender_idx = if message.is_blocking() {
ss.remember_server_message(sidx, pid, tid, &message, client_address)
.map_err(|e| {
klog!("error remembering server message: {:?}", e);
ss.server_from_sidx_mut(sidx)
.expect("server couldn't be located")
.return_available_thread(server_tid);
e
})?
} else {
0
};
let sender = SenderID::new(sidx, sender_idx, Some(pid));
klog!(
"server connection data: sidx: {}, idx: {}, server pid: {}",
sidx,
sender_idx,
server_pid
);
let envelope = MessageEnvelope {
sender: sender.into(),
body: message,
};
#[cfg(target_os = "xous")]
ss.ready_thread(server_pid, server_tid).map_err(|e| {
ss.server_from_sidx_mut(sidx)
.expect("server couldn't be located")
.return_available_thread(server_tid);
e
})?;
let runnable = ss
.runnable(server_pid, Some(server_tid))
.expect("server doesn't exist");
return if blocking && cfg!(baremetal) {
if !runnable {
let (ppid, ptid) = unsafe { SWITCHTO_CALLER.take().unwrap() };
klog!("Activating Server parent process (server is blocked) and switching away from Client");
ss.set_thread_result(
server_pid,
server_tid,
xous_kernel::Result::MessageEnvelope(envelope),
)
.expect("couldn't set result for server thread");
ss.activate_process_thread(tid, ppid, ptid, false)
.map(|_| Ok(xous_kernel::Result::ResumeProcess))
.unwrap_or(Err(xous_kernel::Error::ProcessNotFound))
} else {
klog!("Activating Server context and switching away from Client");
ss.activate_process_thread(tid, server_pid, server_tid, false)
.map(|_| Ok(xous_kernel::Result::MessageEnvelope(envelope)))
.unwrap_or(Err(xous_kernel::Error::ProcessNotFound))
}
} else if blocking && !cfg!(baremetal) {
klog!("Blocking client, since it sent a blocking message");
ss.unschedule_thread(pid, tid)?;
ss.switch_to_thread(server_pid, Some(server_tid))?;
ss.set_thread_result(
server_pid,
server_tid,
xous_kernel::Result::MessageEnvelope(envelope),
)
.map(|_| xous_kernel::Result::BlockedProcess)
} else if cfg!(baremetal) {
klog!("Setting the return value of the Server ({}:{}) to {:?} and returning to Client",
server_pid, server_tid, envelope);
ss.set_thread_result(
server_pid,
server_tid,
xous_kernel::Result::MessageEnvelope(envelope),
)
.map(|_| xous_kernel::Result::Ok)
} else {
klog!(
"setting the return value of the Server to {:?} and returning to Client",
envelope
);
ss.switch_to_thread(server_pid, Some(server_tid))?;
ss.set_thread_result(
server_pid,
server_tid,
xous_kernel::Result::MessageEnvelope(envelope),
)
.map(|_| xous_kernel::Result::Ok)
};
}
klog!(
"no threads available in PID {} to handle this message, so queueing",
server_pid
);
let _queue_idx = ss.queue_server_message(sidx, pid, tid, message, client_address)?;
klog!("queued into index {:x}", _queue_idx);
if blocking {
if cfg!(baremetal) {
let process = ss.get_process(pid).expect("Can't get current process");
let ppid = process.ppid;
unsafe { SWITCHTO_CALLER = None };
ss.activate_process_thread(tid, ppid, 0, false)
.map(|_| Ok(xous_kernel::Result::ResumeProcess))
.unwrap_or(Err(xous_kernel::Error::ProcessNotFound))
} else {
ss.unschedule_thread(pid, tid)?;
Ok(xous_kernel::Result::BlockedProcess)
}
} else {
Ok(xous_kernel::Result::Ok)
}
})
}
fn return_memory(
server_pid: PID,
server_tid: TID,
in_irq: bool,
sender: MessageSender,
buf: MemoryRange,
offset: Option<MemorySize>,
valid: Option<MemorySize>,
) -> SysCallResult {
SystemServices::with_mut(|ss| {
let sender = SenderID::from(sender);
let server = ss
.server_from_sidx_mut(sender.sidx)
.ok_or(xous_kernel::Error::ServerNotFound)?;
if server.pid != server_pid {
return Err(xous_kernel::Error::ServerNotFound);
}
let result = server.take_waiting_message(sender.idx, Some(&buf))?;
klog!("waiting message was: {:?}", result);
let (client_pid, client_tid, _server_addr, client_addr, len) = match result {
WaitingMessage::BorrowedMemory(
client_pid,
client_ctx,
server_addr,
client_addr,
len,
) => (client_pid, client_ctx, server_addr, client_addr, len),
WaitingMessage::MovedMemory => {
return Ok(xous_kernel::Result::Ok);
}
WaitingMessage::ForgetMemory(range) => {
return MemoryManager::with_mut(|mm| {
let mut result = Ok(xous_kernel::Result::Ok);
let virt = range.as_ptr() as usize;
let size = range.len();
if cfg!(baremetal) && virt & 0xfff != 0 {
klog!("VIRT NOT DIVISIBLE BY 4: {:08x}", virt);
return Err(xous_kernel::Error::BadAlignment);
}
for addr in (virt..(virt + size)).step_by(PAGE_SIZE) {
if let Err(e) = mm.unmap_page(addr as *mut usize) {
if result.is_ok() {
result = Err(e);
}
}
}
result
})
}
WaitingMessage::ScalarMessage(_pid, _tid) => {
println!("WARNING: Tried to wait on a message that was a scalar");
return Err(xous_kernel::Error::DoubleFree);
}
WaitingMessage::None => {
println!("WARNING: Tried to wait on a message that didn't exist -- return memory");
return Err(xous_kernel::Error::DoubleFree);
}
};
#[cfg(baremetal)]
let src_virt = _server_addr.get() as _;
#[cfg(not(baremetal))]
let src_virt = buf.as_ptr() as _;
let return_value = xous_kernel::Result::MemoryReturned(offset, valid);
ss.return_memory(
src_virt,
client_pid,
client_tid,
client_addr.get() as _,
len.get(),
)?;
if cfg!(baremetal) {
ss.ready_thread(client_pid, client_tid)?;
}
if !cfg!(baremetal) || in_irq || !ss.runnable(client_pid, Some(client_tid))? {
#[cfg(not(baremetal))]
ss.switch_to_thread(client_pid, Some(client_tid))?;
ss.set_thread_result(client_pid, client_tid, return_value)?;
Ok(xous_kernel::Result::Ok)
} else {
if cfg!(baremetal) {
ss.unschedule_thread(server_pid, server_tid)?;
ss.ready_thread(server_pid, server_tid)?
}
ss.set_thread_result(server_pid, server_tid, xous_kernel::Result::Ok)?;
ss.switch_to_thread(client_pid, Some(client_tid))?;
Ok(return_value)
}
})
}
fn return_result(
server_pid: PID,
server_tid: TID,
in_irq: bool,
sender: MessageSender,
return_value: xous_kernel::Result,
) -> SysCallResult {
SystemServices::with_mut(|ss| {
let sender = SenderID::from(sender);
let server = ss
.server_from_sidx_mut(sender.sidx)
.ok_or(xous_kernel::Error::ServerNotFound)?;
if server.pid != server_pid {
return Err(xous_kernel::Error::ServerNotFound);
}
let result = server.take_waiting_message(sender.idx, None)?;
let (client_pid, client_tid) = match result {
WaitingMessage::ScalarMessage(pid, tid) => (pid, tid),
WaitingMessage::ForgetMemory(_) => {
println!(
"WARNING: Tried to wait on a scalar message that was actually forgettingmemory"
);
return Err(xous_kernel::Error::DoubleFree);
}
WaitingMessage::BorrowedMemory(_, _, _, _, _) => {
println!(
"WARNING: Tried to wait on a scalar message that was actually borrowed memory"
);
return Err(xous_kernel::Error::DoubleFree);
}
WaitingMessage::MovedMemory => {
println!(
"WARNING: Tried to wait on a scalar message that was actually moved memory"
);
return Err(xous_kernel::Error::DoubleFree);
}
WaitingMessage::None => {
println!("WARNING ({}:{}): Tried to wait on a message that didn't exist (irq? {}) -- return {:?}", server_pid.get(), server_tid, if in_irq { "yes"} else {"no"}, result);
return Err(xous_kernel::Error::DoubleFree);
}
};
if cfg!(baremetal) {
ss.ready_thread(client_pid, client_tid)?;
}
if !cfg!(baremetal) || in_irq || !ss.runnable(client_pid, Some(client_tid))? {
ss.set_thread_result(client_pid, client_tid, return_value)?;
Ok(xous_kernel::Result::Ok)
} else {
if cfg!(baremetal) {
ss.unschedule_thread(server_pid, server_tid)?;
ss.ready_thread(server_pid, server_tid)?
}
ss.set_thread_result(server_pid, server_tid, xous_kernel::Result::Ok)?;
ss.switch_to_thread(client_pid, Some(client_tid))?;
Ok(return_value)
}
})
}
fn reply_and_receive_next(
server_pid: PID,
server_tid: TID,
_in_irq: bool,
sender: MessageSender,
arg0: usize,
arg1: usize,
arg2: usize,
arg3: usize,
arg4: usize,
scalar_type: usize,
) -> SysCallResult {
let sender = SenderID::from(sender);
SystemServices::with_mut(|ss| {
struct MessageResponse {
pid: PID,
tid: TID,
result: xous_kernel::Result,
}
let (result, next_message) = {
let server = ss
.server_from_sidx_mut(sender.sidx)
.ok_or(xous_kernel::Error::ServerNotFound)?;
if server.pid != server_pid {
println!(
"WARNING: PIDs don't match! The server is from PID {}, but our PID is {}",
server.pid, server_pid
);
return Err(xous_kernel::Error::ServerNotFound);
}
let waiting_message = server.take_waiting_message(sender.idx, None)?;
let next_message = server.take_next_message(sender.sidx);
if next_message.is_none() {
server.park_thread(server_tid);
}
(waiting_message, next_message)
};
let response = match result {
WaitingMessage::ScalarMessage(pid, tid) => {
let result = match scalar_type {
1 => xous_kernel::Result::Scalar1(arg1),
2 => xous_kernel::Result::Scalar2(arg1, arg2),
_ => xous_kernel::Result::Scalar5(arg0, arg1, arg2, arg3, arg4),
};
MessageResponse { pid, tid, result }
}
WaitingMessage::ForgetMemory(_) => {
println!(
"WARNING: Tried to wait on a scalar message that was actually forgetting memory"
);
return Err(xous_kernel::Error::DoubleFree);
}
WaitingMessage::BorrowedMemory(pid, tid, _server_addr, client_addr, len) => {
#[cfg(baremetal)]
let src_virt = _server_addr.get() as _;
#[cfg(not(baremetal))]
let src_virt = arg1 as _;
ss.return_memory(src_virt, pid, tid, client_addr.get() as _, len.get())?;
MessageResponse {
pid,
tid,
result: xous_kernel::Result::MemoryReturned(
MemorySize::new(arg3),
MemorySize::new(arg4),
),
}
}
WaitingMessage::MovedMemory => {
println!(
"WARNING: Tried to wait on a scalar message that was actually moved memory"
);
return Err(xous_kernel::Error::DoubleFree);
}
WaitingMessage::None => {
println!("WARNING: Tried to wait on a message that didn't exist -- receive and return scalar");
return Err(xous_kernel::Error::DoubleFree);
}
};
if let Some(msg) = next_message {
if cfg!(baremetal) {
ss.set_thread_result(
server_pid,
server_tid,
xous_kernel::Result::MessageEnvelope(msg),
)?;
ss.ready_thread(response.pid, response.tid).unwrap();
ss.set_thread_result(response.pid, response.tid, response.result)?;
ss.activate_process_thread(server_tid, response.pid, response.tid, true)
.map(|_| Ok(xous_kernel::Result::ResumeProcess))
.unwrap_or(Err(xous_kernel::Error::ProcessNotFound))
} else {
ss.switch_to_thread(response.pid, Some(response.tid))?;
ss.set_thread_result(response.pid, response.tid, response.result)?;
Ok(xous_kernel::Result::MessageEnvelope(msg))
}
} else {
if cfg!(baremetal) {
ss.ready_thread(response.pid, response.tid)?;
ss.set_thread_result(response.pid, response.tid, response.result)?;
ss.activate_process_thread(server_tid, response.pid, response.tid, false)
.map(|_| Ok(xous_kernel::Result::ResumeProcess))
.unwrap_or(Err(xous_kernel::Error::ProcessNotFound))
}
else {
ss.unschedule_thread(server_pid, server_tid)?;
ss.switch_to_thread(response.pid, Some(response.tid))?;
ss.set_thread_result(response.pid, response.tid, response.result)?;
Ok(xous_kernel::Result::BlockedProcess)
}
}
})
}
fn receive_message(pid: PID, tid: TID, sid: SID, blocking: ExecutionType) -> SysCallResult {
SystemServices::with_mut(|ss| {
assert!(
ss.thread_is_running(pid, tid),
"current thread is not running"
);
let sidx = ss
.sidx_from_sid(sid, pid)
.ok_or(xous_kernel::Error::ServerNotFound)?;
let server = ss
.server_from_sidx_mut(sidx)
.ok_or(xous_kernel::Error::ServerNotFound)?;
if server.pid != pid {
return Err(xous_kernel::Error::ServerNotFound);
}
if let Some(msg) = server.take_next_message(sidx) {
klog!("waiting messages found -- returning {:x?}", msg);
return Ok(xous_kernel::Result::MessageEnvelope(msg));
}
if blocking == ExecutionType::NonBlocking {
klog!("nonblocking message -- returning None");
return Ok(xous_kernel::Result::None);
}
klog!(
"did not have any waiting messages -- parking thread {}",
tid
);
server.park_thread(tid);
if cfg!(baremetal) {
unsafe { SWITCHTO_CALLER = None };
let ppid = ss.get_process(pid).expect("Can't get current process").ppid;
ss.activate_process_thread(tid, ppid, 0, false)
.map(|_| Ok(xous_kernel::Result::ResumeProcess))
.unwrap_or(Err(xous_kernel::Error::ProcessNotFound))
}
else {
ss.unschedule_thread(pid, tid)
.map(|_| xous_kernel::Result::BlockedProcess)
}
})
}
pub fn handle(pid: PID, tid: TID, in_irq: bool, call: SysCall) -> SysCallResult {
#[cfg(feature = "debug-print")]
print!("KERNEL({}:{}): Syscall {:x?}", pid, tid, call);
#[allow(clippy::let_and_return)]
let result = if in_irq && !call.can_call_from_interrupt() {
Err(xous_kernel::Error::InvalidSyscall)
} else {
handle_inner(pid, tid, in_irq, call)
};
#[cfg(feature = "debug-print")]
println!(
" -> ({}:{}) {:x?}",
crate::arch::current_pid(),
crate::arch::process::Process::current().current_tid(),
result
);
result
}
pub fn handle_inner(pid: PID, tid: TID, in_irq: bool, call: SysCall) -> SysCallResult {
match call {
SysCall::MapMemory(phys, virt, size, req_flags) => {
MemoryManager::with_mut(|mm| {
let phys_ptr = phys
.map(|x| x.get() as *mut u8)
.unwrap_or(core::ptr::null_mut());
let virt_ptr = virt
.map(|x| x.get() as *mut u8)
.unwrap_or(core::ptr::null_mut());
if pid.get() != 1
&& virt
.map(|x| x.get() >= arch::mem::USER_AREA_END)
.unwrap_or(false)
{
println!("Exceeded user area");
return Err(xous_kernel::Error::BadAddress);
} else if size.get() & (PAGE_SIZE - 1) != 0 {
return Err(xous_kernel::Error::BadAlignment);
}
let range = mm.map_range(
phys_ptr,
virt_ptr,
size.get(),
pid,
req_flags,
MemoryType::Default,
)?;
if !phys_ptr.is_null() {
if mm.is_main_memory(phys_ptr) {
unsafe {
range
.as_mut_ptr()
.write_bytes(0, range.len() / core::mem::size_of::<usize>())
};
}
for offset in (range.as_ptr() as usize..(range.as_ptr() as usize + range.len()))
.step_by(PAGE_SIZE)
{
crate::arch::mem::hand_page_to_user(offset as *mut u8)
.expect("couldn't hand page to user");
}
}
Ok(xous_kernel::Result::MemoryRange(range))
})
}
SysCall::UnmapMemory(range) => MemoryManager::with_mut(|mm| {
let mut result = Ok(xous_kernel::Result::Ok);
let virt = range.as_ptr() as usize;
let size = range.len();
if cfg!(baremetal) && virt & 0xfff != 0 {
return Err(xous_kernel::Error::BadAlignment);
}
for addr in (virt..(virt + size)).step_by(PAGE_SIZE) {
if let Err(e) = mm.unmap_page(addr as *mut usize) {
if result.is_ok() {
result = Err(e);
}
}
}
result
}),
SysCall::IncreaseHeap(delta, flags) => {
if delta & 0xfff != 0 {
return Err(xous_kernel::Error::BadAlignment);
}
if delta == 0 {
let (start, length) = ArchProcess::with_inner_mut(|process_inner| {
(process_inner.mem_heap_base, process_inner.mem_heap_size)
});
return Ok(xous_kernel::Result::MemoryRange(unsafe {
MemoryRange::new(
start,
if length == 0 { 4096 } else { length },
)
.unwrap()
}));
}
let start = {
ArchProcess::with_inner_mut(|process_inner| {
if process_inner.mem_heap_size + delta > process_inner.mem_heap_max {
return Err(xous_kernel::Error::OutOfMemory);
}
let start = process_inner.mem_heap_base + process_inner.mem_heap_size;
process_inner.mem_heap_size += delta;
Ok(start as *mut u8)
})?
};
MemoryManager::with_mut(|mm| {
Ok(xous_kernel::Result::MemoryRange(
mm.reserve_range(start, delta, flags)?,
))
})
}
SysCall::DecreaseHeap(delta) => {
if delta & 0xfff != 0 {
return Err(xous_kernel::Error::BadAlignment);
}
let (start, length, end) = ArchProcess::with_inner_mut(|process_inner| {
if delta > process_inner.mem_heap_size {
return Err(xous_kernel::Error::OutOfMemory);
}
let end = process_inner.mem_heap_base + process_inner.mem_heap_size;
process_inner.mem_heap_size -= delta;
Ok((
process_inner.mem_heap_base,
process_inner.mem_heap_size,
end,
))
})?;
MemoryManager::with_mut(|mm| {
for page in ((end - delta)..end).step_by(crate::arch::mem::PAGE_SIZE) {
mm.unmap_page(page as *mut usize)
.expect("unable to unmap page");
}
});
Ok(xous_kernel::Result::MemoryRange(unsafe {
MemoryRange::new(start, length).unwrap()
}))
}
SysCall::SwitchTo(new_pid, new_tid) => SystemServices::with_mut(|ss| {
unsafe {
assert!(
SWITCHTO_CALLER.is_none(),
"SWITCHTO_CALLER was {:?} and not None, indicating SwitchTo was called twice",
SWITCHTO_CALLER,
);
SWITCHTO_CALLER = Some((pid, tid));
}
ss.activate_process_thread(tid, new_pid, new_tid, true)
.map(|_ctx| xous_kernel::Result::ResumeProcess)
}),
SysCall::ClaimInterrupt(no, callback, arg) => {
interrupt_claim(no, pid as definitions::PID, callback, arg)
.map(|_| xous_kernel::Result::Ok)
}
SysCall::Yield => do_yield(pid, tid),
SysCall::ReturnToParent(_pid, _cpuid) => {
unsafe {
if let Some((parent_pid, parent_ctx)) = SWITCHTO_CALLER.take() {
crate::arch::irq::set_isr_return_pair(parent_pid, parent_ctx)
}
};
Ok(xous_kernel::Result::ResumeProcess)
}
SysCall::ReceiveMessage(sid) => receive_message(pid, tid, sid, ExecutionType::Blocking),
SysCall::TryReceiveMessage(sid) => {
receive_message(pid, tid, sid, ExecutionType::NonBlocking)
}
SysCall::WaitEvent => SystemServices::with_mut(|ss| {
let process = ss.get_process(pid).expect("Can't get current process");
let ppid = process.ppid;
unsafe { SWITCHTO_CALLER = None };
if cfg!(baremetal) {
ss.activate_process_thread(tid, ppid, 0, false)
.map(|_| Ok(xous_kernel::Result::ResumeProcess))
.unwrap_or(Err(xous_kernel::Error::ProcessNotFound))
} else {
Ok(xous_kernel::Result::Ok)
}
}),
SysCall::CreateThread(thread_init) => SystemServices::with_mut(|ss| {
ss.create_thread(pid, thread_init).map(|new_tid| {
if cfg!(target_os = "xous") {
ss.switch_to_thread(pid, Some(new_tid))
.expect("couldn't activate new thread");
ss.set_thread_result(pid, tid, xous_kernel::Result::ThreadID(new_tid))
.expect("couldn't set new thread ID");
xous_kernel::Result::ResumeProcess
} else {
xous_kernel::Result::ThreadID(new_tid)
}
})
}),
SysCall::CreateProcess(process_init) => SystemServices::with_mut(|ss| {
ss.create_process(process_init)
.map(xous_kernel::Result::NewProcess)
}),
SysCall::CreateServerWithAddress(name) => SystemServices::with_mut(|ss| {
ss.create_server_with_address(pid, name, true)
.map(|(sid, cid)| xous_kernel::Result::NewServerID(sid, cid))
}),
SysCall::CreateServer => SystemServices::with_mut(|ss| {
ss.create_server(pid, true)
.map(|(sid, cid)| xous_kernel::Result::NewServerID(sid, cid))
}),
SysCall::CreateServerId => {
SystemServices::with_mut(|ss| ss.create_server_id().map(xous_kernel::Result::ServerID))
}
SysCall::TryConnect(sid) => SystemServices::with_mut(|ss| {
ss.connect_to_server(sid)
.map(xous_kernel::Result::ConnectionID)
}),
SysCall::ReturnMemory(sender, buf, offset, valid) => {
return_memory(pid, tid, in_irq, sender, buf, offset, valid)
}
SysCall::ReturnScalar1(sender, arg) => {
return_result(pid, tid, in_irq, sender, xous_kernel::Result::Scalar1(arg))
}
SysCall::ReturnScalar2(sender, arg1, arg2) => return_result(
pid,
tid,
in_irq,
sender,
xous_kernel::Result::Scalar2(arg1, arg2),
),
SysCall::ReturnScalar5(sender, arg1, arg2, arg3, arg4, arg5) => return_result(
pid,
tid,
in_irq,
sender,
xous_kernel::Result::Scalar5(arg1, arg2, arg3, arg4, arg5),
),
SysCall::ReplyAndReceiveNext(sender, a0, a1, a2, a3, a4, scalar_type) => {
reply_and_receive_next(pid, tid, in_irq, sender, a0, a1, a2, a3, a4, scalar_type)
}
SysCall::TrySendMessage(cid, message) => send_message(pid, tid, cid, message),
SysCall::TerminateProcess(_ret) => SystemServices::with_mut(|ss| {
ss.unschedule_thread(pid, tid)?;
ss.terminate_process(pid)?;
unsafe { SWITCHTO_CALLER = None };
Ok(xous_kernel::Result::ResumeProcess)
}),
SysCall::Shutdown => {
SystemServices::with_mut(|ss| ss.shutdown().map(|_| xous_kernel::Result::Ok))
}
SysCall::GetProcessId => Ok(xous_kernel::Result::ProcessID(pid)),
SysCall::GetThreadId => Ok(xous_kernel::Result::ThreadID(tid)),
SysCall::Connect(sid) => {
let result = SystemServices::with_mut(|ss| {
ss.connect_to_server(sid)
.map(xous_kernel::Result::ConnectionID)
});
match result {
Ok(o) => Ok(o),
Err(xous_kernel::Error::ServerNotFound) => retry_syscall(pid, tid),
Err(e) => Err(e),
}
}
SysCall::ConnectForProcess(pid, sid) => {
let result = SystemServices::with_mut(|ss| {
ss.connect_process_to_server(pid, sid)
.map(xous_kernel::Result::ConnectionID)
});
match result {
Ok(o) => Ok(o),
Err(xous_kernel::Error::ServerNotFound) => retry_syscall(pid, tid),
Err(e) => Err(e),
}
}
SysCall::SendMessage(cid, message) => {
let result = send_message(pid, tid, cid, message);
match result {
Ok(o) => Ok(o),
Err(xous_kernel::Error::ServerQueueFull) => retry_syscall(pid, tid),
Err(e) => Err(e),
}
}
SysCall::Disconnect(cid) => SystemServices::with_mut(|ss| {
ss.disconnect_from_server(cid)
.and(Ok(xous_kernel::Result::Ok))
}),
SysCall::DestroyServer(sid) => SystemServices::with_mut(|ss| {
ss.destroy_server(pid, sid).and(Ok(xous_kernel::Result::Ok))
}),
SysCall::JoinThread(other_tid) => {
SystemServices::with_mut(|ss| ss.join_thread(pid, tid, other_tid)).map(|ret| {
if ret == xous_kernel::Result::ResumeProcess {
unsafe { SWITCHTO_CALLER = None };
}
ret
})
}
SysCall::UpdateMemoryFlags(range, flags, pid) => {
if pid.is_some() {
return Err(xous_kernel::Error::ProcessNotChild);
}
MemoryManager::with_mut(|mm| mm.update_memory_flags(range, flags))?;
Ok(xous_kernel::Result::Ok)
}
SysCall::AdjustProcessLimit(index, current, new) => match index {
1 => arch::process::Process::with_inner_mut(|p| {
if p.mem_heap_max == current {
p.mem_heap_max = new;
}
Ok(xous_kernel::Result::Scalar2(index, p.mem_heap_max))
}),
2 => arch::process::Process::with_inner_mut(|p| {
if p.mem_heap_size == current && new < p.mem_heap_max {
p.mem_heap_size = new;
}
Ok(xous_kernel::Result::Scalar2(index, p.mem_heap_size))
}),
_ => Err(xous_kernel::Error::InvalidLimit),
},
#[cfg(feature = "v2p")]
SysCall::VirtToPhys(vaddr) => {
let phys_addr = crate::arch::mem::virt_to_phys(vaddr as usize);
match phys_addr {
Ok(pa) => Ok(xous_kernel::Result::Scalar1(pa)),
Err(_) => Err(xous_kernel::Error::BadAddress),
}
}
_ => Err(xous_kernel::Error::UnhandledSyscall),
}
}