use core::alloc::Layout;
use core::mem;
use core::ptr::NonNull;
use crate::{kernel, KERNEL, sched, sync, time};
use crate::sched::event;
use crate::exec::runnable::RunnableResult;
use crate::exec::thread::ThreadBuilder;
use bern_arch::{ICore, ISyscall};
use bern_arch::arch::{Arch, ArchCore};
use bern_arch::core::ExecMode;
use crate::alloc::wrapper::Wrapper;
use crate::alloc::allocator::AllocError;
use crate::mem::queue::{PushRaw, RawItem};
use crate::sync::channel::ChannelError;
use crate::sync::ipc::semaphore::SemaphoreID;
#[repr(u8)]
pub enum Service {
TaskSpawn,
TaskSleep,
TaskYield,
TaskExit,
EventRegister,
EventAwait,
EventFire,
Alloc,
Dealloc,
KernelStats,
CoreDebugTime,
TickCount,
IpcChannelRegister,
IpcChannelSend,
IpcSemaphoreRegister,
IpcSemaphoreTryAcquire,
}
impl Service {
pub const fn service_id(self) -> u8 {
self as u8
}
}
fn mode_aware_syscall(service: Service, arg0: usize, arg1: usize, arg2: usize) -> usize {
match ArchCore::execution_mode() {
ExecMode::Kernel =>
syscall_handler_impl(service, arg0, arg1, arg2),
ExecMode::Thread =>
Arch::syscall(service.service_id(), arg0, arg1, arg2),
}
}
pub(crate) fn thread_spawn(builder: &mut ThreadBuilder, entry: &&mut (dyn FnMut() -> RunnableResult)) {
mode_aware_syscall(
Service::TaskSpawn,
builder as *mut _ as usize,
entry as *const _ as usize,
0
);
}
pub fn sleep(ms: u32) {
mode_aware_syscall(
Service::TaskSleep,
ms as usize,
0,
0
);
}
pub fn yield_now() {
mode_aware_syscall(
Service::TaskYield,
0,
0,
0
);
}
pub fn task_exit() {
mode_aware_syscall(
Service::TaskExit,
0,
0,
0
);
}
pub(crate) fn event_register() -> usize {
mode_aware_syscall(
Service::EventRegister,
0,
0,
0
)
}
pub(crate) fn event_await(id: usize, timeout: u32) -> Result<(), event::Error> {
let ret_code = mode_aware_syscall(
Service::EventAwait,
id,
timeout as usize,
0
) as u8;
unsafe { mem::transmute(ret_code) }
}
pub(crate) fn event_fire(id: usize) {
mode_aware_syscall(
Service::EventFire,
id,
0,
0
);
}
pub(crate) fn alloc(layout: Layout) -> *mut u8 {
mode_aware_syscall(
Service::Alloc,
layout.size(),
layout.align(),
0,
) as *mut u8
}
pub(crate) fn dealloc(ptr: *mut u8, layout: Layout) {
mode_aware_syscall(
Service::Dealloc,
ptr as usize,
layout.size(),
layout.align()
);
}
pub fn print_kernel_stats() {
mode_aware_syscall(
Service::KernelStats,
0,
0,
0,
);
}
pub fn core_debug_time() -> u32 {
let mut time = 0;
mode_aware_syscall(
Service::CoreDebugTime,
&mut time as *mut _ as usize,
0,
0,
);
time
}
pub fn tick_count() -> u64 {
let mut count = 0;
mode_aware_syscall(
Service::TickCount,
&mut count as *mut _ as usize,
0,
0,
);
count
}
pub(crate) fn ipc_register(recv_channel: &dyn PushRaw) -> Result<usize, AllocError> {
let mut res = Err(AllocError::Other);
mode_aware_syscall(
Service::IpcChannelRegister,
&recv_channel as *const _ as usize,
&mut res as *mut _ as usize,
0
);
res
}
pub(crate) fn ipc_send_raw(id: usize, item: RawItem) -> Result<(), ChannelError> {
let mut res = Err(ChannelError::ChannelClosed);
mode_aware_syscall(
Service::IpcChannelSend,
id,
&item as *const _ as usize,
&mut res as *mut _ as usize,
);
res
}
pub(crate) fn ipc_semaphore_register() -> Result<(SemaphoreID, usize), AllocError> {
let mut res = Err(AllocError::Other);
mode_aware_syscall(
Service::IpcSemaphoreRegister,
0,
&mut res as *mut _ as usize,
0
);
res
}
pub(crate) fn ipc_semaphore_try_aquire(id: SemaphoreID) -> Result<bool, sync::Error> {
let mut res = Err(sync::Error::Poisoned);
mode_aware_syscall(
Service::IpcSemaphoreTryAcquire,
&id as *const _ as usize,
&mut res as *mut _ as usize,
0
);
res
}
#[allow(unused_variables)]
fn syscall_handler_impl(service: Service, arg0: usize, arg1: usize, arg2: usize) -> usize {
#[allow(unreachable_patterns)]
let r = match service {
Service::TaskSpawn => {
let builder: &mut ThreadBuilder = unsafe { mem::transmute(arg0 as *mut ThreadBuilder) };
let runnable: &&mut (dyn FnMut() -> RunnableResult) = unsafe {
mem::transmute(arg1 as *mut &mut (dyn FnMut() -> RunnableResult))
};
ThreadBuilder::build(
builder,
runnable,
);
0
},
Service::TaskSleep => {
let ms: u32 = arg0 as u32;
sched::sleep(ms);
0
},
Service::TaskYield => {
sched::yield_now();
0
},
Service::TaskExit => {
sched::task_terminate();
0
},
Service::EventRegister => {
match sched::event_register() {
Ok(id) => id,
Err(_) => 0,
}
},
Service::EventAwait => {
let id = arg0;
let timeout = arg1;
let result = sched::event_await(id, timeout);
let result: Result<(), event::Error> = Ok(());
let ret_code: u8 = unsafe { mem::transmute(result) };
ret_code as usize
},
Service::EventFire => {
let id = arg0;
sched::event_fire(id);
0
},
Service::Alloc => {
let size = arg0;
let align = arg1;
let layout = unsafe {
Layout::from_size_align_unchecked(size, align)
};
Wrapper::alloc_handler(layout) as usize
}
Service::Dealloc => {
let ptr = arg0 as *mut u8;
let size = arg1;
let align = arg2;
let layout = unsafe {
Layout::from_size_align_unchecked(size, align)
};
Wrapper::dealloc_handler(ptr, layout);
0
}
Service::KernelStats => {
kernel::print_stats();
sched::print_thread_stats();
0
}
Service::CoreDebugTime => {
let time = arg0 as *mut u32;
unsafe {
time.write( ArchCore::debug_time())
}
0
}
Service::TickCount => {
let count = arg0 as *mut u64;
unsafe {
count.write(time::tick_count())
}
0
}
Service::IpcChannelRegister => {
let recv_queue: &&dyn PushRaw = unsafe { mem::transmute(arg0) };
let res: &mut Result<usize, AllocError> = unsafe { mem::transmute(arg1) };
*res = KERNEL.register_channel(NonNull::from(*recv_queue));
0
}
Service::IpcChannelSend => {
let id = arg0;
let item: &RawItem = unsafe { mem::transmute(arg1) };
let res: &mut Result<(), ChannelError> = unsafe { mem::transmute(arg2) };
*res = KERNEL.with_channel(id, |ch| {
ch.push_back(&item)
.map_err(ChannelError::Queue)
});
0
}
Service::IpcSemaphoreRegister => {
let res: &mut Result<(SemaphoreID, usize), AllocError> = unsafe { mem::transmute(arg1) };
*res = KERNEL.register_semaphore();
0
}
Service::IpcSemaphoreTryAcquire => {
let id = &arg0 as &SemaphoreID;
let res: &mut Result<bool, sync::Error> = unsafe { mem::transmute(arg1) };
*res = KERNEL.with_semaphore(*id, |s| {
Ok(false)
}).or(Err(sync::Error::Poisoned));
0
}
_ => 0,
};
r
}
#[allow(unused_variables)]
#[no_mangle]
pub extern "Rust" fn syscall_handler(service: Service, arg0: usize, arg1: usize, arg2: usize) -> usize {
let r = syscall_handler_impl(service, arg0, arg1, arg2);
r
}