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

Last change on this file since 778 was 774, checked in by alain, 9 years ago

The _sys_fat_dump() kernel function has been introduced to support the
new giet_fat_dump() system call, used by the shell to display disk sectors of a FAT partition.

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