Skip to content

kernel::syscall

Kernel dispatch ABI (plan W5.1, Option A).

The trusted-task API calls these #[no_mangle] functions directly via extern "Rust" linkage — there is no syscall instruction. Each function that mutates scheduler/IPC state does so inside a critical section (scheduler::with / cs_with) so it cannot race the trap handler (plan W2.2). Opt-in unprivileged tasks cannot execute these functions. They use the separate, pointer-free api::isolated supervisor ABI instead.

fn _flint_sys_cs_enter() -> u32

Enter the kernel’s critical section; returns the state _flint_sys_cs_exit needs to leave it. Backs api::sync::CsCell, so api stays ignorant of which architecture’s interrupt mask this is.

Raw enter/exit rather than a closure-taking with, because a closure cannot cross an extern "Rust" boundary generically.

fn _flint_sys_cs_exit(saved: u32)

Leave a critical section entered with _flint_sys_cs_enter.

fn _flint_sys_current_core() -> u8

The core the caller is running on, as a raw index. Backs [api::smp::current_core].

A raw u8 rather than a CoreId so the syscall boundary stays a plain ABI, matching _flint_sys_spawn_on; api rebuilds the CoreId.

fn _flint_sys_current_id() -> hal::types::TaskId

References: TaskId

fn _flint_sys_current_name() -> &'static str
fn _flint_sys_dma_alloc(size: u32) -> Result<hal::DmaHandle, hal::DmaError>

Allocate a DMA-safe buffer. Backs [api::dma::alloc].

References: DmaError, DmaHandle

fn _flint_sys_dma_available() -> u32

Bytes still free in the DMA pool. Backs [api::dma::available].

fn _flint_sys_dma_await(id: hal::DmaTransferId, timeout_ms: u32) -> Result<(), hal::DmaError>

Block until id completes or timeout_ms elapses. Backs [api::dma::await_transfer].

References: DmaError, DmaTransferId

fn _flint_sys_dma_begin(handle: &hal::DmaHandle) -> Result<hal::DmaTransferId, hal::DmaError>

Begin a transfer over an owned buffer and mint its completion id. Backs [api::dma::begin].

References: DmaError, DmaHandle, DmaTransferId

fn _flint_sys_dma_begin_pair(source: &hal::DmaHandle, destination: &hal::DmaHandle) -> Result<hal::DmaTransferId, hal::DmaError>

Begin one full-duplex transfer over two owned buffers.

References: DmaError, DmaHandle, DmaTransferId

unsafe fn _flint_sys_interrupt_connect(source: u8, handler: fn(..)) -> Result<hal::CpuInt, hal::ConnectError>

Route a peripheral source to the first free CPU input and register handler. Backs [api::interrupt::connect].

handler runs in trap context: short, non-blocking, and it must acknowledge its peripheral. See interrupt::connect.

References: ConnectError, CpuInt

fn _flint_sys_log_write(level: api::debug::log::Level, args: &core::fmt::Arguments<'_>)

References: Level

fn _flint_sys_mutex_lock(mutex: *const core::ffi::c_void) -> bool
fn _flint_sys_mutex_unlock(mutex: *const core::ffi::c_void)
fn _flint_sys_now_us() -> u64

Microseconds since boot, from the free-running hardware counter. Backs [api::time::now_us].

Lock-free by design so it can be read from trap context — see [crate::clock::now_us], which selects a hardware microsecond counter when the SoC has one and falls back to the scaled scheduler tick when it does not. Either way the answer is monotonic and correctly ordered.

fn _flint_sys_panic(args: &core::fmt::Arguments<'_>) -> !
fn _flint_sys_queue_block_recv(q_addr: usize, timeout_ms: u32) -> bool

Block the calling task waiting to receive on an empty queue, with timeout.

fn _flint_sys_queue_block_send(q_addr: usize, timeout_ms: u32) -> bool

Block the calling task waiting to send on a full queue, with timeout. Returns true if a slot became available (caller should retry try_send), false on timeout.

fn _flint_sys_queue_wake_receiver(q_addr: usize)

Wake one receiver after a successful send.

fn _flint_sys_queue_wake_sender(q_addr: usize)

Wake one sender after a successful receive.

fn _flint_sys_sleep_ms(ms: u32)
fn _flint_sys_spawn(name: &'static str, entry: fn(..), priority: hal::types::Priority, stack_size: usize) -> Option<hal::types::TaskId>

References: Priority, TaskId

fn _flint_sys_spawn_on(core: u8, name: &'static str, entry: fn(..), priority: hal::types::Priority, stack_size: usize) -> Option<hal::types::TaskId>

Spawn pinned to core.

core is a raw index rather than a CoreId so the syscall boundary stays a plain ABI. Out of range is rejected rather than clamped: a task pinned to a core that does not exist would never be scheduled anywhere, and silently running it on core 0 instead would defeat the reason it was pinned.

References: Priority, TaskId

fn _flint_sys_task_exit() -> !

End the calling task. Same path a task takes when its entry function returns; api::task::exit is the explicit spelling of it.

fn _flint_sys_timer_cancel(id: u32)
fn _flint_sys_timer_every(ms: u32, cb: fn(..)) -> u32
fn _flint_sys_timer_now_ms() -> u64
fn _flint_sys_timer_once(ms: u32, cb: fn(..)) -> u32
fn _flint_sys_yield()