= GIET_VM / User-Level System Calls = The [source:soft/giet_vm/giet_libs/stdio.c stdio.c] and [source:soft/giet_vm/giet_libs/stdio.h stdio.h] files define all system calls provided to user applications by the GIET-VM. They are generally prefixed by ''giet_''. [[PageOutline]] All these functions use a ''syscall'' instruction to enter the system. In case of system call failure (illegal arguments), the calling task is killed with a ''giet_exit()''. Therefore, for all these system calls, the return value has not to be tested by the calling task. == __Processor related system calls__ == === 1) void '''giet_proc_xyp'''( unsigned int* cluster_x, unsigned int* cluster_y unsigned int* lpid )=== This function returns the processor identifiers (X,Y,P) from the wired global processor index in CP0_PROCID. * cluster_x : X cluster coordinate * cluster_y : Y cluster coordinate * lpid : local processor index No error possible, as the fixed format is gpid = ( ( cluster_x << Y_WIDTH + cluster_y ) << P_WIDTH ) + lpid === 2) unsigned int '''giet_proctime'''() === This function returns the local processor time from the CP0_TIME register (number of cycles from reset). No error possible, as the processor implements a 32 bits wrapping register. === 3) unsigned int '''giet_rand'''() === This function returns a pseudo-random value derived from both the CP0_PROCID and CP0_TIME registers. No error possible, as the return value is always between 0 & 65535. == __User task related system calls__ == === 1) unsigned int '''giet_proc_task_id'''() === This functions returns (from the calling task context) the local task index, identifying the task amongst all task running on the same processor. No error possible. === 2) unsigned int '''giet_global_task_id'''() === This functions returns (from the calling task context) the global task id, unique in the system. No error possible. === 3) unsigned int '''giet_thread_id'''() === This functions returns (from the calling task context) the thread index, identiying the task in a given vspace. No error possible. == __Coprocessors related system calls__ == The GIET_VM allows user applications to use hardware accelerators (called coprocessors). These coprocessors can be distributed in the architecture, but there is at most one coprocessor per cluster. To be supported by the GIET_VM, a coprocessor must use the '''vci_mwmr_dma''' component, that is a generic multi-channels DMA controller. The '''vci_mwmr_dma''' component provide to coprocessor a variable number of TO_COPROC or FROM_COPROC ports, that implement FIFO interfaces. Coprocessor can request to transfer one or several bursts of 32 bits words, without address. The burst size (generally a cache line), the number of TO_COPROC and FROM_COPROC ports, and the number of bursts for a given port are hardware parameters, depending on the coprocessor type. Each port define a private communication channel between the coprocessor and a user memory buffer. The total number of channels cannot be larger than 16. A channel is identified by an index, and the TO_COPROC channels have the smallest indexes. The user application must use the ''giet_coproc_alloc()'' system call to get a private hardware coprocessor. Then it must use the ''giet_coproc_channel_init()'' system call to configure the TO_COPROC/FROM_COPROC channels. Finally, the coprocessor and the communication channels are activated by the ''giet_coproc_run()'' system call. The '''vci_mwmr_dma''' component implements two transfer modes: * In '''MODE_MWMR''', each channel FSM implements the 7 steps MWMR protocol, and transfer an "infinite" data stream, between one coprocessor port and a MWMR software FIFO in memory. The ''giet_coproc_run()'' system call is non blocking, as the synchronisation is done through the MWMR FIFOs (no transfer completion event). The MWR IRQ is only asserted if a VCI error is reported in a memory access. * In '''MODE_DMA_IRQ''' or '''MODE_DMA_NO_IRQ''', each channel FSM transfers a single buffer between one coprocessor port and the memory, and keep blocked when the transfer is completed. - In '''MODE_DMA_IRQ''', the calling task is descheduled, after coprocessor activation, in the ''giet_coproc_run()'' system call. It is rescheduled by the MWR IRQ signaling the global completion. The _mwr_isr() scan all channels status registers to report possible addressing errors, and reset the communication channels. - In '''MODE_DMA_NO_IRQ''', the ''giet_coproc_run()'' system call returns after coprocessor activation, and the user application must use the blocking ''giet_coproc_completed()'' system call that directly scan the channels registers to detect completion, report errors, and reset the channels. '''WARNING''': For a given coprocessor, all channels must be running in the same mode. '''WARNING''' : For all channels, the memory buffer base address and size must be multiple of the hardware burst size. The VCI transactions corresponding to different TO_COPROC / FROM_COPROC channels are interleaved and parallelized on the VCI network. Besides the TO_COPROC/FROM_COPROC communication channels, the '''vci_mwmr_dma''' component support up to 16 coprocessor-specific configuration/status registers. * The '''configuration''' registers are Read and Write. * The '''status''' registers are Read only. The list of currently supported coprocessors and their characteristics are defined below: || coproc_type || Function ||nb_to_coproc || nb_from_coproc || nb_config || nb_status || || MWR_COPROC_GCD || Greater Common Divider || 2 || 1 || 1 || 0 || || MWR_COPROC_DCT || Discrete Cosinus Transform || 1 || 1 || 1 || 0 || || MWR_COPROC_CPY || Memory Copy || 1 || 1 || 1 || 0 || === 1) void '''giet_coproc_alloc'''( unsigned int coproc_type , unsigned int* coproc_info ) === This function allocates a private coprocessor to the calling task, taking a lock to grant exclusive ownership, and register the coprocessor coordinates in the task context. In the current implementation, the task exit if there is no coprocessor of requested type in the same cluster as the calling task. In case of success, it returns the coprocessor characteristics in the '''coproc_info''' variable. * '''coproc_type''' : see supported types above. * '''coproc_info''' (return value) : nb_to_coprocs = info[7:0] / nb_from_coproc = info[15:8] / nb_config = info[23:16] / nb_status = info[31:24] === 2) void '''giet_coproc_channel_init'''( unsigned int channel , giet_coproc_channel_t* desc ) === This function initializes a TO_COPROC/FROM_COPROC communication channel. It uses the he following structure (defined in the [source:soft/giet_vm/giet_libs/stdio.h stdio.h] file) to specify the channel parameters: {{{ 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; }}} * '''channel''' communication channel index. TO_COPROC channels use the smallest indexes. * '''desc''' pointer on the giet_coproc_channel_t structure. === 3) void '''giet_coproc_run'''( unsigned int coproc_reg_index ) === This function activates all communication channels and the allocated coprocessor itself. * '''coproc_reg_index''' : coprocessor configuration register index to be written for coprocessor activation. === 4) void '''giet_coproc_completed'''( ) === This blocking function can be used to synchronize a software task with an hardware coprocessor running in DMA_NO_IRQ mode. It polls the status register of all communication channels, and returns only when all transfers are completed. This function exit when at least one channel status register indicates a bus error (illegal memory access). === 5) void '''giet_coproc_release'''( unsigned int coproc_reg_index ) === This function releases the coprocessor allocated to the calling task, after deactivation. * '''coproc_reg_index''' : coprocessor configuration register index to be written for coprocessor deactivation. == __TTY related system calls__ == The GIET_VM allows an user task to use a private TTY terminal, or to display log message on the kernel TTY0 terminal. === 1) void '''giet_tty_alloc'''() === This function allocates a private terminal to the calling task, and registers the terminal index in the task context. The calling task exit if no TTY terminal available. === 2) void '''giet_tty_printf'''( char* format, ... ) === This function print formated text on a private terminal that must have been allocated to the calling task by the ''get_tty_alloc()'' function. Therefore, it does not take any lock, but checks terminal allocation. Only a limited number of formats are supported: * %d : signed decimal * %u : unsigned decimal * %x : 32 bits hexadecimal * %l : 64 bits hexadecimal * %c : char * %s : string Task exit if private terminal index not defined, or in case of illegal format. === 3) void '''giet_tty_getc'''( char* byte ) === This blocking function fetches a single character from the private terminal that must have been allocated to the calling task in the application mapping. It uses the TTY_RX_IRQ interrupt, and the associated kernel buffer. Task exit if private TTY index not defined. === 4) void '''giet_tty_getw'''( unsigned int* val ) === This blocking function fetches a string of decimal characters (most significant digit first) to build a 32-bits unsigned integer from the private TTY terminal that must have been allocated to the calling task in the application mapping. It uses the TTY_RX_IRQ interrupt, and the associated kernel buffer. The non-blocking system function _tty_read is called several times, and the decimal characters are written in a 32 characters buffer until a character is read. It ignores non-decimal characters, and displays an echo for each decimal character. The character is interpreted, and previous characters can be cancelled. When the character is received, the string is converted to an unsigned int value. If the number of decimal digit is too large for the 32 bits range, the zero value is returned. Task exit if private TTY index not defined. === 5) void '''giet_tty_gets'''( char* buf, unsigned int bufsize ) === This blocking function fetches a string from the private terminal that must have been allocated to the calling task in the application mapping. It writes the string to a fixed length buffer. It uses the TTY_RX_IRQ interrupt, and the associated kernel buffer. Up to (bufsize - 1) characters (including the non printable characters) are copied into buffer, and the string is completed by a NUL character. The character is interpreted, and the function close the string with a NUL character if is read. The character is interpreted, and the corresponding character(s) are removed from the target buffer. It does not provide an echo. Task exit if private TTY index not defined. === 6) void '''giet_shr_printf'''( char* format, ... ) === This function print formated text on the kernel terminal. It takes the TTY lock for exclusive access. It supports the same formats as the giet_tty_printf() function. Task exit in case of illegal format. == __Timer related system calls__ == The GIET_VM allows an user task to activate a private timer channel, generating periodical IRQs. This timer is allocated in the external multi-timers peripheral. === 1) void '''giet_timer_alloc'''() This function allocates a private user timer to the calling task, and registers the channel index in the task context. Task exit if no timer channel available === 2) void '''giet_timer_start'''( unsigned int period ) This function starts the private timer allocated to the calling task. Task exit if no channel allocated. === 3) void '''giet_timer_stop'''( ) === This function stops the private timer allocated to the calling task. Task exit if no channel allocated. == __File system related system calls__ == The Giet-VM supports a FAT32 file system, and uses distributed data structures to access the file system: * The Inode-Tree (distributed on all clusters) is the internal representation of the File System tree. * The Fat-Cache (distributed on all clusters) is used to cache the FAT region of the block device. * The Fat-Cache (distributed on all clusters / one cache per open file) is used to cache the DATA region of the block device. * The File-Descriptor-Array (in cluster[0,0]) contains the open files descriptors. * The Fat-Descriptor (in cluster[0,0] contains the FAT32 general information. === 1) int '''giet_fat_open'''( char* pathname, unsigned int flags ) === This function allocates a file descriptor to the calling task, for the file identified by its absolute pathname from root. If several tasks try to open the same file, each task obtains a private file descriptor. The semantic is similar to the UNIX open() function, but the UNIX oflags and the UNIX access rights are not supported. The two following flags can be ''ored'' in the '''flags''' argument: * O_RDONLY : the file will accessed as read-only. Default value is read/write. * O_CREATE : the file will be created if it does not exist on the file system. Default value is no creation. If the specified directory does not exist, an error is returned. WARNING: A node name (file or directory) cannot be larger than 37 characters. Returns file descriptor index if success Returns -1 if error. === 2) int '''giet_fat_close'''( unsigned int fd_id ) === Close a file identified by the ''fd_id'' file descriptor. It decrements the reference count in the inode associated to the file, and release the fd_id entry in the file descriptors array. If the reference count is zero, it writes all dirty clusters on block device, and releases the memory allocated to the file_cache. Returns 0 if success. Returns -1 if error. === 3) int '''get_fat_file_info'''( unsigned int fd_id , unsigned int* size , unsigned int* offset ) === This function returns the "size" and the current "offset" value for a file identified by the "fd_id" argument. Returns 0 if success. Returns -1 if error. === 4) int '''giet_fat_read'''( unsigned int fd_id , void* buffer , unsigned int count ) === This function has the same semantic as the UNIX "read()" function. It transfers "count" bytes from the kernel File_Cache associated to the file identified by "fd_id", to the user "buffer", starting from the current file offset. The offset value is incremented by count. In case of miss in the File_Cache, it loads all involved clusters into cache. Returns number of bytes actually transferred if success. Returns 0 if (offset + count) is larger than the file size. Returns -1 if error. === 5) int '''giet_fat_write'''( unsigned int fd_id , void* buffer, unsigned int count ) === This function has the same semantic as the UNIX "write()" function. It transfers "count" bytes from the user "buffer" to the kernel File_Cache associated to the file identified by "fd_id", starting from the current file offset. The offset value is incremented by count. It increases the file size and allocate new clusters if (count + offset) is larger than the current file size. Then it loads and updates all involved clusters in the cache. The FAT region on block device is updated if new clusters are allocated, but the block device DATA region is NOT updated. Returns number of bytes actually transferred if success. Returns -1 if error. === 6) int '''giet_fat_lseek'''( unsigned int fd_id , unsigned int offset , unsigned int whence ) === This function has the same semantic as the UNIX lseek() function. It repositions the offset in the file descriptor "fd_id", according to the "offset" and "whence" arguments. The two accepted values for the whence argument are SEEK_SET (new_offset <= offset), and SEEK_CUR (new_offset <= current_offset + offset). Returns new offset value (bytes) if success. Returns -1 if error. === 7) int '''giet_fat_rm'''( char* pathname ) === This function has the same semantic as the UNIX unlink() function. It deletes a file identified by the absolute "pathname" argument from the sile system. AN error is reported if the references count (number of open file descriptor) is not zero. All clusters allocated to this file in the block device DATA region are released. The Inode-Tree is updated. the Fat-Cache is updated, and the FAT region is updated on the block device. The memory allocated for the associated File_Cache is released. Returns 0 if success. Returns -1 if error. === 8) int '''get_fat_mkdir'''( char* pathname ) === This function has the same semantic as the UNIX mkdir() function. It creates in the file system the directory specified by the absolute "pathname" argument. The Inode-Tree is updated. One cluster is allocated to the new directory, containing the "." and ".." entries. The associated File-Cache is created. The Fat-Cache is updated, and the FAT region on block device is updated. The DATA region on block device is updated. Returns 0 if success. Returns -1 if error. === 9) int '''get_fat_rmdir'''( char* pathname ) === This function has the same semantic as the UNIX mkdir() function. It deletes the directory specified by the absolute "pathname" argument from the file system. The Fat-Cache is updated, and the FAT region on block device is updated. The Inode-Tree is updated. The memory allocated to the File-Cache is released. Returns 0 if success. Returns -1 if error. == __Network related system call__ == The GIET_VM allows a user task to get and use a private NIC channel, using the CMA component (chained buffers DMA) to transfer packets to or an user buffer. The NIC channel and the CMA channel are registered in the task context. === 1) unsigned int '''giet_nic_tx_alloc'''( unsigned int xmax, unsigned int ymax) === This function allocates a private NIC_TX channel (coming with the associated kernel NIC_TX chbuf), and a private CMA channel to the calling task. It registers both indexes in the calling task context, and returns the NIC channel index. This channel can be shared by severals tasks of a parallel multi-tasks application. The packets are transfered by the hardware to the NIC from a distributed kernel chbuf (one 4 Kbytes container per cluster), where the number of involved clusters is defined by the (xmax / ymax) parameters. The (xmax / ymax) arguments cannot be larger than (X_SIZE / Y_SIZE) defining the max number of clusters in the platform, but they can be smaller. The calling task exit if no available NIC_TX channel, if no available CMA channel, if (xmax / ymax) are too large, or if there is not enough memory for the distributed kernel containers in one selected cluster. === 2) unsigned int '''giet_nic_rx_alloc'''( unsigned int xmax, unsigned int ymax ) === This function allocates a private NIC_RX channel (coming with the associated kernel NIC_RX chbuf), and a private CMA channel to the calling task. It registers both indexes in the calling task context, and returns the NIC channel index. This channel can be shared by severals tasks of a parallel multi-tasks application. The packets are transfered by the hardware from the NIC to a distributed kernel chbuf (one 4 Kbytes container per cluster), where the number of involved clusters is defined by the (xmax / ymax) parameters. The (xmax / ymax) arguments cannot be larger than (X_SIZE / Y_SIZE) defining the max number of clusters in the platform, but they can be smaller. The calling task exit if no available NIC_TX channel, if no available CMA channel, if (xmax / ymax) are too large, or if there is not enough memory for the distributed kernel containers in one selected cluster. === 3) void '''giet_nic_tx_start'''( unsigned int channel ) === This function activates both the NIC_TX channel, and the CMA channel allocated to the calling task to transfer packets from the distributed kernel chbuf to the NIC. The calling task exit if no allocated NIC_TX channel or no allocated CMA channel, or if the NIC channel argument does not fit the channel allocated to the calling task. === 4) void '''giet_nic_rx_start'''( unsigned int channel ) === This function activates both the NIC_RX channel, and the CMA channel allocated to the calling task to transfer packets from the NIC to the distributed kernel chbuf. The calling task exit if no allocated NIC_RX channel or no allocated CMA channel. === 5) void '''giet_nic_tx_move'''( unsigned int nic_channel, void* buffer ) === This blocking function transfer one container (GIET_NIC_CHBUF_SIZE bytes) from an user buffer to the kernel chbuf defined by the nic_channel argument. * '''nic_channel''' define the NIC channel index. * '''buffer''' is the container base address in user space. Several user tasks can concurrently access the same chbuf, because the syscall handler takes the lock protecting the chbuf. It returns only when the container has been fully transfered. The calling task exit if the buffer is not in user space, or if the NIC channel is too large, or in case of timeout. === 6) void '''giet_nic_rx_move'''( unsigned int nic_channel, void* buffer ) === This blocking function transfer one container (GIET_NIC_CHBUF_SIZE bytes) from the kernel chbuf defined by the nic_channel argument to an user buffer. * '''nic_channel''' define the NIC channel index. * '''buffer''' is the container base address in user space. Several user tasks can concurrently access the same chbuf, because the syscall handler takes the lock protecting the chbuf. It returns only when the container has been fully transfered. The calling task exit if the buffer is not in user space, or if the NIC channel is too large, or in case of timeout. === 7) void '''giet_nic_tx_stop( unsigned int channel ) === This function desactivates both the NIC_TX channel and the CMA channel allocated to the calling task. The calling task exit if no allocated NIC_TX channel or no allocated CMA channel. === 8) void '''giet_nic_rx_stop( unsigned int channel ) === This function desactivates both the NIC_RX channel and the CMA channel allocated to the calling task. The calling task exit if no allocated NIC_RX channel or no allocated CMA channel. === 9) void '''giet_nic_rx_clear'''( unsigned int channel ) === This function reset all instrumentation (packets counters) associated to the RX channels. === 10) void '''giet_nic_tx_clear'''( unsigned int channel ) === This function reset all instrumentation (packets counters) associated to the TX channels. === 11) void '''giet_nic_rx_stats( unsigned int channel ) === This function display on kernel TTY0 the content of the instrumentation registers associated to the RX channels. === 12) void '''giet_nic_tx_stats( unsigned int channel ) === This function display on kernel TTY0 the content of the instrumentation registers associated to the TX channels. == __Frame Buffer related system calls__ == To display images, an user task can access the frame buffer through a memcpy() or through the ''Chained Buffer DMA'' controller (called CMA). The four first functions use a private CMA channel that is registered in the task context. The Two last functions use a memcpy(). === 1) void '''giet_fbf_cma_alloc'''() This function allocates a private CMA channel to the calling task, and registers the channel index in the task context. Task exit if no CMA channel available === 2) void '''giet_fbf_cma_start'''( void* buf0, void* buf1, unsigned int length ) === This function initializes the chained buffer DMA controller (CMA) to transfer a stream of images from two user buffers to the frame buffer. It must be used in conjunction with the giet_fbf_cma_display() function. A CMA channel should have been allocated to the calling task in the application mapping. * '''buf0''' is the first user buffer base address * '''buf1''' is the second user buffer base address, * '''length''' is the buffer size (bytes). === 3) void '''giet_fbf_cma_display'''( unsigned int buffer ) === This function enables the transfer of the buffer specified by the ''buffer'' argument (0 or 1). === 4) void '''giet_fbf_cma_stop'''( ) === This function desactivates the CMA channel allocated to the calling task. === 5) void '''giet_fbf_sync_read'''( unsigned int offset, void* buffer, unsigned int length ) === This blocking function use a memcopy strategy to transfer data from the frame buffer to an user buffer: ''offset'' defines the offset (in bytes) in the frame buffer, ''buffer'' is the user buffer base address, ''length'' is the number of bytes to be transfered. === 6) void '''giet_fbf_sync_write'''( unsigned int offset, void* buffer, unsigned int length ) === This blocking function use a memcopy strategy to transfer data from an user buffer to the frame buffer: ''offset'' defines the offset (in bytes) in the frame buffer, ''buffer'' is the user buffer base address, ''length'' is the number of bytes to be transfered. == __Miscelaneous system calls__ == === 1) void '''giet_exit'''( char* string ) === This function stops execution of the calling task with a TTY message explaining the cause. The user task is descheduled and becomes not runable: it does not consume processor cycles anymore. === 2) void '''giet_assert'''( unsigned int condition, char* string ) === This function uses the giet_exit() system call to kill the calling task if the condition is false. === 3) void '''giet_context_switch'''() === The user task calling this function is descheduled and the processor is allocated to another task. === 4) void '''giet_procs_number'''( unsigned int* x_size , unsigned int* y_size , unsigned int* nprocs ) === This function returns the actual number of processors in a clusterized 2D mesh architecture. * '''x_size''' number of clusters containing processors in a row. * '''y_size''' number of clusters containing processors in a column. * '''nprocs''' number of processors per cluster. === 5) void '''giet_vseg_get_vbase'''( char* vspace_name, char* vseg_name, unsigned int* vbase) === This function returns in argument ''vbase'' the virtual base address of a vseg defined in the mapping_info data structure. The vseg is identified by the two arguments ''vspace_name'' and ''vseg_name''. In case of error (such as undefined vspace or undefined vseg), it makes a giet_exit(). === 6) void '''giet_vseg_get_length'''( char* vspace_name, char* vseg_name, unsigned int* length) === This function returns in argument ''length'' the length (bytes) of a vseg defined in the mapping_info data structure. The vseg is identified by the two arguments ''vspace_name'' and ''vseg_name''. In case of error (such as undefined vspace or undefined vseg), it makes a giet_exit(). === 7) void '''giet_heap_info'''( unsigned int* vaddr, unsigned int* length, unsigned int x, unsigned int y ); This function supports access to the running task's heap or to a remote heap. If (x < X_SIZE) and (y < Y_SIZE), it returns the base address and length of the heap associated to any task running on cluster(x,y). Otherwise, it returns the base address and length of the heap associated to the calling task. In case of error (such as undefined heap segment in the selected cluster, it returns heap_size = 0). === 8) void '''giet_get_xy'''( void* ptr, unsigned int* px, unsigned int* py ) === This function takes as input a virtual address (''ptr'' argument), and returns through the ''px,py'' arguments the coordinates of the cluster containing the physical address associated to ''ptr''. In case of error (unmapped virtual address), it makes a giet_exit().