blob: f114e6ba68d1b5c70dd5c3cd37df170a91414bd8 [file] [log] [blame]
// Copyright 2025 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::task::{CurrentTask, ExitStatus};
use starnix_sync::{Locked, Unlocked};
use std::sync::atomic::{AtomicPtr, Ordering};
/// The type of function that must be provided by the kernel binary to enter the syscall loop.
pub type SyscallLoopEntry = fn(&mut Locked<Unlocked>, &mut CurrentTask) -> ExitStatus;
// Need to make sure the function pointer is actually just a pointer to store it safely in atomic.
static_assertions::assert_eq_size!(SyscallLoopEntry, *const ());
static SYSCALL_LOOP_ENTRY: AtomicPtr<()> = AtomicPtr::new(std::ptr::null_mut());
/// Initialize the syscall loop entry function.
pub fn initialize_syscall_loop(enter_loop: SyscallLoopEntry) {
SYSCALL_LOOP_ENTRY.store(enter_loop as *mut (), Ordering::Relaxed);
}
/// Enter the syscall loop on the calling thread.
///
/// Returns the final exit status of the task.
pub(crate) fn enter_syscall_loop(
locked: &mut Locked<Unlocked>,
current_task: &mut CurrentTask,
) -> ExitStatus {
let raw_entry: *mut () = SYSCALL_LOOP_ENTRY.load(Ordering::Relaxed);
assert!(!raw_entry.is_null(), "must call initialize_syscall_loop() before executing tasks");
// SAFETY: the static variable only has SyscallLoopEntry values stored into it.
let entry: SyscallLoopEntry = unsafe {
let raw_entry_ptr = &raw_entry as *const *mut ();
let entry_ptr = raw_entry_ptr as *const SyscallLoopEntry;
*entry_ptr
};
entry(locked, current_task)
}