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

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

Modify the system functions associated to hardware coprocessors:
Introduce two explicit arguments "cluster_xy" and "cluster_type"
to allows any task to control a coprocessor located in any cluster.

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