genode/base-mb/include/kernel/syscalls.h

569 lines
16 KiB
C++
Executable File

/*
* \brief Kernels syscall frontend
* \author Martin stein
* \date 2010.07.02
*/
#ifndef _INCLUDE__KERNEL__SYSCALLS_H_
#define _INCLUDE__KERNEL__SYSCALLS_H_
/* Kernel includes */
#include <kernel/types.h>
#include <cpu/config.h>
/**
* 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_ */