mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-23 15:32:25 +00:00
569 lines
16 KiB
C++
Executable File
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_ */
|