/* * \brief Kernels syscall frontend * \author Martin stein * \date 2010.07.02 */ #ifndef _INCLUDE__KERNEL__SYSCALLS_H_ #define _INCLUDE__KERNEL__SYSCALLS_H_ /* Kernel includes */ #include #include /** * Inline assembly clobber lists for syscalls with no arguments */ #define SYSCALL_7_ASM_CLOBBER "r24", SYSCALL_6_ASM_CLOBBER #define SYSCALL_6_ASM_CLOBBER "r25", SYSCALL_5_ASM_CLOBBER #define SYSCALL_5_ASM_CLOBBER "r26", SYSCALL_4_ASM_CLOBBER #define SYSCALL_4_ASM_CLOBBER "r27", SYSCALL_3_ASM_CLOBBER #define SYSCALL_3_ASM_CLOBBER "r28", SYSCALL_2_ASM_CLOBBER #define SYSCALL_2_ASM_CLOBBER "r29", SYSCALL_1_ASM_CLOBBER #define SYSCALL_1_ASM_CLOBBER SYSCALL_0_ASM_CLOBBER #define SYSCALL_0_ASM_CLOBBER "r31", "r30" /** * Inline assembly list for write access during syscalls with no arguments */ #define SYSCALL_0_ASM_WRITE \ [result] "=m" (result), \ [r15_buf] "+m" (r15_buf), \ [opcode] "+m" (opcode) /** * Inline assembly lists for write access during syscalls with arguments */ #define SYSCALL_1_ASM_WRITE [arg_0] "+m" (arg_0), SYSCALL_0_ASM_WRITE #define SYSCALL_2_ASM_WRITE [arg_1] "+m" (arg_1), SYSCALL_1_ASM_WRITE #define SYSCALL_3_ASM_WRITE [arg_2] "+m" (arg_2), SYSCALL_2_ASM_WRITE #define SYSCALL_4_ASM_WRITE [arg_3] "+m" (arg_3), SYSCALL_3_ASM_WRITE #define SYSCALL_5_ASM_WRITE [arg_4] "+m" (arg_4), SYSCALL_4_ASM_WRITE #define SYSCALL_6_ASM_WRITE [arg_5] "+m" (arg_5), SYSCALL_5_ASM_WRITE #define SYSCALL_7_ASM_WRITE [arg_6] "+m" (arg_6), SYSCALL_6_ASM_WRITE /** * Inline assembly ops for syscalls with no arguments * - r19-r31 are save when occuring in the clobber list * r15 is a 'dedicated' register and so we have to save it manually */ #define SYSCALL_0_ASM_OPS \ "lwi r31, %[opcode] \n" \ "swi r15, %[r15_buf] \n" \ "brki r15, 0x8 \n" \ "or r0, r0, r0 \n" \ "lwi r15, %[r15_buf] \n" \ "swi r30, %[result] " /** * Inline assembly ops for syscalls with arguments */ #define SYSCALL_1_ASM_OPS "lwi r30, %[arg_0]\n" SYSCALL_0_ASM_OPS #define SYSCALL_2_ASM_OPS "lwi r29, %[arg_1]\n" SYSCALL_1_ASM_OPS #define SYSCALL_3_ASM_OPS "lwi r28, %[arg_2]\n" SYSCALL_2_ASM_OPS #define SYSCALL_4_ASM_OPS "lwi r27, %[arg_3]\n" SYSCALL_3_ASM_OPS #define SYSCALL_5_ASM_OPS "lwi r26, %[arg_4]\n" SYSCALL_4_ASM_OPS #define SYSCALL_6_ASM_OPS "lwi r25, %[arg_5]\n" SYSCALL_5_ASM_OPS #define SYSCALL_7_ASM_OPS "lwi r24, %[arg_6]\n" SYSCALL_6_ASM_OPS /** * Inline assembly lists for read access during syscalls with arguments */ #define SYSCALL_0_ASM_READ #define SYSCALL_1_ASM_READ SYSCALL_0_ASM_READ #define SYSCALL_2_ASM_READ SYSCALL_1_ASM_READ #define SYSCALL_3_ASM_READ SYSCALL_2_ASM_READ #define SYSCALL_4_ASM_READ SYSCALL_3_ASM_READ #define SYSCALL_5_ASM_READ SYSCALL_4_ASM_READ #define SYSCALL_6_ASM_READ SYSCALL_5_ASM_READ #define SYSCALL_7_ASM_READ SYSCALL_6_ASM_READ namespace Kernel { using namespace Cpu; typedef unsigned int Syscall_arg; /** * Syscall with 1 Argument */ ALWAYS_INLINE inline int syscall(Syscall_id opcode); /** * Syscall with 2 Arguments */ ALWAYS_INLINE inline int syscall(Syscall_id opcode, Syscall_arg arg_0); /** * Syscall with 3 Arguments */ ALWAYS_INLINE inline int syscall(Syscall_id opcode, Syscall_arg arg_0, Syscall_arg arg_1); /** * Syscall with 4 Arguments */ ALWAYS_INLINE inline int syscall(Syscall_id opcode, Syscall_arg arg_0, Syscall_arg arg_1, Syscall_arg arg_2); /** * Syscall with 5 Arguments */ ALWAYS_INLINE inline int syscall(Syscall_id opcode, Syscall_arg arg_0, Syscall_arg arg_1, Syscall_arg arg_2, Syscall_arg arg_3); /** * Syscall with 6 Arguments */ ALWAYS_INLINE inline int syscall(Syscall_id opcode, Syscall_arg arg_0, Syscall_arg arg_1, Syscall_arg arg_2, Syscall_arg arg_3, Syscall_arg arg_4); /** * Syscall with 7 Arguments */ ALWAYS_INLINE inline int syscall(Syscall_id opcode, Syscall_arg arg_0, Syscall_arg arg_1, Syscall_arg arg_2, Syscall_arg arg_3, Syscall_arg arg_4, Syscall_arg arg_5); /** * Syscall with 8 Arguments */ ALWAYS_INLINE inline int syscall(Syscall_id opcode, Syscall_arg arg_0, Syscall_arg arg_1, Syscall_arg arg_2, Syscall_arg arg_3, Syscall_arg arg_4, Syscall_arg arg_5, Syscall_arg arg_6); /** * Yield thread execution and coninue with next */ inline void thread_yield(); /** * Block thread that calls this */ inline void thread_sleep(); /** * Create and start threads * * \param tid ident that thread should get * \param pid threads protection domain * \param pager_id threads page fault handler thread * \param utcb_p virtual address of utcb * \param vip initial virtual ip * \param vsp initial virtual sp * \param param scheduling parameters, not used by now * \return 0 if new thread was created * n > 0 if any error has occured (errorcodes planned) */ inline int thread_create(Thread_id tid, Protection_id pid, Thread_id pager_tid, Utcb* utcb_p, Cpu::addr_t vip, Cpu::addr_t vsp, unsigned int params); /** * Kill thread - only with root rights * * \param tid ident of thread * \return 0 if thread is awake after syscall * n > 0 if any error has occured (errorcodes planned) */ inline int thread_kill(Thread_id tid); /** * Unblock denoted thread * * \param tid ident of thread thats blocked * \detail works only if destination has same protection * domain or caller has rootrights * \return 0 if thread is awake after syscall * n > 0 if any error has occured (errorcodes planned) */ inline int thread_wake(Thread_id tid); /** * Re-set pager of another thread * * \param dst_tid thread whose pager shall be changed * \param pager_tid ident of pager thread * \detail works only if caller has rootrights * \return 0 if new pager of thread is successfully set * n > 0 if any error has occured (errorcodes planned) */ inline int thread_pager(Thread_id dst_tid, Thread_id pager_tid); /** * Reply last and wait for new ipc request * * \param msg_length length of reply message * \return length of received message */ inline int ipc_serve(unsigned int reply_size); /** * Send ipc request denoted in utcb to specific thread * * \param dest_id ident of destination thread * \param msg_length number of request-message words * \return number of reply-message words, or * zero if request was not successfull */ inline int ipc_request(Thread_id dest_tid, unsigned int msg_size); /** * Load pageresolution to memory managment unit * * \param p_addr physical page address * \param v_addr virtual page address * \param pid protection domain ident * \param size size of page * \param permissions permission flags for page * \return 0 if thread is awake after syscall * n > 0 if any error has occured (errorcodes planned) */ inline int tlb_load(Cpu::addr_t p_address, Cpu::addr_t v_address, Protection_id pid, Paging::Physical_page::size_t size, Paging::Physical_page::Permissions permissions); /** * Flush page resolution area from tlb * * \param pid protection domain id * \param start startaddress of area * \param size_kbyte size of area in 1KB units * \return 0 if new thread was created * n > 0 if any error has occured (errorcodes planned) */ inline int tlb_flush(Protection_id pid, Cpu::addr_t start, unsigned size); /** * Print char to serial ouput * * \param c char to print */ inline void print_char(char c); /** * Print various informations about a specific thread * \param i Unique ID of the thread, if it remains 0 take our own ID */ inline void print_info(Thread_id const & i = 0); /** * Allocate an IRQ to the calling thread if the IRQ is * not allocated yet to another thread * * \param i Unique ID of the IRQ * \return 0 If the IRQ is allocated to this thread now * n != 0 If the IRQ is not allocated to this thread already * (code of the error that has occured) */ inline int irq_allocate(Irq_id i); /** * Free an IRQ from allocation if it is allocated by the * calling thread * * \param i Unique ID of the IRQ * \return 0 If the IRQ is free now * n != 0 If the IRQ is allocated already * (code of the error that has occured) */ inline int irq_free(Irq_id i); /** * Sleep till the 'Irq_message'-queue of this thread is not * empty. For any IRQ that is allocated by this thread and occures * between the kernel-entrance inside 'irq_wait' and the next time this * thread wakes up, an 'Irq_message' with metadata about the according * IRQ is added to the threads 'Irq_message'-queue. * When returning from 'irq_wait' the first message from the threads * 'Irq_message'-queue is dequeued and written to the threads UTCB-base. */ inline void irq_wait(); } void Kernel::print_info(Thread_id const & i) { syscall(PRINT_INFO, (Syscall_arg) i); } void Kernel::irq_wait() { syscall(IRQ_WAIT); } int Kernel::irq_allocate(Irq_id i) { return syscall(IRQ_ALLOCATE, (Syscall_arg) i); } int Kernel::irq_free(Irq_id i) { return syscall(IRQ_FREE, (Syscall_arg) i); } void Kernel::thread_yield() { syscall(THREAD_YIELD); } void Kernel::thread_sleep() { syscall(THREAD_SLEEP); } int Kernel::thread_create(Thread_id tid, Protection_id pid, Thread_id pager_tid, Utcb* utcb_p, Cpu::addr_t vip, Cpu::addr_t vsp, unsigned int params) { return syscall(THREAD_CREATE, (Syscall_arg) tid, (Syscall_arg) pid, (Syscall_arg) pager_tid, (Syscall_arg) utcb_p, (Syscall_arg) vip, (Syscall_arg) vsp, (Syscall_arg) params); } int Kernel::thread_kill(Thread_id tid) { return syscall(THREAD_KILL, (Syscall_arg) tid); } int Kernel::thread_wake(Thread_id tid) { return syscall(THREAD_WAKE, (Syscall_arg) tid); } int Kernel::thread_pager(Thread_id dst_tid, Thread_id pager_tid) { return syscall( THREAD_PAGER, (Syscall_arg) dst_tid, (Syscall_arg) pager_tid); } int Kernel::ipc_serve(unsigned int reply_size) { return syscall(IPC_SERVE, (Syscall_arg) reply_size); } int Kernel::ipc_request(Thread_id dest_tid, unsigned int msg_size) { return syscall( IPC_REQUEST, (Syscall_arg) dest_tid, (Syscall_arg) msg_size); } int Kernel::tlb_load(Cpu::addr_t p_address, Cpu::addr_t v_address, Protection_id pid, Paging::Physical_page::size_t size, Paging::Physical_page::Permissions permissions) { return syscall( TLB_LOAD, (Syscall_arg) p_address, (Syscall_arg) v_address, (Syscall_arg) pid, (Syscall_arg) size, (Syscall_arg) permissions); } int Kernel::tlb_flush(Protection_id pid, Cpu::addr_t start, unsigned size) { return syscall( TLB_FLUSH, (Syscall_arg) pid, (Syscall_arg) start, (Syscall_arg) size); } void Kernel::print_char(char c) { syscall(PRINT_CHAR, (Syscall_arg) c); } int Kernel::syscall(Syscall_id opcode) { int result; unsigned int r15_buf; asm volatile(SYSCALL_0_ASM_OPS : SYSCALL_0_ASM_WRITE : SYSCALL_0_ASM_READ : SYSCALL_0_ASM_CLOBBER); return result; } int Kernel::syscall(Syscall_id opcode, Syscall_arg arg_0) { int result; unsigned int r15_buf; asm volatile(SYSCALL_1_ASM_OPS : SYSCALL_1_ASM_WRITE : SYSCALL_1_ASM_READ : SYSCALL_1_ASM_CLOBBER); return result; } int Kernel::syscall(Syscall_id opcode, Syscall_arg arg_0, Syscall_arg arg_1) { int result; unsigned int r15_buf; asm volatile(SYSCALL_2_ASM_OPS : SYSCALL_2_ASM_WRITE : SYSCALL_2_ASM_READ : SYSCALL_2_ASM_CLOBBER); return result; } int Kernel::syscall(Syscall_id opcode, Syscall_arg arg_0, Syscall_arg arg_1, Syscall_arg arg_2) { int result; unsigned int r15_buf; asm volatile(SYSCALL_3_ASM_OPS : SYSCALL_3_ASM_WRITE : SYSCALL_3_ASM_READ : SYSCALL_3_ASM_CLOBBER); return result; } int Kernel::syscall(Syscall_id opcode, Syscall_arg arg_0, Syscall_arg arg_1, Syscall_arg arg_2, Syscall_arg arg_3) { int result; unsigned int r15_buf; asm volatile(SYSCALL_4_ASM_OPS : SYSCALL_4_ASM_WRITE : SYSCALL_4_ASM_READ : SYSCALL_4_ASM_CLOBBER); return result; } int Kernel::syscall(Syscall_id opcode, Syscall_arg arg_0, Syscall_arg arg_1, Syscall_arg arg_2, Syscall_arg arg_3, Syscall_arg arg_4) { int result; unsigned int r15_buf; asm volatile(SYSCALL_5_ASM_OPS : SYSCALL_5_ASM_WRITE : SYSCALL_5_ASM_READ : SYSCALL_5_ASM_CLOBBER); return result; } int Kernel::syscall(Syscall_id opcode, Syscall_arg arg_0, Syscall_arg arg_1, Syscall_arg arg_2, Syscall_arg arg_3, Syscall_arg arg_4, Syscall_arg arg_5) { int result; unsigned int r15_buf; asm volatile(SYSCALL_6_ASM_OPS : SYSCALL_6_ASM_WRITE : SYSCALL_6_ASM_READ : SYSCALL_6_ASM_CLOBBER); return result; } int Kernel::syscall(Syscall_id opcode, Syscall_arg arg_0, Syscall_arg arg_1, Syscall_arg arg_2, Syscall_arg arg_3, Syscall_arg arg_4, Syscall_arg arg_5, Syscall_arg arg_6) { int result; unsigned int r15_buf; asm volatile(SYSCALL_7_ASM_OPS : SYSCALL_7_ASM_WRITE : SYSCALL_7_ASM_READ : SYSCALL_7_ASM_CLOBBER); return result; } #endif /* _INCLUDE__KERNEL__SYSCALLS_H_ */