source: soft/giet_vm/giet_kernel/sys_handler.c @ 760

Last change on this file since 760 was 760, checked in by alain, 8 years ago
  • Property svn:executable set to *
File size: 133.3 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : sys_handler.c
3// Date     : 01/04/2012
4// Author   : alain greiner and joel porquet
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7
8#include <sys_handler.h>
9#include <tty_driver.h>
10#include <tim_driver.h>
11#include <nic_driver.h>
12#include <mmc_driver.h>
13#include <mwr_driver.h>
14#include <cma_driver.h>
15#include <ctx_handler.h>
16#include <fat32.h>
17#include <elf-types.h>
18#include <utils.h>
19#include <kernel_malloc.h>
20#include <tty0.h>
21#include <vmem.h>
22#include <hard_config.h>
23#include <giet_config.h>
24#include <mapping_info.h>
25#include <irq_handler.h>
26#include <io.h>
27
28#if !defined(X_SIZE)
29# error: You must define X_SIZE in the hard_config.h file
30#endif
31
32#if !defined(Y_SIZE)
33# error: You must define Y_SIZE in the hard_config.h file
34#endif
35
36#if !defined(NB_PROCS_MAX)
37# error: You must define NB_PROCS_MAX in the hard_config.h file
38#endif
39
40#if !defined(SEG_BOOT_MAPPING_BASE)
41# error: You must define SEG_BOOT_MAPPING_BASE in the hard_config.h file
42#endif
43
44#if !defined(NB_TTY_CHANNELS)
45# error: You must define NB_TTY_CHANNELS in the hard_config.h file
46#endif
47
48#if (NB_TTY_CHANNELS < 1)
49# error: NB_TTY_CHANNELS cannot be smaller than 1!
50#endif
51
52#if !defined(NB_TIM_CHANNELS)
53# error: You must define NB_TIM_CHANNELS in the hard_config.h file
54#endif
55
56#if !defined(NB_NIC_CHANNELS)
57# error: You must define NB_NIC_CHANNELS in the hard_config.h file
58#endif
59
60#if !defined(NB_CMA_CHANNELS)
61# error: You must define NB_CMA_CHANNELS in the hard_config.h file
62#endif
63
64#if !defined(GIET_NO_HARD_CC)
65# error: You must define GIET_NO_HARD_CC in the giet_config.h file
66#endif
67
68#if !defined ( GIET_NIC_MAC4 )
69# error: You must define GIET_NIC_MAC4 in the giet_config.h file
70#endif
71
72#if !defined ( GIET_NIC_MAC2 )
73# error: You must define GIET_NIC_MAC2 in the giet_config.h file
74#endif
75
76////////////////////////////////////////////////////////////////////////////
77//        Extern variables
78////////////////////////////////////////////////////////////////////////////
79
80// allocated in tty0.c file.
81extern sqt_lock_t _tty0_sqt_lock;
82
83// allocated in mwr_driver.c file.
84extern simple_lock_t  _coproc_lock[X_SIZE*Y_SIZE];
85extern unsigned int   _coproc_type[X_SIZE*Y_SIZE];
86extern unsigned int   _coproc_info[X_SIZE*Y_SIZE];
87extern unsigned int   _coproc_mode[X_SIZE*Y_SIZE];
88extern unsigned int   _coproc_error[X_SIZE*Y_SIZE];
89extern unsigned int   _coproc_trdid[X_SIZE*Y_SIZE];
90
91// allocated in tty_driver.c file.
92extern tty_fifo_t   _tty_rx_fifo[NB_TTY_CHANNELS];
93
94// allocated in kernel_init.c file
95extern static_scheduler_t* _schedulers[X_SIZE][Y_SIZE][NB_PROCS_MAX]; 
96
97// allocated in kernel_init.c file
98extern unsigned long long  _ptabs_paddr[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE]; 
99
100////////////////////////////////////////////////////////////////////////////////
101//     Allocator protecting exclusive access to FBF by a single application.
102// - The number of users in a given application should be set by a single
103//   thread using an _atomic_test_and_set().
104// - The allocator is atomically decremented by each user thread when
105//   the thread exit.   
106////////////////////////////////////////////////////////////////////////////////
107
108__attribute__((section(".kdata")))
109unsigned int _fbf_alloc = 0;
110
111////////////////////////////////////////////////////////////////////////////////
112//     Channel allocators for multi-channels peripherals
113// - The array _***_channel_allocator[channel] defines the number of user
114//   threads for a dynamically allocated channel of peripheral ***.
115// - The array _***_channel_wti[channel] defines the WTI index and the
116//   processor coordinates for the processor receiving the channel WTI.
117////////////////////////////////////////////////////////////////////////////////
118
119#if NB_TTY_CHANNELS
120__attribute__((section(".kdata")))
121unsigned int _tty_channel_alloc[NB_TTY_CHANNELS] = {0};
122
123__attribute__((section(".kdata")))
124unsigned int _tty_channel_wti[NB_TTY_CHANNELS];
125#endif
126
127#if NB_TIM_CHANNELS
128__attribute__((section(".kdata")))
129unsigned int _tim_channel_alloc[NB_TIM_CHANNELS] = {0};
130
131__attribute__((section(".kdata")))
132unsigned int _tim_channel_wti[NB_TIM_CHANNELS];
133#endif
134
135#if NB_CMA_CHANNELS
136__attribute__((section(".kdata")))
137unsigned int _cma_channel_alloc[NB_CMA_CHANNELS] = {0};
138
139__attribute__((section(".kdata")))
140unsigned int _cma_channel_wti[NB_CMA_CHANNELS];
141#endif
142
143#if NB_NIC_CHANNELS
144__attribute__((section(".kdata")))
145unsigned int _nic_rx_channel_alloc[NB_NIC_CHANNELS] = {0};
146
147__attribute__((section(".kdata")))
148unsigned int _nic_rx_channel_wti[NB_NIC_CHANNELS];
149
150__attribute__((section(".kdata")))
151unsigned int _nic_tx_channel_alloc[NB_NIC_CHANNELS] = {0};
152
153__attribute__((section(".kdata")))
154unsigned int _nic_tx_channel_wti[NB_NIC_CHANNELS];
155#endif
156
157////////////////////////////////////////////////////////////////////////////
158//     NIC_RX and NIC_TX kernel chbuf arrays
159////////////////////////////////////////////////////////////////////////////
160
161__attribute__((section(".kdata")))
162nic_chbuf_t  _nic_ker_rx_chbuf[NB_NIC_CHANNELS] __attribute__((aligned(64)));
163
164__attribute__((section(".kdata")))
165nic_chbuf_t  _nic_ker_tx_chbuf[NB_NIC_CHANNELS] __attribute__((aligned(64)));
166
167////////////////////////////////////////////////////////////////////////////
168//     FBF related chbuf
169// The physical address of this chbuf is required for L2 cache sync.
170////////////////////////////////////////////////////////////////////////////
171
172__attribute__((section(".kdata")))
173fbf_chbuf_t          _fbf_ker_chbuf  __attribute__((aligned(64)));
174
175__attribute__((section(".kdata")))
176unsigned long long   _fbf_chbuf_paddr;
177
178////////////////////////////////////////////////////////////////////////////
179//    Initialize the syscall vector with syscall handlers
180// Note: This array must be synchronised with the define in file stdio.h
181////////////////////////////////////////////////////////////////////////////
182
183__attribute__((section(".kdata")))
184const void * _syscall_vector[64] = 
185{
186    &_sys_proc_xyp,                  /* 0x00 */
187    &_get_proctime,                  /* 0x01 */
188    &_sys_procs_number,              /* 0x02 */
189    &_sys_xy_from_ptr,               /* 0x03 */
190    &_sys_ukn,                       /* 0x04 */
191    &_sys_vseg_get_vbase,            /* 0x05 */
192    &_sys_vseg_get_length,           /* 0x06 */
193    &_sys_heap_info,                 /* 0x07 */
194    &_sys_fbf_size,                  /* 0x08 */
195    &_sys_fbf_alloc,                 /* 0x09 */ 
196
197#if NB_CMA_CHANNELS
198    &_sys_fbf_cma_alloc,             /* 0x0A */
199    &_sys_fbf_cma_init_buf,          /* 0x0B */
200    &_sys_fbf_cma_start,             /* 0x0C */
201    &_sys_fbf_cma_display,           /* 0x0D */
202    &_sys_fbf_cma_stop,              /* 0x0E */
203    &_sys_fbf_cma_check,             /* 0x0F */
204#else
205    &_sys_ukn,                       /* 0x0A */
206    &_sys_ukn,                       /* 0x0B */
207    &_sys_ukn,                       /* 0x0C */
208    &_sys_ukn,                       /* 0x0D */
209    &_sys_ukn,                       /* 0x0E */
210    &_sys_ukn,                       /* 0x0F */
211#endif
212
213    &_sys_applications_status,       /* 0x10 */
214    &_sys_fbf_sync_write,            /* 0x11 */
215    &_sys_fbf_sync_read,             /* 0x12 */
216    &_sys_ukn,                       /* 0x13 */
217    &_sys_tim_alloc,                 /* 0x14 */
218    &_sys_tim_start,                 /* 0x15 */ 
219    &_sys_tim_stop,                  /* 0x16 */
220    &_sys_kill_application,          /* 0x17 */
221    &_sys_exec_application,          /* 0x18 */   
222    &_sys_ukn,                       /* 0x19 */
223    &_sys_pthread_control,           /* 0x1A */
224    &_sys_pthread_yield,             /* 0x1B */
225    &_sys_pthread_kill,              /* 0x1C */
226    &_sys_pthread_create,            /* 0x1D */
227    &_sys_pthread_join,              /* 0x1E */
228    &_sys_pthread_exit,              /* 0x1F */
229
230    &_fat_open,                      /* 0x20 */
231    &_sys_fat_read,                  /* 0x21 */
232    &_sys_fat_write,                 /* 0x22 */
233    &_fat_lseek,                     /* 0x23 */
234    &_fat_file_info,                 /* 0x24 */
235    &_fat_close,                     /* 0x25 */
236    &_fat_remove,                    /* 0x26 */
237    &_fat_rename,                    /* 0x27 */
238    &_fat_mkdir,                     /* 0x28 */
239    &_fat_opendir,                   /* 0x29 */
240    &_fat_closedir,                  /* 0x2A */
241    &_fat_readdir,                   /* 0x2B */
242    &_sys_fat_pread,                 /* 0x2C */
243    &_sys_fat_mmap,                  /* 0x2D */
244    &_sys_fat_munmap,                /* 0x2E */
245    &_sys_ukn,                       /* 0x2F */
246
247#if NB_NIC_CHANNELS
248    &_sys_nic_alloc,                 /* 0x30 */
249    &_sys_nic_start,                 /* 0x31 */
250    &_sys_nic_move,                  /* 0x32 */
251    &_sys_nic_stop,                  /* 0x33 */
252    &_sys_nic_stats,                 /* 0x34 */
253    &_sys_nic_clear,                 /* 0x35 */ 
254#else
255    &_sys_ukn,                       /* 0x30 */
256    &_sys_ukn,                       /* 0x31 */
257    &_sys_ukn,                       /* 0x32 */
258    &_sys_ukn,                       /* 0x33 */
259    &_sys_ukn,                       /* 0x34 */
260    &_sys_ukn,                       /* 0x35 */
261#endif
262
263    &_sys_tty_write,                 /* 0x36 */
264    &_sys_tty_read,                  /* 0x37 */
265    &_sys_tty_alloc,                 /* 0x38 */
266    &_sys_ukn,                       /* 0x39 */
267    &_sys_ukn,                       /* 0x3A */
268    &_sys_coproc_completed,          /* 0x3B */
269    &_sys_coproc_alloc,              /* 0x3C */
270    &_sys_coproc_channel_init,       /* 0x3D */
271    &_sys_coproc_run,                /* 0x3E */
272    &_sys_coproc_release,            /* 0x3F */
273};
274
275
276
277///////////////////////////////////////////////////////////////////////////////////
278//           File system related syscall handlers
279///////////////////////////////////////////////////////////////////////////////////
280
281///////////////////////////////////////////////////////////////////////////////////
282// This function is called by the _sys_fat_mmap() function.
283// It implements a simplistic pages allocator from the MMAP vseg of the vspace
284// identified by the <vspace_id> argument. The number of pages is defined by
285// the <count> argument.
286// Allocated pages are never released, and the allocator is the "psegid" field
287// in the vseg mapping, that is initialised to 0 by the boot code.
288// In order to support concurrent system calls, the allocator must be
289// atomically incremented.
290///////////////////////////////////////////////////////////////////////////////////
291// Returns the buffer vbase address in case of success.
292// Returns 0 in case of error (no MMAP vseg or not enough space).
293///////////////////////////////////////////////////////////////////////////////////
294static unsigned int _mmap_pages_alloc( unsigned int  vspace_id,
295                                       unsigned int  count )
296{
297    mapping_header_t*   header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
298    mapping_vspace_t*   vspace  = _get_vspace_base( header );
299    mapping_vseg_t*     vseg    = _get_vseg_base( header );
300
301    // loop on the vsegs to find the MMAP vseg vbase, length, and offset
302    unsigned int  vseg_id;
303    unsigned int  vbase;   
304    unsigned int  offset;   
305    unsigned int  length;
306    unsigned int  found = 0;
307    for (vseg_id = vspace[vspace_id].vseg_offset;
308         vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs);
309         vseg_id++) 
310    {
311        if ( vseg[vseg_id].type == VSEG_TYPE_MMAP ) 
312        {
313            offset = _atomic_increment( &vseg[vseg_id].psegid , count );
314            vbase  = vseg[vseg_id].vbase;
315            length = vseg[vseg_id].length;
316            found  = 1;
317            break;
318        }
319    }
320
321    if ( (found == 0) || (((offset + count)<<12) > length) )
322    {
323        return 0;
324    }
325    else
326    {
327        return vbase + (offset<<12);
328    }
329}  // end _mmap_pages_alloc()
330
331
332///////////////////////////////////////////////////////////////////////////////////
333// This function implements the giet_fat_read() system call.
334///////////////////////////////////////////////////////////////////////////////////
335int _sys_fat_read( unsigned int fd_id,
336                   unsigned int vaddr,
337                   unsigned int count )
338{
339    return _fat_read( fd_id,
340                      vaddr,
341                      count,
342                      0,                       // no paddr extension
343                      0,                       // no forced offset
344                      0 );                     // no special mode
345}
346
347////////////////////////////////////////////////////////////////
348// This function implements the giet_fat_pread() system call.
349////////////////////////////////////////////////////////////////
350int _sys_fat_pread( unsigned int fd_id,
351                    unsigned int vaddr,
352                    unsigned int count,
353                    unsigned int offset )
354{
355    return _fat_read( fd_id,
356                      vaddr,
357                      count,
358                      0,                        // no paddr extension
359                      offset,
360                      FAT_FORCED_OFFSET );     
361}
362
363////////////////////////////////////////////////////////////////
364// This function implements the giet_fat_write() system call.
365////////////////////////////////////////////////////////////////
366int _sys_fat_write( unsigned int fd_id,
367                    unsigned int vaddr,
368                    unsigned int count )
369{
370    return _fat_write( fd_id,
371                       vaddr,
372                       count,
373                       0,                       // no paddr extension
374                       0 );                     // no special mode
375}
376
377///////////////////////////////////////////////////////////////////////////////////
378// This function implements the "giet_fat_mmap()" system call.
379// It allocates <count> contiguous pages from the MMAP vseg of the calling vspace.
380// It maps all these pages directly to the file_cache defined by <fd_id>.
381// The <offset> in the file is a number of pages.
382// The <prot> argument defines the access modes MAP_PROT_WRITE and MAP_PROT_EXEC.
383// In writable mode, the file size is extended to the (offset + count) pages.
384// In non writable mode, the file size must be >= (offset + count) pages.
385// It has the following limitations:
386// - it does not support MAP_PRIVATE (no copy on write).
387// - it does not support MAP_FIXED (no forced user buffer address).
388// - it does not support MAP_ANONYMOUS (only file mapping).
389// - the <offset> and <count> arguments must multiple of 4 Kbytes.
390///////////////////////////////////////////////////////////////////////////////////
391// Returns memory buffer vbase in case of success.
392// Returns 0 on error.
393///////////////////////////////////////////////////////////////////////////////////
394int _sys_fat_mmap( unsigned int fd_id,
395                   unsigned int count, 
396                   unsigned int offset,
397                   unsigned int prot )
398{
399    // takes the FAT lock and register it in thread context
400    static_scheduler_t*  psched = _get_sched();
401    unsigned int         ltid   = _get_thread_ltid();
402    _spin_lock_acquire( &_fat.fat_lock );
403    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
404
405    // check fd_id overflow
406    if ( fd_id >= GIET_OPEN_FILES_MAX )
407    {
408        _spin_lock_release( &_fat.fat_lock );
409        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
410
411        _printf("\n[GIET ERROR] _sys_fat_mmap(): illegal file descriptor\n");
412        return 0;
413    }
414
415    // check file open
416    if ( _fat.fd[fd_id].allocated == 0 )
417    {
418        _spin_lock_release( &_fat.fat_lock );
419        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
420
421        _printf("\n[GIET ERROR] _sys_fat_mmap(): file not open\n" );
422        return 0;
423    }
424
425    // get access modes
426    unsigned int writable   = prot & MAP_PROT_WRITE;
427    unsigned int executable = prot & MAP_PROT_EXEC;
428
429    // get inode pointer 
430    fat_inode_t* inode  = _fat.fd[fd_id].inode;
431
432    // check file writable
433    if ( _fat.fd[fd_id].read_only && writable )
434    {
435        _spin_lock_release( &_fat.fat_lock );
436        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
437
438        _printf("\n[GIET ERROR] _sys_fat_mmap(): file <%s> is read-only\n",
439                inode->name );
440        return 0;
441    }
442
443    // get vspace index and calling proc coordinates
444    unsigned int vsid    = _get_context_slot( CTX_VSID_ID );
445
446    // compute first and last cluster indexes
447    unsigned int  first_cluster  = offset;
448    unsigned int  last_cluster   = offset + count - 1; 
449
450#if GIET_DEBUG_MMAP
451unsigned int procid  = _get_procid();
452unsigned int x_id    = procid >> (Y_WIDTH + P_WIDTH);
453unsigned int y_id    = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
454unsigned int p_id    = procid & ((1<<P_WIDTH)-1);
455if ( _get_proctime() > GIET_DEBUG_MMAP )
456_printf("\n[DEBUG MMAP] _sys_fat_mmap() : P[%d,%d,%d] enters at cycle %d\n"
457        " for file %s / size = %x / cluster = %x / cache = %x / desc[0] = %x\n"
458        " first_cluster = %d / last_cluster = %d\n",
459        x_id , y_id , p_id , _get_proctime() ,
460        inode->name , inode->size , inode->cluster ,
461        (unsigned int)inode->cache , (unsigned int)inode->cache->children[0] ,
462        first_cluster , last_cluster );
463#endif
464
465    // get buffer vbase from MMAP vseg in calling vspace
466    unsigned int buffer_vbase = _mmap_pages_alloc( vsid, count ); 
467    if ( buffer_vbase == 0 ) 
468    {
469        _spin_lock_release( &_fat.fat_lock );
470        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
471
472        _printf("\n[GIET ERROR] _sys_fat_mmap(): no space in MMAP vseg to map file %s\n",
473                _fat.fd[fd_id].inode->name );
474        return 0;
475    }
476 
477    // set flags for all pages in buffer
478    unsigned int flags = 0;
479    flags |= PTE_C;                    // cachable
480    flags |= PTE_U;                    // user access
481    flags |= PTE_L;                    // local access (unused)
482    flags |= PTE_R;                    // remote access (unused)
483    if ( executable ) flags |= PTE_X;
484    if ( writable   ) flags |= PTE_W;
485
486    // loop on pages to be mapped
487    unsigned int cid;
488    unsigned int user_vaddr = buffer_vbase;
489    for ( cid = first_cluster ; cid <= last_cluster ; cid++ ) 
490    {
491        // get file_cache buffer vaddr
492        unsigned char*     cache_vaddr;
493        fat_cache_desc_t*  pdesc;
494        if ( _get_file_cache_buffer( inode,
495                                     cid,
496                                     writable,
497                                     &pdesc ) )
498        {
499            _spin_lock_release( &_fat.fat_lock );
500            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
501
502            _printf("\n[FAT ERROR] _sys_fat_mmap(): cannot access file <%s>\n",
503                    _fat.fd[fd_id].inode->name );
504            return 0;
505        }
506
507        cache_vaddr = pdesc->buffer;
508       
509        // compute buffer paddr
510        unsigned long long  cache_paddr;
511        unsigned int        unused;
512        cache_paddr = _v2p_translate( (unsigned int)cache_vaddr, &unused );
513
514        // map the user_vaddr to cache_paddr
515        // in all pages tables defined for the vspace
516        unsigned int x_cur;
517        unsigned int y_cur;
518        for  ( x_cur = 0 ; x_cur < X_SIZE ; x_cur++ )
519        {
520            for  ( y_cur = 0 ; y_cur < Y_SIZE ; y_cur++ )
521            {
522                if ( _ptabs_paddr[vsid][x_cur][y_cur] )  // Page table is defined
523                {
524                    _v2p_add_pte2( vsid,
525                                   x_cur,
526                                   y_cur,
527                                   user_vaddr >> 12,
528                                   flags,
529                                   cache_paddr >> 12,
530                                   0 );
531                }
532            }
533        }
534
535#if GIET_DEBUG_MMAP
536if ( _get_proctime() > GIET_DEBUG_MMAP )
537_printf("\n[DEBUG MMAP] _sys_fat_mmap() : P[%d,%d,%d] map cluster %d\n"
538        " user_vaddr = %x / cache_paddr = %l\n",
539        x_id , y_id , p_id , cid , user_vaddr , cache_paddr );
540#endif
541
542        // increment user buffer vaddr
543        user_vaddr += 4096;
544    }
545
546    // releases the FAT lock
547    _spin_lock_release( &_fat.fat_lock );
548    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
549
550#if GIET_DEBUG_MMAP
551if ( _get_proctime() > GIET_DEBUG_MMAP )
552_printf("\n[DEBUG MMAP] _sys_fat_mmap() : P[%d,%d,%d] returns buffer %x for file %s\n",
553        x_id , y_id , p_id , buffer_vbase , inode->name );
554#endif
555
556   // returns pointer on mapped buffer in user space
557    return buffer_vbase;
558
559}  // end _sys_fat_mmap()
560
561
562//////////////////////////////////////////////////////////////////
563// This function implements the giet_fat_munmap() system call.
564//////////////////////////////////////////////////////////////////
565int _sys_fat_munmap( unsigned int vaddr,
566                     unsigned int count ) 
567{
568    // get vspace index
569    unsigned int  vsid   = _get_context_slot( CTX_VSID_ID );
570
571    // loop on pages
572    unsigned int page;
573    for ( page = 0 ; page < count ; page++ )
574    {
575        unsigned int vpn = (vaddr>>12) + page;
576
577        // loop on all page tables defined for the vspace
578        unsigned int x_cur;
579        unsigned int y_cur;
580        for  ( x_cur = 0 ; x_cur < X_SIZE ; x_cur++ )
581        {
582            for  ( y_cur = 0 ; y_cur < Y_SIZE ; y_cur++ )
583            {
584                if ( _ptabs_paddr[vsid][x_cur][y_cur] )  // Page table is defined
585                {
586                    _v2p_del_pte2( vsid , x_cur , y_cur , vpn );
587                }
588            }
589        }
590    }
591    return 0;
592}  // end _sys_fat_munmap()
593
594
595
596//////////////////////////////////////////////////////////////////////////////
597//           Applications related syscall handlers
598//////////////////////////////////////////////////////////////////////////////
599
600////////////////////////////////////////////////////////////////////////
601// This function is called by the _sys_exec_application() function
602// to reload all data segments contained in an application.elf file.
603// File checking is minimal, because these segments have already
604// been loaded by the boot code.
605////////////////////////////////////////////////////////////////////////
606static unsigned int _load_writable_segments( mapping_vspace_t*  vspace )
607{
608
609#if GIET_DEBUG_EXEC 
610unsigned int gpid       = _get_procid();
611unsigned int cluster_xy = gpid >> P_WIDTH;
612unsigned int p          = gpid & ((1<<P_WIDTH)-1);
613unsigned int x          = cluster_xy >> Y_WIDTH;
614unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
615if ( _get_proctime() > GIET_DEBUG_EXEC )
616_printf("\n[DEBUG EXEC] _load_writable_segments() at cycle %d\n"
617        "P[%d,%d,%d] enters for %s\n",
618        _get_proctime() , x , y , p , vspace->name );
619#endif
620
621    mapping_header_t*  header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
622    mapping_vseg_t*    vseg    = _get_vseg_base(header);
623
624    unsigned int vseg_id;        // vseg index in mapping
625    char         buf[4096];      // buffer to store one cluster
626    unsigned int fd    = 0;      // file descriptor
627    unsigned int found = 0;
628
629    // first scan on vsegs in vspace to find the .elf pathname
630    for (vseg_id = vspace->vseg_offset;
631         vseg_id < (vspace->vseg_offset + vspace->vsegs);
632         vseg_id++)
633    {
634        if( vseg[vseg_id].type == VSEG_TYPE_ELF )
635        {
636            // open the .elf file associated to vspace
637            fd = _fat_open( vseg[vseg_id].binpath , O_RDONLY );
638            if ( fd < 0 ) return 1;
639
640#if GIET_DEBUG_EXEC
641if ( _get_proctime() > GIET_DEBUG_EXEC )
642_printf("\n[DEBUG EXEC] _load_writable_segments() at cycle %d\n"
643        "P[%d,%d,%d] open %s / fd = %d\n", 
644        _get_proctime() , x , y , p , vseg[vseg_id].binpath , fd );
645#endif
646            found = 1;
647            break;
648 
649        }
650    }
651 
652    // check .elf file found
653    if ( found == 0 )
654    {
655        _printf("\n[GIET ERROR] _load_writable_segments() : .elf not found\n");
656        return 1;
657    }
658
659    // load Elf-Header into buffer from .elf file
660    if ( _fat_lseek( fd, 0, SEEK_SET ) < 0 )
661    {
662        _printf("\n[GIET ERROR] _load_writable_segments() : cannot seek\n");
663        _fat_close( fd );
664        return 1;
665    }
666    if ( _fat_read( fd, (unsigned int)buf, 4096, 0, 0, 0 ) < 0 )
667    {
668        _printf("\n[GIET ERROR] _load_writable_segments() : cannot read\n");
669        _fat_close( fd );
670        return 1;
671    }
672
673#if GIET_DEBUG_EXEC
674if ( _get_proctime() > GIET_DEBUG_EXEC )
675_printf("\n[DEBUG EXEC] _load_writable_segments() at cycle %d\n"
676        "P[%d,%d,%d] loaded Elf-Header\n",
677        _get_proctime() , x , y , p );
678#endif
679
680    // get nsegments and Program-Header-Table offset from Elf-Header
681    Elf32_Ehdr*  elf_header_ptr = (Elf32_Ehdr*)buf;
682    unsigned int offset         = elf_header_ptr->e_phoff;
683    unsigned int nsegments      = elf_header_ptr->e_phnum;
684
685    // load Program-Header-Table from .elf file
686    if ( _fat_lseek( fd, offset, SEEK_SET ) < 0 )
687    {
688        _fat_close( fd );
689        return 1;
690    }
691    if ( _fat_read( fd, (unsigned int)buf, 4096, 0, 0, 0 ) < 0 )
692    {
693        _fat_close( fd );
694        return 1;
695    }
696
697#if GIET_DEBUG_EXEC
698if ( _get_proctime() > GIET_DEBUG_EXEC )
699_printf("\n[DEBUG EXEC] _load_writable_segments() at cycle %d\n"
700        "P[%d,%d,%d] loaded Program-Header-Table\n",
701        _get_proctime() , x , y , p );
702#endif
703
704    // set Program-Header-Table pointer
705    Elf32_Phdr*  elf_pht_ptr = (Elf32_Phdr*)buf;
706
707    // second scan on vsegs in vspace to load the seg_data segments :
708    // - type == VSEG_TYPE_ELF
709    // - non eXecutable
710    for (vseg_id = vspace->vseg_offset;
711         vseg_id < (vspace->vseg_offset + vspace->vsegs);
712         vseg_id++)
713    {
714        if( (vseg[vseg_id].type == VSEG_TYPE_ELF) &&   // type ELF
715            ((vseg[vseg_id].mode & 0x4) == 0) )        // non executable
716        {
717            // get vbase and pbase
718            paddr_t      pbase = vseg[vseg_id].pbase; 
719            unsigned int vbase = vseg[vseg_id].vbase;
720
721            // scan segments in Progam-Header-Table to find match
722            // No match checking as the segment was previously found
723            unsigned int seg;
724            for (seg = 0 ; seg < nsegments ; seg++)
725            {
726                if ( (elf_pht_ptr[seg].p_type == PT_LOAD) &&    // loadable
727                     (elf_pht_ptr[seg].p_flags & PF_W)    &&    // writable
728                     (elf_pht_ptr[seg].p_vaddr == vbase) )      // matching
729                {
730                    // Get segment offset and size in .elf file
731                    unsigned int seg_offset = elf_pht_ptr[seg].p_offset;
732                    unsigned int seg_size   = elf_pht_ptr[seg].p_filesz;
733
734                    // compute destination address and extension for _fat_read()
735                    unsigned int dest   = (unsigned int)pbase;
736                    unsigned int extend = (unsigned int)(pbase>>32);
737
738                    // load the segment
739                    if ( _fat_lseek( fd, seg_offset, SEEK_SET ) < 0 ) 
740                    {
741                        _fat_close( fd );
742                        return 1;
743                    }
744                    if ( _fat_read( fd, dest, seg_size, extend, 0, FAT_PADDR_MODE ) < 0 )
745                    {
746                        _fat_close( fd );
747                        return 1;
748                    }
749                }
750            }
751
752#if GIET_DEBUG_EXEC
753if ( _get_proctime() > GIET_DEBUG_EXEC )
754_printf("\n[DEBUG EXEC] _load_writable_segments() at cycle %d\n"
755        "P[%d,%d,%d] loaded segment %x\n",
756        _get_proctime() , x , y , p , vbase );
757#endif
758        }
759    }  // end loop on writable & loadable segments
760
761    // close .elf file
762    _fat_close( fd );
763
764    return 0;
765}  // end load_writable_segments()
766
767
768
769///////////////////////////////////////
770int _sys_exec_application( char* name )
771{
772    mapping_header_t * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
773    mapping_vspace_t * vspace  = _get_vspace_base(header);
774    mapping_thread_t * thread  = _get_thread_base(header);
775    mapping_vseg_t   * vseg    = _get_vseg_base(header);
776
777    unsigned int vspace_id;
778    unsigned int thread_id;
779
780#if GIET_DEBUG_EXEC
781unsigned int gpid       = _get_procid();
782unsigned int cluster_xy = gpid >> P_WIDTH;
783unsigned int p          = gpid & ((1<<P_WIDTH)-1);
784unsigned int x          = cluster_xy >> Y_WIDTH;
785unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
786if ( _get_proctime() > GIET_DEBUG_EXEC )
787_printf("\n[DEBUG EXEC] _sys_exec_application() at cycle %d\n"
788        "P[%d,%d,%d] enters for vspace %s\n",
789        _get_proctime() , x, y, p, name );
790#endif
791
792    unsigned int y_size = header->y_size;
793
794    // scan vspaces to find matching vspace name
795    for (vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++) 
796    {
797        if ( _strcmp( vspace[vspace_id].name, name ) == 0 )  // vspace found
798        {
799
800#if GIET_DEBUG_EXEC
801if ( _get_proctime() > GIET_DEBUG_EXEC )
802_printf("\n[DEBUG EXEC] _sys_exec_application() at cycle %d\n"
803        "P[%d,%d,%d] found vspace %s\n",
804        _get_proctime() , x, y, p, name );
805#endif
806            // reload writable segments
807            if ( _load_writable_segments( &vspace[vspace_id] ) )
808            {
809                _printf("[GIET ERROR] _sys_exec_application() : "
810                        "can't load data segment for vspace %s\n", name );
811                return SYSCALL_CANNOT_LOAD_DATA_SEGMENT;
812            }
813 
814#if GIET_DEBUG_EXEC
815if ( _get_proctime() > GIET_DEBUG_EXEC )
816_printf("\n[DEBUG EXEC] _sys_exec_application() at cycle %d\n"
817        "P[%d,%d,%d] loaded all writable segments for vspace %s\n",
818        _get_proctime() , x, y, p, name );
819#endif
820            // scan threads in vspace with three goals :
821            // - check all threads desactivated
822            // - re-initialise all threads contexts
823            // - find main thread
824            unsigned int        main_found  = 0;
825            unsigned int        main_ltid   = 0;
826            static_scheduler_t* main_psched = NULL;
827            unsigned int        min         = vspace[vspace_id].thread_offset; 
828            unsigned int        max         = min + vspace[vspace_id].threads; 
829            for ( thread_id = min ; thread_id < max ; thread_id++ ) 
830            {
831                // get thread identifiers : [x,y,p,ltid]
832                unsigned int cid   = thread[thread_id].clusterid;
833                unsigned int x     = cid / y_size;
834                unsigned int y     = cid % y_size;
835                unsigned int p     = thread[thread_id].proclocid;
836                unsigned int ltid  = thread[thread_id].ltid;
837                unsigned int vsid  = thread[thread_id].stack_vseg_id;
838
839                // get scheduler pointer
840                static_scheduler_t* psched = _schedulers[x][y][p];
841
842                // check thread non active
843                if ( psched->context[ltid].slot[CTX_NORUN_ID] == 0 )  // runnable !!!
844                {
845                    _printf("\n[GIET ERROR] in _sys_exec_application() : "
846                            "thread %s already active in vspace %s\n",
847                            thread[thread_id].name, name );
848                    return SYSCALL_THREAD_ALREADY_ACTIVE;
849                }
850               
851                // initialise thread context
852                unsigned int ctx_epc = psched->context[ltid].slot[CTX_ENTRY_ID];
853                unsigned int ctx_sp  = vseg[vsid].vbase + vseg[vsid].length;
854                unsigned int ctx_ra  = (unsigned int)&_ctx_eret;
855                unsigned int ctx_sr  = GIET_SR_INIT_VALUE;
856
857                psched->context[ltid].slot[CTX_EPC_ID] = ctx_epc;
858                psched->context[ltid].slot[CTX_RA_ID]  = ctx_ra;
859                psched->context[ltid].slot[CTX_SR_ID]  = ctx_sr;
860                psched->context[ltid].slot[CTX_SP_ID]  = ctx_sp;
861
862                // register information required to activate main thread
863                // actual activation done when threads initialisation is completed
864                if ( thread[thread_id].is_main ) 
865                {
866                    main_psched = psched;
867                    main_ltid   = ltid;
868                    main_found  = 1;
869                }
870 
871#if GIET_DEBUG_EXEC
872if ( _get_proctime() > GIET_DEBUG_EXEC )
873_printf("\n[DEBUG EXEC] _sys_exec_application() at cycle %d\n"
874        "P[%d,%d,%d] initialise thread %s in vspace %s\n",
875        _get_proctime() , x, y, p, thread[thread_id].name , name );
876#endif
877            }  // end loop on threads
878
879            // activate main thread
880            if ( main_found )
881            {
882                main_psched->context[main_ltid].slot[CTX_NORUN_ID] = 0;
883            }
884            else
885            {
886                _printf("\n[GIET ERROR] in _sys_exec_application() : "
887                        "main not found in vspace %s\n", name );
888                return SYSCALL_MAIN_NOT_FOUND;
889            }
890             
891            _printf("\n[GIET WARNING] application %s launched : %d threads\n",
892                    name , max-min );
893
894            return SYSCALL_OK;
895        }
896    }  // end of loop on vspaces
897
898    // vspace not found
899    _printf("\n[GIET ERROR] in _sys_exec_application() : "
900            "vspace %s not found\n", name );
901    return SYSCALL_VSPACE_NOT_FOUND;
902
903}  // end _sys_exec_application()
904   
905
906///////////////////////////////////////
907int _sys_kill_application( char* name )
908{
909    mapping_header_t * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
910    mapping_vspace_t * vspace  = _get_vspace_base(header);
911    mapping_thread_t * thread  = _get_thread_base(header);
912
913    unsigned int vspace_id;
914    unsigned int thread_id;
915
916#if GIET_DEBUG_EXEC
917unsigned int gpid       = _get_procid();
918unsigned int cluster_xy = gpid >> P_WIDTH;
919unsigned int p          = gpid & ((1<<P_WIDTH)-1);
920unsigned int x          = cluster_xy >> Y_WIDTH;
921unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
922if ( _get_proctime() > GIET_DEBUG_EXEC )
923_printf("\n[DEBUG EXEC] _sys_kill_application() at cycle %d\n"
924        "P[%d,%d,%d] enters for vspace %s\n",
925        _get_proctime() , x , y , p , name );
926#endif
927
928    // shell cannot be killed
929    if ( _strcmp( name , "shell" ) == 0 )
930    {
931        _printf("\n[GIET ERROR] in _sys_kill_application() : "
932                "%s application cannot be killed\n", name );
933        return SYSCALL_APPLI_CANNOT_BE_KILLED;
934    }
935
936    // scan vspaces to find matching vspace name
937    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
938    {
939        if ( _strcmp( vspace[vspace_id].name, name ) == 0 ) 
940        {
941            // scan threads to send KILL signal to all threads in vspace
942            unsigned int y_size = header->y_size;
943            unsigned int min    = vspace[vspace_id].thread_offset; 
944            unsigned int max    = min + vspace[vspace_id].threads; 
945            for ( thread_id = min ; thread_id < max ; thread_id++ ) 
946            {
947                unsigned int cid   = thread[thread_id].clusterid;
948                unsigned int x     = cid / y_size;
949                unsigned int y     = cid % y_size;
950                unsigned int p     = thread[thread_id].proclocid;
951                unsigned int ltid  = thread[thread_id].ltid;
952
953                // get scheduler pointer for processor running the thread
954                static_scheduler_t* psched  = (static_scheduler_t*)_schedulers[x][y][p];
955
956                // set KILL signal bit
957                _atomic_or( &psched->context[ltid].slot[CTX_SIGS_ID] , SIGS_MASK_KILL );
958            } 
959
960            _printf("\n[GIET WARNING] application %s killed / %d threads\n",
961                    name , max-min );
962
963            return SYSCALL_OK;
964        }
965    }  // en loop on vspaces
966
967    _printf("\n[GIET ERROR] in _sys_kill_application() : "
968            "application %s not found\n", name );
969    return SYSCALL_VSPACE_NOT_FOUND;
970
971}  // end _sys_kill_application()
972   
973
974
975//////////////////////////////////////////
976int _sys_applications_status( char* name )
977{
978    mapping_header_t *  header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
979    mapping_thread_t *  thread  = _get_thread_base(header);
980    mapping_vspace_t *  vspace  = _get_vspace_base(header);
981    mapping_cluster_t * cluster = _get_cluster_base(header);
982
983    unsigned int thread_id;   // thread index in mapping
984    unsigned int vspace_id;   // vspace index in mapping
985
986    // scan vspaces
987    for( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )
988    {
989        if ( (name == NULL) || (_strcmp(vspace[vspace_id].name , name ) == 0) )
990        {
991            _user_printf("\n*** vspace %s\n", vspace[vspace_id].name );
992
993            // scan all threads in vspace
994            unsigned int min = vspace[vspace_id].thread_offset ;
995            unsigned int max = min + vspace[vspace_id].threads ;
996            for ( thread_id = min ; thread_id < max ; thread_id++ )
997            {
998                unsigned int         clusterid = thread[thread_id].clusterid;
999                unsigned int         p         = thread[thread_id].proclocid;
1000                unsigned int         x         = cluster[clusterid].x;
1001                unsigned int         y         = cluster[clusterid].y;
1002                unsigned int         ltid      = thread[thread_id].ltid;
1003                static_scheduler_t*  psched    = (static_scheduler_t*)_schedulers[x][y][p];
1004                unsigned int         norun     = psched->context[ltid].slot[CTX_NORUN_ID];
1005                unsigned int         tty       = psched->context[ltid].slot[CTX_TTY_ID];
1006                unsigned int         current   = psched->current;
1007
1008                if ( current == ltid )
1009                _user_printf(" - thread %s / P[%d,%d,%d] / ltid = %d / "
1010                             "TTY = %d / norun = %x : running\n", 
1011                             thread[thread_id].name, x, y, p, ltid, tty, norun );
1012                else if ( norun == 0 )
1013                _user_printf(" - thread %s / P[%d,%d,%d] / ltid = %d / "
1014                             "TTY = %d / norun = %x : runable\n", 
1015                             thread[thread_id].name, x, y, p, ltid, tty, norun);
1016                else
1017                _user_printf(" - thread %s / P[%d,%d,%d] / ltid = %d / "
1018                             "TTY = %d / norun = %x : blocked\n", 
1019                             thread[thread_id].name, x, y, p, ltid, tty, norun);
1020            }
1021        }
1022    }
1023    _user_printf("\n");
1024
1025    return SYSCALL_OK;
1026}  // end _sys_applications_status()
1027
1028
1029
1030/////////////////////////////////////////////////////////////////////////////
1031//          Threads related syscall handlers
1032/////////////////////////////////////////////////////////////////////////////
1033
1034////////////////////////////////////////////////
1035int _sys_pthread_create( unsigned int*  buffer,
1036                         void*          attr,
1037                         void*          function,
1038                         void*          arg )
1039{
1040    // attr argument not supported
1041    if ( attr != NULL )
1042    {
1043        _printf("\n[GIET ERROR] in _sys_pthread_create() : "
1044                "attr argument not supported\n" );
1045       
1046        return SYSCALL_PTHREAD_ARGUMENT_NOT_SUPPORTED;
1047    }
1048
1049    // get pointers in mapping
1050    mapping_header_t*    header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1051    mapping_thread_t*    thread   = _get_thread_base(header);
1052    mapping_vspace_t*    vspace   = _get_vspace_base(header);
1053    mapping_cluster_t*   cluster  = _get_cluster_base(header);
1054
1055    // get scheduler for processor running the calling thread
1056    static_scheduler_t* psched = (static_scheduler_t*)_get_sched();
1057
1058    // get calling thread local index in scheduler
1059    unsigned int  current = psched->current;
1060
1061    // get vspace index
1062    unsigned int  vspace_id = psched->context[current].slot[CTX_VSID_ID];
1063
1064#if GIET_DEBUG_EXEC
1065unsigned int gpid       = _get_procid();
1066unsigned int cluster_xy = gpid >> P_WIDTH;
1067unsigned int p          = gpid & ((1<<P_WIDTH)-1);
1068unsigned int x          = cluster_xy >> Y_WIDTH;
1069unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1070if ( _get_proctime() > GIET_DEBUG_EXEC )
1071_printf("\n[DEBUG EXEC] _sys_pthread_create() at cycle %d\n"
1072        "P[%d,%d,%d] enters for vspace %s / entry = %x\n",
1073        _get_proctime() , x , y , p , vspace[vspace_id].name , (unsigned int)function );
1074#endif
1075
1076    unsigned int thread_id;        // searched thread : local index in mapping
1077    unsigned int clusterid;        // searched thread : cluster index
1078    unsigned int lpid;             // searched thread : processor local index
1079    unsigned int ltid;             // searched thread : scheduler thread index
1080    unsigned int cx;               // searched thread : X coordinate for searched thread
1081    unsigned int cy;               // searched thread : Y coordinate for searched thread
1082    unsigned int entry;            // searched thread : entry point
1083    unsigned int norun;            // searched thread : norun vector
1084    unsigned int trdid;            // searched thread : thread identifier
1085
1086    // scan threads in vspace to find an inactive thread matching function
1087    unsigned int min   = vspace[vspace_id].thread_offset;
1088    unsigned int max   = min + vspace[vspace_id].threads;
1089    unsigned int found = 0;
1090    for ( thread_id = min ; (thread_id < max) && (found == 0) ; thread_id++ )
1091    {
1092        // get thread coordinates [cx,cy,lpid] and ltid from mapping
1093        ltid       = thread[thread_id].ltid;
1094        clusterid  = thread[thread_id].clusterid; 
1095        lpid       = thread[thread_id].proclocid;
1096        cx = cluster[clusterid].x;
1097        cy = cluster[clusterid].y;
1098
1099        // get thread scheduler pointer
1100        psched = _schedulers[cx][cy][lpid];
1101
1102        // get thread entry-point, norun-vector, and trdid from context
1103        entry = psched->context[ltid].slot[CTX_ENTRY_ID];
1104        norun = psched->context[ltid].slot[CTX_NORUN_ID];
1105        trdid = psched->context[ltid].slot[CTX_TRDID_ID];
1106
1107        // check matching
1108        if ( ((unsigned int)function == entry ) && 
1109             (norun & NORUN_MASK_THREAD)  ) found = 1;
1110
1111    }  // end loop on threads
1112
1113    if ( found )  // one matching inactive thread has been found
1114    {
1115        // set argument value in thread context
1116        if ( arg != NULL ) psched->context[ltid].slot[CTX_A0_ID] = (unsigned int)arg;
1117
1118        // activate thread
1119        psched->context[ltid].slot[CTX_NORUN_ID] = 0;
1120
1121        // return launched thead global identifier
1122        *buffer   = trdid;
1123               
1124#if GIET_DEBUG_EXEC
1125if ( _get_proctime() > GIET_DEBUG_EXEC )
1126_printf("\n[DEBUG EXEC] _sys_pthread_create() at cycle %d\n"
1127        "P[%d,%d,%d] exit : thread %x launched in vspace %s\n",
1128        _get_proctime() , x , y , p , trdid , vspace[vspace_id].name );
1129#endif
1130        return SYSCALL_OK;
1131    }
1132    else         // no matching thread found
1133    {
1134        _printf("\n[GIET ERROR] in _sys_pthread_create() : "
1135                "no matching thread for entry = %x in vspace %s\n",
1136                (unsigned int)function , vspace[vspace_id].name );
1137       
1138        return SYSCALL_THREAD_NOT_FOUND;
1139    }
1140
1141} // end _sys_pthread_create()
1142
1143
1144///////////////////////////////////////////
1145int _sys_pthread_join( unsigned int  trdid,
1146                       void*         ptr )
1147{
1148    // ptr argument not supported
1149    if ( ptr != NULL )
1150    {
1151        _printf("\n[GIET ERROR] in _sys_pthread_join() : "
1152                "ptr argument not supported, must be NULL\n" );
1153       
1154        return SYSCALL_PTHREAD_ARGUMENT_NOT_SUPPORTED;
1155    }
1156
1157    // get calling thread vspace
1158    unsigned int  caller_vspace = _get_context_slot( CTX_VSID_ID );
1159               
1160#if GIET_DEBUG_EXEC
1161unsigned int gpid       = _get_procid();
1162unsigned int cluster_xy = gpid >> P_WIDTH;
1163unsigned int p          = gpid & ((1<<P_WIDTH)-1);
1164unsigned int x          = cluster_xy >> Y_WIDTH;
1165unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1166if ( _get_proctime() > GIET_DEBUG_EXEC )
1167_printf("\n[DEBUG EXEC] _sys_pthread_join() at cycle %d\n"
1168        "P[%d,%d,%d] enters for thread %x in vspace %d\n",
1169        _get_proctime() , x , y , p , trdid , caller_vspace );
1170#endif
1171
1172    // get target thread indexes from trdid
1173    unsigned int cx   = (trdid>>24) & 0xFF;
1174    unsigned int cy   = (trdid>>16) & 0xFF;
1175    unsigned int lpid = (trdid>>8 ) & 0xFF;
1176    unsigned int ltid = (trdid    ) & 0xFF;
1177
1178    // get target thread scheduler, vspace and registered trdid
1179    static_scheduler_t*  psched   = _schedulers[cx][cy][lpid];
1180    unsigned int target_vspace    = psched->context[ltid].slot[CTX_VSID_ID];
1181    unsigned int registered_trdid = psched->context[ltid].slot[CTX_TRDID_ID];
1182
1183    // check trdid
1184    if ( trdid != registered_trdid )
1185    {
1186       _printf("\nerror in _sys_pthread_join() : "
1187               "trdid = %x / registered_trdid = %x\n",
1188               trdid , registered_trdid );
1189
1190       return SYSCALL_UNCOHERENT_THREAD_CONTEXT;
1191    }
1192   
1193    // check calling thread and target thread in same vspace
1194    if ( caller_vspace != target_vspace )
1195    {
1196       _printf("\n[GIET ERROR] in _sys_pthread_join() : "
1197               " calling thread and target thread not in same vspace\n");
1198
1199       return SYSCALL_NOT_IN_SAME_VSPACE;
1200    }
1201
1202    // get target thread state
1203    unsigned int* pnorun = &psched->context[ltid].slot[CTX_NORUN_ID];
1204
1205    asm volatile ( "2000:                      \n"                         
1206                   "move  $11,  %0             \n"   /* $11 <= pnorun        */
1207                   "lw    $11,  0($11)         \n"   /* $11 <= norun         */
1208                   "andi  $11,  $11,    1      \n"   /* $11 <= norun & 0x1   */
1209                   "beqz  $11,  2000b          \n"   
1210                   :
1211                   : "r" (pnorun)
1212                   : "$11" );
1213
1214#if GIET_DEBUG_EXEC
1215if ( _get_proctime() > GIET_DEBUG_EXEC )
1216_printf("\n[DEBUG EXEC] _sys_pthread_join() at cycle %d\n"
1217        "P[%d,%d,%d] exit for thread %x in vspace %d\n",
1218        _get_proctime() , x , y , p , trdid , caller_vspace );
1219#endif
1220
1221    return SYSCALL_OK;
1222
1223}  // end _sys_pthread_join()
1224                       
1225
1226////////////////////////////////////////
1227int _sys_pthread_kill( pthread_t  trdid,
1228                       int        signal )
1229{
1230    // get calling thread vspace
1231    unsigned int  caller_vspace = _get_context_slot( CTX_VSID_ID );
1232
1233#if GIET_DEBUG_EXEC
1234unsigned int gpid       = _get_procid();
1235unsigned int cluster_xy = gpid >> P_WIDTH;
1236unsigned int p          = gpid & ((1<<P_WIDTH)-1);
1237unsigned int x          = cluster_xy >> Y_WIDTH;
1238unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1239if ( _get_proctime() > GIET_DEBUG_EXEC )
1240_printf("\n[DEBUG EXEC] _sys_pthread_kill() at cycle %d\n"
1241        "P[%d,%d,%d] enters for thread %x in vspace %d\n",
1242        _get_proctime() , x , y , p , trdid , caller_vspace );
1243#endif
1244
1245
1246    // get and check target thread indexes from trdid
1247    unsigned int cx   = (trdid>>24) & 0xFF;
1248    unsigned int cy   = (trdid>>16) & 0xFF;
1249    unsigned int lpid = (trdid>>8 ) & 0xFF;
1250    unsigned int ltid = (trdid    ) & 0xFF;
1251
1252    // get target thread scheduler, vspace and registered trdid
1253    static_scheduler_t*  psched       = _schedulers[cx][cy][lpid];
1254    unsigned int target_vspace        = psched->context[ltid].slot[CTX_VSID_ID];
1255    unsigned int registered_trdid = psched->context[ltid].slot[CTX_TRDID_ID];
1256
1257    // check trdid
1258    if ( trdid != registered_trdid )
1259    {
1260       _printf("\n[GIET ERROR] in _sys_pthread_kill() : trdid = %x"
1261               " / registered_trdid = %x\n", trdid , registered_trdid );
1262       return SYSCALL_UNCOHERENT_THREAD_CONTEXT;
1263    }
1264   
1265    // check calling thread and target thread in same vspace
1266    if ( caller_vspace != target_vspace )
1267    {
1268       _printf("\n[GIET ERROR] in _sys_pthread_kill() : not in same vspace\n");
1269       return SYSCALL_NOT_IN_SAME_VSPACE;
1270    }
1271
1272    // register KILL signal in target thread context if required
1273    if ( signal )
1274    {
1275        _atomic_or( &psched->context[ltid].slot[CTX_SIGS_ID] , SIGS_MASK_KILL );
1276    }
1277
1278#if GIET_DEBUG_EXEC
1279if ( _get_proctime() > GIET_DEBUG_EXEC )
1280_printf("\n[DEBUG EXEC] _sys_pthread_kill() at cycle %d\n"
1281        "P[%d,%d,%d] exit for thread %x in vspace %d\n",
1282        _get_proctime() , x , y , p , trdid , caller_vspace );
1283#endif
1284
1285    return SYSCALL_OK;
1286
1287}  // end _sys_pthread_kill()
1288
1289
1290/////////////////////////////////////
1291int _sys_pthread_exit( void* string ) 
1292{
1293    mapping_header_t * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1294    mapping_vspace_t * vspace  = _get_vspace_base(header);
1295
1296    unsigned int ltid       = _get_context_slot(CTX_LTID_ID);
1297    unsigned int trdid      = _get_context_slot(CTX_TRDID_ID);
1298    unsigned int vsid       = _get_context_slot(CTX_VSID_ID);
1299
1300    // print exit message
1301    if ( string != NULL )
1302    {
1303        _printf("\n[GIET WARNING] Exit thread %x in vspace %s\n"
1304                "               Cause : %s\n\n",
1305                     trdid , vspace[vsid].name , (char*) string );
1306    }
1307   
1308    // get scheduler pointer for calling thread
1309    static_scheduler_t*  psched = (static_scheduler_t*)_get_sched();
1310
1311    // register KILL signal in calling thread context (suicid request)
1312    _atomic_or( &psched->context[ltid].slot[CTX_SIGS_ID] , SIGS_MASK_KILL );
1313
1314    // deschedule calling thread
1315    unsigned int save_sr; 
1316    _it_disable( &save_sr );
1317
1318    _ctx_switch();
1319
1320    return SYSCALL_OK;
1321
1322}  // end _sys_pthread_exit()
1323
1324////////////////////////
1325int _sys_pthread_yield() 
1326{
1327    unsigned int save_sr;
1328
1329    _it_disable( &save_sr );
1330    _ctx_switch();
1331    _it_restore( &save_sr );
1332
1333    return SYSCALL_OK;
1334}
1335
1336//////////////////////////////////////////////////
1337int _sys_pthread_control( unsigned  int  command,
1338                          char*     vspace_name,
1339                          char*     thread_name )
1340{
1341
1342#if GIET_DEBUG_EXEC
1343unsigned int gpid       = _get_procid();
1344unsigned int cluster_xy = gpid >> P_WIDTH;
1345unsigned int p          = gpid & ((1<<P_WIDTH)-1);
1346unsigned int x          = cluster_xy >> Y_WIDTH;
1347unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1348if ( _get_proctime() > GIET_DEBUG_EXEC )
1349_printf("\n[DEBUG EXEC] _sys_pthread_control() at cycle %d\n"
1350        "P[%d,%d,%d] enter for vspace %s / thread %s / command = %d\n",
1351        _get_proctime() , x , y , p , vspace_name, thread_name, command );
1352#endif
1353
1354    // get pointers in mapping
1355    mapping_header_t*    header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1356    mapping_thread_t*    thread   = _get_thread_base(header);
1357    mapping_vspace_t*    vspace   = _get_vspace_base(header);
1358    mapping_cluster_t*   cluster  = _get_cluster_base(header);
1359
1360    unsigned int found;
1361
1362    // search vspace name to get vspace index: vsid
1363    found = 0;
1364    unsigned int   vsid;
1365    for( vsid = 0 ; vsid < header->vspaces ; vsid++ )
1366    {
1367        if ( _strcmp( vspace[vsid].name, vspace_name ) == 0 )
1368        {
1369            found = 1;
1370            break;
1371        }
1372    }
1373
1374    if ( found == 0 ) return SYSCALL_VSPACE_NOT_FOUND;
1375
1376    // search thread name in vspace to get thread index: tid
1377    found = 0;
1378    unsigned int   tid;
1379    unsigned int   min = vspace[vsid].thread_offset;
1380    unsigned int   max = min + vspace[vsid].threads;
1381    for( tid = min ; tid < max ; tid++ )
1382    {
1383        if ( _strcmp( thread[tid].name, thread_name ) == 0 )
1384        {
1385            found = 1;
1386            break;
1387        }
1388    }
1389
1390    if ( found == 0 ) return SYSCALL_THREAD_NOT_FOUND;
1391
1392    // get target thread coordinates
1393    unsigned int cid  = thread[tid].clusterid;
1394    unsigned int cx   = cluster[cid].x;
1395    unsigned int cy   = cluster[cid].y;
1396    unsigned int cp   = thread[tid].proclocid;
1397    unsigned int ltid = thread[tid].ltid;
1398
1399    // get target thread scheduler
1400    static_scheduler_t* psched = _schedulers[cx][cy][cp];
1401
1402    // check trdid and vsid
1403    unsigned int trdid = cx<<24 | cy<<16 | cp<<8 | ltid;
1404    if ( (psched->context[ltid].slot[CTX_TRDID_ID] != trdid) ||
1405         (psched->context[ltid].slot[CTX_VSID_ID]  != vsid) )
1406    {
1407        return SYSCALL_UNCOHERENT_THREAD_CONTEXT;
1408    }
1409
1410    // execute command
1411    if ( command == THREAD_CMD_PAUSE ) 
1412    {
1413        _atomic_or ( &psched->context[ltid].slot[CTX_NORUN_ID],  NORUN_MASK_THREAD );
1414        return SYSCALL_OK;
1415    }
1416    else if ( command == THREAD_CMD_RESUME )
1417    {
1418        _atomic_and( &psched->context[ltid].slot[CTX_NORUN_ID], ~NORUN_MASK_THREAD );
1419        return SYSCALL_OK;
1420    }
1421    else if ( command == THREAD_CMD_CONTEXT )
1422    {
1423        _user_printf( " - CTX_TRDID  = %x\n"
1424                      " - CTX_VSID   = %x\n"
1425                      " - CTX_EPC    = %x\n"
1426                      " - CTX_PTAB   = %x\n"
1427                      " - CTX_PTPR   = %x\n"
1428                      " - CTX_SR     = %x\n"
1429                      " - CTX_RA     = %x\n"
1430                      " - CTX_SP     = %x\n"
1431                      " - CTX_ENTRY  = %x\n"
1432                      " - CTX_NORUN  = %x\n"
1433                      " - CTX_SIGS   = %x\n"
1434                      " - CTX_LOCKS  = %x\n"
1435                      " - CTX_TTY    = %x\n"
1436                      " - CTX_NIC_RX = %x\n"
1437                      " - CTX_NIC_TX = %x\n"
1438                      " - CTX_CMA_RX = %x\n"
1439                      " - CTX_CMA_TX = %x\n"
1440                      " - CTX_CMA_FB = %x\n",
1441                      psched->context[ltid].slot[CTX_TRDID_ID], 
1442                      psched->context[ltid].slot[CTX_VSID_ID], 
1443                      psched->context[ltid].slot[CTX_EPC_ID], 
1444                      psched->context[ltid].slot[CTX_PTAB_ID], 
1445                      psched->context[ltid].slot[CTX_PTPR_ID], 
1446                      psched->context[ltid].slot[CTX_SR_ID], 
1447                      psched->context[ltid].slot[CTX_RA_ID], 
1448                      psched->context[ltid].slot[CTX_SP_ID], 
1449                      psched->context[ltid].slot[CTX_ENTRY_ID], 
1450                      psched->context[ltid].slot[CTX_NORUN_ID],
1451                      psched->context[ltid].slot[CTX_SIGS_ID],
1452                      psched->context[ltid].slot[CTX_LOCKS_ID],
1453                      psched->context[ltid].slot[CTX_TTY_ID],
1454                      psched->context[ltid].slot[CTX_NIC_RX_ID],
1455                      psched->context[ltid].slot[CTX_NIC_TX_ID],
1456                      psched->context[ltid].slot[CTX_CMA_RX_ID],
1457                      psched->context[ltid].slot[CTX_CMA_TX_ID],
1458                      psched->context[ltid].slot[CTX_CMA_FB_ID] );
1459        return SYSCALL_OK;
1460    }
1461    else
1462    {
1463        return SYSCALL_ILLEGAL_THREAD_COMMAND_TYPE;
1464    }
1465
1466} // end _sys_pthread_control()
1467
1468
1469
1470
1471//////////////////////////////////////////////////////////////////////////////
1472//           Coprocessors related syscall handlers
1473//////////////////////////////////////////////////////////////////////////////
1474
1475//////////////////////////////////////////////////
1476int _sys_coproc_alloc( unsigned int   cluster_xy,
1477                       unsigned int   coproc_type,
1478                       unsigned int*  return_info )
1479{
1480    mapping_header_t  * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1481    mapping_cluster_t * cluster = _get_cluster_base(header);
1482    mapping_periph_t  * periph  = _get_periph_base(header);
1483
1484    // compute cluster coordinates and cluster index in mapping
1485    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1486    unsigned int x          = (cluster_xy>>Y_WIDTH) & ((1<<X_WIDTH)-1);
1487    unsigned int cluster_id = x * Y_SIZE + y;
1488 
1489    // search coprocessor in cluster
1490    mapping_periph_t*  found = NULL;
1491    unsigned int min   = cluster[cluster_id].periph_offset;
1492    unsigned int max   = min + cluster[cluster_id].periphs;
1493    unsigned int periph_id;
1494    for ( periph_id = min ; periph_id < max ; periph_id++ )
1495    {
1496        if ( (periph[periph_id].type == PERIPH_TYPE_MWR) &&
1497             (periph[periph_id].subtype == coproc_type) )
1498        {
1499            found = &periph[periph_id];
1500            break;
1501        }
1502    } 
1503
1504    if ( found != NULL )
1505    {
1506        // get the lock
1507        _simple_lock_acquire( &_coproc_lock[cluster_id] );
1508
1509        // register coproc characteristics in kernel arrays
1510        _coproc_type[cluster_id] = coproc_type;
1511        _coproc_info[cluster_id] = (found->arg0 & 0xFF)     |
1512                                   (found->arg1 & 0xFF)<<8  |
1513                                   (found->arg2 & 0xFF)<<16 |
1514                                   (found->arg3 & 0xFF)<<24 ;
1515
1516        // returns coprocessor info
1517        *return_info = _coproc_info[cluster_id];
1518
1519#if GIET_DEBUG_COPROC
1520_printf("\n[DEBUG COPROC] _sys_coproc_alloc() at cycle %d\n"
1521        "type = %d in cluster[%d,%d] / coproc_info = %x\n",
1522        _get_proctime() , coproc_type, x , y , *return_info );
1523#endif
1524        return SYSCALL_OK;
1525    }
1526    else
1527    {
1528         _printf("\n[GIET_ERROR] in _sys_coproc_alloc(): "
1529                 "no coprocessor with type %d in cluster[%d,%d]\n",
1530                 coproc_type , x , y );
1531
1532        return SYSCALL_COPROCESSOR_NOT_FOUND;
1533    }
1534}  // end _sys_coproc_alloc()
1535
1536////////////////////////////////////////////////////////
1537int _sys_coproc_release( unsigned int cluster_xy,
1538                         unsigned int coproc_type )
1539{
1540    // compute cluster coordinates and cluster index
1541    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1542    unsigned int x          = (cluster_xy>>Y_WIDTH) & ((1<<X_WIDTH)-1);
1543    unsigned int cluster_id = x * Y_SIZE + y;
1544
1545    // check coprocessor type
1546    if ( _coproc_type[cluster_id] != coproc_type )
1547    {
1548         _printf("\n[GIET_ERROR] in _sys_coproc_release(): "
1549                 "no coprocessor of type %d allocated in cluster[%d,%d]\n", 
1550                 coproc_type, x , y );
1551
1552         return SYSCALL_COPROCESSOR_NON_ALLOCATED;
1553    }
1554
1555    unsigned int info       = _coproc_info[cluster_id];
1556    unsigned int nb_to      = info & 0xFF;
1557    unsigned int nb_from    = (info>>8) & 0xFF;
1558    unsigned int channel;
1559
1560    // stops coprocessor and communication channels
1561    _mwr_set_coproc_register( cluster_xy , 0 , 0 );
1562    for ( channel = 0 ; channel < (nb_from + nb_to) ; channel++ )
1563    {
1564        _mwr_set_channel_register( cluster_xy , channel , MWR_CHANNEL_RUNNING , 0 );
1565    }
1566
1567    // release coprocessor lock
1568    _simple_lock_release( &_coproc_lock[cluster_id] );
1569
1570#if GIET_DEBUG_COPROC
1571_printf("\n[DEBUG COPROC] _sys_coproc_release() at cycle %d\n"
1572        "type = %d in cluster[%d,%d]\n",
1573        _get_proctime() , coproc_type , x , y );
1574#endif
1575
1576    return SYSCALL_OK;
1577}  // end _sys_coproc_release()
1578
1579////////////////////////////////////////////////////////////////
1580int _sys_coproc_channel_init( unsigned int            cluster_xy,
1581                              unsigned int            coproc_type,
1582                              unsigned int            channel,
1583                              giet_coproc_channel_t*  desc )
1584{
1585    // compute cluster coordinates and cluster index
1586    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1587    unsigned int x          = (cluster_xy>>Y_WIDTH) & ((1<<X_WIDTH)-1);
1588    unsigned int cluster_id = x * Y_SIZE + y;
1589
1590    // check coprocessor type
1591    if ( _coproc_type[cluster_id] != coproc_type )
1592    {
1593         _printf("\n[GIET_ERROR] in _sys_coproc_release(): "
1594                 "no coprocessor of type %d allocated in cluster[%d,%d]\n", 
1595                 coproc_type, x , y );
1596
1597         return SYSCALL_COPROCESSOR_NON_ALLOCATED;
1598    }
1599
1600    // check channel mode
1601    unsigned mode = desc->channel_mode;
1602    if ( (mode != MODE_MWMR) && 
1603         (mode != MODE_DMA_IRQ) && 
1604         (mode != MODE_DMA_NO_IRQ) )
1605    {
1606         _printf("\n[GIET_ERROR] in _sys_coproc_channel_init(): "
1607                 "illegal mode\n");
1608
1609         return SYSCALL_COPROCESSOR_ILLEGAL_MODE;
1610    }
1611
1612    // get memory buffer size
1613    unsigned int size = desc->buffer_size;
1614 
1615    // physical addresses
1616    unsigned long long buffer_paddr;
1617    unsigned int       buffer_lsb;
1618    unsigned int       buffer_msb;
1619    unsigned long long status_paddr = 0;
1620    unsigned int       status_lsb;
1621    unsigned int       status_msb;
1622    unsigned long long lock_paddr = 0;
1623    unsigned int       lock_lsb;
1624    unsigned int       lock_msb;
1625
1626    unsigned int       flags;     // unused
1627
1628    // compute memory buffer physical address
1629    buffer_paddr = _v2p_translate( desc->buffer_vaddr , &flags );
1630    buffer_lsb   = (unsigned int)buffer_paddr;
1631    buffer_msb   = (unsigned int)(buffer_paddr>>32); 
1632
1633    // call MWMR_DMA driver
1634    _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_MODE, mode ); 
1635    _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_SIZE, size ); 
1636    _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_BUFFER_LSB, buffer_lsb ); 
1637    _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_BUFFER_MSB, buffer_msb ); 
1638                       
1639    if ( mode == MODE_MWMR )
1640    {
1641        // compute MWMR descriptor physical address
1642        status_paddr = _v2p_translate( desc->status_vaddr , &flags );
1643        status_lsb = (unsigned int)status_paddr;
1644        status_msb = (unsigned int)(status_paddr>>32); 
1645
1646        // call MWMR_DMA driver
1647        _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_MWMR_LSB, status_lsb ); 
1648        _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_MWMR_MSB, status_msb ); 
1649
1650        // compute lock physical address
1651        lock_paddr = _v2p_translate( desc->lock_vaddr , &flags );
1652        lock_lsb = (unsigned int)lock_paddr;
1653        lock_msb = (unsigned int)(lock_paddr>>32); 
1654
1655        // call MWMR_DMA driver
1656        _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_LOCK_LSB, lock_lsb ); 
1657        _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_LOCK_MSB, lock_msb ); 
1658    }
1659
1660#if GIET_DEBUG_COPROC
1661_printf("\n[DEBUG COPROC] _sys_coproc_channel_init() at cycle %d\n"
1662        "cluster[%d,%d] / channel = %d / mode = %d / buffer_size = %d\n"
1663        "buffer_vaddr = %x / status_vaddr = %x / lock_vaddr = %x\n"
1664        "buffer_paddr = %l / status_paddr = %l / lock_paddr = %l\n",
1665        _get_proctime() , x , y , channel , mode , size ,
1666        desc->buffer_vaddr, desc->status_vaddr, desc->lock_vaddr,
1667        buffer_paddr, status_paddr, lock_paddr );
1668#endif
1669       
1670    return SYSCALL_OK;
1671} // end _sys_coproc_channel_init()
1672
1673//////////////////////////////////////////////
1674int _sys_coproc_run( unsigned int  cluster_xy,
1675                     unsigned int  coproc_type )
1676{
1677    // compute cluster coordinates and cluster index
1678    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1679    unsigned int x          = (cluster_xy>>Y_WIDTH) & ((1<<X_WIDTH)-1);
1680    unsigned int cluster_id = x * Y_SIZE + y;
1681
1682    // check coprocessor type
1683    if ( _coproc_type[cluster_id] != coproc_type )
1684    {
1685         _printf("\n[GIET_ERROR] in _sys_coproc_release(): "
1686                 "no coprocessor of type %d allocated in cluster[%d,%d]\n", 
1687                 coproc_type, x , y );
1688
1689         return SYSCALL_COPROCESSOR_NON_ALLOCATED;
1690    }
1691
1692    unsigned int info       = _coproc_info[cluster_id];
1693    unsigned int nb_to      = info & 0xFF;
1694    unsigned int nb_from    = (info>>8) & 0xFF;
1695    unsigned int mode       = 0xFFFFFFFF;
1696    unsigned int channel;
1697
1698    // check channels modes, and register coprocessor running mode
1699    for ( channel = 0 ; channel < (nb_from + nb_to) ; channel++ )
1700    {
1701        unsigned int temp;
1702        temp = _mwr_get_channel_register( cluster_xy , channel , MWR_CHANNEL_MODE );
1703
1704        if ( mode == 0xFFFFFFFF ) 
1705        {
1706            mode = temp;
1707        }
1708        else if ( temp != mode )
1709        {
1710            _printf("\n[GIET_ERROR] in _sys_coproc_run(): "
1711                    "channels don't have same mode in coprocessor[%d,%d]\n", x , y );
1712
1713            return SYSCALL_COPROCESSOR_ILLEGAL_MODE;
1714        }
1715    }
1716    _coproc_mode[cluster_id] = mode;
1717
1718    // start all communication channels
1719    for ( channel = 0 ; channel < (nb_from + nb_to) ; channel++ )
1720    {
1721        _mwr_set_channel_register( cluster_xy , channel , MWR_CHANNEL_RUNNING , 1 );
1722    }
1723
1724    //////////////////////////////////////////////////////////////////////////
1725    if ( (mode == MODE_MWMR) || (mode == MODE_DMA_NO_IRQ) )  // no descheduling
1726    {
1727        // start coprocessor
1728        _mwr_set_coproc_register( cluster_xy , 0 , 1 );
1729
1730#if GIET_DEBUG_COPROC
1731if ( mode == MODE_MWMR )
1732_printf("\n[DEBUG COPROC] _sys_coproc_run() at cycle %d\n"
1733        "type = %d / cluster[%d,%d] / MODE_MWMR\n", 
1734        _get_proctime() , coproc_type , x , y );
1735else
1736_printf("\n[DEBUG COPROC] _sys_coproc_run() at cycle %d\n"
1737        "type = %d / cluster[%d,%d] / MODE_DMA_NO_IRQ\n", 
1738        _get_proctime() , coproc_type , x , y );
1739#endif
1740
1741        return SYSCALL_OK;
1742    }
1743    ///////////////////////////////////////////////////////////////////////////
1744    else                                // mode == MODE_DMA_IRQ => descheduling
1745    {
1746        // register calling thread trdid
1747        unsigned int trdid = _get_thread_trdid();
1748        _coproc_trdid[cluster_id] = trdid;
1749
1750        // enters critical section
1751        unsigned int save_sr;
1752        _it_disable( &save_sr ); 
1753
1754        // set NORUN_MASK_COPROC bit
1755        static_scheduler_t* psched  = _get_sched();
1756        unsigned int        ltid    = _get_thread_ltid();
1757        unsigned int*       ptr     = &psched->context[ltid].slot[CTX_NORUN_ID];
1758        _atomic_or( ptr , NORUN_MASK_COPROC );
1759
1760        // start coprocessor
1761        _mwr_set_coproc_register( cluster_xy , 0 , 1 );
1762
1763#if GIET_DEBUG_COPROC
1764_printf("\n[DEBUG COPROC] _sys_coproc_run() at cycle %d\n"
1765        "thread %x starts coprocessor / type = %d / cluster[%d,%d] / MODE_DMA_IRQ\n", 
1766        _get_proctime() , trdid , coproc_type , x , y );
1767#endif
1768
1769        // deschedule thread
1770        _ctx_switch(); 
1771
1772#if GIET_DEBUG_COPROC
1773_printf("\n[DEBUG COPROC] _sys_coproc_run() at cycle %d\n"
1774        "thread %x resume after coprocessor[%d,%d] completion\n", 
1775        _get_proctime() , trdid , x , y );
1776#endif
1777
1778        // restore SR
1779        _it_restore( &save_sr );
1780
1781        // return error computed by mwr_isr()
1782        return _coproc_error[cluster_id];
1783    } 
1784} // end _sys_coproc_run()
1785
1786////////////////////////////////////////////////////
1787int _sys_coproc_completed( unsigned int  cluster_xy,
1788                           unsigned int  coproc_type )
1789{
1790    // compute cluster coordinates and cluster index
1791    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1792    unsigned int x          = (cluster_xy>>Y_WIDTH) & ((1<<X_WIDTH)-1);
1793    unsigned int cluster_id = x * Y_SIZE + y;
1794
1795    // check coprocessor type
1796    if ( _coproc_type[cluster_id] != coproc_type )
1797    {
1798         _printf("\n[GIET_ERROR] in _sys_coproc_release(): "
1799                 "no coprocessor of type %d allocated in cluster[%d,%d]\n", 
1800                 coproc_type, x , y );
1801
1802         return SYSCALL_COPROCESSOR_NON_ALLOCATED;
1803    }
1804
1805    unsigned int mode = _coproc_mode[cluster_id];
1806
1807    // analyse possible errors
1808    if ( mode == MODE_DMA_NO_IRQ )
1809    {
1810        unsigned int info       = _coproc_info[cluster_id];
1811        unsigned int nb_to      = info & 0xFF;
1812        unsigned int nb_from    = (info>>8) & 0xFF;
1813        unsigned int error      = 0;
1814        unsigned int channel;
1815        unsigned int status;
1816
1817        // get status for all channels, and signal reported errors
1818        for ( channel = 0 ; channel < (nb_to +nb_from) ; channel++ )
1819        {
1820            do
1821            {
1822                status = _mwr_get_channel_register( cluster_xy, channel,
1823                                                    MWR_CHANNEL_STATUS );
1824                if ( status == MWR_CHANNEL_ERROR_DATA )
1825                {
1826                    _printf("\n[GIET_ERROR] in _sys_coproc_completed(): "
1827                            "channel %d / DATA_ERROR\n", channel );
1828                    error = 1;
1829                }
1830                else if ( status == MWR_CHANNEL_ERROR_LOCK )
1831                {
1832                    _printf("\n[GIET_ERROR] in _sys_coproc_completed()"
1833                            " / channel %d / LOCK_ERROR\n", channel );
1834                    error = 1;
1835                }
1836                else if ( status == MWR_CHANNEL_ERROR_DESC )
1837                {
1838                    _printf("\n[GIET_ERROR] in _sys_coproc_completed()"
1839                            " / channel %d / DESC_ERROR\n", channel );
1840                    error = 1;
1841                }
1842            } 
1843            while ( status == MWR_CHANNEL_BUSY );
1844
1845            // reset channel
1846            _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_RUNNING , 0 ); 
1847
1848        }  // end for channels
1849
1850        if ( error )
1851        {
1852            return SYSCALL_COPROCESSOR_ILLEGAL_MODE;
1853        }
1854        else
1855        {
1856
1857#if GIET_DEBUG_COPROC
1858_printf("\n[DEBUG COPROC] _sys_coproc_completed() at cycle %d\n"
1859        "coprocessor type = %d / cluster[%d,%d] completes operation for thread %d\n", 
1860        _get_proctime() , coproc_type , x , y , _get_thread_trdid() );
1861#endif
1862            return SYSCALL_OK;
1863        }
1864    }
1865    else  // mode == MODE_MWMR or MODE_DMA_IRQ
1866    {
1867        _printf("\n[GIET ERROR] in sys_coproc_completed(): "
1868                "coprocessor[%d,%d] is not running in MODE_DMA_NO_IRQ\n", x , y );
1869
1870        return SYSCALL_COPROCESSOR_ILLEGAL_MODE;
1871    }
1872} // end _sys_coproc_completed()
1873
1874
1875//////////////////////////////////////////////////////////////////////////////
1876//             TTY related syscall handlers
1877//////////////////////////////////////////////////////////////////////////////
1878
1879/////////////////////////////////////////
1880int _sys_tty_alloc( unsigned int shared )
1881{
1882    unsigned int channel = 0;    // allocated TTY channel
1883
1884    // get vsid for the calling thread
1885    unsigned int vsid  = _get_context_slot( CTX_VSID_ID );
1886
1887    mapping_header_t  *header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1888    mapping_vspace_t  *vspace   = _get_vspace_base(header);
1889    mapping_thread_t  *thread   = _get_thread_base(header);
1890   
1891    // compute number of users
1892    unsigned int users;
1893    if ( shared )  users = vspace[vsid].threads;
1894    else           users = 1;
1895
1896#if NB_TTY_CHANNELS > 1
1897    // get trdid for the calling thread
1898    unsigned int trdid = _get_thread_trdid();
1899
1900    // get a TTY channel
1901    for ( channel = 0 ; channel < NB_TTY_CHANNELS ; channel++ )
1902    {
1903        unsigned int* palloc  = &_tty_channel_alloc[channel];
1904
1905        if ( _atomic_test_and_set( palloc , users ) == 0 ) break;
1906    }
1907    if ( ( channel >= NB_TTY_CHANNELS ) )
1908    {
1909        _printf("\n[GIET_ERROR] in _sys_tty_alloc() : "
1910                "no TTY channel available for thread %x\n", trdid );
1911        return SYSCALL_NO_CHANNEL_AVAILABLE;
1912    }
1913
1914    // initialise allocated TTY channel
1915    _tty_init( channel );
1916
1917    // allocate a WTI mailbox to the calling proc if external IRQ
1918    unsigned int wti_id;
1919    if ( USE_PIC ) _ext_irq_alloc( ISR_TTY_RX , channel , &wti_id ); 
1920
1921    // register wti_id and coordinates for processor receiving WTI
1922    unsigned int procid = _get_procid();
1923    unsigned int x      = procid >> (Y_WIDTH + P_WIDTH);
1924    unsigned int y      = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1925    unsigned int p      = procid & ((1<<P_WIDTH)-1);
1926    _tty_channel_wti[channel] = x<<24 | y<<16 | p<<8 | wti_id;
1927
1928#else
1929
1930    unsigned int* palloc  = &_tty_channel_alloc[0];
1931    _atomic_increment( palloc, users );
1932
1933#endif
1934   
1935    // update CTX_TTY_ID
1936    if ( shared )         // for all threads in vspace
1937    {
1938        // scan threads in vspace
1939        unsigned int tid;
1940        for (tid = vspace[vsid].thread_offset;
1941             tid < (vspace[vsid].thread_offset + vspace[vsid].threads);
1942             tid++)
1943        {
1944            unsigned int y_size        = header->y_size;
1945            unsigned int cid           = thread[tid].clusterid;
1946            unsigned int x             = cid / y_size;
1947            unsigned int y             = cid % y_size;
1948            unsigned int p             = thread[tid].proclocid;
1949            unsigned int ltid          = thread[tid].ltid;
1950            static_scheduler_t* psched = (static_scheduler_t*)_schedulers[x][y][p];
1951
1952            psched->context[ltid].slot[CTX_TTY_ID] = channel;
1953        }
1954    }
1955    else                  // for calling thread only
1956    {
1957        _set_context_slot( CTX_TTY_ID, channel );
1958    }
1959
1960    return SYSCALL_OK;
1961}  // end _sys_tty_alloc()
1962
1963//////////////////////
1964int _sys_tty_release()     // NOTE: not a syscall: used by _ctx_kill_thread()
1965{
1966    unsigned int channel = _get_context_slot( CTX_TTY_ID );
1967
1968    if ( channel == -1 )
1969    {
1970        unsigned int trdid = _get_thread_trdid();
1971        _printf("\n[GIET_ERROR] in _sys_tty_release() : "
1972                "TTY channel already released for thread %x\n", trdid );
1973
1974        return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
1975    }
1976
1977    // reset CTX_TTY_ID for the calling thread
1978    _set_context_slot( CTX_TTY_ID , 0xFFFFFFFF );
1979
1980    // atomically decrement the _tty_channel_allocator[] array
1981    _atomic_increment( &_tty_channel_alloc[channel] , -1 );
1982
1983    // release WTI mailbox if TTY channel no more used
1984    if ( USE_PIC  && (_tty_channel_alloc[channel] == 0) ) 
1985    {
1986        _ext_irq_release( ISR_TTY_RX , channel );
1987    }
1988
1989    return SYSCALL_OK;
1990}  // end sys_tty_release()
1991
1992////////////////////////////////////////
1993int _sys_tty_write( const char*  buffer,   
1994                    unsigned int length,    // number of characters
1995                    unsigned int channel)   // channel index
1996{
1997    unsigned int  nwritten;
1998
1999    // compute and check tty channel
2000    if( channel == 0xFFFFFFFF )  channel = _get_context_slot(CTX_TTY_ID);
2001
2002    if( channel >= NB_TTY_CHANNELS )
2003    {
2004        _printf("\n[GIET_ERROR] in _sys_tty_write() : "
2005                "no TTY channel allocated for thread %x\n", _get_thread_trdid() );
2006
2007        return SYSCALL_CHANNEL_NON_ALLOCATED;
2008    }
2009
2010    // write string to TTY channel
2011    for (nwritten = 0; nwritten < length; nwritten++) 
2012    {
2013        // check tty's status
2014        if ( _tty_get_register( channel, TTY_STATUS ) & 0x2 )  break;
2015
2016        // write one byte
2017        if (buffer[nwritten] == '\n') 
2018        {
2019            _tty_set_register( channel, TTY_WRITE, (unsigned int)'\r' );
2020        }
2021        _tty_set_register( channel, TTY_WRITE, (unsigned int)buffer[nwritten] );
2022    }
2023   
2024    return nwritten;
2025}
2026
2027///////////////////////////////////////
2028int _sys_tty_read( char*        buffer, 
2029                   unsigned int length,    // unused
2030                   unsigned int channel)   // channel index
2031{
2032    // compute and check tty channel
2033    if( channel == 0xFFFFFFFF )  channel = _get_context_slot(CTX_TTY_ID);
2034
2035    if( channel >= NB_TTY_CHANNELS )
2036    {
2037        _printf("\n[GIET_ERROR] in _sys_tty_read() : "
2038                "no TTY channel allocated for thread %x\n", _get_thread_trdid() );
2039
2040        return SYSCALL_CHANNEL_NON_ALLOCATED;
2041    }
2042
2043    unsigned int save_sr;
2044    unsigned int found = 0;
2045
2046    // get pointer on TTY_RX FIFO
2047    tty_fifo_t*  fifo = &_tty_rx_fifo[channel];
2048
2049    // try to read one character from FIFO
2050    // blocked in while loop until success
2051    while ( found == 0 )
2052    {
2053        if ( fifo->sts == 0)   // FIFO empty => deschedule
2054        {
2055            // enters critical section
2056             _it_disable( &save_sr );
2057
2058            // set NORUN_MASK_TTY bit for calling thread
2059            static_scheduler_t* psched  = (static_scheduler_t*)_get_sched();
2060            unsigned int ltid = psched->current;
2061            _atomic_or( &psched->context[ltid].slot[CTX_NORUN_ID] , NORUN_MASK_TTY );
2062
2063            // register descheduling thread trdid
2064            fifo->trdid = _get_thread_trdid();
2065
2066             // deschedule calling thread
2067            _ctx_switch();
2068
2069            // exit critical section
2070            _it_restore( &save_sr );
2071        }
2072        else                             // FIFO not empty => get one character
2073        {
2074            *buffer   = fifo->data[fifo->ptr];
2075            fifo->sts = fifo->sts - 1;
2076            fifo->ptr = (fifo->ptr + 1) % TTY_FIFO_DEPTH;
2077            found     = 1;
2078        }
2079    }
2080
2081    return 1;
2082}
2083
2084
2085
2086//////////////////////////////////////////////////////////////////////////////
2087//             TIMER related syscall handlers
2088//////////////////////////////////////////////////////////////////////////////
2089
2090////////////////////
2091int _sys_tim_alloc()
2092{
2093
2094#if NB_TIM_CHANNELS
2095
2096    unsigned int channel;    // allocated TIMER channel
2097
2098    unsigned int trdid = _get_thread_trdid();
2099
2100    // check no TIMER already allocated to calling thread
2101    if ( _get_context_slot( CTX_TIM_ID ) < NB_TIM_CHANNELS )
2102    {
2103        _printf("\n[GIET_ERROR] in _sys_tim_alloc() : "
2104                "TIMER channel already allocated to thread %x\n", trdid );
2105
2106        return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
2107    }
2108
2109    // get a TIMER channel
2110    for ( channel = 0 ; channel < NB_TIM_CHANNELS ; channel++ )
2111    {
2112        unsigned int* palloc  = &_tim_channel_alloc[channel];
2113
2114        if ( _atomic_test_and_set( palloc , 1 ) == 0 ) break;
2115    }
2116    if ( channel >= NB_TIM_CHANNELS )
2117    {
2118        _printf("\n[GIET_ERROR] in _sys_tim_alloc() : "
2119                "no TIMER channel available for thread %x\n", trdid );
2120
2121        return SYSCALL_NO_CHANNEL_AVAILABLE;
2122    }
2123
2124    // allocate a WTI mailbox to the calling proc if external IRQ
2125    unsigned int wti_id;
2126    if ( USE_PIC ) _ext_irq_alloc( ISR_TIMER , channel , &wti_id ); 
2127
2128    // register wti_id and coordinates for processor receiving WTI
2129    unsigned int procid = _get_procid();
2130    unsigned int x      = procid >> (Y_WIDTH + P_WIDTH);
2131    unsigned int y      = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
2132    unsigned int p      = procid & ((1<<P_WIDTH)-1);
2133    _tim_channel_wti[channel] = x<<24 | y<<16 | p<<8 | wti_id;
2134   
2135    // update CTX_TIM_ID in thread context
2136    _set_context_slot( CTX_TIM_ID, channel );
2137
2138    return SYSCALL_OK;
2139
2140#else
2141
2142    _printf("\n[GIET ERROR] in _sys_tim_alloc(): NB_TIM_CHANNELS == 0\n");
2143
2144    return SYSCALL_NO_CHANNEL_AVAILABLE;
2145
2146#endif
2147}  // end _sys_tim_alloc()
2148
2149
2150//////////////////////
2151int _sys_tim_release()     // NOTE: not a syscall: used by _ctx_kill_thread()
2152{
2153
2154#if NB_TIM_CHANNELS
2155
2156    unsigned int channel = _get_context_slot( CTX_TIM_ID );
2157
2158    if ( channel == -1 )
2159    {
2160        unsigned int trdid = _get_thread_trdid();
2161        _printf("\n[GIET_ERROR] in _sys_tim_release(): "
2162                "TIMER channel already released for thread %x\n", trdid );
2163
2164        return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
2165    }
2166
2167    // reset CTX_TIM_ID for the calling thread
2168    _set_context_slot( CTX_TIM_ID , 0xFFFFFFFF );
2169
2170    // reset the _tim_channel_alloc[] array
2171    _tim_channel_alloc[channel] = 0;
2172
2173    // release WTI mailbox if TTY channel no more used
2174    if ( USE_PIC ) 
2175    {
2176        _ext_irq_release( PERIPH_TYPE_TIM , channel );
2177    }
2178
2179    return SYSCALL_OK;
2180
2181#else
2182
2183    _printf("\n[GIET ERROR] in _sys_tim_release(): NB_TIM_CHANNELS = 0\n");
2184
2185    return SYSCALL_NO_CHANNEL_AVAILABLE;
2186
2187#endif
2188}  // end _sys_tim_release()
2189
2190/////////////////////////////////////////
2191int _sys_tim_start( unsigned int period )
2192{
2193
2194#if NB_TIM_CHANNELS
2195
2196    // get timer index
2197    unsigned int channel = _get_context_slot( CTX_TIM_ID );
2198
2199    if ( channel >= NB_TIM_CHANNELS )
2200    {
2201        _printf("\n[GIET_ERROR] in _sys_tim_start(): not enough TIM channels\n");
2202
2203        return SYSCALL_NO_CHANNEL_AVAILABLE;
2204    }
2205
2206    // start timer
2207    _timer_start( channel, period );
2208
2209    return SYSCALL_OK;
2210
2211#else
2212
2213    _printf("\n[GIET ERROR] in _sys_tim_start() : NB_TIM_CHANNELS = 0\n");
2214
2215    return SYSCALL_NO_CHANNEL_AVAILABLE;
2216
2217#endif
2218}
2219
2220///////////////////
2221int _sys_tim_stop()
2222{
2223
2224#if NB_TIM_CHANNELS
2225
2226    // get timer index
2227    unsigned int channel = _get_context_slot( CTX_TIM_ID );
2228
2229    if ( channel >= NB_TIM_CHANNELS )
2230    {
2231        _printf("\n[GIET_ERROR] in _sys_tim_stop() : illegal timer index\n");
2232
2233        return SYSCALL_CHANNEL_NON_ALLOCATED;
2234    }
2235
2236    // stop timer
2237    _timer_stop( channel );
2238
2239    return SYSCALL_OK;
2240
2241#else
2242
2243    _printf("\n[GIET ERROR] in _sys_tim_stop() : NB_TIM_CHANNELS = 0\n");
2244
2245    return SYSCALL_NO_CHANNEL_AVAILABLE;
2246
2247#endif
2248}
2249
2250
2251//////////////////////////////////////////////////////////////////////////////
2252//             NIC related syscall handlers
2253//////////////////////////////////////////////////////////////////////////////
2254
2255#define NIC_CONTAINER_SIZE 4096
2256
2257#if NB_NIC_CHANNELS && NB_CMA_CHANNELS
2258
2259////////////////////////////////////////
2260int _sys_nic_alloc( unsigned int is_rx,
2261                    unsigned int xmax,
2262                    unsigned int ymax )
2263{
2264    mapping_header_t  *header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
2265    mapping_vspace_t  *vspace   = _get_vspace_base(header);
2266    mapping_thread_t  *thread   = _get_thread_base(header);
2267
2268    // get calling thread trdid, vspace index, and number of threads
2269    unsigned int trdid = _get_thread_trdid();
2270    unsigned int vsid  = _get_context_slot( CTX_VSID_ID );
2271    unsigned int users = vspace[vsid].threads;
2272
2273    // check xmax / ymax parameters
2274    if ( (xmax > X_SIZE) || (ymax > Y_SIZE) )
2275    {
2276        _printf("\n[GIET_ERROR] in _sys_nic_alloc() "
2277                "xmax or ymax argument too large for thread %x\n", trdid );
2278
2279        return SYSCALL_ILLEGAL_ARGUMENT;
2280    }
2281
2282    ////////////////////////////////////////////////////////
2283    // Step 1: get and register CMA and NIC channel index //
2284    ////////////////////////////////////////////////////////
2285
2286    unsigned int   nic_channel;
2287    unsigned int   cma_channel;
2288    unsigned int*  palloc;
2289
2290    // get a NIC_RX or NIC_TX channel
2291    for ( nic_channel = 0 ; nic_channel < NB_NIC_CHANNELS ; nic_channel++ )
2292    {
2293        if ( is_rx ) palloc = &_nic_rx_channel_alloc[nic_channel];
2294        else         palloc = &_nic_tx_channel_alloc[nic_channel];
2295
2296        if ( _atomic_test_and_set( palloc , users ) == 0 ) break;
2297    }
2298    if ( (nic_channel >= NB_NIC_CHANNELS) )
2299    {
2300        _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
2301                "no NIC channel available for thread %x\n", trdid );
2302
2303        return SYSCALL_NO_CHANNEL_AVAILABLE;
2304    }
2305
2306    // get a CMA channel
2307    for ( cma_channel = 0 ; cma_channel < NB_CMA_CHANNELS ; cma_channel++ )
2308    {
2309        palloc = &_cma_channel_alloc[cma_channel];
2310
2311        if ( _atomic_test_and_set( palloc , users ) == 0 ) break;
2312    }
2313    if ( cma_channel >= NB_CMA_CHANNELS )
2314    {
2315        _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
2316                "no CMA channel available for thread %x\n", trdid );
2317        if ( is_rx )  _nic_rx_channel_alloc[nic_channel] = 0;
2318        else          _nic_tx_channel_alloc[nic_channel] = 0;
2319
2320        return SYSCALL_NO_CHANNEL_AVAILABLE;
2321    }
2322
2323#if GIET_DEBUG_NIC
2324_printf("\n[DEBUG NIC] sys_nic_alloc() at cycle %d\n"
2325        "thread %d get nic_channel = %d / cma_channel = %d\n",
2326        _get_proctime() , trdid , nic_channel , cma_channel );
2327#endif
2328
2329    // register nic_index and cma_index in all threads
2330    // contexts that are in the same vspace
2331    unsigned int tid;
2332    for (tid = vspace[vsid].thread_offset;
2333         tid < (vspace[vsid].thread_offset + vspace[vsid].threads);
2334         tid++)
2335    {
2336        unsigned int y_size        = header->y_size;
2337        unsigned int cid           = thread[tid].clusterid;
2338        unsigned int x             = cid / y_size;
2339        unsigned int y             = cid % y_size;
2340        unsigned int p             = thread[tid].proclocid;
2341        unsigned int ltid          = thread[tid].ltid;
2342        static_scheduler_t* psched = (static_scheduler_t*)_schedulers[x][y][p];
2343
2344        if ( is_rx )
2345        {
2346            if ( (psched->context[ltid].slot[CTX_NIC_RX_ID] < NB_NIC_CHANNELS) ||
2347                 (psched->context[ltid].slot[CTX_CMA_RX_ID] < NB_CMA_CHANNELS) )
2348            {
2349                _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
2350                        "NIC_RX or CMA_RX channel already allocated for thread %x\n", trdid );
2351                _nic_rx_channel_alloc[nic_channel] = 0;
2352                _cma_channel_alloc[cma_channel]    = 0;
2353
2354                return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
2355            }
2356            else
2357            {
2358                psched->context[ltid].slot[CTX_NIC_RX_ID] = nic_channel;
2359                psched->context[ltid].slot[CTX_CMA_RX_ID] = cma_channel;
2360            }
2361        }
2362        else // is_tx
2363        {
2364            if ( (psched->context[ltid].slot[CTX_NIC_TX_ID] < NB_NIC_CHANNELS) ||
2365                 (psched->context[ltid].slot[CTX_CMA_TX_ID] < NB_CMA_CHANNELS) )
2366            {
2367                _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
2368                        "NIC_TX or CMA_TX channel already allocated for thread %x\n", trdid );
2369                _nic_tx_channel_alloc[nic_channel] = 0;
2370                _cma_channel_alloc[cma_channel]    = 0;
2371
2372                return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
2373            }
2374            else
2375            {
2376                psched->context[ltid].slot[CTX_NIC_TX_ID] = nic_channel;
2377                psched->context[ltid].slot[CTX_CMA_TX_ID] = cma_channel;
2378            }
2379        }
2380    }  // end loop on threads
2381
2382    /////////////////////////////////////////////////////////////////////////////////
2383    // Step 2: loop on all the clusters                                            //
2384    // Allocate the kernel containers and status, compute the container and the    //
2385    // status physical addresses, fill and synchronize the kernel CHBUF descriptor //
2386    /////////////////////////////////////////////////////////////////////////////////
2387
2388    // physical addresses to be registered in the CMA registers
2389    unsigned long long nic_chbuf_pbase;     // NIC chbuf physical address
2390    unsigned long long ker_chbuf_pbase;     // kernel chbuf physical address
2391
2392    // allocate one kernel container and one status variable per cluster in the
2393    // (xmax / ymax) mesh
2394    unsigned int        cx;                 // cluster X coordinate
2395    unsigned int        cy;                 // cluster Y coordinate
2396    unsigned int        index;              // container index in chbuf
2397    unsigned int        vaddr;              // virtual address
2398    unsigned long long  cont_paddr;         // container physical address
2399    unsigned long long  sts_paddr;          // container status physical address
2400
2401    unsigned int        flags;              // for _v2p_translate()
2402
2403    for ( cx = 0 ; cx < xmax ; cx++ )
2404    {
2405        for ( cy = 0 ; cy < ymax ; cy++ )
2406        {
2407            // compute index in chbuf
2408            index = (cx * ymax) + cy; 
2409
2410            // allocate the kernel container
2411            vaddr = (unsigned int)_remote_malloc( NIC_CONTAINER_SIZE, cx, cy );
2412
2413            if ( vaddr == 0 )  // not enough kernel heap memory in cluster[cx,cy]
2414            {
2415                _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
2416                        "not enough kernel heap in cluster[%d,%d]\n", cx, cy );
2417
2418                return SYSCALL_OUT_OF_KERNEL_HEAP_MEMORY;
2419            }
2420
2421            // compute container physical address
2422            cont_paddr = _v2p_translate( vaddr , &flags );
2423
2424            // checking container address alignment
2425            if ( cont_paddr & 0x3F )
2426            {
2427                _printf("\n[GIET ERROR] in _sys_nic_alloc() : "
2428                        "container address in cluster[%d,%d] not aligned\n", cx, cy);
2429
2430                return SYSCALL_ADDRESS_NON_ALIGNED;
2431            }
2432
2433#if GIET_DEBUG_NIC
2434_printf("\n[DEBUG NIC] _sys_nic_alloc() at cycle %d\n"
2435        "thread %x allocates a container in cluster[%d,%d] / vaddr = %x / paddr = %l\n",
2436        -get_proctime() , trdid , cx , cy , vaddr, cont_paddr );
2437#endif
2438
2439            // allocate the kernel container status
2440            // it occupies 64 bytes but only last bit is useful (1 for full and 0 for empty)
2441            vaddr = (unsigned int)_remote_malloc( 64, cx, cy );
2442
2443            if ( vaddr == 0 )  // not enough kernel heap memory in cluster[cx,cy]
2444            {
2445                _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
2446                        "not enough kernel heap in cluster[%d,%d]\n", cx, cy );
2447
2448                return SYSCALL_OUT_OF_KERNEL_HEAP_MEMORY;
2449            }
2450
2451            // compute status physical address
2452            sts_paddr = _v2p_translate( vaddr , &flags );
2453
2454            // checking status address alignment
2455            if ( sts_paddr & 0x3F )
2456            {
2457                _printf("\n[GIET ERROR] in _sys_nic_alloc() : "
2458                        "status address in cluster[%d,%d] not aligned\n", cx, cy);
2459
2460                return SYSCALL_ADDRESS_NON_ALIGNED;
2461            }
2462
2463            // initialize chbuf entry
2464            // The buffer descriptor has the following structure:
2465            // - the 26 LSB bits contain bits[6:31] of the buffer physical address
2466            // - the 26 following bits contain bits[6:31] of the physical address where the
2467            //   buffer status is located
2468            // - the 12 MSB bits contain the common address extension of the buffer and its
2469            //   status
2470            if ( is_rx )
2471                _nic_ker_rx_chbuf[nic_channel].buf_desc[index] =
2472                    (unsigned long long)
2473                    ((sts_paddr & 0xFFFFFFFFULL) >> 6) +
2474                    (((cont_paddr & 0xFFFFFFFFFFFULL) >> 6) << 26);
2475            else
2476                _nic_ker_tx_chbuf[nic_channel].buf_desc[index] =
2477                    (unsigned long long)
2478                    ((sts_paddr & 0xFFFFFFC0ULL) >> 6) +
2479                    (((cont_paddr & 0xFFFFFFFFFC0ULL) >> 6) << 26);
2480
2481#if GIET_DEBUG_NIC
2482_printf("\n[DEBUG NIC] _sys_nic_alloc() at cycle %d\n"
2483        "thread %x allocates a status in cluster[%d,%d] / vaddr = %x / paddr = %l\n"
2484        "   descriptor = %l\n",
2485        _get_proctime() , trdid , cx , cy , vaddr, sts_paddr,
2486        (unsigned long long)((sts_paddr & 0xFFFFFFFFULL) >> 6) + 
2487        (((cont_paddr & 0xFFFFFFFFFFFULL) >> 6) << 26) );
2488#endif
2489        }
2490    }
2491
2492    // complete kernel chbuf initialisation
2493    if ( is_rx )
2494    {
2495        _nic_ker_rx_chbuf[nic_channel].xmax = xmax;
2496        _nic_ker_rx_chbuf[nic_channel].ymax = ymax;
2497    }
2498    else
2499    {
2500        _nic_ker_tx_chbuf[nic_channel].xmax = xmax;
2501        _nic_ker_tx_chbuf[nic_channel].ymax = ymax;
2502    }
2503
2504    // compute the kernel chbuf descriptor physical address
2505    if ( is_rx ) vaddr = (unsigned int)( &_nic_ker_rx_chbuf[nic_channel] );
2506    else         vaddr = (unsigned int)( &_nic_ker_tx_chbuf[nic_channel] );
2507
2508    ker_chbuf_pbase = _v2p_translate( vaddr , &flags );
2509
2510#if GIET_DEBUG_NIC
2511_printf("\n[DEBUG NIC] _sys_nic_alloc() at cycle %d\n"
2512        "thread %x initialise kernel chbuf / vaddr = %x / paddr = %l\n",
2513        _get_proctime() , trdid , vaddr , ker_chbuf_pbase );
2514#endif
2515
2516    // sync the kernel chbuf in L2 after write in L2
2517    _mmc_sync( ker_chbuf_pbase, sizeof( nic_chbuf_t ) );
2518
2519    ///////////////////////////////////////////////////////////////
2520    // Step 3: compute the NIC chbuf descriptor physical address //
2521    ///////////////////////////////////////////////////////////////
2522
2523    unsigned int offset;
2524    if ( is_rx ) offset = 0x4100;
2525    else         offset = 0x4110;
2526    nic_chbuf_pbase = (((unsigned long long)((X_IO << Y_WIDTH) + Y_IO))<<32) |
2527                      (SEG_NIC_BASE + (nic_channel<<15) + offset);
2528
2529#if GIET_DEBUG_NIC
2530_printf("\n[DEBUG NIC] _sys_nic_alloc() at cycle %d\n"
2531        "thread %x get NIC chbuf paddr = %l\n",
2532        _get_proctime() , trdid , nic_chbuf_pbase );
2533#endif
2534
2535    ////////////////////////////////////////////////////////////////////////////////
2536    // Step 4: initialize CMA registers defining the source & destination chbufs //
2537    ////////////////////////////////////////////////////////////////////////////////
2538
2539    if ( is_rx )               // NIC to kernel
2540    {
2541        _cma_set_register( cma_channel, CHBUF_SRC_DESC , (unsigned int)(nic_chbuf_pbase) );
2542        _cma_set_register( cma_channel, CHBUF_SRC_EXT  , (unsigned int)(nic_chbuf_pbase>>32) );
2543        _cma_set_register( cma_channel, CHBUF_SRC_NBUFS, 2 );
2544        _cma_set_register( cma_channel, CHBUF_DST_DESC , (unsigned int)(ker_chbuf_pbase) );
2545        _cma_set_register( cma_channel, CHBUF_DST_EXT  , (unsigned int)(ker_chbuf_pbase>>32) );
2546        _cma_set_register( cma_channel, CHBUF_DST_NBUFS, xmax * ymax );
2547    }
2548    else                      // kernel to NIC
2549    {
2550        _cma_set_register( cma_channel, CHBUF_SRC_DESC , (unsigned int)(ker_chbuf_pbase) );
2551        _cma_set_register( cma_channel, CHBUF_SRC_EXT  , (unsigned int)(ker_chbuf_pbase>>32) );
2552        _cma_set_register( cma_channel, CHBUF_SRC_NBUFS, xmax * ymax );
2553        _cma_set_register( cma_channel, CHBUF_DST_DESC , (unsigned int)(nic_chbuf_pbase) );
2554        _cma_set_register( cma_channel, CHBUF_DST_EXT  , (unsigned int)(nic_chbuf_pbase>>32) );
2555        _cma_set_register( cma_channel, CHBUF_DST_NBUFS, 2 );
2556    }
2557
2558#if GIET_DEBUG_NIC
2559_printf("\n[DEBUG NIC] _sys_nic_alloc() at cycle %d\n"
2560        "thread %x exit\n", 
2561        _get_proctime() , trdid );
2562#endif
2563
2564    return SYSCALL_OK;
2565} // end _sys_nic_alloc()
2566
2567
2568//////////////////////////////////////////
2569int _sys_nic_release( unsigned int is_rx )     // NOTE: not a syscall: used by _ctx_kill_thread()
2570{
2571    unsigned int trdid = _get_thread_trdid();
2572
2573    unsigned int nic_channel;
2574    unsigned int cma_channel;
2575   
2576    // update the kernel tables
2577    if ( is_rx )
2578    {
2579        nic_channel = _get_context_slot( CTX_NIC_RX_ID );
2580        cma_channel = _get_context_slot( CTX_CMA_RX_ID );
2581
2582        if ( (nic_channel >= NB_NIC_CHANNELS) )
2583        {
2584            _printf("\n[GIET ERROR] in _sys_nic_release() : "
2585                    "NIC_RX channel already released for thread %x\n", trdid );
2586
2587            return SYSCALL_CHANNEL_NON_ALLOCATED;
2588        }
2589        if ( (cma_channel >= NB_CMA_CHANNELS) )
2590        {
2591            _printf("\n[GIET ERROR] in _sys_nic_release() : "
2592                    "CMA_RX channel already released for thread %x\n", trdid );
2593
2594            return SYSCALL_CHANNEL_NON_ALLOCATED;
2595        }
2596
2597        // atomically decrement the NIC and CMA channel allocators
2598        _atomic_increment( &_nic_rx_channel_alloc[nic_channel] , -1 );
2599        _atomic_increment( &_cma_channel_alloc[cma_channel] , -1 );
2600   
2601        // stop the NIC and CMA peripherals channels if no more users
2602        if ( (_nic_rx_channel_alloc[nic_channel] == 0) &&
2603             (_cma_channel_alloc[cma_channel] == 0) )  _sys_nic_stop( 1 );
2604
2605        // reset the calling thread context slots
2606        _set_context_slot( CTX_NIC_RX_ID , 0xFFFFFFFF );
2607        _set_context_slot( CTX_CMA_RX_ID , 0xFFFFFFFF );
2608    }         
2609    else
2610    {
2611        nic_channel = _get_context_slot( CTX_NIC_TX_ID );
2612        cma_channel = _get_context_slot( CTX_CMA_TX_ID );
2613
2614        if ( (nic_channel >= NB_NIC_CHANNELS) )
2615        {
2616            _printf("\n[GIET ERROR] in _sys_nic_release() : "
2617                    "NIC_TX channel already released for thread %x\n", trdid );
2618
2619            return SYSCALL_CHANNEL_NON_ALLOCATED;
2620        }
2621        if ( (cma_channel >= NB_CMA_CHANNELS) )
2622        {
2623            _printf("\n[GIET ERROR] in _sys_nic_release() : "
2624                    "CMA_TX channel already released for thread %x\n", trdid );
2625
2626            return SYSCALL_CHANNEL_NON_ALLOCATED;
2627        }
2628
2629        // atomically decrement the NIC and CMA channel allocators
2630        _atomic_increment( &_nic_tx_channel_alloc[nic_channel] , -1 );
2631        _atomic_increment( &_cma_channel_alloc[cma_channel] , -1 );
2632   
2633        // stop the NIC and CMA peripherals channels if no more users
2634        if ( (_nic_tx_channel_alloc[nic_channel] == 0) &&
2635             (_cma_channel_alloc[cma_channel] == 0) )  _sys_nic_stop( 0 );
2636
2637        // reset the calling thread context slots
2638        _set_context_slot( CTX_NIC_TX_ID , 0xFFFFFFFF );
2639        _set_context_slot( CTX_CMA_TX_ID , 0xFFFFFFFF );
2640    }
2641
2642    return SYSCALL_OK;
2643}  // end sys_nic_release()
2644
2645
2646////////////////////////////////////////
2647int _sys_nic_start( unsigned int is_rx )
2648{
2649    unsigned int trdid  = _get_context_slot( CTX_TRDID_ID );
2650
2651    unsigned int nic_channel;
2652    unsigned int cma_channel;
2653
2654    // get NIC channel index and CMA channel index from thread context
2655    if ( is_rx )
2656    {
2657        nic_channel = _get_context_slot( CTX_NIC_RX_ID );
2658        cma_channel = _get_context_slot( CTX_CMA_RX_ID );
2659    }
2660    else
2661    {
2662        nic_channel = _get_context_slot( CTX_NIC_TX_ID );
2663        cma_channel = _get_context_slot( CTX_CMA_TX_ID );
2664    }
2665
2666#if GIET_DEBUG_NIC
2667_printf("\n[DEBUG NIC] _sys_nic_start() at cycle %d\n"
2668        "thread %x enter / NIC channel = %d / CMA channel = %d\n",
2669        _get_proctime() , trdid , nic_channel, cma_channel );
2670#endif
2671
2672    // check NIC and CMA channels index
2673    if ( nic_channel >= NB_NIC_CHANNELS )
2674    {
2675        _printf("\n[GIET_ERROR] in _sys_nic_start() : "
2676                "illegal NIC channel for thread %x\n", trdid );
2677        return -1111;
2678    }
2679    if ( cma_channel >= NB_CMA_CHANNELS )
2680    {
2681        _printf("\n[GIET_ERROR] in _sys_nic_start() : "
2682                "illegal CMA channel for thread %x\n", trdid );
2683        return -1111;
2684    }
2685
2686    // start CMA transfer
2687    _cma_set_register( cma_channel, CHBUF_BUF_SIZE , NIC_CONTAINER_SIZE );
2688    _cma_set_register( cma_channel, CHBUF_PERIOD   , 0 );                  // OUT_OF_ORDER
2689    _cma_set_register( cma_channel, CHBUF_RUN      , MODE_NORMAL );
2690
2691    // activates NIC channel
2692    _nic_channel_start( nic_channel, is_rx, GIET_NIC_MAC4, GIET_NIC_MAC2 );
2693
2694#if GIET_DEBUG_NIC
2695    _printf("\n[DEBUG NIC] _sys_nic_start() at cycle %d\n"
2696            "thread %d exit\n",
2697            _get_proctime() , trdid );
2698#endif
2699
2700    return SYSCALL_OK;
2701}  // end _sys_nic_start()
2702
2703
2704//////////////////////////////////////
2705int _sys_nic_move( unsigned int is_rx,
2706                   void*        buffer )
2707{
2708    unsigned int trdid  = _get_context_slot( CTX_TRDID_ID );
2709
2710    unsigned int channel;
2711
2712#if GIET_DEBUG_NIC
2713_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n",
2714        "thread %x enters\n",
2715        _get_proctime() , trdid );
2716#endif
2717
2718    // get NIC channel index from thread context
2719    if ( is_rx )  channel = _get_context_slot( CTX_NIC_RX_ID );
2720    else          channel = _get_context_slot( CTX_NIC_TX_ID );
2721
2722    // check NIC channel index
2723    if ( channel >= NB_NIC_CHANNELS )
2724    {
2725        _printf("\n[GIET_ERROR] in _sys_nic_move() : "
2726                "NIC channel non allocated for thread %x\n", trdid );
2727
2728        return SYSCALL_CHANNEL_NON_ALLOCATED;
2729    }
2730
2731    // get kernel chbuf virtual address
2732    nic_chbuf_t* ker_chbuf;
2733    if ( is_rx )  ker_chbuf = &_nic_ker_rx_chbuf[channel];
2734    else          ker_chbuf = &_nic_ker_tx_chbuf[channel];
2735
2736    // get xmax / ymax parameters
2737    unsigned int xmax = ker_chbuf->xmax;
2738    unsigned int ymax = ker_chbuf->ymax;
2739
2740    // get cluster coordinates for the processor running the calling thread
2741    unsigned int  procid = _get_procid();
2742    unsigned int  cx     = procid >> (Y_WIDTH + P_WIDTH);
2743    unsigned int  cy     = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
2744   
2745    // check processor coordinates / (xmax,ymax)
2746    if ( (cx >= xmax) || (cy >= ymax) )
2747    {
2748        _printf("\n[GIET_ERROR] in _sys_nic_move(): "
2749         "processor coordinates [%d,%d] larger than (xmax,ymax) = [%d,%d]\n",
2750         cx , cy , xmax , ymax );
2751
2752        return SYSCALL_ILLEGAL_ARGUMENT;
2753    }
2754   
2755    unsigned long long usr_buf_paddr;       // user buffer physical address
2756    unsigned long long ker_buf_paddr;       // kernel buffer physical address
2757    unsigned long long ker_sts_paddr;       // kernel buffer status physical address
2758    unsigned long long ker_buf_desc;        // kernel buffer descriptor
2759    unsigned int       ker_sts;             // kernel buffer status (full or empty)
2760    unsigned int       index;               // kernel buffer index in chbuf
2761    unsigned int       flags;               // for _v2P_translate
2762
2763    // Compute user buffer physical address and check access rights
2764    usr_buf_paddr = _v2p_translate( (unsigned int)buffer , &flags );
2765
2766    if ( (flags & PTE_U) == 0 )
2767    {
2768        _printf("\n[GIET ERROR] in _sys_nic_tx_move() : "
2769                "buffer address non user accessible\n");
2770
2771        return SYSCALL_ADDRESS_NON_USER_ACCESSIBLE;
2772    }
2773
2774#if GIET_DEBUG_NIC
2775_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2776        "thread %x get user buffer : paddr = %l\n",
2777        _get_proctime() , trdid , usr_buf_paddr );
2778#endif
2779
2780    // compute buffer index, buffer descriptor paddr and buffer status paddr
2781    index = (ymax * cx) + cy;
2782    ker_buf_desc = ker_chbuf->buf_desc[index];
2783    ker_sts_paddr = ((ker_buf_desc & 0xFFF0000000000000ULL) >> 20) +
2784                    ((ker_buf_desc & 0x3FFFFFFULL) << 6);
2785
2786#if GIET_DEBUG_NIC
2787_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2788        "thread %x get ker_buf_desc %d / paddr = %l\n",
2789        _get_proctime(), trdid , index , ker_buf_desc );
2790#endif
2791
2792    // poll local kernel container status until success
2793    while ( 1 )
2794    {
2795        // inval buffer descriptor in L2 before read in L2
2796        _mmc_inval( ker_sts_paddr, 4 );
2797        ker_sts = _physical_read( ker_sts_paddr );
2798
2799#if GIET_DEBUG_NIC
2800_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2801        "thread %x get status %d /  paddr = %l / status = %x\n",
2802        _get_proctime() , trdid , index , ker_sts_paddr, ker_sts );
2803#endif
2804
2805        // test buffer status and break if found
2806        if ( ( is_rx != 0 ) && ( ker_sts == 0x1 ) ) break;
2807        if ( ( is_rx == 0 ) && ( ker_sts == 0 ) ) break;
2808    }
2809
2810    // compute kernel buffer physical address
2811    ker_buf_paddr = (ker_buf_desc & 0xFFFFFFFFFC000000ULL) >> 20;
2812   
2813    // move one container
2814    if ( is_rx )              // RX transfer
2815    {
2816        // inval kernel buffer in L2 before read in L2
2817        _mmc_inval( ker_buf_paddr, NIC_CONTAINER_SIZE );
2818
2819        // transfer data from kernel buffer to user buffer
2820        _physical_memcpy( usr_buf_paddr, 
2821                          ker_buf_paddr, 
2822                          NIC_CONTAINER_SIZE );
2823#if GIET_DEBUG_NIC
2824_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2825        "thread %x transfer kernel buffer %l to user buffer %l\n",
2826        _get_proctime() , trdid , ker_buf_paddr , usr_buf_paddr );
2827#endif
2828
2829    }
2830    else                      // TX transfer
2831    {
2832        // transfer data from user buffer to kernel buffer
2833        _physical_memcpy( ker_buf_paddr, 
2834                          usr_buf_paddr, 
2835                          NIC_CONTAINER_SIZE );
2836
2837        // sync kernel buffer in L2 after write in L2
2838        _mmc_sync( ker_buf_paddr, NIC_CONTAINER_SIZE );
2839
2840#if GIET_DEBUG_NIC
2841_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2842        "thread %x transfer user buffer %l to kernel buffer %l\n",
2843        _get_proctime() , trdid , usr_buf_paddr , ker_buf_paddr );
2844#endif
2845
2846    }
2847
2848    // update kernel chbuf status
2849    if ( is_rx ) _physical_write ( ker_sts_paddr, 0 );
2850    else         _physical_write ( ker_sts_paddr, 0x1 );
2851
2852    // sync kernel chbuf in L2 after write in L2
2853    _mmc_sync( ker_sts_paddr, 4 );
2854
2855#if GIET_DEBUG_NIC
2856_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2857        "thread %x exit\n",
2858        _get_proctime() , trdid );
2859#endif
2860
2861    return SYSCALL_OK;
2862} // end _sys_nic_move()
2863
2864
2865///////////////////////////////////////
2866int _sys_nic_stop( unsigned int is_rx )
2867{
2868    unsigned int trdid  = _get_context_slot( CTX_TRDID_ID );
2869
2870    unsigned int nic_channel;
2871    unsigned int cma_channel;
2872
2873    // get NIC channel index and CMA channel index
2874    if ( is_rx )
2875    {
2876        nic_channel = _get_context_slot( CTX_NIC_RX_ID );
2877        cma_channel = _get_context_slot( CTX_CMA_RX_ID );
2878    }
2879    else
2880    {
2881        nic_channel = _get_context_slot( CTX_NIC_TX_ID );
2882        cma_channel = _get_context_slot( CTX_CMA_TX_ID );
2883    }
2884
2885    // check NIC and CMA channels index
2886    if ( nic_channel >= NB_NIC_CHANNELS )
2887    {
2888        _printf("\n[GIET_ERROR] in _sys_nic_stop() : " 
2889                "NIC channel non allocated for thread %x\n", trdid );
2890
2891        return SYSCALL_CHANNEL_NON_ALLOCATED;
2892    }
2893    if ( cma_channel >= NB_CMA_CHANNELS )
2894    {
2895        _printf("\n[GIET_ERROR] in _sys_nic_stop() : "
2896                "CMA channel non allocated for thread %x\n", trdid );
2897 
2898        return SYSCALL_CHANNEL_NON_ALLOCATED;
2899    }
2900
2901    // desactivates the CMA channel
2902    _cma_set_register( cma_channel, CHBUF_RUN , MODE_IDLE );
2903
2904    // wait until CMA channel IDLE
2905    unsigned int volatile status;
2906    do
2907    {
2908         status = _cma_get_register( cma_channel, CHBUF_STATUS );
2909    } 
2910    while ( status ); 
2911
2912    // desactivates the NIC channel
2913    _nic_channel_stop( nic_channel, is_rx );
2914
2915    return SYSCALL_OK;
2916}  // end _sys_nic_stop()
2917
2918////////////////////////////////////////
2919int _sys_nic_clear( unsigned int is_rx )
2920{
2921    unsigned int trdid  = _get_context_slot( CTX_TRDID_ID );
2922
2923    unsigned int channel;
2924
2925    // get NIC channel
2926    if ( is_rx )  channel = _get_context_slot( CTX_NIC_RX_ID );
2927    else          channel = _get_context_slot( CTX_NIC_TX_ID );
2928
2929    if ( channel >= NB_NIC_CHANNELS )
2930    {
2931        _printf("\n[GIET_ERROR] in _sys_nic_clear() : "
2932                "NIC channel non allocated for thread %x\n", trdid );
2933
2934        return SYSCALL_CHANNEL_NON_ALLOCATED;
2935    }
2936
2937    if ( is_rx )
2938    {
2939        _nic_set_global_register( NIC_G_NPKT_RX_G2S_RECEIVED       , 0 );
2940        _nic_set_global_register( NIC_G_NPKT_RX_DES_TOO_SMALL      , 0 );
2941        _nic_set_global_register( NIC_G_NPKT_RX_DES_TOO_BIG        , 0 );
2942        _nic_set_global_register( NIC_G_NPKT_RX_DES_MFIFO_FULL     , 0 );
2943        _nic_set_global_register( NIC_G_NPKT_RX_DES_CRC_FAIL       , 0 );
2944        _nic_set_global_register( NIC_G_NPKT_RX_DISPATCH_RECEIVED  , 0 );
2945        _nic_set_global_register( NIC_G_NPKT_RX_DISPATCH_BROADCAST , 0 );
2946        _nic_set_global_register( NIC_G_NPKT_RX_DISPATCH_DST_FAIL  , 0 );
2947        _nic_set_global_register( NIC_G_NPKT_RX_DISPATCH_CH_FULL   , 0 );
2948    } 
2949    else
2950    {
2951        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_RECEIVED  , 0 );
2952        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_TRANSMIT  , 0 );
2953        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_TOO_BIG   , 0 );
2954        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_TOO_SMALL , 0 );
2955        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_SRC_FAIL  , 0 );
2956        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_BYPASS    , 0 );
2957        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_BROADCAST , 0 );
2958    }
2959    return SYSCALL_OK;
2960}  // en _sys_nic_clear()
2961
2962////////////////////////////////////////
2963int _sys_nic_stats( unsigned int is_rx )
2964{
2965    unsigned int trdid  = _get_context_slot( CTX_TRDID_ID );
2966
2967    unsigned int nic_channel;
2968
2969    // get NIC channel
2970    if ( is_rx )  nic_channel = _get_context_slot( CTX_NIC_RX_ID );
2971    else          nic_channel = _get_context_slot( CTX_NIC_TX_ID );
2972
2973    if ( nic_channel >= NB_NIC_CHANNELS )
2974    {
2975        _printf("\n[GIET_ERROR] in _sys_nic_stats() : "
2976                "NIC channel non allocated for thread %x\n", trdid );
2977
2978        return SYSCALL_CHANNEL_NON_ALLOCATED;
2979    }
2980
2981    if ( is_rx )
2982    {
2983        unsigned int received   = _nic_get_global_register( NIC_G_NPKT_RX_G2S_RECEIVED       );
2984        unsigned int too_small  = _nic_get_global_register( NIC_G_NPKT_RX_DES_TOO_SMALL      );
2985        unsigned int too_big    = _nic_get_global_register( NIC_G_NPKT_RX_DES_TOO_BIG        );
2986        unsigned int fifo_full  = _nic_get_global_register( NIC_G_NPKT_RX_DES_MFIFO_FULL     );
2987        unsigned int crc_fail   = _nic_get_global_register( NIC_G_NPKT_RX_DES_CRC_FAIL       );
2988        unsigned int broadcast  = _nic_get_global_register( NIC_G_NPKT_RX_DISPATCH_BROADCAST );
2989        unsigned int dst_fail   = _nic_get_global_register( NIC_G_NPKT_RX_DISPATCH_DST_FAIL  );
2990        unsigned int ch_full    = _nic_get_global_register( NIC_G_NPKT_RX_DISPATCH_CH_FULL   );
2991
2992        _printf("\n### Network Controller RX Statistics ###\n"
2993                "- packets received : %d\n"
2994                "- too small        : %d\n"
2995                "- too big          : %d\n"
2996                "- fifo full        : %d\n" 
2997                "- crc fail         : %d\n" 
2998                "- dst mac fail     : %d\n" 
2999                "- channel full     : %d\n" 
3000                "- broadcast        : %d\n",
3001                received,
3002                too_small,
3003                too_big,
3004                fifo_full,
3005                crc_fail,
3006                dst_fail,
3007                ch_full,
3008                broadcast );
3009    } 
3010    else
3011    {
3012        unsigned int received   = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_RECEIVED  );
3013        unsigned int too_big    = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_TOO_BIG   );
3014        unsigned int too_small  = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_TOO_SMALL );
3015        unsigned int src_fail   = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_SRC_FAIL  );
3016        unsigned int bypass     = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_BYPASS    );
3017        unsigned int broadcast  = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_BROADCAST );
3018
3019        _printf("\n### Network Controller TX Statistics ###\n"
3020                "- packets received : %d\n"
3021                "- too small        : %d\n"
3022                "- too big          : %d\n"
3023                "- src mac fail     : %d\n" 
3024                "- bypass           : %d\n" 
3025                "- broadcast        : %d\n",
3026                received,
3027                too_big,
3028                too_small,
3029                src_fail,
3030                bypass,
3031                broadcast );
3032    }
3033    return SYSCALL_OK;
3034}  // end _sys_nic_stats()
3035
3036#endif // if NB_NIC_CHANNELS && NB_CMA_CHANNELS
3037
3038/////////////////////////////////////////////////////////////////////////////////////////
3039//    FBF related syscall handlers
3040/////////////////////////////////////////////////////////////////////////////////////////
3041
3042//////////////////////////////////////
3043int _sys_fbf_size( unsigned int* width,
3044                   unsigned int* height )
3045{
3046    if ( USE_FBF == 0 )
3047    {
3048        *width  = 0;
3049        *height = 0;
3050    }
3051    else
3052    {
3053        *width  = FBUF_X_SIZE;
3054        *height = FBUF_Y_SIZE;
3055    }
3056
3057    return SYSCALL_OK;
3058}
3059
3060////////////////////
3061int _sys_fbf_alloc()
3062{
3063    mapping_header_t  *header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
3064    mapping_vspace_t  *vspace   = _get_vspace_base(header);
3065    mapping_thread_t  *thread   = _get_thread_base(header);
3066   
3067    // compute number of users
3068    unsigned int   vsid  = _get_context_slot(CTX_VSID_ID);
3069    unsigned int   users = vspace[vsid].threads;
3070
3071    // access FBF allocator
3072    // register it in all threads contexts
3073    if ( _atomic_test_and_set( &_fbf_alloc , users ) == 0 )     // FBF available   
3074    {
3075        unsigned int   min   = vspace[vsid].thread_offset;
3076        unsigned int   max   = min + users;
3077        unsigned int   tid;
3078        for ( tid = min ; tid < max ; tid++ )
3079        {
3080            unsigned int y_size        = header->y_size;
3081            unsigned int cid           = thread[tid].clusterid;
3082            unsigned int x             = cid / y_size;
3083            unsigned int y             = cid % y_size;
3084            unsigned int p             = thread[tid].proclocid;
3085            unsigned int ltid          = thread[tid].ltid;
3086            static_scheduler_t* psched = (static_scheduler_t*)_schedulers[x][y][p];
3087            _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FBF ); 
3088        }
3089        return SYSCALL_OK;
3090    }
3091    else                                                       // FBF already allocated
3092    {
3093        return SYSCALL_SHARED_PERIPHERAL_BUSY;
3094    }
3095}
3096
3097//////////////////////
3098int _sys_fbf_release()    // not a syscall: used by _ctx_kill_thread()
3099{
3100    // get calling thread scheduler, ltid and trdid
3101    static_scheduler_t*  psched = _get_sched();
3102    unsigned int         ltid   = _get_thread_ltid();
3103    unsigned int         trdid  = _get_thread_trdid();
3104
3105    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
3106    {
3107        _printf("\n[GIET ERROR] in _sys_fbf_release() : "
3108                "FBF not allocated to thread %x\n", trdid );
3109
3110        return SYSCALL_CHANNEL_NON_ALLOCATED;
3111    }
3112
3113    // decrement FBF allocator
3114    // reset the calling thread context
3115    _atomic_increment( &_fbf_alloc , 0xFFFFFFFF );
3116    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FBF ); 
3117
3118    return SYSCALL_OK;   
3119}
3120
3121/////////////////////////////////////////////
3122int _sys_fbf_sync_write( unsigned int offset,
3123                         void*        buffer,
3124                         unsigned int length )
3125{
3126    // get calling thread scheduler, ltid and trdid
3127    static_scheduler_t*  psched = _get_sched();
3128    unsigned int         ltid   = _get_thread_ltid();
3129    unsigned int         trdid  = _get_thread_trdid();
3130
3131    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
3132    {
3133        _printf("\n[GIET ERROR] in _sys_fbf_release() : "
3134                "FBF not allocated to thread %x\n", trdid );
3135
3136        return SYSCALL_CHANNEL_NON_ALLOCATED;
3137    }
3138
3139    char* fbf_address = (char *)SEG_FBF_BASE + offset;
3140    memcpy( fbf_address, buffer, length);
3141
3142    return SYSCALL_OK;
3143}
3144
3145/////////////////////////////////////////////
3146int _sys_fbf_sync_read(  unsigned int offset,
3147                         void*        buffer,
3148                         unsigned int length )
3149{
3150    // get calling thread scheduler, ltid and trdid
3151    static_scheduler_t*  psched = _get_sched();
3152    unsigned int         ltid   = _get_thread_ltid();
3153    unsigned int         trdid  = _get_thread_trdid();
3154
3155    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
3156    {
3157        _printf("\n[GIET ERROR] in _sys_fbf_release() : "
3158                "FBF not allocated to thread %x\n", trdid );
3159
3160        return SYSCALL_CHANNEL_NON_ALLOCATED;
3161    }
3162
3163    char* fbf_address = (char *)SEG_FBF_BASE + offset;
3164    memcpy( buffer, fbf_address, length);
3165
3166    return SYSCALL_OK;
3167}
3168
3169#if NB_CMA_CHANNELS
3170
3171////////////////////////////////////////////
3172int _sys_fbf_cma_alloc( unsigned int nbufs )
3173{
3174    // compute trdid and vsid for the calling thread
3175    unsigned int vsid  = _get_context_slot( CTX_VSID_ID );
3176    unsigned int trdid = _get_thread_trdid();
3177
3178    if ( _get_context_slot( CTX_CMA_FB_ID ) < NB_CMA_CHANNELS )
3179    {
3180        _printf("\n[GIET ERROR] in _sys_fbf_cma_alloc() : "
3181                "CMA channel already allocated for thread %x\n", trdid );
3182        return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
3183    }
3184
3185    // compute number of threads in vspace from mapping
3186    mapping_header_t  *header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
3187    mapping_vspace_t  *vspace   = _get_vspace_base(header);
3188    mapping_thread_t  *thread   = _get_thread_base(header);
3189    unsigned int      first     = vspace[vsid].thread_offset;
3190    unsigned int      threads   = vspace[vsid].threads;
3191
3192    // get a CMA channel
3193    unsigned int channel;
3194    for ( channel = 0 ; channel < NB_CMA_CHANNELS ; channel++ )
3195    {
3196        unsigned int*  palloc = &_cma_channel_alloc[channel];
3197        if ( _atomic_test_and_set( palloc , threads ) == 0 ) break;
3198    }
3199
3200    if ( channel >= NB_CMA_CHANNELS )
3201    {
3202        _printf("\n[GIET ERROR] in _sys_fbf_cma_alloc() : no CMA channel available\n");
3203        return SYSCALL_NO_CHANNEL_AVAILABLE;
3204    }
3205
3206    // check nbufs argument
3207    if ( nbufs > 256 )
3208    {
3209        _printf("\n[GIET ERROR] in _sys_fbf_cma_alloc() : nbufs larger than 256\n");
3210        return SYSCALL_ILLEGAL_ARGUMENT;
3211    }
3212
3213    // loop on all threads to register channel in thread contexts
3214    unsigned int      tid;
3215    for ( tid = first ; tid < (first + threads) ; tid++ )
3216    {
3217        unsigned int         y_size = header->y_size;
3218        unsigned int         cid    = thread[tid].clusterid;
3219        unsigned int         x      = cid / y_size;
3220        unsigned int         y      = cid % y_size;
3221        unsigned int         p      = thread[tid].proclocid;
3222        unsigned int         ltid   = thread[tid].ltid;
3223        static_scheduler_t* psched  = (static_scheduler_t*)_schedulers[x][y][p];
3224        psched->context[ltid].slot[CTX_CMA_FB_ID] = channel; 
3225    }
3226
3227    unsigned int vaddr;
3228    unsigned int flags;
3229
3230    // compute frame buffer physical addresses
3231    vaddr = (unsigned int)SEG_FBF_BASE;
3232    unsigned long long fbf_buf_paddr = _v2p_translate( vaddr , &flags );
3233
3234    // initialize the FBF chbuf
3235    // we don't register a status address in the fbf_desc, because
3236    // the CMA does not test the status for the frame buffer (no synchro)
3237    _fbf_ker_chbuf.nbufs    = nbufs;
3238    _fbf_ker_chbuf.fbf_desc = (((fbf_buf_paddr & 0xFFFFFFFFFFFULL) >> 6 ) << 26);
3239
3240    // register FBF chbuf physical address
3241    vaddr = (unsigned int)(&_fbf_ker_chbuf);
3242    _fbf_chbuf_paddr = _v2p_translate( vaddr , &flags );
3243
3244#if GIET_DEBUG_FBF_CMA
3245_printf("\n[FBF_CMA DEBUG] _sys_fbf_cma_alloc()\n"
3246        " - channel               = %d\n"
3247        " - vaddr(_ker_fbf_chbuf) = %x\n"
3248        " - paddr(_ker_fbf_chbuf) = %l\n"
3249        " - nbufs                 = %d\n" 
3250        " - fbf_desc              = %l\n",
3251        channel , vaddr , _fbf_chbuf_paddr , nbufs , _fbf_ker_chbuf.fbf_desc );
3252#endif
3253
3254    return SYSCALL_OK;
3255} // end sys_fbf_cma_alloc()
3256
3257//////////////////////////
3258int _sys_fbf_cma_release()  // Not a syscall : used by _ctx_kill_thread()
3259{
3260    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
3261    unsigned int trdid   = _get_thread_trdid();
3262
3263    if ( channel >= NB_CMA_CHANNELS )
3264    {
3265        _printf("\n[GIET_ERROR] in _sys_fbf_cma_release() : "
3266                "CMA_FB channel already released for thread %x\n", trdid );
3267
3268        return SYSCALL_CHANNEL_NON_ALLOCATED;
3269    }
3270
3271    if ( _cma_channel_alloc[channel] == 1 )  // the calling thread is the last user
3272    {
3273        // stop the CMA transfer
3274        _sys_fbf_cma_stop();
3275
3276        // reset the CMA channel allocator
3277        _cma_channel_alloc[channel] = 0;
3278    }
3279    else                                     // not the last user
3280    {
3281        // atomically decrement the CMA channel allocator
3282        _atomic_increment( &_cma_channel_alloc[channel] , -1 );
3283    }
3284
3285    // reset CTX_CMA_FB_ID slot in calling thread context
3286    _set_context_slot( CTX_CMA_FB_ID, 0xFFFFFFFF );
3287
3288    return SYSCALL_OK;
3289} // end _sys_fbf_cma_release()
3290
3291///////////////////////////////////////////////////
3292int _sys_fbf_cma_init_buf( unsigned int index,
3293                           void*        buf_vaddr, 
3294                           void*        sts_vaddr )
3295{
3296    unsigned int       vaddr;           // virtual address
3297    unsigned int       flags;           // for _v2p_translate()
3298    unsigned long long buf_paddr;       // user buffer physical address
3299    unsigned long long sts_paddr;       // user status physical address
3300
3301    // get calling thread scheduler, ltid and trdid
3302    static_scheduler_t*  psched = _get_sched();
3303    unsigned int         ltid   = _get_thread_ltid();
3304    unsigned int         trdid  = _get_thread_trdid();
3305
3306    // check FBF allocated
3307    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
3308    {
3309        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
3310                "FBF not allocated to thread %x\n", trdid );
3311
3312        return SYSCALL_CHANNEL_NON_ALLOCATED;
3313    }
3314
3315    // get channel index
3316    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
3317
3318    if ( channel >= NB_CMA_CHANNELS )
3319    {
3320        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
3321                "CMA channel non allocated to thread %x\n", trdid );
3322
3323        return SYSCALL_CHANNEL_NON_ALLOCATED;
3324    }
3325
3326#if GIET_DEBUG_FBF_CMA
3327_printf("\n[FBF_CMA DEBUG] _sys_fbf_cma_init_buf()\n"
3328        " - channel     = %d / index = %d\n"
3329        " - buf vaddr   = %x\n"
3330        " - sts vaddr   = %x\n",
3331        channel, index,
3332        (unsigned int)buf_vaddr,
3333        (unsigned int)sts_vaddr );
3334#endif
3335
3336    // checking index argument
3337    if ( index >= _fbf_ker_chbuf.nbufs )
3338    {
3339        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
3340                "user buffer index too large %x\n", trdid );
3341
3342        return SYSCALL_CHANNEL_NON_ALLOCATED;
3343    }
3344
3345    // checking user buffer and status addresses alignment
3346    if ( ((unsigned int)buf_vaddr & 0x3F) || ((unsigned int)sts_vaddr & 0x3F) )
3347    {
3348        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
3349                "user buffer or status not aligned for thread %x\n", trdid );
3350
3351        return SYSCALL_ADDRESS_NON_ALIGNED;
3352    }
3353
3354    // Compute user buffer and status physical addresses
3355    vaddr = (unsigned int)buf_vaddr;
3356    buf_paddr = _v2p_translate( vaddr , &flags );
3357    if ((flags & PTE_U) == 0) 
3358    {
3359        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
3360                "buffer not in user space for thread %x\n", trdid );
3361
3362        return SYSCALL_ADDRESS_NON_USER_ACCESSIBLE;
3363    }
3364
3365    vaddr = (unsigned int)sts_vaddr;
3366    sts_paddr = _v2p_translate( vaddr , &flags );
3367    if ((flags & PTE_U) == 0) 
3368    {
3369        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
3370                "status not in user space for thread %x\n", trdid);
3371
3372        return SYSCALL_ADDRESS_NON_USER_ACCESSIBLE;
3373    }
3374
3375    // check user buffer and user status in same cluster
3376    if ( (buf_paddr & 0xFF00000000ULL) != (sts_paddr & 0xFF00000000ULL) ) 
3377    {
3378        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
3379                "user status and buffer not in same cluster for thread %x\n", trdid);
3380
3381        return SYSCALL_ADDRESS_NON_USER_ACCESSIBLE;
3382    }
3383
3384    // initialize _fbf_ker_chbuf.usr_desc[index]
3385    _fbf_ker_chbuf.usr_desc[index] = ((sts_paddr & 0xFFFFFFFFULL) >> 6) +
3386                                     (((buf_paddr & 0xFFFFFFFFFFULL) >> 6 ) << 26);
3387
3388#if GIET_DEBUG_FBF_CMA
3389_printf(" - buf paddr   = %l\n"
3390        " - sts paddr   = %l\n"
3391        " - usr_desc[%d] = %l\n",
3392        buf_paddr,
3393        sts_paddr,
3394        index , _fbf_ker_chbuf.usr_desc[index] );
3395#endif
3396
3397    return SYSCALL_OK;
3398
3399} // end sys_fbf_cma_init_buf()
3400
3401////////////////////////
3402int _sys_fbf_cma_start() 
3403{
3404    // get calling thread scheduler, ltid and trdid
3405    static_scheduler_t*  psched = _get_sched();
3406    unsigned int         ltid   = _get_thread_ltid();
3407    unsigned int         trdid  = _get_thread_trdid();
3408
3409    // check FBF allocated
3410    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
3411    {
3412        _printf("\n[GIET ERROR] in _sys_fbf_release() : "
3413                "FBF not allocated to thread %x\n", trdid );
3414
3415        return SYSCALL_CHANNEL_NON_ALLOCATED;
3416    }
3417
3418    // get CMA channel index
3419    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
3420
3421    if ( channel >= NB_CMA_CHANNELS )
3422    {
3423        _printf("\n[GIET ERROR] in _fbf_cma_start() : "
3424                "CMA channel non allocated\n");
3425
3426        return SYSCALL_CHANNEL_NON_ALLOCATED;
3427    }
3428
3429    // check buffers initialization
3430    if ( _fbf_ker_chbuf.nbufs == 0 )
3431    {
3432        _printf("\n[GIET ERROR] in _sys_fbf_cma_start(): "
3433                "FBF chbuf not initialized for thread %x\n", trdid );
3434
3435        return SYSCALL_MISSING_INITIALISATION;
3436    }
3437
3438    // synchronize FBF chbuf that will be read by CMA peripheral
3439    if ( USE_IOB )
3440    {
3441        // SYNC request for fbf_chbuf descriptor
3442        _mmc_sync( _fbf_chbuf_paddr , sizeof( fbf_chbuf_t ) );
3443    }
3444
3445    // start CMA transfer
3446    unsigned long long paddr = _fbf_chbuf_paddr;
3447    unsigned int dst_chbuf_paddr_lsb = (unsigned int)(paddr & 0xFFFFFFFF);
3448    unsigned int dst_chbuf_paddr_ext = (unsigned int)(paddr >> 32);
3449    unsigned int src_chbuf_paddr_lsb = dst_chbuf_paddr_lsb + 8;
3450    unsigned int src_chbuf_paddr_ext = dst_chbuf_paddr_ext;
3451
3452#if GIET_DEBUG_FBF_CMA
3453_printf("\n[FBF_CMA DEBUG] _sys_fbf_cma_start()\n"
3454        " - src_chbuf_paddr_lsb = %x\n"
3455        " - src_chbuf_paddr_ext = %x\n"
3456        " - src_chbuf_nbufs     = %d\n"
3457        " - dst_chbuf_paddr_lsb = %x\n"
3458        " - dst_chbuf_paddr_ext = %x\n"
3459        " - dst_chbuf_nbufs     = 1 \n"
3460        " - buffer_size         = %d\n",
3461        src_chbuf_paddr_lsb,
3462        src_chbuf_paddr_ext,
3463        _fbf_ker_chbuf.nbufs,
3464        dst_chbuf_paddr_lsb,
3465        dst_chbuf_paddr_ext,
3466        FBUF_X_SIZE * FBUF_Y_SIZE );
3467#endif
3468
3469    _cma_set_register( channel, CHBUF_SRC_DESC , src_chbuf_paddr_lsb );
3470    _cma_set_register( channel, CHBUF_SRC_EXT  , src_chbuf_paddr_ext );
3471    _cma_set_register( channel, CHBUF_SRC_NBUFS, _fbf_ker_chbuf.nbufs );
3472    _cma_set_register( channel, CHBUF_DST_DESC , dst_chbuf_paddr_lsb );
3473    _cma_set_register( channel, CHBUF_DST_EXT  , dst_chbuf_paddr_ext );
3474    _cma_set_register( channel, CHBUF_DST_NBUFS, 1 );
3475    _cma_set_register( channel, CHBUF_BUF_SIZE , FBUF_X_SIZE*FBUF_Y_SIZE );
3476    _cma_set_register( channel, CHBUF_PERIOD   , 1000 );
3477    _cma_set_register( channel, CHBUF_RUN      , MODE_NO_DST_SYNC );
3478
3479    return SYSCALL_OK;
3480
3481} // end _sys_fbf_cma_start()
3482
3483////////////////////////////////////////////
3484int _sys_fbf_cma_check( unsigned int index )
3485{
3486    // get calling thread scheduler, ltid and trdid
3487    static_scheduler_t*  psched = _get_sched();
3488    unsigned int         ltid   = _get_thread_ltid();
3489    unsigned int         trdid  = _get_thread_trdid();
3490
3491    // check FBF allocated
3492    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
3493    {
3494        _printf("\n[GIET ERROR] in _sys_fbf_cma_check() : "
3495                "FBF not allocated to thread %x\n", trdid );
3496
3497        return SYSCALL_CHANNEL_NON_ALLOCATED;
3498    }
3499
3500    // get channel index
3501    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
3502
3503    if ( channel >= NB_CMA_CHANNELS )
3504    {
3505        _printf("\n[GIET ERROR] in _sys_fbf_cma_check() : "
3506                "CMA channel non allocated to thread %x\n", trdid );
3507
3508        return SYSCALL_CHANNEL_NON_ALLOCATED;
3509    }
3510
3511    // check buffer index
3512    if ( index >= _fbf_ker_chbuf.nbufs )
3513    {
3514        _printf("\n[GIET ERROR] in _sys_fbf_cma_check() : "
3515                "buffer index too large for thread %x\n", trdid );
3516
3517        return SYSCALL_CHANNEL_NON_ALLOCATED;
3518    }
3519
3520    // compute user buffer status physical addresses
3521    unsigned long long usr_sts_paddr;
3522    fbf_chbuf_t* pdesc = &_fbf_ker_chbuf;     
3523    usr_sts_paddr = ((pdesc->usr_desc[index] & 0xFFF0000000000000ULL) >> 20) + 
3524                    ((pdesc->usr_desc[index] & 0x3FFFFFFULL) << 6);         
3525
3526#if GIET_DEBUG_FBF_CMA
3527_printf("\n[FBF_CMA DEBUG] enters _sys_fbf_cma_check()\n"
3528        " - cma channel      = %d\n"
3529        " - buffer index     = %d\n"
3530        " - usr_desc value   = %l\n"
3531        " - fbf_desc value   = %l\n"
3532        " - usr status paddr = %l\n",
3533        channel,
3534        index,
3535        _fbf_ker_chbuf.usr_desc[index],
3536        _fbf_ker_chbuf.fbf_desc,
3537        usr_sts_paddr );
3538#endif
3539
3540    // waiting user buffer released by the CMA component)
3541    unsigned int full;
3542    do
3543    { 
3544        // INVAL L2 cache copy of user buffer status     
3545        // because it is modified in RAM by the CMA component
3546        _mmc_inval( usr_sts_paddr , 4 );       
3547
3548        full = _physical_read( usr_sts_paddr );
3549    }
3550    while ( full );
3551
3552    return SYSCALL_OK;
3553
3554}  // end _sys_fbf_cma_check()
3555
3556//////////////////////////////////////////////
3557int _sys_fbf_cma_display( unsigned int index )
3558{
3559    // get calling thread scheduler, ltid and trdid
3560    static_scheduler_t*  psched = _get_sched();
3561    unsigned int         ltid   = _get_thread_ltid();
3562    unsigned int         trdid  = _get_thread_trdid();
3563
3564    // check FBF allocated
3565    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
3566    {
3567        _printf("\n[GIET ERROR] in _sys_fbf_cma_display() : "
3568                "FBF not allocated to thread %x\n", trdid );
3569
3570        return SYSCALL_CHANNEL_NON_ALLOCATED;
3571    }
3572
3573    // get channel index
3574    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
3575
3576    if ( channel >= NB_CMA_CHANNELS )
3577    {
3578        _printf("\n[GIET ERROR] in _sys_fbf_cma_display() : "
3579                "CMA channel non allocated to thread %x\n", trdid );
3580
3581        return SYSCALL_CHANNEL_NON_ALLOCATED;
3582    }
3583
3584    // check buffer index
3585    if ( index >= _fbf_ker_chbuf.nbufs )
3586    {
3587        _printf("\n[GIET ERROR] in _sys_fbf_cma_display() : "
3588                "buffer index too large for thread %x\n", trdid );
3589
3590        return SYSCALL_CHANNEL_NON_ALLOCATED;
3591    }
3592
3593    // compute user buffer and status physical addresses
3594    unsigned long long usr_sts_paddr;
3595    unsigned long long usr_buf_paddr;
3596
3597    fbf_chbuf_t* pdesc = &_fbf_ker_chbuf;     
3598
3599    usr_sts_paddr = ((pdesc->usr_desc[index] & 0xFFF0000000000000ULL) >> 20) + 
3600                    ((pdesc->usr_desc[index] & 0x3FFFFFFULL) << 6);         
3601
3602    usr_buf_paddr = ((pdesc->usr_desc[index] & 0xFFFFFFFFFC000000ULL) >> 20); 
3603
3604#if GIET_DEBUG_FBF_CMA
3605_printf("\n[FBF_CMA DEBUG] enters _sys_fbf_cma_display()\n"
3606        " - cma channel      = %d\n"
3607        " - buffer index     = %d\n"
3608        " - usr buffer paddr = %l\n"
3609        " - usr status paddr = %l\n",
3610        channel,
3611        index,
3612        usr_buf_paddr, 
3613        usr_sts_paddr ); 
3614#endif
3615       
3616    // SYNC request, because this buffer will be read from XRAM by the CMA component
3617    _mmc_sync( usr_buf_paddr , FBUF_X_SIZE * FBUF_Y_SIZE );
3618
3619    // set user buffer status
3620    _physical_write( usr_sts_paddr, 0x1 );
3621
3622    // SYNC request, because this status will be read from XRAM by the CMA component
3623    _mmc_sync( usr_sts_paddr, 4 );
3624
3625    return SYSCALL_OK;
3626
3627} // end _sys_fbf_cma_display()
3628
3629///////////////////////
3630int _sys_fbf_cma_stop()
3631{
3632    // get channel index
3633    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
3634
3635    if ( channel >= NB_CMA_CHANNELS )
3636    {
3637        _printf("\n[GIET ERROR] in _sys_fbf_cma_stop() : CMA channel non allocated\n");
3638
3639        return SYSCALL_CHANNEL_NON_ALLOCATED;
3640    }
3641
3642    // Desactivate CMA channel
3643    _cma_set_register( channel, CHBUF_RUN, MODE_IDLE );
3644
3645    return SYSCALL_OK;
3646
3647} // end _sys_fbf_cma_stop()
3648
3649#endif // if NB_CMA_CHANNELS
3650
3651
3652//////////////////////////////////////////////////////////////////////////////
3653//           Miscelaneous syscall handlers
3654//////////////////////////////////////////////////////////////////////////////
3655
3656///////////////
3657int _sys_ukn() 
3658{
3659    _printf("\n[GIET ERROR] Undefined System Call / EPC = %x\n", _get_epc() );
3660
3661    return SYSCALL_UNDEFINED_SYSTEM_CALL;
3662}
3663
3664////////////////////////////////////
3665int _sys_proc_xyp( unsigned int* x,
3666                   unsigned int* y,
3667                   unsigned int* p )
3668{
3669    unsigned int gpid = _get_procid();  // global processor index from CPO register
3670
3671    *x = (gpid >> (Y_WIDTH + P_WIDTH)) & ((1<<X_WIDTH)-1);
3672    *y = (gpid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
3673    *p = gpid & ((1<<P_WIDTH)-1);
3674
3675    return SYSCALL_OK;
3676}
3677
3678////////////////////////////////////////////
3679int _sys_procs_number( unsigned int* x_size,
3680                       unsigned int* y_size,
3681                       unsigned int* nprocs )
3682{
3683    mapping_header_t * header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
3684    mapping_cluster_t * cluster = _get_cluster_base(header);
3685
3686    unsigned int x;
3687    unsigned int y;
3688    unsigned int okmin = 1;
3689    unsigned int okmax = 1;
3690
3691    // compute max values
3692    unsigned int xmax  = header->x_size;
3693    unsigned int ymax  = header->y_size;
3694    unsigned int procs = cluster[0].procs;
3695
3696    // check the (ymax-1) lower rows
3697    for ( y = 0 ; y < ymax-1 ; y++ )
3698    {
3699        for ( x = 0 ; x < xmax ; x++ )
3700        {
3701            if (cluster[x*ymax+y].procs != procs ) okmin = 0;
3702        }
3703    }
3704
3705    // check the upper row
3706    for ( x = 0 ; x < xmax ; x++ )
3707    {
3708        if (cluster[x*ymax+ymax-1].procs != procs ) okmax = 0;
3709    }
3710
3711    // return values
3712    if ( okmin && okmax )
3713    {
3714        *x_size = xmax;
3715        *y_size = ymax;
3716        *nprocs = procs;
3717    }
3718    else if ( okmin )
3719    {
3720        *x_size = xmax;
3721        *y_size = ymax-1;
3722        *nprocs = procs;
3723    }
3724    else
3725    {
3726        *x_size = 0;
3727        *y_size = 0;
3728        *nprocs = 0;
3729    }
3730    return SYSCALL_OK;
3731}
3732
3733///////////////////////////////////////////////////////
3734int _sys_vseg_get_vbase( char*             vspace_name, 
3735                         char*             vseg_name, 
3736                         unsigned int*     vbase ) 
3737{
3738    mapping_header_t * header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
3739    mapping_vspace_t * vspace = _get_vspace_base(header);
3740    mapping_vseg_t * vseg     = _get_vseg_base(header);
3741
3742    unsigned int vspace_id;
3743    unsigned int vseg_id;
3744
3745    // scan vspaces
3746    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
3747    {
3748        if (_strncmp( vspace[vspace_id].name, vspace_name, 31) == 0) 
3749        {
3750            // scan vsegs
3751            for (vseg_id = vspace[vspace_id].vseg_offset; 
3752                 vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs); 
3753                 vseg_id++) 
3754            {
3755                if (_strncmp(vseg[vseg_id].name, vseg_name, 31) == 0) 
3756                {
3757                    *vbase = vseg[vseg_id].vbase;
3758                    return SYSCALL_OK;
3759                }
3760            } 
3761        }
3762    } 
3763    return SYSCALL_VSEG_NOT_FOUND;
3764}
3765
3766/////////////////////////////////////////////////////////
3767int _sys_vseg_get_length( char*         vspace_name, 
3768                          char*         vseg_name,
3769                          unsigned int* length ) 
3770{
3771    mapping_header_t * header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
3772    mapping_vspace_t * vspace = _get_vspace_base(header);
3773    mapping_vseg_t * vseg     = _get_vseg_base(header);
3774
3775    unsigned int vspace_id;
3776    unsigned int vseg_id;
3777
3778    // scan vspaces
3779    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
3780    {
3781        if (_strncmp( vspace[vspace_id].name, vspace_name, 31) == 0) 
3782        {
3783            // scan vsegs
3784            for (vseg_id = vspace[vspace_id].vseg_offset; 
3785                 vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs); 
3786                 vseg_id++) 
3787            {
3788                if (_strncmp(vseg[vseg_id].name, vseg_name, 31) == 0) 
3789                {
3790                    *length = vseg[vseg_id].length;
3791                    return SYSCALL_OK;
3792                }
3793            } 
3794        }
3795    } 
3796    return SYSCALL_VSEG_NOT_FOUND;
3797}
3798
3799////////////////////////////////////////
3800int _sys_xy_from_ptr( void*         ptr,
3801                      unsigned int* x,
3802                      unsigned int* y )
3803{
3804    unsigned int flags;
3805    unsigned long long paddr = _v2p_translate( (unsigned int)ptr , &flags );
3806   
3807    *x = (paddr>>36) & 0xF;
3808    *y = (paddr>>32) & 0xF;
3809
3810    return SYSCALL_OK;
3811}
3812
3813/////////////////////////////////////////
3814int _sys_heap_info( unsigned int* vaddr, 
3815                    unsigned int* length,
3816                    unsigned int  x,
3817                    unsigned int  y ) 
3818{
3819    // checking parameters
3820    if ( (x >= X_SIZE) || (y >= Y_SIZE) ) 
3821    {
3822        *vaddr  = 0;
3823        *length = 0;
3824        _printf("\n[GIET ERROR] in _sys_heap_info() : "
3825                "illegal (%d,%d) coordinates\n", x , y );
3826        return SYSCALL_ILLEGAL_CLUSTER_COORDINATES;
3827    }
3828
3829    mapping_header_t * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
3830    mapping_thread_t * thread  = _get_thread_base(header);
3831    mapping_vseg_t *   vseg    = _get_vseg_base(header);
3832    mapping_vspace_t * vspace  = _get_vspace_base(header);
3833
3834    unsigned int thread_id;
3835    unsigned int vspace_id;
3836    unsigned int vseg_id = 0xFFFFFFFF;
3837
3838    // get calling thread vspace index
3839    vspace_id = _get_context_slot(CTX_VSID_ID);
3840
3841    // scan all threads in vspace to find one in clyster[x,y]
3842    unsigned int min = vspace[vspace_id].thread_offset ;
3843    unsigned int max = min + vspace[vspace_id].threads ;
3844    for ( thread_id = min ; thread_id < max ; thread_id++ )
3845    {
3846        if ( thread[thread_id].clusterid == (x * Y_SIZE + y) )
3847        {
3848            vseg_id = thread[thread_id].heap_vseg_id;
3849            break;
3850        }
3851    }
3852
3853    // analysing the vseg_id
3854    if ( vseg_id != 0xFFFFFFFF ) 
3855    {
3856        *vaddr  = vseg[vseg_id].vbase;
3857        *length = vseg[vseg_id].length;
3858    }
3859    else 
3860    {
3861        *vaddr  = 0;
3862        *length = 0;
3863        _printf("error in _sys_heap_info() : no heap in cluster (%d,%d)\n", x , y );
3864    }
3865    return SYSCALL_OK;
3866}  // end _sys_heap_info()
3867
3868
3869// Local Variables:
3870// tab-width: 4
3871// c-basic-offset: 4
3872// c-file-offsets:((innamespace . 0)(inline-open . 0))
3873// indent-tabs-mode: nil
3874// End:
3875// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
3876
Note: See TracBrowser for help on using the repository browser.