blob: 5e23bcf72e5b0764efe5e4bd24d76208440fad6f [file]
// Copyright 2025 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
use pw_cast::CastInto;
use pw_status::{Error, Result, StatusCode};
use syscall_defs::SysCallInterface;
pub use syscall_defs::{ExitStatus, Signals, WaitReturn};
use syscall_user::SysCall;
use crate::buffer::AsSyscallBuffer;
use crate::time::Instant;
#[inline(always)]
pub fn object_wait(
object_handle: u32,
signal_mask: Signals,
deadline: Instant,
) -> Result<WaitReturn> {
SysCall::object_wait(object_handle, signal_mask.bits(), deadline.ticks())
}
#[inline(always)]
pub fn wait_group_add(
wait_group: u32,
object: u32,
signal_mask: Signals,
user_data: usize,
) -> Result<()> {
SysCall::wait_group_add(wait_group, object, signal_mask, user_data)
}
#[inline(always)]
pub fn wait_group_remove(wait_group: u32, object: u32) -> Result<()> {
SysCall::wait_group_remove(wait_group, object)
}
#[inline(always)]
pub fn channel_transact<BufSend, BufRecv>(
object_handle: u32,
send_data: &BufSend,
recv_data: &mut BufRecv,
deadline: Instant,
) -> Result<usize>
where
BufSend: AsSyscallBuffer + ?Sized,
BufRecv: AsSyscallBuffer + ?Sized,
{
let (send_data, send_len) = send_data.as_raw();
let (recv_data, recv_len) = recv_data.as_raw_mut();
unsafe {
SysCall::channel_transact(
object_handle,
send_data,
send_len,
recv_data,
recv_len,
deadline.ticks(),
)
.map(|ret| ret.cast_into())
}
}
#[inline(always)]
/// Start an asynchronous transaction on a channel.
///
/// # Safety
///
/// This function effectively borrows the memory pointed to by `send_data` and `recv_data` for the
/// duration of the transaction. The caller must ensure that:
///
/// 1. The memory pointed to by `send_data` and `recv_data` remains valid and is not mutated until
/// the transaction is either completed via `channel_async_transact_complete` or cancelled via
/// `channel_async_cancel`.
/// 2. The `recv_data` buffer is large enough to hold the expected response.
///
/// Violating these requirements may result in undefined behavior.
pub unsafe fn channel_async_transact(
object_handle: u32,
send_data: *const u8,
send_len: usize,
recv_data: *mut u8,
recv_len: usize,
) -> Result<()> {
unsafe {
SysCall::channel_async_transact(object_handle, send_data, send_len, recv_data, recv_len)
}
}
#[inline(always)]
pub fn channel_async_transact_complete(object_handle: u32) -> Result<usize> {
SysCall::channel_async_transact_complete(object_handle).map(|ret| ret.cast_into())
}
#[inline(always)]
pub fn channel_async_cancel(object_handle: u32) -> Result<()> {
SysCall::channel_async_cancel(object_handle)
}
#[inline(always)]
pub fn channel_read<Buf>(object_handle: u32, offset: usize, buffer: &mut Buf) -> Result<usize>
where
Buf: AsSyscallBuffer + ?Sized,
{
let (buffer, length) = buffer.as_raw_mut();
unsafe {
SysCall::channel_read(object_handle, offset, buffer, length).map(|ret| ret.cast_into())
}
}
#[inline(always)]
pub fn channel_read_exact<Buf>(object_handle: u32, offset: usize, buffer: &mut Buf) -> Result<()>
where
Buf: AsSyscallBuffer + ?Sized,
{
let total_size = buffer.total_size();
let read = channel_read(object_handle, offset, buffer)?;
if read != total_size {
return Err(Error::OutOfRange);
}
Ok(())
}
pub fn channel_respond<Buf>(object_handle: u32, buffer: &Buf) -> Result<()>
where
Buf: AsSyscallBuffer + ?Sized,
{
let (buffer, length) = buffer.as_raw();
unsafe { SysCall::channel_respond(object_handle, buffer, length) }
}
#[inline(always)]
pub fn interrupt_ack(object_handle: u32, signal_mask: Signals) -> Result<()> {
SysCall::interrupt_ack(object_handle, signal_mask)
}
/// Set (`set=true`) or clear (`set=false`) `Signals::USER` on the paired peer.
#[inline(always)]
pub fn object_set_peer_user_signal(object_handle: u32, set: bool) -> Result<()> {
SysCall::object_set_peer_user_signal(object_handle, set)
}
#[inline(always)]
pub fn debug_putc(c: char) -> Result<u32> {
SysCall::debug_putc(c.into())
}
#[inline(always)]
pub fn debug_shutdown(status: Result<()>) -> Result<()> {
SysCall::debug_shutdown(status.status_code())
}
#[inline(always)]
pub fn debug_log<Buf>(buffer: &Buf) -> Result<()>
where
Buf: AsSyscallBuffer + ?Sized,
{
let (buffer, length) = buffer.as_raw();
unsafe { SysCall::debug_log(buffer, length) }
}
#[inline(always)]
pub fn debug_nop() -> Result<()> {
SysCall::debug_nop()
}
#[inline(always)]
pub fn debug_trigger_interrupt(irq: u32) -> Result<()> {
SysCall::debug_trigger_interrupt(irq)
}
#[must_use]
#[inline(always)]
pub fn debug_clock_now() -> Instant {
Instant::from_ticks(SysCall::debug_clock_now())
}
#[inline(always)]
pub fn thread_start(object_handle: u32, initial_pc: usize, initial_sp: usize) -> Result<()> {
SysCall::thread_start(object_handle, initial_pc, initial_sp)
}
#[inline(always)]
pub fn task_terminate(object_handle: u32) -> Result<()> {
SysCall::task_terminate(object_handle)
}
#[inline(always)]
pub fn task_join(object_handle: u32) -> Result<ExitStatus> {
SysCall::task_join(object_handle)
}
#[inline(always)]
pub fn process_start(object_handle: u32) -> Result<()> {
SysCall::process_start(object_handle)
}
#[inline(always)]
pub fn process_exit(exit_code: u32) -> ! {
SysCall::process_exit(exit_code)
}
#[inline(always)]
pub fn thread_exit(exit_code: u32) -> ! {
SysCall::thread_exit(exit_code)
}