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

Last change on this file since 825 was 820, checked in by cfuguet, 8 years ago

Improving the pthread_join function:

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