= GIET-VM / Syscall Handlers = The [source:soft/giet_vm/giet_kernel/sys_handler.c sys_handler.c] and [source:soft/giet_vm/giet_kernel/sys_handler.h sys_handler.h] files define the kernel data structure and functions that are used to handle the system calls. These functions are prefixed by ''_'' to remind that they can only be executed by a processor in kernel mode. [[PageOutline]] == __Applications related syscall handlers__ == These functions can be used to dynamically activate / deactivate an application. === 1) int '''_sys_exec_application'''( char* name ) === === 2) int '''_sys_kill_application'''( char* name ) === === 3) int '''_sys_applications_status'''( ) === These functions implement a subset of the POSIX threads API. == __Threads related syscall handlers__ == === 1) int '''_sys_pthread_create'''( pthread_t * trdid , void * attr , void * function , void * arg ) === This function search in the mapping a thread that is declared in the same space as the calling (parent) thread, and has the entry point defined by the function . If it found a matching thread in the mapping, this thread is activated. * '''trdid''' : pointer on buffer for allocated trdid. * '''attr''' : the attribute argument is not supported : must be NULL. * '''function''' : pointer on the thread entry function. * '''arg''' : pointer on function argument. Returns 0 if success / returns -1 if matching thread not found. === 2) int '''_sys_pthread_join'''( pthread_t trdid ) === This blocking function returns only when the thread identified by the argument exit. * '''trdid''' : expected thead identifier. Returns 0 if success / returns negative value if expected thread not found. === 3) int '''_sys_pthread_kill'''( pthread_t trdid , int signal ) === This function send signal to the thread identified by the argument. If the argument value is non-zero, the target thread is desactivated at the next scheduling point. * '''trdid''' : target thead identifier. * '''signal''' : target killed if non-zero. Returns 0 if success / returns negative value if target thread not found. === 4) int '''_sys_pthread_exit'''( void* string ) === This function deschedules and desactivates the calling thread. * '''string''' : message printed on the kernel TTY. === 5) int '''_sys_pthread_yield'''( ) === This function deschedule the calling thread. === 6) void '''_sys_kthread_create'''( unsigned int * trdid , unsigned int x , unsigned int y , unsigned int p , char * name , void * function , unsigned int arg ) === This function initializes a kernel thread context, for a core identified by the arguments, in a given scheduler. It allocate a new "ltid" and update the threads field in the scheduler. It is used in kernel-init to create the NIC_TX_MOVE and NIC_RX_MOVE kernel threads. * '''trdid''' : pointer on buffer for allocated trdid. * '''x''' : X cluster coordinate. * '''y''' : Y cluster coordinate. * '''p''' : local processor index in cluster. * '''name''' : thread name (for debug). * '''function''' : pointer on the entry function. * '''arg''' : entry function argument value. == __Coprocessors related syscall handlers__ == These functions are used to access coprocessors connected to the VCI network with a ''vci_mwmr_dma'' controller. They make the assumption that there is only one hardware coprocessor per cluster, and a coprocessor can be identified by the cluster coordinates. The following structure (defined in the stdio.h file) is used to define a specific TO_COPROC / FROM_COPROC channel. {{{ typedef struct giet_coproc_channel { unsigned int channel_mode; // MWMR / DMA_IRQ / DMA_NO_IRQ unsigned int buffer_size; // memory buffer size unsigned int buffer_vaddr; // memory buffer virtual address unsigned int mwmr_vaddr; // MWMR descriptor virtual address unsigned int lock_vaddr; // lock for MWMR virtual address } giet_coproc_channel_t; }}} === 1) int '''_sys_coproc_alloc'''( unsigned int coproc_type , unsigned int* coproc_info , unsigned int* cluster_xy ) === This function allocates an hardware coprocessor to the calling task. * '''coproc_type''' : requested processor type. * '''coproc_info''' : returns the number of ports (TO_COPROC / FROM_COPROC / CONFIG ) * '''cluster_xy''' : returns the cluster coordinates. In this implementation, the the requested coprocessor must be in the same cluster as the processor running the calling task. === 2) int '''_sys_coproc_release'''( unsigned int cluster_xy ) === This function des-allocates a previously allocated coprocessor. * ''' cluster_xy''' : cluster coordinates. === 3) int '''_sys_coproc_channel_init'''( unsigned int cluster_xy , unsigned int channel , giet_coproc_channel_t* desc ) === This function initializes specific TO_COPROC or FROM_COPROC communication channel. * '''cluster_xy''' : cluster coordinates. * '''channel''' : channel index. * '''desc''' : pointer on the channel descriptor. === 4) int '''_sys_coproc_channel_start'''( unsigned int cluster_xy , unsigned int channel ) === This function starts a specific TO_COPROC / FROM_COPROC communication channel. * '''cluster_xy''' : cluster coordinates. * '''channel''' : channel index. === 5) int '''_sys_coproc_channel_stop'''( unsigned int cluster_xc , unsigned int channel ) === This function stops a specific TO_COPROC / FROM_COPROC communication channel. * '''cluster_xy''' : cluster coordinates. * '''channel''' : channel index. === 6) int '''_sys_coproc_channel_completed'''( unsigned int cluster_xy , unsigned int channel ) === This blocking function polls the CHANNEL_STATUS register, and returns only when the transfer is completed. Returns the status value (non-zero value in case of error). It should be used when a channel is operating in MODE_DMA_NO_IRQ. * '''cluster_xy''' : cluster coordinates. * '''channel''' : channel index. == __TTY related syscall handlers__ == === 1) int '''_sys_tty_alloc'''( unsigned int shared ) === This function allocates a private TTY terminal to the calling thread, and registers the TTY terminal index (called channel) in the thread context. If the argument is non-zero, the same TTY channel is registered in the context of all others threads in the same vspace, resulting in one single TTY terminal shared by all threads in the vspace. The number of users is registered in the _tty_users[channel] array. An external IRQ (WTI) is dynamically allocated to the processor running the calling thread. The processor coordinates[x,y,p] and the WTI index are registered in the _tty_wti[channel] array. Returns 0 if success. Returns -1 if no available TTY channel, or TTY already allocated. === 2) int '''_sys_tty_release'''( ) === This function release the TTY channel allocated to the calling thread. The corresponding thread context slot is reset (0xFFFFFFFF value), and the _tty_users[channel] entry is decremented. The corresponding channel keep busy until the value stored in _tty_users[channel] is non-zero. Returns 0 if success. Returns -1 if TTY already released. === 3) int '''_sys_tty_write'''( const char* buffer, unsigned int length, unsigned int channel ) === This non-blocking function writes a character string from a fixed-length buffer to a TTY terminal identified by the channel argument. If channel argument is 0xFFFFFFFF, the TTY index is found in the task context. It is non blocking: it tests the TTY_STATUS register, and stops the transfer as soon as the TTY_STATUS[WRITE] bit is set. Returns -1 if no TTT terminal allocated to the calling task. Returns the number of characters that have been written if a terminal is allocated. === 4) int '''_sys_tty_read'''( char* buffer, unsigned int length, unsigned int channel ) === This non-blocking function fetches one character from the terminal identified by the ''channel'' argument. If the ''channel'' argument is 0xFFFFFFFF, the TTY index is obtained from the current task context. It uses the TTY_GET_IRQ[tty_id] interrupt and the buffer must have been filled by the TTY_ISR. It test the _tty_rx_full[tty_id] variable, read the _tty_rx_buf[tty_id] buffer, writes this character to the target buffer, and resets the_tty_rx_full[tty_id] register. The length argument is not used. Returns -1 if no TTY terminal allocated to the calling task. Returns the number of characters that have been read if a terminal is allocated (can be 0 or 1). == __TIMER retated syscall handlers__ == === 1) int '''_sys_tim_alloc'''() === This function allocates a private timer to the calling thread, and register the timer index (called channel) in the thread context. The timer is not shared: a 1 value is registered in the _tim_users[channel] array. An external IRQ (WTI) is dynamically allocated to the processor running the calling thread. The processor coordinates[x,y,p] and the WTI index are registered in the _tty_wti[channel] array. Returns 0 if success. Return -1 if no timer available, or timer already allocated. === 2) int '''_sys_tim_release'''() === This function release the TIMER channel allocated to the calling thread. The corresponding thread context slot is reset (0xFFFFFFFF value), and the _tty_users[channel] entry is reset to 0. Returns 0 if success. Returns -1 if timer already released. === 3) int '''_sys_tim_start'''( unsigned int period ) === This function activates the timer allocated to the calling thread. The argument defines the IRQ period. Returns 0 if success. Returns -1 if no allocated timer. === 4) int '''_sys_tim_stop'''() === This function stops the user timer channel allocated to the calling task. Returns 0 if success. Returns -1 if no allocated timer. == __NIC related syscall handlers__ == === 1) void '''_sys_nic_init'''( ) === This function is called by the kernel_init() function. It allocates and initializes, for each NIC channel, the kernel NIC_TX_FIFO and the NIC_RX / NIC_TX kernel threads. === 2) int '''_sys_nic_open'''( ) === This function allocates a socket index to the calling thread, and allocates the socket descriptor in the same cluster as the calling thread. Then it allocates and initialize the NIC_RX_FIFO associated to the socket. Returns 0 if success. Returns -1 if no socket available. === 3) int '''_sys_nic_bind'''( unsigned int index , unsigned int local_addr , unsigned int local_port ) === This function register the local IP address and local port number in the socket descriptor identified by the argument. * '''index''' : socket index. * '''local_addr''' : local IPV4 address. * '''local_port''' : local port. Returns 0 if success, returns -1 if the socket is not allocated to calling thread. === 4) int '''_sys_nic_connect'''( unsigned int index , unsigned int remote_addr , unsigned int remote_port ) === This function register the local IP address and local port number in the socket descriptor identified by the argument. * '''index''' : socket index. * '''remote_addr''' : local IPV4 address. * '''remote_port''' : local port. Returns 0 if success. Returns -1 if the socket is not allocated to calling thread. === 5) int '''_sys_nic_close'''( unsigned int index ) === This function release the memory allocated for a socket identified by the argument. * '''index''' : socket index. Returns 0 if success, returns -1 if the socket is not allocated to calling thread. === 6) int '''_sys_nic_write'''( unsigned int index , unsigned int vaddr , unsigned int count ) === This blocking function moves a RAW packet from the user buffer to the kernel NIC_TX_FIFO, after building the ETH/IP/UDP headers. In this first implementation, we use a polling strategy in case of FIFO full. * '''index''' : socket index. * '''vaddr''' : virtual base address of source user buffer. * '''count''' : number of bytes. Returns number of bytes written if success / returns -1 if error === 7) int '''_sys_nic_read'''( unsigned int index , unsigned int vaddr , unsigned int count ) === This blocking function moves a RAW packet from the kernel NIC_RX_FIFO, to the user buffer, after removing the ETH/IP/UDP headers. In this first implementation, we use a polling strategy in case of FIFO empty. * '''index''' : socket index. * '''vaddr''' : virtual base address of destination user buffer. * '''count''' : max number of bytes in user buffer. Returns number of bytes read if success / returns -1 if error === 8) void '''_sys_nic_tx_move'''( unsigned int channel ) === This function is executed by the NIC_TX kernel thread. It continuously move a stream of ETH paquets from the NIC_TX_FIFO (associated to a given NIC channel) to the NIC_TX_QUEUE (associated to the same channel). The NIC_TX_QUEUE implementation depends on the available NIC hardware (it is implemented as a CHBUF for the VciMasterNic component). It blocks if the source TX_FIFO is empty or if the dest TX_QUEUE is full.In this first implementation, the blocking uses a busy-waiting policy, but this should be replaced by a descheduling policy. * '''channel''' : NIC channel index. === 9) void '''_sys_nic_rx_move'''( unsigned int channel ) === This function is executed by the NIC_RX kernel thread. It continuously move a stream of ETH paquets from the NIC_RX_QUEUE (associated to a given NIC channel) to several NIC_RX_FIFOs (one per socket). The NIC_RX_QUEUE implementation depends on the available NIC hardware (it is implemented as a CHBUF for the VciMasterNic component). It blocks if the source RX_QUEUE is empty or if the dest TX_FIFO is full. In this first implementation, the blocking uses a busy-waiting policy, but this should be replaced by a descheduling policy. * '''channel''' : NIC channel index. == __FBF related syscall handlers__ == === 1) int '''_sys_fbf_size'''( unsigned int* width , unsigned int* height ) === This function returns in the and buffers the Frame Buffer size. It returns always SYSCALL_OK. === 2) int '''_sys_fbf_alloc'''() === This function takes the exclusive ownership of the frame buffer for the calling thread application. It must be called by a single thread. It register the number of potential users : all threads in the same space as the calling thread. It returns SYSCALL_OK in case of success. It returns SYSCALL_SHARED_PERIPHERAL_BUSY if the frame buffer is already allocated. === 3) int '''_sys_fbf_release'''() === This function decrement the number of registered users for the frame buffer. It must be called by all the threads of a given application to completely release the frame buffer. It returns SYSCALL_OK in case of success. It returns SYCALL_CHANNEL_NON_ALLOCATED if the frame buffer was not allocated. === 4) int '''_sys_fbf_cma_alloc'''( unsigned int nbufs ) === This function allocates a private CMA channel, that can be used by all threads in the same space as the calling thread. It must be called by a single thread, but the channel index is registered in all threads contexts in the same vspace. The argument define the CMA length (number of chained buffers). Ir returns SYSCALL_OK in case of success. It returns SYSCALL_NO_CHANNEL_AVAILABLE if no CMA channel available. It returns SYSCALL_CHANNEL_ALREADY_ALLOCATED if CMA already allocated. It returns SYSCALL_ILLEGAL_ARGUMENT if is larger than 256. === 5) int '''_sys_fbf_cma_release'''() === This function decrement the number of registered users for the allocated CMA channel. It must be called by all the threads of a given application to completely release the CMA channel. It stops the CMA transfer, when the last thread in the space releases the CMA channel. It returns SYSCALL_OK in case of success. It returns SYCALL_CHANNEL_NON_ALLOCATED if the CMA channel was not allocated. === 6) int '''_sys_fbf_cma_init_buf'''( unsigned int index , void* buf_vaddr , void* sts_vaddr ) === This function register an user buffer and a buffer status in the the CHBUF descriptor associated to the frame buffer. The argument is the buffer index in the CHBUF. The and arguments are the pointers on the user buffer and status. Both the user buffer and the user status must be 64 bytes aligned. It returns SYSCALL_OK in case of success. It returns SYCALL_CHANNEL_NON_ALLOCATED if the CMA channel was not allocated. It returns SYSCALL_ADDRESS_NON_ALIGNED if the buffer or status are not 64 bytes aligned. It returns SYSCALL_ADDRESS_NON_USER_ACCESSIBLE if addresses are protected. === 7) int '''_sys_fbf_cma_start'''( ) === This function activates the CMA channel to transfer of a stream of images from the user buffers to the frame buffer. The user buffers musThe CMA component is configured in IN_ORDER transfer mode (blocking when the expected source buffer is not available). It returns SYSCALL_OK in case of success. It returns SYCALL_CHANNEL_NON_ALLOCATED if the CMA channel was not allocated. It returns SYSCALL_MISSING_INITIALISATION if the CHBUF was not initialized. === 8) int '''_sys_fbf_cma_check'''( unsigned int index ) === This blocking function checks that the user buffer identified by the argument is empty, and can be reused by the application. It makes an INVAL request to the L2 cache, before testing the source buffer status, because it is modified in XRAM by the CMA component. It returns SYSCALL_OK when the buffer is empty. It returns SYCALL_CHANNEL_NON_ALLOCATED if the CMA channel was not allocated. === 9) int '''_sys_fbf_cma_display'''( unsigned int index ) === This function must be used to signal that the user buffer identified by the argument is full and can be transferred to the frame buffer. It makes a SYNC request to the L2 cache, for both the source user buffer the status, because these data will be read from XRAM by the CMA component. It returns SYSCALL_OK in case of success. It returns SYCALL_CHANNEL_NON_ALLOCATED if the CMA channel was not allocated. === 10) int '''_sys_fbf_cma_stop'''() === This function desactivares the CMA channel allocated to the calling task. It returns SYSCALL_OK in case of success. It returns SYCALL_CHANNEL_NON_ALLOCATED if the CMA channel was not allocated. === 11) int '''_sys_fbf_sync_write'''( unsigned int offset, void* buffer, unsigned int length ) === This function transfer data from an user buffer to the frame_buffer device using a memcpy. * '''offset''' : offset (in bytes) in the frame buffer. * '''buffer''' : base address of the memory buffer. * '''length''' : number of bytes to be transfered. === 12) int '''_sys_fbf_sync_read'''( unsigned int offset, void* buffer, unsigned int length ) === This function transfer data from the frame_buffer device to anuser buffer using a memcpy. * '''offset''' : offset (in bytes) in the frame buffer. * '''buffer''' : base address of the memory buffer. * '''length''' : number of bytes to be transfered. == __Miscelaneous syscall handlers__ == === 1) int '''_sys_ukn'''() === This function executed in case of undefined syscall. It just display an error message on TTY0. === 2) int '''_sys_proc_xyp'''( unsigned int* x, unsigned int*, unsigned int* p ) === This function returns the processor (x,y,p) identifiers. === 3) int '''_sys_task_exit'''() === The calling task goes to sleeping state, after printing an exit message. It is descheduled and enters the "not runable" mode. === 4) int '''_sys_context_switch'''() === This function deschedules the calling task. It mask interrupts before calling the _ctx_switch, and restore it when the task is rescheduled. === 5) int '''_sys_local_task_id'''() === This function returns the current task local index (amongst tasks running on a given processor). === 6) int '''_sys_global_task_id'''() === This function returns the current task global index (amongst all tasks running on all processors). === 7) int '''_sys_thread_id'''() === This function returns the current task thread index (amongst all tasks in a given multi-tasks application). === 8) int '''_sys_procs_number'''( unsigned int* x_size, unsigned int* y_size, unsigned int* nprocs ) === Returns in the arguments the 2D mesh size (only clusters containing processors), and the number of processors per cluster. === 9) int '''_sys_vseg_get_vbase'''( char* vspace_name, char* vobj_name, unsigned int* vbase ) === This function returns in the ''vbase'' argument the virtual base address of the private vseg identified by the (vspace_name / vseg_name ) couple. Returns 0 if success, -1 if vobj not found. === 10) int '''_sys_vseg_get_length'''( char* vspace_name, char* vseg_name, unsigned int* length ) === This function returns in the ''length'' argument the length of the private vseg identified by the (vspace_name / vseg_name ) couple. Returns 0 if success, -1 if vobj not found === 11) int '''_sys_xy_from_ptr'''( void* ptr, unsigned int* x, unsigned int* y ) === This function returns in the (x,y) arguments the coordinates of the cluster where is mapped the ptr virtual address. It use the _get_context_slot() function to get the calling task page table, and uses the _v2p_translate() function to obtain the physical address. Returns 0 if success, -1 if ptr not mapped in the calling task vspace. === 12) int '''_sys_heap_info'''( unsigned int* vaddr, unsigned int* length, unsigned int x, unsigned int y ) === This function returns the information associated to a user heap vseg : vaddr and length. * If (x < X_SIZE) and (y < Y_SIZE), it return the heap associated to any task running in cluster(x,y). * else, it return the heap associated to the calling task. Returns 0 if success, returns -1 if not found.