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

Last change on this file since 728 was 725, checked in by alain, 9 years ago

Modify FBF_CMA syscall handlers to support chbufs containing more than two buffers.

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