lifeblood_os/liblbos/src/syscalls.rs

204 lines
No EOL
7 KiB
Rust

use crate::arch::{stall, syscall};
use crate::TaskSetup;
#[repr(C)]
pub struct KernelInfo {
pub current_process_count: usize,
pub total_mem_blocks: usize,
pub free_mem_blocks: usize,
}
#[repr(u16)]
pub enum KTaskNotificationRequest {
DoNothing = 0,
SayHi = 1,
}
#[repr(u32)]
pub enum SysCall {
/// does absolutely nothing
NoAction = 0,
/// provide pointer to kernel info struct in first arg and it will be filled
KernelInfo = 1,
/// provide TaskSetup pointer in first arg and task will spawn, returns new task id
CreateTask = 2,
/// the currently executing task will exit
ExitTask = 3,
/// returns the current task id
CurrentTask = 4,
/// takes all available characters in the INBUF, places them in the given buffer, and returns the number of characters placed in the buffer
ReadInbuf = 5,
/// writes the given N characters in the buffer to the serial port
WriteTerminal = 6,
/// allocates N blocks of contiguous memory and returns the first block
AllocBlocks = 7,
/// frees N blocks starting at the given block
FreeBlocks = 8,
/// reads N sectors from the hard block device and writes them to the given block, this syscall will block the current task
/// returns 0 on success and 1 on failure
ReadHBD = 9,
/// sends a notification to the given task.
/// (taskid, addr) -> ret
/// returns 0 on success and 1 on failure (i.e. taskid is invalid)
/// addr is one block of memory.
/// calling this syscall will NOT block the current process, you must call WaitForNotification to
/// receive your reply.
/// the point at which you are allowed to free the block is dependent on the task that is waiting for the notification,
/// however in general it is not safe to free the block until a WaitForNotifAck is called.
/// IMPORTANT NOTE:
/// sending multiple notifications to a single task without calling WaitForNotifAck is NOT SUPPORTED
/// doing this results in undefined behavior
SendNotification = 10,
/// waits for a notification to arrive
/// () -> addr
/// this will block indefinitely until a notification arrives,^
/// use PendingNotifications to check if there are any pending notifications if you want to avoid blocking.
/// return value is an address to one block of memory.
/// this return value should also be used as a method of identified associated notifications,
/// i.e. in a system like the following
/// TASK1 - - - TASK2 - - - TASK1
/// send recv,send recv
/// the same block should be used for all notifications, and overwritten repeatedly
WaitForNotification = 11,
/// returns number of pending notifications
PendingNotifications = 12,
/// waits for a sent notification to be received
/// (taskid) -> 0
WaitForNotifAck = 13,
/// returns the environment pointer for the given task
EnvironmentPointer = 14,
/// disables the kernel framebuffer console, allowing you to use it for other purposes.
/// if there is no device providing a gpu, this will not do anything.
DisableFramebufferConsole = 15,
/// enables the kernel framebuffer console, this will result in an immediate framebuffer console reset.
/// if the framebuffer console is already enabled, then it will be reset upon calling this.
/// if there is no device providing a gpu, this will not do anything.
EnableFramebufferConsole = 16,
/// gets a pointer to the framebuffer
/// if there is no device providing a gpu, this will return a null pointer
FramebufferPointer = 17,
/// flushes changes done within the given rectangle to the framebuffer
/// if there is no device providing a gpu, this will not do anything
FlushFramebufferRect = 18,
/// initializes kernel, ONLY CALL ONCE! IN FACT, YOU PROBABLY NEVER NEED TO CALL THIS
InitKernel = 666
}
pub fn sc2usize(sc: SysCall) -> usize {
sc as usize
}
pub fn usize2sc(u: usize) -> SysCall {
match u {
0 => SysCall::NoAction,
1 => SysCall::KernelInfo,
2 => SysCall::CreateTask,
3 => SysCall::ExitTask,
4 => SysCall::CurrentTask,
5 => SysCall::ReadInbuf,
6 => SysCall::WriteTerminal,
7 => SysCall::AllocBlocks,
8 => SysCall::FreeBlocks,
9 => SysCall::ReadHBD,
10 => SysCall::SendNotification,
11 => SysCall::WaitForNotification,
12 => SysCall::PendingNotifications,
13 => SysCall::WaitForNotifAck,
14 => SysCall::EnvironmentPointer,
15 => SysCall::DisableFramebufferConsole,
16 => SysCall::EnableFramebufferConsole,
17 => SysCall::FramebufferPointer,
18 => SysCall::FlushFramebufferRect,
666 => SysCall::InitKernel,
_ => SysCall::NoAction,
}
}
pub fn kinfo() -> KernelInfo {
let mut kinfo = KernelInfo {
current_process_count: 0,
total_mem_blocks: 0,
free_mem_blocks: 0,
};
syscall(SysCall::KernelInfo, &mut kinfo as *mut KernelInfo as usize, 0, 0, 0, 0, 0);
kinfo
}
pub fn create_task(ts: TaskSetup) -> u8 {
syscall(SysCall::CreateTask, &ts as *const TaskSetup as usize, 0, 0, 0, 0, 0) as u8
}
pub fn exit() -> ! {
syscall(SysCall::ExitTask, 0, 0, 0, 0, 0, 0);
loop {
stall();
}
}
pub fn current_task() -> u8 {
syscall(SysCall::CurrentTask, 0, 0, 0, 0, 0, 0) as u8
}
pub fn read_inbuf(buf: &mut [u8]) -> usize {
syscall(SysCall::ReadInbuf, buf.as_mut_ptr() as usize, buf.len(), 0, 0, 0, 0)
}
pub fn alloc_blocks(n: usize) -> usize {
syscall(SysCall::AllocBlocks, n, 0, 0, 0, 0, 0)
}
pub fn free_blocks(addr: usize, n: usize) {
syscall(SysCall::FreeBlocks, addr, n, 0, 0, 0, 0);
}
pub fn write_terminal(buf: &[u8]) {
syscall(SysCall::WriteTerminal, buf.as_ptr() as usize, buf.len(), 0, 0, 0, 0);
}
pub fn read_hbd(sector: usize, buf_addr: usize, count: usize) -> usize {
syscall(SysCall::ReadHBD, sector, buf_addr, count, 0, 0, 0)
}
pub fn send_notification(taskid: u8, addr: usize) {
syscall(SysCall::SendNotification, taskid as usize, addr, 0, 0, 0, 0);
}
pub fn wait_for_notification() -> usize {
syscall(SysCall::WaitForNotification, 0, 0, 0, 0, 0, 0)
}
pub fn pending_notifications() -> usize {
syscall(SysCall::PendingNotifications, 0, 0, 0, 0, 0, 0)
}
pub fn wait_for_notif_ack(taskid: u8) {
syscall(SysCall::WaitForNotifAck, taskid as usize, 0, 0, 0, 0, 0);
}
pub fn environment_pointer() -> usize {
syscall(SysCall::EnvironmentPointer, 0, 0, 0, 0, 0, 0)
}
pub fn disable_framebuffer_console() {
syscall(SysCall::DisableFramebufferConsole, 0, 0, 0, 0, 0, 0);
}
pub fn enable_framebuffer_console() {
syscall(SysCall::EnableFramebufferConsole, 0, 0, 0, 0, 0, 0);
}
pub fn framebuffer_pointer() -> usize {
syscall(SysCall::FramebufferPointer, 0, 0, 0, 0, 0, 0)
}
pub fn flush_framebuffer_rect(x: usize, y: usize, w: usize, h: usize) {
syscall(SysCall::FlushFramebufferRect, x, y, w, h, 0, 0);
}
pub fn init_kernel() {
syscall(SysCall::InitKernel, 0, 0, 0, 0, 0, 0);
}