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, /// 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, 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 init_kernel() { syscall(SysCall::InitKernel, 0, 0, 0, 0, 0, 0); }