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

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

Introducing the coremark benchmark

  • Property svn:executable set to *
File size: 120.5 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 vspace %s\n"
964                "               Cause : %s\n\n",
965                     trdid , vspace[vsid].name , (char*) string );
966    }
967   
968    // get scheduler pointer for calling thread
969    static_scheduler_t*  psched = (static_scheduler_t*)_get_sched();
970
971    // register KILL signal in calling thread context (suicid request)
972    _atomic_or( &psched->context[ltid].slot[CTX_SIGS_ID] , SIGS_MASK_KILL );
973
974    // deschedule calling thread
975    unsigned int save_sr; 
976    _it_disable( &save_sr );
977
978    _ctx_switch();
979
980    return SYSCALL_OK;
981
982}  // end _sys_pthread_exit()
983
984////////////////////////
985int _sys_pthread_yield() 
986{
987    unsigned int save_sr;
988
989    _it_disable( &save_sr );
990    _ctx_switch();
991    _it_restore( &save_sr );
992
993    return SYSCALL_OK;
994}
995
996//////////////////////////////////////////////////
997int _sys_pthread_control( unsigned  int  command,
998                          char*     vspace_name,
999                          char*     thread_name )
1000{
1001
1002#if GIET_DEBUG_EXEC
1003unsigned int gpid       = _get_procid();
1004unsigned int cluster_xy = gpid >> P_WIDTH;
1005unsigned int p          = gpid & ((1<<P_WIDTH)-1);
1006unsigned int x          = cluster_xy >> Y_WIDTH;
1007unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1008if ( _get_proctime() > GIET_DEBUG_EXEC )
1009_printf("\n[DEBUG EXEC] _sys_pthread_control() at cycle %d\n"
1010        "P[%d,%d,%d] enter for vspace %s / thread %s / command = %d\n",
1011        _get_proctime() , x , y , p , vspace_name, thread_name, command );
1012#endif
1013
1014    // get pointers in mapping
1015    mapping_header_t*    header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1016    mapping_thread_t*    thread   = _get_thread_base(header);
1017    mapping_vspace_t*    vspace   = _get_vspace_base(header);
1018    mapping_cluster_t*   cluster  = _get_cluster_base(header);
1019
1020    unsigned int found;
1021
1022    // search vspace name to get vspace index: vsid
1023    found = 0;
1024    unsigned int   vsid;
1025    for( vsid = 0 ; vsid < header->vspaces ; vsid++ )
1026    {
1027        if ( _strcmp( vspace[vsid].name, vspace_name ) == 0 )
1028        {
1029            found = 1;
1030            break;
1031        }
1032    }
1033
1034    if ( found == 0 ) return SYSCALL_VSPACE_NOT_FOUND;
1035
1036    // search thread name in vspace to get thread index: tid
1037    found = 0;
1038    unsigned int   tid;
1039    unsigned int   min = vspace[vsid].thread_offset;
1040    unsigned int   max = min + vspace[vsid].threads;
1041    for( tid = min ; tid < max ; tid++ )
1042    {
1043        if ( _strcmp( thread[tid].name, thread_name ) == 0 )
1044        {
1045            found = 1;
1046            break;
1047        }
1048    }
1049
1050    if ( found == 0 ) return SYSCALL_THREAD_NOT_FOUND;
1051
1052    // get target thread coordinates
1053    unsigned int cid  = thread[tid].clusterid;
1054    unsigned int cx   = cluster[cid].x;
1055    unsigned int cy   = cluster[cid].y;
1056    unsigned int cp   = thread[tid].proclocid;
1057    unsigned int ltid = thread[tid].ltid;
1058
1059    // get target thread scheduler
1060    static_scheduler_t* psched = _schedulers[cx][cy][cp];
1061
1062    // check trdid and vsid
1063    unsigned int trdid = cx<<24 | cy<<16 | cp<<8 | ltid;
1064    if ( (psched->context[ltid].slot[CTX_TRDID_ID] != trdid) ||
1065         (psched->context[ltid].slot[CTX_VSID_ID]  != vsid) )
1066    {
1067        return SYSCALL_UNCOHERENT_THREAD_CONTEXT;
1068    }
1069
1070    // execute command
1071    if ( command == THREAD_CMD_PAUSE ) 
1072    {
1073        _atomic_or ( &psched->context[ltid].slot[CTX_NORUN_ID],  NORUN_MASK_THREAD );
1074        return SYSCALL_OK;
1075    }
1076    else if ( command == THREAD_CMD_RESUME )
1077    {
1078        _atomic_and( &psched->context[ltid].slot[CTX_NORUN_ID], ~NORUN_MASK_THREAD );
1079        return SYSCALL_OK;
1080    }
1081    else if ( command == THREAD_CMD_CONTEXT )
1082    {
1083        _user_printf( " - CTX_TRDID  = %x\n"
1084                      " - CTX_VSID   = %x\n"
1085                      " - CTX_EPC    = %x\n"
1086                      " - CTX_PTAB   = %x\n"
1087                      " - CTX_PTPR   = %x\n"
1088                      " - CTX_SR     = %x\n"
1089                      " - CTX_RA     = %x\n"
1090                      " - CTX_SP     = %x\n"
1091                      " - CTX_ENTRY  = %x\n"
1092                      " - CTX_NORUN  = %x\n"
1093                      " - CTX_SIGS   = %x\n"
1094                      " - CTX_LOCKS  = %x\n"
1095                      " - CTX_TTY    = %x\n"
1096                      " - CTX_NIC_RX = %x\n"
1097                      " - CTX_NIC_TX = %x\n"
1098                      " - CTX_CMA_RX = %x\n"
1099                      " - CTX_CMA_TX = %x\n"
1100                      " - CTX_CMA_FB = %x\n",
1101                      psched->context[ltid].slot[CTX_TRDID_ID], 
1102                      psched->context[ltid].slot[CTX_VSID_ID], 
1103                      psched->context[ltid].slot[CTX_EPC_ID], 
1104                      psched->context[ltid].slot[CTX_PTAB_ID], 
1105                      psched->context[ltid].slot[CTX_PTPR_ID], 
1106                      psched->context[ltid].slot[CTX_SR_ID], 
1107                      psched->context[ltid].slot[CTX_RA_ID], 
1108                      psched->context[ltid].slot[CTX_SP_ID], 
1109                      psched->context[ltid].slot[CTX_ENTRY_ID], 
1110                      psched->context[ltid].slot[CTX_NORUN_ID],
1111                      psched->context[ltid].slot[CTX_SIGS_ID],
1112                      psched->context[ltid].slot[CTX_LOCKS_ID],
1113                      psched->context[ltid].slot[CTX_TTY_ID],
1114                      psched->context[ltid].slot[CTX_NIC_RX_ID],
1115                      psched->context[ltid].slot[CTX_NIC_TX_ID],
1116                      psched->context[ltid].slot[CTX_CMA_RX_ID],
1117                      psched->context[ltid].slot[CTX_CMA_TX_ID],
1118                      psched->context[ltid].slot[CTX_CMA_FB_ID] );
1119        return SYSCALL_OK;
1120    }
1121    else
1122    {
1123        return SYSCALL_ILLEGAL_THREAD_COMMAND_TYPE;
1124    }
1125
1126} // end _sys_pthread_control()
1127
1128
1129
1130
1131//////////////////////////////////////////////////////////////////////////////
1132//           Coprocessors related syscall handlers
1133//////////////////////////////////////////////////////////////////////////////
1134
1135//////////////////////////////////////////////////
1136int _sys_coproc_alloc( unsigned int   cluster_xy,
1137                       unsigned int   coproc_type,
1138                       unsigned int*  return_info )
1139{
1140    mapping_header_t  * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1141    mapping_cluster_t * cluster = _get_cluster_base(header);
1142    mapping_periph_t  * periph  = _get_periph_base(header);
1143
1144    // compute cluster coordinates and cluster index in mapping
1145    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1146    unsigned int x          = (cluster_xy>>Y_WIDTH) & ((1<<X_WIDTH)-1);
1147    unsigned int cluster_id = x * Y_SIZE + y;
1148 
1149    // search coprocessor in cluster
1150    mapping_periph_t*  found = NULL;
1151    unsigned int min   = cluster[cluster_id].periph_offset;
1152    unsigned int max   = min + cluster[cluster_id].periphs;
1153    unsigned int periph_id;
1154    for ( periph_id = min ; periph_id < max ; periph_id++ )
1155    {
1156        if ( (periph[periph_id].type == PERIPH_TYPE_MWR) &&
1157             (periph[periph_id].subtype == coproc_type) )
1158        {
1159            found = &periph[periph_id];
1160            break;
1161        }
1162    } 
1163
1164    if ( found != NULL )
1165    {
1166        // get the lock
1167        _simple_lock_acquire( &_coproc_lock[cluster_id] );
1168
1169        // register coproc characteristics in kernel arrays
1170        _coproc_type[cluster_id] = coproc_type;
1171        _coproc_info[cluster_id] = (found->arg0 & 0xFF)     |
1172                                   (found->arg1 & 0xFF)<<8  |
1173                                   (found->arg2 & 0xFF)<<16 |
1174                                   (found->arg3 & 0xFF)<<24 ;
1175
1176        // returns coprocessor info
1177        *return_info = _coproc_info[cluster_id];
1178
1179#if GIET_DEBUG_COPROC
1180_printf("\n[DEBUG COPROC] _sys_coproc_alloc() at cycle %d\n"
1181        "type = %d in cluster[%d,%d] / coproc_info = %x\n",
1182        _get_proctime() , coproc_type, x , y , *return_info );
1183#endif
1184        return SYSCALL_OK;
1185    }
1186    else
1187    {
1188         _printf("\n[GIET_ERROR] in _sys_coproc_alloc(): "
1189                 "no coprocessor with type %d in cluster[%d,%d]\n",
1190                 coproc_type , x , y );
1191
1192        return SYSCALL_COPROCESSOR_NOT_FOUND;
1193    }
1194}  // end _sys_coproc_alloc()
1195
1196////////////////////////////////////////////////////////
1197int _sys_coproc_release( unsigned int cluster_xy,
1198                         unsigned int coproc_type )
1199{
1200    // compute cluster coordinates and cluster index
1201    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1202    unsigned int x          = (cluster_xy>>Y_WIDTH) & ((1<<X_WIDTH)-1);
1203    unsigned int cluster_id = x * Y_SIZE + y;
1204
1205    // check coprocessor type
1206    if ( _coproc_type[cluster_id] != coproc_type )
1207    {
1208         _printf("\n[GIET_ERROR] in _sys_coproc_release(): "
1209                 "no coprocessor of type %d allocated in cluster[%d,%d]\n", 
1210                 coproc_type, x , y );
1211
1212         return SYSCALL_COPROCESSOR_NON_ALLOCATED;
1213    }
1214
1215    unsigned int info       = _coproc_info[cluster_id];
1216    unsigned int nb_to      = info & 0xFF;
1217    unsigned int nb_from    = (info>>8) & 0xFF;
1218    unsigned int channel;
1219
1220    // stops coprocessor and communication channels
1221    _mwr_set_coproc_register( cluster_xy , 0 , 0 );
1222    for ( channel = 0 ; channel < (nb_from + nb_to) ; channel++ )
1223    {
1224        _mwr_set_channel_register( cluster_xy , channel , MWR_CHANNEL_RUNNING , 0 );
1225    }
1226
1227    // release coprocessor lock
1228    _simple_lock_release( &_coproc_lock[cluster_id] );
1229
1230#if GIET_DEBUG_COPROC
1231_printf("\n[DEBUG COPROC] _sys_coproc_release() at cycle %d\n"
1232        "type = %d in cluster[%d,%d]\n",
1233        _get_proctime() , coproc_type , x , y );
1234#endif
1235
1236    return SYSCALL_OK;
1237}  // end _sys_coproc_release()
1238
1239////////////////////////////////////////////////////////////////
1240int _sys_coproc_channel_init( unsigned int            cluster_xy,
1241                              unsigned int            coproc_type,
1242                              unsigned int            channel,
1243                              giet_coproc_channel_t*  desc )
1244{
1245    // compute cluster coordinates and cluster index
1246    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1247    unsigned int x          = (cluster_xy>>Y_WIDTH) & ((1<<X_WIDTH)-1);
1248    unsigned int cluster_id = x * Y_SIZE + y;
1249
1250    // check coprocessor type
1251    if ( _coproc_type[cluster_id] != coproc_type )
1252    {
1253         _printf("\n[GIET_ERROR] in _sys_coproc_release(): "
1254                 "no coprocessor of type %d allocated in cluster[%d,%d]\n", 
1255                 coproc_type, x , y );
1256
1257         return SYSCALL_COPROCESSOR_NON_ALLOCATED;
1258    }
1259
1260    // check channel mode
1261    unsigned mode = desc->channel_mode;
1262    if ( (mode != MODE_MWMR) && 
1263         (mode != MODE_DMA_IRQ) && 
1264         (mode != MODE_DMA_NO_IRQ) )
1265    {
1266         _printf("\n[GIET_ERROR] in _sys_coproc_channel_init(): "
1267                 "illegal mode\n");
1268
1269         return SYSCALL_COPROCESSOR_ILLEGAL_MODE;
1270    }
1271
1272    // get memory buffer size
1273    unsigned int size = desc->buffer_size;
1274 
1275    // physical addresses
1276    unsigned long long buffer_paddr;
1277    unsigned int       buffer_lsb;
1278    unsigned int       buffer_msb;
1279    unsigned long long status_paddr = 0;
1280    unsigned int       status_lsb;
1281    unsigned int       status_msb;
1282    unsigned long long lock_paddr = 0;
1283    unsigned int       lock_lsb;
1284    unsigned int       lock_msb;
1285
1286    unsigned int       flags;     // unused
1287
1288    // compute memory buffer physical address
1289    buffer_paddr = _v2p_translate( desc->buffer_vaddr , &flags );
1290    buffer_lsb   = (unsigned int)buffer_paddr;
1291    buffer_msb   = (unsigned int)(buffer_paddr>>32); 
1292
1293    // call MWMR_DMA driver
1294    _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_MODE, mode ); 
1295    _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_SIZE, size ); 
1296    _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_BUFFER_LSB, buffer_lsb ); 
1297    _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_BUFFER_MSB, buffer_msb ); 
1298                       
1299    if ( mode == MODE_MWMR )
1300    {
1301        // compute MWMR descriptor physical address
1302        status_paddr = _v2p_translate( desc->status_vaddr , &flags );
1303        status_lsb = (unsigned int)status_paddr;
1304        status_msb = (unsigned int)(status_paddr>>32); 
1305
1306        // call MWMR_DMA driver
1307        _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_MWMR_LSB, status_lsb ); 
1308        _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_MWMR_MSB, status_msb ); 
1309
1310        // compute lock physical address
1311        lock_paddr = _v2p_translate( desc->lock_vaddr , &flags );
1312        lock_lsb = (unsigned int)lock_paddr;
1313        lock_msb = (unsigned int)(lock_paddr>>32); 
1314
1315        // call MWMR_DMA driver
1316        _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_LOCK_LSB, lock_lsb ); 
1317        _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_LOCK_MSB, lock_msb ); 
1318    }
1319
1320#if GIET_DEBUG_COPROC
1321_printf("\n[DEBUG COPROC] _sys_coproc_channel_init() at cycle %d\n"
1322        "cluster[%d,%d] / channel = %d / mode = %d / buffer_size = %d\n"
1323        "buffer_vaddr = %x / status_vaddr = %x / lock_vaddr = %x\n"
1324        "buffer_paddr = %l / status_paddr = %l / lock_paddr = %l\n",
1325        _get_proctime() , x , y , channel , mode , size ,
1326        desc->buffer_vaddr, desc->status_vaddr, desc->lock_vaddr,
1327        buffer_paddr, status_paddr, lock_paddr );
1328#endif
1329       
1330    return SYSCALL_OK;
1331} // end _sys_coproc_channel_init()
1332
1333//////////////////////////////////////////////
1334int _sys_coproc_run( unsigned int  cluster_xy,
1335                     unsigned int  coproc_type )
1336{
1337    // compute cluster coordinates and cluster index
1338    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1339    unsigned int x          = (cluster_xy>>Y_WIDTH) & ((1<<X_WIDTH)-1);
1340    unsigned int cluster_id = x * Y_SIZE + y;
1341
1342    // check coprocessor type
1343    if ( _coproc_type[cluster_id] != coproc_type )
1344    {
1345         _printf("\n[GIET_ERROR] in _sys_coproc_release(): "
1346                 "no coprocessor of type %d allocated in cluster[%d,%d]\n", 
1347                 coproc_type, x , y );
1348
1349         return SYSCALL_COPROCESSOR_NON_ALLOCATED;
1350    }
1351
1352    unsigned int info       = _coproc_info[cluster_id];
1353    unsigned int nb_to      = info & 0xFF;
1354    unsigned int nb_from    = (info>>8) & 0xFF;
1355    unsigned int mode       = 0xFFFFFFFF;
1356    unsigned int channel;
1357
1358    // check channels modes, and register coprocessor running mode
1359    for ( channel = 0 ; channel < (nb_from + nb_to) ; channel++ )
1360    {
1361        unsigned int temp;
1362        temp = _mwr_get_channel_register( cluster_xy , channel , MWR_CHANNEL_MODE );
1363
1364        if ( mode == 0xFFFFFFFF ) 
1365        {
1366            mode = temp;
1367        }
1368        else if ( temp != mode )
1369        {
1370            _printf("\n[GIET_ERROR] in _sys_coproc_run(): "
1371                    "channels don't have same mode in coprocessor[%d,%d]\n", x , y );
1372
1373            return SYSCALL_COPROCESSOR_ILLEGAL_MODE;
1374        }
1375    }
1376    _coproc_mode[cluster_id] = mode;
1377
1378    // start all communication channels
1379    for ( channel = 0 ; channel < (nb_from + nb_to) ; channel++ )
1380    {
1381        _mwr_set_channel_register( cluster_xy , channel , MWR_CHANNEL_RUNNING , 1 );
1382    }
1383
1384    //////////////////////////////////////////////////////////////////////////
1385    if ( (mode == MODE_MWMR) || (mode == MODE_DMA_NO_IRQ) )  // no descheduling
1386    {
1387        // start coprocessor
1388        _mwr_set_coproc_register( cluster_xy , 0 , 1 );
1389
1390#if GIET_DEBUG_COPROC
1391if ( mode == MODE_MWMR )
1392_printf("\n[DEBUG COPROC] _sys_coproc_run() at cycle %d\n"
1393        "type = %d / cluster[%d,%d] / MODE_MWMR\n", 
1394        _get_proctime() , coproc_type , x , y );
1395else
1396_printf("\n[DEBUG COPROC] _sys_coproc_run() at cycle %d\n"
1397        "type = %d / cluster[%d,%d] / MODE_DMA_NO_IRQ\n", 
1398        _get_proctime() , coproc_type , x , y );
1399#endif
1400
1401        return SYSCALL_OK;
1402    }
1403    ///////////////////////////////////////////////////////////////////////////
1404    else                                // mode == MODE_DMA_IRQ => descheduling
1405    {
1406        // register calling thread trdid
1407        unsigned int trdid = _get_thread_trdid();
1408        _coproc_trdid[cluster_id] = trdid;
1409
1410        // enters critical section
1411        unsigned int save_sr;
1412        _it_disable( &save_sr ); 
1413
1414        // set NORUN_MASK_COPROC bit
1415        static_scheduler_t* psched  = _get_sched();
1416        unsigned int        ltid    = _get_thread_ltid();
1417        unsigned int*       ptr     = &psched->context[ltid].slot[CTX_NORUN_ID];
1418        _atomic_or( ptr , NORUN_MASK_COPROC );
1419
1420        // start coprocessor
1421        _mwr_set_coproc_register( cluster_xy , 0 , 1 );
1422
1423#if GIET_DEBUG_COPROC
1424_printf("\n[DEBUG COPROC] _sys_coproc_run() at cycle %d\n"
1425        "thread %x starts coprocessor / type = %d / cluster[%d,%d] / MODE_DMA_IRQ\n", 
1426        _get_proctime() , trdid , coproc_type , x , y );
1427#endif
1428
1429        // deschedule thread
1430        _ctx_switch(); 
1431
1432#if GIET_DEBUG_COPROC
1433_printf("\n[DEBUG COPROC] _sys_coproc_run() at cycle %d\n"
1434        "thread %x resume after coprocessor[%d,%d] completion\n", 
1435        _get_proctime() , trdid , x , y );
1436#endif
1437
1438        // restore SR
1439        _it_restore( &save_sr );
1440
1441        // return error computed by mwr_isr()
1442        return _coproc_error[cluster_id];
1443    } 
1444} // end _sys_coproc_run()
1445
1446////////////////////////////////////////////////////
1447int _sys_coproc_completed( unsigned int  cluster_xy,
1448                           unsigned int  coproc_type )
1449{
1450    // compute cluster coordinates and cluster index
1451    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1452    unsigned int x          = (cluster_xy>>Y_WIDTH) & ((1<<X_WIDTH)-1);
1453    unsigned int cluster_id = x * Y_SIZE + y;
1454
1455    // check coprocessor type
1456    if ( _coproc_type[cluster_id] != coproc_type )
1457    {
1458         _printf("\n[GIET_ERROR] in _sys_coproc_release(): "
1459                 "no coprocessor of type %d allocated in cluster[%d,%d]\n", 
1460                 coproc_type, x , y );
1461
1462         return SYSCALL_COPROCESSOR_NON_ALLOCATED;
1463    }
1464
1465    unsigned int mode = _coproc_mode[cluster_id];
1466
1467    // analyse possible errors
1468    if ( mode == MODE_DMA_NO_IRQ )
1469    {
1470        unsigned int info       = _coproc_info[cluster_id];
1471        unsigned int nb_to      = info & 0xFF;
1472        unsigned int nb_from    = (info>>8) & 0xFF;
1473        unsigned int error      = 0;
1474        unsigned int channel;
1475        unsigned int status;
1476
1477        // get status for all channels, and signal reported errors
1478        for ( channel = 0 ; channel < (nb_to +nb_from) ; channel++ )
1479        {
1480            do
1481            {
1482                status = _mwr_get_channel_register( cluster_xy, channel,
1483                                                    MWR_CHANNEL_STATUS );
1484                if ( status == MWR_CHANNEL_ERROR_DATA )
1485                {
1486                    _printf("\n[GIET_ERROR] in _sys_coproc_completed(): "
1487                            "channel %d / DATA_ERROR\n", channel );
1488                    error = 1;
1489                }
1490                else if ( status == MWR_CHANNEL_ERROR_LOCK )
1491                {
1492                    _printf("\n[GIET_ERROR] in _sys_coproc_completed()"
1493                            " / channel %d / LOCK_ERROR\n", channel );
1494                    error = 1;
1495                }
1496                else if ( status == MWR_CHANNEL_ERROR_DESC )
1497                {
1498                    _printf("\n[GIET_ERROR] in _sys_coproc_completed()"
1499                            " / channel %d / DESC_ERROR\n", channel );
1500                    error = 1;
1501                }
1502            } 
1503            while ( status == MWR_CHANNEL_BUSY );
1504
1505            // reset channel
1506            _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_RUNNING , 0 ); 
1507
1508        }  // end for channels
1509
1510        if ( error )
1511        {
1512            return SYSCALL_COPROCESSOR_ILLEGAL_MODE;
1513        }
1514        else
1515        {
1516
1517#if GIET_DEBUG_COPROC
1518_printf("\n[DEBUG COPROC] _sys_coproc_completed() at cycle %d\n"
1519        "coprocessor type = %d / cluster[%d,%d] completes operation for thread %d\n", 
1520        _get_proctime() , coproc_type , x , y , _get_thread_trdid() );
1521#endif
1522            return SYSCALL_OK;
1523        }
1524    }
1525    else  // mode == MODE_MWMR or MODE_DMA_IRQ
1526    {
1527        _printf("\n[GIET ERROR] in sys_coproc_completed(): "
1528                "coprocessor[%d,%d] is not running in MODE_DMA_NO_IRQ\n", x , y );
1529
1530        return SYSCALL_COPROCESSOR_ILLEGAL_MODE;
1531    }
1532} // end _sys_coproc_completed()
1533
1534
1535//////////////////////////////////////////////////////////////////////////////
1536//             TTY related syscall handlers
1537//////////////////////////////////////////////////////////////////////////////
1538
1539/////////////////////////////////////////
1540int _sys_tty_alloc( unsigned int shared )
1541{
1542    unsigned int channel;    // allocated TTY channel
1543
1544    // get trdid and vsid for the calling thread
1545    unsigned int vsid  = _get_context_slot( CTX_VSID_ID );
1546    unsigned int trdid = _get_thread_trdid();
1547
1548    mapping_header_t  *header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1549    mapping_vspace_t  *vspace   = _get_vspace_base(header);
1550    mapping_thread_t  *thread   = _get_thread_base(header);
1551   
1552    // compute number of users
1553    unsigned int users;
1554    if ( shared )  users = vspace[vsid].threads;
1555    else           users = 1;
1556
1557    // get a TTY channel
1558    for ( channel = 0 ; channel < NB_TTY_CHANNELS ; channel++ )
1559    {
1560        unsigned int* palloc  = &_tty_channel_alloc[channel];
1561
1562        if ( _atomic_test_and_set( palloc , users ) == 0 ) break;
1563    }
1564    if ( channel >= NB_TTY_CHANNELS )
1565    {
1566        _printf("\n[GIET_ERROR] in _sys_tty_alloc() : "
1567                "no TTY channel available for thread %x\n", trdid );
1568        return SYSCALL_NO_CHANNEL_AVAILABLE;
1569    }
1570
1571    // initialise allocated TTY channel
1572    _tty_init( channel );
1573
1574    // allocate a WTI mailbox to the calling proc if external IRQ
1575    unsigned int wti_id;
1576    if ( USE_PIC ) _ext_irq_alloc( ISR_TTY_RX , channel , &wti_id ); 
1577
1578    // register wti_id and coordinates for processor receiving WTI
1579    unsigned int procid = _get_procid();
1580    unsigned int x      = procid >> (Y_WIDTH + P_WIDTH);
1581    unsigned int y      = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1582    unsigned int p      = procid & ((1<<P_WIDTH)-1);
1583    _tty_channel_wti[channel] = x<<24 | y<<16 | p<<8 | wti_id;
1584   
1585    // update CTX_TTY_ID
1586    if ( shared )         // for all threads in vspace
1587    {
1588        // scan threads in vspace
1589        unsigned int tid;
1590        for (tid = vspace[vsid].thread_offset;
1591             tid < (vspace[vsid].thread_offset + vspace[vsid].threads);
1592             tid++)
1593        {
1594            unsigned int y_size        = header->y_size;
1595            unsigned int cid           = thread[tid].clusterid;
1596            unsigned int x             = cid / y_size;
1597            unsigned int y             = cid % y_size;
1598            unsigned int p             = thread[tid].proclocid;
1599            unsigned int ltid          = thread[tid].ltid;
1600            static_scheduler_t* psched = (static_scheduler_t*)_schedulers[x][y][p];
1601
1602            psched->context[ltid].slot[CTX_TTY_ID] = channel;
1603        }
1604    }
1605    else                  // for calling thread only
1606    {
1607        _set_context_slot( CTX_TTY_ID, channel );
1608    }
1609
1610    return SYSCALL_OK;
1611}  // end _sys_tty_alloc()
1612
1613//////////////////////
1614int _sys_tty_release()     // NOTE: not a syscall: used by _ctx_kill_thread()
1615{
1616    unsigned int channel = _get_context_slot( CTX_TTY_ID );
1617
1618    if ( channel == -1 )
1619    {
1620        unsigned int trdid = _get_thread_trdid();
1621        _printf("\n[GIET_ERROR] in _sys_tty_release() : "
1622                "TTY channel already released for thread %x\n", trdid );
1623
1624        return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
1625    }
1626
1627    // reset CTX_TTY_ID for the calling thread
1628    _set_context_slot( CTX_TTY_ID , 0xFFFFFFFF );
1629
1630    // atomically decrement the _tty_channel_allocator[] array
1631    _atomic_increment( &_tty_channel_alloc[channel] , -1 );
1632
1633    // release WTI mailbox if TTY channel no more used
1634    if ( USE_PIC  && (_tty_channel_alloc[channel] == 0) ) 
1635    {
1636        _ext_irq_release( ISR_TTY_RX , channel );
1637    }
1638
1639    return SYSCALL_OK;
1640}  // end sys_tty_release()
1641
1642////////////////////////////////////////
1643int _sys_tty_write( const char*  buffer,   
1644                    unsigned int length,    // number of characters
1645                    unsigned int channel)   // channel index
1646{
1647    unsigned int  nwritten;
1648
1649    // compute and check tty channel
1650    if( channel == 0xFFFFFFFF )  channel = _get_context_slot(CTX_TTY_ID);
1651
1652    if( channel >= NB_TTY_CHANNELS )
1653    {
1654        _printf("\n[GIET_ERROR] in _sys_tty_write() : "
1655                "no TTY channel allocated for thread %x\n", _get_thread_trdid() );
1656
1657        return SYSCALL_CHANNEL_NON_ALLOCATED;
1658    }
1659
1660    // write string to TTY channel
1661    for (nwritten = 0; nwritten < length; nwritten++) 
1662    {
1663        // check tty's status
1664        if ( _tty_get_register( channel, TTY_STATUS ) & 0x2 )  break;
1665
1666        // write one byte
1667        if (buffer[nwritten] == '\n') 
1668        {
1669            _tty_set_register( channel, TTY_WRITE, (unsigned int)'\r' );
1670        }
1671        _tty_set_register( channel, TTY_WRITE, (unsigned int)buffer[nwritten] );
1672    }
1673   
1674    return nwritten;
1675}
1676
1677///////////////////////////////////////
1678int _sys_tty_read( char*        buffer, 
1679                   unsigned int length,    // unused
1680                   unsigned int channel)   // channel index
1681{
1682    // compute and check tty channel
1683    if( channel == 0xFFFFFFFF )  channel = _get_context_slot(CTX_TTY_ID);
1684
1685    if( channel >= NB_TTY_CHANNELS )
1686    {
1687        _printf("\n[GIET_ERROR] in _sys_tty_read() : "
1688                "no TTY channel allocated for thread %x\n", _get_thread_trdid() );
1689
1690        return SYSCALL_CHANNEL_NON_ALLOCATED;
1691    }
1692
1693    unsigned int save_sr;
1694    unsigned int found = 0;
1695
1696    // get pointer on TTY_RX FIFO
1697    tty_fifo_t*  fifo = &_tty_rx_fifo[channel];
1698
1699    // try to read one character from FIFO
1700    // blocked in while loop until success
1701    while ( found == 0 )
1702    {
1703        if ( fifo->sts == 0)   // FIFO empty => deschedule
1704        {
1705            // enters critical section
1706             _it_disable( &save_sr );
1707
1708            // set NORUN_MASK_TTY bit for calling thread
1709            static_scheduler_t* psched  = (static_scheduler_t*)_get_sched();
1710            unsigned int ltid = psched->current;
1711            _atomic_or( &psched->context[ltid].slot[CTX_NORUN_ID] , NORUN_MASK_TTY );
1712
1713            // register descheduling thread trdid
1714            fifo->trdid = _get_thread_trdid();
1715
1716             // deschedule calling thread
1717            _ctx_switch();
1718
1719            // exit critical section
1720            _it_restore( &save_sr );
1721        }
1722        else                             // FIFO not empty => get one character
1723        {
1724            *buffer   = fifo->data[fifo->ptr];
1725            fifo->sts = fifo->sts - 1;
1726            fifo->ptr = (fifo->ptr + 1) % TTY_FIFO_DEPTH;
1727            found     = 1;
1728        }
1729    }
1730
1731    return 1;
1732}
1733
1734
1735
1736//////////////////////////////////////////////////////////////////////////////
1737//             TIMER related syscall handlers
1738//////////////////////////////////////////////////////////////////////////////
1739
1740////////////////////
1741int _sys_tim_alloc()
1742{
1743
1744#if NB_TIM_CHANNELS
1745
1746    unsigned int channel;    // allocated TIMER channel
1747
1748    unsigned int trdid = _get_thread_trdid();
1749
1750    // check no TIMER already allocated to calling thread
1751    if ( _get_context_slot( CTX_TIM_ID ) < NB_TIM_CHANNELS )
1752    {
1753        _printf("\n[GIET_ERROR] in _sys_tim_alloc() : "
1754                "TIMER channel already allocated to thread %x\n", trdid );
1755
1756        return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
1757    }
1758
1759    // get a TIMER channel
1760    for ( channel = 0 ; channel < NB_TIM_CHANNELS ; channel++ )
1761    {
1762        unsigned int* palloc  = &_tim_channel_alloc[channel];
1763
1764        if ( _atomic_test_and_set( palloc , 1 ) == 0 ) break;
1765    }
1766    if ( channel >= NB_TIM_CHANNELS )
1767    {
1768        _printf("\n[GIET_ERROR] in _sys_tim_alloc() : "
1769                "no TIMER channel available for thread %x\n", trdid );
1770
1771        return SYSCALL_NO_CHANNEL_AVAILABLE;
1772    }
1773
1774    // allocate a WTI mailbox to the calling proc if external IRQ
1775    unsigned int wti_id;
1776    if ( USE_PIC ) _ext_irq_alloc( ISR_TIMER , channel , &wti_id ); 
1777
1778    // register wti_id and coordinates for processor receiving WTI
1779    unsigned int procid = _get_procid();
1780    unsigned int x      = procid >> (Y_WIDTH + P_WIDTH);
1781    unsigned int y      = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1782    unsigned int p      = procid & ((1<<P_WIDTH)-1);
1783    _tim_channel_wti[channel] = x<<24 | y<<16 | p<<8 | wti_id;
1784   
1785    // update CTX_TIM_ID in thread context
1786    _set_context_slot( CTX_TIM_ID, channel );
1787
1788    return SYSCALL_OK;
1789
1790#else
1791
1792    _printf("\n[GIET ERROR] in _sys_tim_alloc(): NB_TIM_CHANNELS == 0\n");
1793
1794    return SYSCALL_NO_CHANNEL_AVAILABLE;
1795
1796#endif
1797}  // end _sys_tim_alloc()
1798
1799
1800//////////////////////
1801int _sys_tim_release()     // NOTE: not a syscall: used by _ctx_kill_thread()
1802{
1803
1804#if NB_TIM_CHANNELS
1805
1806    unsigned int channel = _get_context_slot( CTX_TIM_ID );
1807
1808    if ( channel == -1 )
1809    {
1810        unsigned int trdid = _get_thread_trdid();
1811        _printf("\n[GIET_ERROR] in _sys_tim_release(): "
1812                "TIMER channel already released for thread %x\n", trdid );
1813
1814        return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
1815    }
1816
1817    // reset CTX_TIM_ID for the calling thread
1818    _set_context_slot( CTX_TIM_ID , 0xFFFFFFFF );
1819
1820    // reset the _tim_channel_alloc[] array
1821    _tim_channel_alloc[channel] = 0;
1822
1823    // release WTI mailbox if TTY channel no more used
1824    if ( USE_PIC ) 
1825    {
1826        _ext_irq_release( PERIPH_TYPE_TIM , channel );
1827    }
1828
1829    return SYSCALL_OK;
1830
1831#else
1832
1833    _printf("\n[GIET ERROR] in _sys_tim_release(): NB_TIM_CHANNELS = 0\n");
1834
1835    return SYSCALL_NO_CHANNEL_AVAILABLE;
1836
1837#endif
1838}  // end _sys_tim_release()
1839
1840/////////////////////////////////////////
1841int _sys_tim_start( unsigned int period )
1842{
1843
1844#if NB_TIM_CHANNELS
1845
1846    // get timer index
1847    unsigned int channel = _get_context_slot( CTX_TIM_ID );
1848
1849    if ( channel >= NB_TIM_CHANNELS )
1850    {
1851        _printf("\n[GIET_ERROR] in _sys_tim_start(): not enough TIM channels\n");
1852
1853        return SYSCALL_NO_CHANNEL_AVAILABLE;
1854    }
1855
1856    // start timer
1857    _timer_start( channel, period );
1858
1859    return SYSCALL_OK;
1860
1861#else
1862
1863    _printf("\n[GIET ERROR] in _sys_tim_start() : NB_TIM_CHANNELS = 0\n");
1864
1865    return SYSCALL_NO_CHANNEL_AVAILABLE;
1866
1867#endif
1868}
1869
1870///////////////////
1871int _sys_tim_stop()
1872{
1873
1874#if NB_TIM_CHANNELS
1875
1876    // get timer index
1877    unsigned int channel = _get_context_slot( CTX_TIM_ID );
1878
1879    if ( channel >= NB_TIM_CHANNELS )
1880    {
1881        _printf("\n[GIET_ERROR] in _sys_tim_stop() : illegal timer index\n");
1882
1883        return SYSCALL_CHANNEL_NON_ALLOCATED;
1884    }
1885
1886    // stop timer
1887    _timer_stop( channel );
1888
1889    return SYSCALL_OK;
1890
1891#else
1892
1893    _printf("\n[GIET ERROR] in _sys_tim_stop() : NB_TIM_CHANNELS = 0\n");
1894
1895    return SYSCALL_NO_CHANNEL_AVAILABLE;
1896
1897#endif
1898}
1899
1900
1901//////////////////////////////////////////////////////////////////////////////
1902//             NIC related syscall handlers
1903//////////////////////////////////////////////////////////////////////////////
1904
1905#define NIC_CONTAINER_SIZE 4096
1906
1907#if NB_NIC_CHANNELS
1908
1909////////////////////////////////////////
1910int _sys_nic_alloc( unsigned int is_rx,
1911                    unsigned int xmax,
1912                    unsigned int ymax )
1913{
1914    mapping_header_t  *header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1915    mapping_vspace_t  *vspace   = _get_vspace_base(header);
1916    mapping_thread_t  *thread   = _get_thread_base(header);
1917
1918    // get calling thread trdid, vspace index, and number of threads
1919    unsigned int trdid = _get_thread_trdid();
1920    unsigned int vsid  = _get_context_slot( CTX_VSID_ID );
1921    unsigned int users = vspace[vsid].threads;
1922
1923    // check xmax / ymax parameters
1924    if ( (xmax > X_SIZE) || (ymax > Y_SIZE) )
1925    {
1926        _printf("\n[GIET_ERROR] in _sys_nic_alloc() "
1927                "xmax or ymax argument too large for thread %x\n", trdid );
1928
1929        return SYSCALL_ILLEGAL_ARGUMENT;
1930    }
1931
1932    ////////////////////////////////////////////////////////
1933    // Step 1: get and register CMA and NIC channel index //
1934    ////////////////////////////////////////////////////////
1935
1936    unsigned int   nic_channel;
1937    unsigned int   cma_channel;
1938    unsigned int*  palloc;
1939
1940    // get a NIC_RX or NIC_TX channel
1941    for ( nic_channel = 0 ; nic_channel < NB_NIC_CHANNELS ; nic_channel++ )
1942    {
1943        if ( is_rx ) palloc = &_nic_rx_channel_alloc[nic_channel];
1944        else         palloc = &_nic_tx_channel_alloc[nic_channel];
1945
1946        if ( _atomic_test_and_set( palloc , users ) == 0 ) break;
1947    }
1948    if ( (nic_channel >= NB_NIC_CHANNELS) )
1949    {
1950        _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
1951                "no NIC channel available for thread %x\n", trdid );
1952
1953        return SYSCALL_NO_CHANNEL_AVAILABLE;
1954    }
1955
1956    // get a CMA channel
1957    for ( cma_channel = 0 ; cma_channel < NB_CMA_CHANNELS ; cma_channel++ )
1958    {
1959        palloc = &_cma_channel_alloc[cma_channel];
1960
1961        if ( _atomic_test_and_set( palloc , users ) == 0 ) break;
1962    }
1963    if ( cma_channel >= NB_CMA_CHANNELS )
1964    {
1965        _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
1966                "no CMA channel available for thread %x\n", trdid );
1967        if ( is_rx )  _nic_rx_channel_alloc[nic_channel] = 0;
1968        else          _nic_tx_channel_alloc[nic_channel] = 0;
1969
1970        return SYSCALL_NO_CHANNEL_AVAILABLE;
1971    }
1972
1973#if GIET_DEBUG_NIC
1974_printf("\n[DEBUG NIC] sys_nic_alloc() at cycle %d\n"
1975        "thread %d get nic_channel = %d / cma_channel = %d\n",
1976        _get_proctime() , trdid , nic_channel , cma_channel );
1977#endif
1978
1979    // register nic_index and cma_index in all threads
1980    // contexts that are in the same vspace
1981    unsigned int tid;
1982    for (tid = vspace[vsid].thread_offset;
1983         tid < (vspace[vsid].thread_offset + vspace[vsid].threads);
1984         tid++)
1985    {
1986        unsigned int y_size        = header->y_size;
1987        unsigned int cid           = thread[tid].clusterid;
1988        unsigned int x             = cid / y_size;
1989        unsigned int y             = cid % y_size;
1990        unsigned int p             = thread[tid].proclocid;
1991        unsigned int ltid          = thread[tid].ltid;
1992        static_scheduler_t* psched = (static_scheduler_t*)_schedulers[x][y][p];
1993
1994        if ( is_rx )
1995        {
1996            if ( (psched->context[ltid].slot[CTX_NIC_RX_ID] < NB_NIC_CHANNELS) ||
1997                 (psched->context[ltid].slot[CTX_CMA_RX_ID] < NB_CMA_CHANNELS) )
1998            {
1999                _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
2000                        "NIC_RX or CMA_RX channel already allocated for thread %x\n", trdid );
2001                _nic_rx_channel_alloc[nic_channel] = 0;
2002                _cma_channel_alloc[cma_channel]    = 0;
2003
2004                return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
2005            }
2006            else
2007            {
2008                psched->context[ltid].slot[CTX_NIC_RX_ID] = nic_channel;
2009                psched->context[ltid].slot[CTX_CMA_RX_ID] = cma_channel;
2010            }
2011        }
2012        else // is_tx
2013        {
2014            if ( (psched->context[ltid].slot[CTX_NIC_TX_ID] < NB_NIC_CHANNELS) ||
2015                 (psched->context[ltid].slot[CTX_CMA_TX_ID] < NB_CMA_CHANNELS) )
2016            {
2017                _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
2018                        "NIC_TX or CMA_TX channel already allocated for thread %x\n", trdid );
2019                _nic_tx_channel_alloc[nic_channel] = 0;
2020                _cma_channel_alloc[cma_channel]    = 0;
2021
2022                return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
2023            }
2024            else
2025            {
2026                psched->context[ltid].slot[CTX_NIC_TX_ID] = nic_channel;
2027                psched->context[ltid].slot[CTX_CMA_TX_ID] = cma_channel;
2028            }
2029        }
2030    }  // end loop on threads
2031
2032    /////////////////////////////////////////////////////////////////////////////////
2033    // Step 2: loop on all the clusters                                            //
2034    // Allocate the kernel containers and status, compute the container and the    //
2035    // status physical addresses, fill and synchronize the kernel CHBUF descriptor //
2036    /////////////////////////////////////////////////////////////////////////////////
2037
2038    // physical addresses to be registered in the CMA registers
2039    unsigned long long nic_chbuf_pbase;     // NIC chbuf physical address
2040    unsigned long long ker_chbuf_pbase;     // kernel chbuf physical address
2041
2042    // allocate one kernel container and one status variable per cluster in the
2043    // (xmax / ymax) mesh
2044    unsigned int        cx;                 // cluster X coordinate
2045    unsigned int        cy;                 // cluster Y coordinate
2046    unsigned int        index;              // container index in chbuf
2047    unsigned int        vaddr;              // virtual address
2048    unsigned long long  cont_paddr;         // container physical address
2049    unsigned long long  sts_paddr;          // container status physical address
2050
2051    unsigned int        flags;              // for _v2p_translate()
2052
2053    for ( cx = 0 ; cx < xmax ; cx++ )
2054    {
2055        for ( cy = 0 ; cy < ymax ; cy++ )
2056        {
2057            // compute index in chbuf
2058            index = (cx * ymax) + cy; 
2059
2060            // allocate the kernel container
2061            vaddr = (unsigned int)_remote_malloc( NIC_CONTAINER_SIZE, cx, cy );
2062
2063            if ( vaddr == 0 )  // not enough kernel heap memory in cluster[cx,cy]
2064            {
2065                _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
2066                        "not enough kernel heap in cluster[%d,%d]\n", cx, cy );
2067
2068                return SYSCALL_OUT_OF_KERNEL_HEAP_MEMORY;
2069            }
2070
2071            // compute container physical address
2072            cont_paddr = _v2p_translate( vaddr , &flags );
2073
2074            // checking container address alignment
2075            if ( cont_paddr & 0x3F )
2076            {
2077                _printf("\n[GIET ERROR] in _sys_nic_alloc() : "
2078                        "container address in cluster[%d,%d] not aligned\n", cx, cy);
2079
2080                return SYSCALL_ADDRESS_NON_ALIGNED;
2081            }
2082
2083#if GIET_DEBUG_NIC
2084_printf("\n[DEBUG NIC] _sys_nic_alloc() at cycle %d\n"
2085        "thread %x allocates a container in cluster[%d,%d] / vaddr = %x / paddr = %l\n",
2086        -get_proctime() , trdid , cx , cy , vaddr, cont_paddr );
2087#endif
2088
2089            // allocate the kernel container status
2090            // it occupies 64 bytes but only last bit is useful (1 for full and 0 for empty)
2091            vaddr = (unsigned int)_remote_malloc( 64, cx, cy );
2092
2093            if ( vaddr == 0 )  // not enough kernel heap memory in cluster[cx,cy]
2094            {
2095                _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
2096                        "not enough kernel heap in cluster[%d,%d]\n", cx, cy );
2097
2098                return SYSCALL_OUT_OF_KERNEL_HEAP_MEMORY;
2099            }
2100
2101            // compute status physical address
2102            sts_paddr = _v2p_translate( vaddr , &flags );
2103
2104            // checking status address alignment
2105            if ( sts_paddr & 0x3F )
2106            {
2107                _printf("\n[GIET ERROR] in _sys_nic_alloc() : "
2108                        "status address in cluster[%d,%d] not aligned\n", cx, cy);
2109
2110                return SYSCALL_ADDRESS_NON_ALIGNED;
2111            }
2112
2113            // initialize chbuf entry
2114            // The buffer descriptor has the following structure:
2115            // - the 26 LSB bits contain bits[6:31] of the buffer physical address
2116            // - the 26 following bits contain bits[6:31] of the physical address where the
2117            //   buffer status is located
2118            // - the 12 MSB bits contain the common address extension of the buffer and its
2119            //   status
2120            if ( is_rx )
2121                _nic_ker_rx_chbuf[nic_channel].buf_desc[index] =
2122                    (unsigned long long)
2123                    ((sts_paddr & 0xFFFFFFFFULL) >> 6) +
2124                    (((cont_paddr & 0xFFFFFFFFFFFULL) >> 6) << 26);
2125            else
2126                _nic_ker_tx_chbuf[nic_channel].buf_desc[index] =
2127                    (unsigned long long)
2128                    ((sts_paddr & 0xFFFFFFC0ULL) >> 6) +
2129                    (((cont_paddr & 0xFFFFFFFFFC0ULL) >> 6) << 26);
2130
2131#if GIET_DEBUG_NIC
2132_printf("\n[DEBUG NIC] _sys_nic_alloc() at cycle %d\n"
2133        "thread %x allocates a status in cluster[%d,%d] / vaddr = %x / paddr = %l\n"
2134        "   descriptor = %l\n",
2135        _get_proctime() , trdid , cx , cy , vaddr, sts_paddr,
2136        (unsigned long long)((sts_paddr & 0xFFFFFFFFULL) >> 6) + 
2137        (((cont_paddr & 0xFFFFFFFFFFFULL) >> 6) << 26) );
2138#endif
2139        }
2140    }
2141
2142    // complete kernel chbuf initialisation
2143    if ( is_rx )
2144    {
2145        _nic_ker_rx_chbuf[nic_channel].xmax = xmax;
2146        _nic_ker_rx_chbuf[nic_channel].ymax = ymax;
2147    }
2148    else
2149    {
2150        _nic_ker_tx_chbuf[nic_channel].xmax = xmax;
2151        _nic_ker_tx_chbuf[nic_channel].ymax = ymax;
2152    }
2153
2154    // compute the kernel chbuf descriptor physical address
2155    if ( is_rx ) vaddr = (unsigned int)( &_nic_ker_rx_chbuf[nic_channel] );
2156    else         vaddr = (unsigned int)( &_nic_ker_tx_chbuf[nic_channel] );
2157
2158    ker_chbuf_pbase = _v2p_translate( vaddr , &flags );
2159
2160#if GIET_DEBUG_NIC
2161_printf("\n[DEBUG NIC] _sys_nic_alloc() at cycle %d\n"
2162        "thread %x initialise kernel chbuf / vaddr = %x / paddr = %l\n",
2163        _get_proctime() , trdid , vaddr , ker_chbuf_pbase );
2164#endif
2165
2166    // sync the kernel chbuf in L2 after write in L2
2167    _mmc_sync( ker_chbuf_pbase, sizeof( nic_chbuf_t ) );
2168
2169    ///////////////////////////////////////////////////////////////
2170    // Step 3: compute the NIC chbuf descriptor physical address //
2171    ///////////////////////////////////////////////////////////////
2172
2173    unsigned int offset;
2174    if ( is_rx ) offset = 0x4100;
2175    else         offset = 0x4110;
2176    nic_chbuf_pbase = (((unsigned long long)((X_IO << Y_WIDTH) + Y_IO))<<32) |
2177                      (SEG_NIC_BASE + (nic_channel<<15) + offset);
2178
2179#if GIET_DEBUG_NIC
2180_printf("\n[DEBUG NIC] _sys_nic_alloc() at cycle %d\n"
2181        "thread %x get NIC chbuf paddr = %l\n",
2182        _get_proctime() , trdid , nic_chbuf_pbase );
2183#endif
2184
2185    ////////////////////////////////////////////////////////////////////////////////
2186    // Step 4: initialize CMA registers defining the source & destination chbufs //
2187    ////////////////////////////////////////////////////////////////////////////////
2188
2189    if ( is_rx )               // NIC to kernel
2190    {
2191        _cma_set_register( cma_channel, CHBUF_SRC_DESC , (unsigned int)(nic_chbuf_pbase) );
2192        _cma_set_register( cma_channel, CHBUF_SRC_EXT  , (unsigned int)(nic_chbuf_pbase>>32) );
2193        _cma_set_register( cma_channel, CHBUF_SRC_NBUFS, 2 );
2194        _cma_set_register( cma_channel, CHBUF_DST_DESC , (unsigned int)(ker_chbuf_pbase) );
2195        _cma_set_register( cma_channel, CHBUF_DST_EXT  , (unsigned int)(ker_chbuf_pbase>>32) );
2196        _cma_set_register( cma_channel, CHBUF_DST_NBUFS, xmax * ymax );
2197    }
2198    else                      // kernel to NIC
2199    {
2200        _cma_set_register( cma_channel, CHBUF_SRC_DESC , (unsigned int)(ker_chbuf_pbase) );
2201        _cma_set_register( cma_channel, CHBUF_SRC_EXT  , (unsigned int)(ker_chbuf_pbase>>32) );
2202        _cma_set_register( cma_channel, CHBUF_SRC_NBUFS, xmax * ymax );
2203        _cma_set_register( cma_channel, CHBUF_DST_DESC , (unsigned int)(nic_chbuf_pbase) );
2204        _cma_set_register( cma_channel, CHBUF_DST_EXT  , (unsigned int)(nic_chbuf_pbase>>32) );
2205        _cma_set_register( cma_channel, CHBUF_DST_NBUFS, 2 );
2206    }
2207
2208#if GIET_DEBUG_NIC
2209_printf("\n[DEBUG NIC] _sys_nic_alloc() at cycle %d\n"
2210        "thread %x exit\n", 
2211        _get_proctime() , trdid );
2212#endif
2213
2214    return SYSCALL_OK;
2215} // end _sys_nic_alloc()
2216
2217
2218//////////////////////////////////////////
2219int _sys_nic_release( unsigned int is_rx )     // NOTE: not a syscall: used by _ctx_kill_thread()
2220{
2221    unsigned int trdid = _get_thread_trdid();
2222
2223    unsigned int nic_channel;
2224    unsigned int cma_channel;
2225   
2226    // update the kernel tables
2227    if ( is_rx )
2228    {
2229        nic_channel = _get_context_slot( CTX_NIC_RX_ID );
2230        cma_channel = _get_context_slot( CTX_CMA_RX_ID );
2231
2232        if ( (nic_channel >= NB_NIC_CHANNELS) )
2233        {
2234            _printf("\n[GIET ERROR] in _sys_nic_release() : "
2235                    "NIC_RX channel already released for thread %x\n", trdid );
2236
2237            return SYSCALL_CHANNEL_NON_ALLOCATED;
2238        }
2239        if ( (cma_channel >= NB_CMA_CHANNELS) )
2240        {
2241            _printf("\n[GIET ERROR] in _sys_nic_release() : "
2242                    "CMA_RX channel already released for thread %x\n", trdid );
2243
2244            return SYSCALL_CHANNEL_NON_ALLOCATED;
2245        }
2246
2247        // atomically decrement the NIC and CMA channel allocators
2248        _atomic_increment( &_nic_rx_channel_alloc[nic_channel] , -1 );
2249        _atomic_increment( &_cma_channel_alloc[cma_channel] , -1 );
2250   
2251        // stop the NIC and CMA peripherals channels if no more users
2252        if ( (_nic_rx_channel_alloc[nic_channel] == 0) &&
2253             (_cma_channel_alloc[cma_channel] == 0) )  _sys_nic_stop( 1 );
2254
2255        // reset the calling thread context slots
2256        _set_context_slot( CTX_NIC_RX_ID , 0xFFFFFFFF );
2257        _set_context_slot( CTX_CMA_RX_ID , 0xFFFFFFFF );
2258    }         
2259    else
2260    {
2261        nic_channel = _get_context_slot( CTX_NIC_TX_ID );
2262        cma_channel = _get_context_slot( CTX_CMA_TX_ID );
2263
2264        if ( (nic_channel >= NB_NIC_CHANNELS) )
2265        {
2266            _printf("\n[GIET ERROR] in _sys_nic_release() : "
2267                    "NIC_TX channel already released for thread %x\n", trdid );
2268
2269            return SYSCALL_CHANNEL_NON_ALLOCATED;
2270        }
2271        if ( (cma_channel >= NB_CMA_CHANNELS) )
2272        {
2273            _printf("\n[GIET ERROR] in _sys_nic_release() : "
2274                    "CMA_TX channel already released for thread %x\n", trdid );
2275
2276            return SYSCALL_CHANNEL_NON_ALLOCATED;
2277        }
2278
2279        // atomically decrement the NIC and CMA channel allocators
2280        _atomic_increment( &_nic_tx_channel_alloc[nic_channel] , -1 );
2281        _atomic_increment( &_cma_channel_alloc[cma_channel] , -1 );
2282   
2283        // stop the NIC and CMA peripherals channels if no more users
2284        if ( (_nic_tx_channel_alloc[nic_channel] == 0) &&
2285             (_cma_channel_alloc[cma_channel] == 0) )  _sys_nic_stop( 0 );
2286
2287        // reset the calling thread context slots
2288        _set_context_slot( CTX_NIC_TX_ID , 0xFFFFFFFF );
2289        _set_context_slot( CTX_CMA_TX_ID , 0xFFFFFFFF );
2290    }
2291
2292    return SYSCALL_OK;
2293}  // end sys_nic_release()
2294
2295
2296////////////////////////////////////////
2297int _sys_nic_start( unsigned int is_rx )
2298{
2299    unsigned int trdid  = _get_context_slot( CTX_TRDID_ID );
2300
2301    unsigned int nic_channel;
2302    unsigned int cma_channel;
2303
2304    // get NIC channel index and CMA channel index from thread context
2305    if ( is_rx )
2306    {
2307        nic_channel = _get_context_slot( CTX_NIC_RX_ID );
2308        cma_channel = _get_context_slot( CTX_CMA_RX_ID );
2309    }
2310    else
2311    {
2312        nic_channel = _get_context_slot( CTX_NIC_TX_ID );
2313        cma_channel = _get_context_slot( CTX_CMA_TX_ID );
2314    }
2315
2316#if GIET_DEBUG_NIC
2317_printf("\n[DEBUG NIC] _sys_nic_start() at cycle %d\n"
2318        "thread %x enter / NIC channel = %d / CMA channel = %d\n",
2319        _get_proctime() , trdid , nic_channel, cma_channel );
2320#endif
2321
2322    // check NIC and CMA channels index
2323    if ( nic_channel >= NB_NIC_CHANNELS )
2324    {
2325        _printf("\n[GIET_ERROR] in _sys_nic_start() : "
2326                "illegal NIC channel for thread %x\n", trdid );
2327        return -1111;
2328    }
2329    if ( cma_channel >= NB_CMA_CHANNELS )
2330    {
2331        _printf("\n[GIET_ERROR] in _sys_nic_start() : "
2332                "illegal CMA channel for thread %x\n", trdid );
2333        return -1111;
2334    }
2335
2336    // start CMA transfer
2337    _cma_set_register( cma_channel, CHBUF_BUF_SIZE , NIC_CONTAINER_SIZE );
2338    _cma_set_register( cma_channel, CHBUF_PERIOD   , 0 );                  // OUT_OF_ORDER
2339    _cma_set_register( cma_channel, CHBUF_RUN      , MODE_NORMAL );
2340
2341    // activates NIC channel
2342    _nic_channel_start( nic_channel, is_rx, GIET_NIC_MAC4, GIET_NIC_MAC2 );
2343
2344#if GIET_DEBUG_NIC
2345    _printf("\n[DEBUG NIC] _sys_nic_start() at cycle %d\n"
2346            "thread %d exit\n",
2347            _get_proctime() , trdid );
2348#endif
2349
2350    return SYSCALL_OK;
2351}  // end _sys_nic_start()
2352
2353
2354//////////////////////////////////////
2355int _sys_nic_move( unsigned int is_rx,
2356                   void*        buffer )
2357{
2358    unsigned int trdid  = _get_context_slot( CTX_TRDID_ID );
2359
2360    unsigned int channel;
2361
2362#if GIET_DEBUG_NIC
2363_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n",
2364        "thread %x enters\n",
2365        _get_proctime() , trdid );
2366#endif
2367
2368    // get NIC channel index from thread context
2369    if ( is_rx )  channel = _get_context_slot( CTX_NIC_RX_ID );
2370    else          channel = _get_context_slot( CTX_NIC_TX_ID );
2371
2372    // check NIC channel index
2373    if ( channel >= NB_NIC_CHANNELS )
2374    {
2375        _printf("\n[GIET_ERROR] in _sys_nic_move() : "
2376                "NIC channel non allocated for thread %x\n", trdid );
2377
2378        return SYSCALL_CHANNEL_NON_ALLOCATED;
2379    }
2380
2381    // get kernel chbuf virtual address
2382    nic_chbuf_t* ker_chbuf;
2383    if ( is_rx )  ker_chbuf = &_nic_ker_rx_chbuf[channel];
2384    else          ker_chbuf = &_nic_ker_tx_chbuf[channel];
2385
2386    // get xmax / ymax parameters
2387    unsigned int xmax = ker_chbuf->xmax;
2388    unsigned int ymax = ker_chbuf->ymax;
2389
2390    // get cluster coordinates for the processor running the calling thread
2391    unsigned int  procid = _get_procid();
2392    unsigned int  cx     = procid >> (Y_WIDTH + P_WIDTH);
2393    unsigned int  cy     = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
2394   
2395    // check processor coordinates / (xmax,ymax)
2396    if ( (cx >= xmax) || (cy >= ymax) )
2397    {
2398        _printf("\n[GIET_ERROR] in _sys_nic_move(): "
2399         "processor coordinates [%d,%d] larger than (xmax,ymax) = [%d,%d]\n",
2400         cx , cy , xmax , ymax );
2401
2402        return SYSCALL_ILLEGAL_ARGUMENT;
2403    }
2404   
2405    unsigned long long usr_buf_paddr;       // user buffer physical address
2406    unsigned long long ker_buf_paddr;       // kernel buffer physical address
2407    unsigned long long ker_sts_paddr;       // kernel buffer status physical address
2408    unsigned long long ker_buf_desc;        // kernel buffer descriptor
2409    unsigned int       ker_sts;             // kernel buffer status (full or empty)
2410    unsigned int       index;               // kernel buffer index in chbuf
2411    unsigned int       flags;               // for _v2P_translate
2412
2413    // Compute user buffer physical address and check access rights
2414    usr_buf_paddr = _v2p_translate( (unsigned int)buffer , &flags );
2415
2416    if ( (flags & PTE_U) == 0 )
2417    {
2418        _printf("\n[GIET ERROR] in _sys_nic_tx_move() : "
2419                "buffer address non user accessible\n");
2420
2421        return SYSCALL_ADDRESS_NON_USER_ACCESSIBLE;
2422    }
2423
2424#if GIET_DEBUG_NIC
2425_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2426        "thread %x get user buffer : paddr = %l\n",
2427        _get_proctime() , trdid , usr_buf_paddr );
2428#endif
2429
2430    // compute buffer index, buffer descriptor paddr and buffer status paddr
2431    index = (ymax * cx) + cy;
2432    ker_buf_desc = ker_chbuf->buf_desc[index];
2433    ker_sts_paddr = ((ker_buf_desc & 0xFFF0000000000000ULL) >> 20) +
2434                    ((ker_buf_desc & 0x3FFFFFFULL) << 6);
2435
2436#if GIET_DEBUG_NIC
2437_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2438        "thread %x get ker_buf_desc %d / paddr = %l\n",
2439        _get_proctime(), trdid , index , ker_buf_desc );
2440#endif
2441
2442    // poll local kernel container status until success
2443    while ( 1 )
2444    {
2445        // inval buffer descriptor in L2 before read in L2
2446        _mmc_inval( ker_sts_paddr, 4 );
2447        ker_sts = _physical_read( ker_sts_paddr );
2448
2449#if GIET_DEBUG_NIC
2450_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2451        "thread %x get status %d /  paddr = %l / status = %x\n",
2452        _get_proctime() , trdid , index , ker_sts_paddr, ker_sts );
2453#endif
2454
2455        // test buffer status and break if found
2456        if ( ( is_rx != 0 ) && ( ker_sts == 0x1 ) ) break;
2457        if ( ( is_rx == 0 ) && ( ker_sts == 0 ) ) break;
2458    }
2459
2460    // compute kernel buffer physical address
2461    ker_buf_paddr = (ker_buf_desc & 0xFFFFFFFFFC000000ULL) >> 20;
2462   
2463    // move one container
2464    if ( is_rx )              // RX transfer
2465    {
2466        // inval kernel buffer in L2 before read in L2
2467        _mmc_inval( ker_buf_paddr, NIC_CONTAINER_SIZE );
2468
2469        // transfer data from kernel buffer to user buffer
2470        _physical_memcpy( usr_buf_paddr, 
2471                          ker_buf_paddr, 
2472                          NIC_CONTAINER_SIZE );
2473#if GIET_DEBUG_NIC
2474_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2475        "thread %x transfer kernel buffer %l to user buffer %l\n",
2476        _get_proctime() , trdid , ker_buf_paddr , usr_buf_paddr );
2477#endif
2478
2479    }
2480    else                      // TX transfer
2481    {
2482        // transfer data from user buffer to kernel buffer
2483        _physical_memcpy( ker_buf_paddr, 
2484                          usr_buf_paddr, 
2485                          NIC_CONTAINER_SIZE );
2486
2487        // sync kernel buffer in L2 after write in L2
2488        _mmc_sync( ker_buf_paddr, NIC_CONTAINER_SIZE );
2489
2490#if GIET_DEBUG_NIC
2491_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2492        "thread %x transfer user buffer %l to kernel buffer %l\n",
2493        _get_proctime() , trdid , usr_buf_paddr , ker_buf_paddr );
2494#endif
2495
2496    }
2497
2498    // update kernel chbuf status
2499    if ( is_rx ) _physical_write ( ker_sts_paddr, 0 );
2500    else         _physical_write ( ker_sts_paddr, 0x1 );
2501
2502    // sync kernel chbuf in L2 after write in L2
2503    _mmc_sync( ker_sts_paddr, 4 );
2504
2505#if GIET_DEBUG_NIC
2506_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2507        "thread %x exit\n",
2508        _get_proctime() , trdid );
2509#endif
2510
2511    return SYSCALL_OK;
2512} // end _sys_nic_move()
2513
2514
2515///////////////////////////////////////
2516int _sys_nic_stop( unsigned int is_rx )
2517{
2518    unsigned int trdid  = _get_context_slot( CTX_TRDID_ID );
2519
2520    unsigned int nic_channel;
2521    unsigned int cma_channel;
2522
2523    // get NIC channel index and CMA channel index
2524    if ( is_rx )
2525    {
2526        nic_channel = _get_context_slot( CTX_NIC_RX_ID );
2527        cma_channel = _get_context_slot( CTX_CMA_RX_ID );
2528    }
2529    else
2530    {
2531        nic_channel = _get_context_slot( CTX_NIC_TX_ID );
2532        cma_channel = _get_context_slot( CTX_CMA_TX_ID );
2533    }
2534
2535    // check NIC and CMA channels index
2536    if ( nic_channel >= NB_NIC_CHANNELS )
2537    {
2538        _printf("\n[GIET_ERROR] in _sys_nic_stop() : " 
2539                "NIC channel non allocated for thread %x\n", trdid );
2540
2541        return SYSCALL_CHANNEL_NON_ALLOCATED;
2542    }
2543    if ( cma_channel >= NB_CMA_CHANNELS )
2544    {
2545        _printf("\n[GIET_ERROR] in _sys_nic_stop() : "
2546                "CMA channel non allocated for thread %x\n", trdid );
2547 
2548        return SYSCALL_CHANNEL_NON_ALLOCATED;
2549    }
2550
2551    // desactivates the CMA channel
2552    _cma_set_register( cma_channel, CHBUF_RUN , MODE_IDLE );
2553
2554    // wait until CMA channel IDLE
2555    unsigned int volatile status;
2556    do
2557    {
2558         status = _cma_get_register( cma_channel, CHBUF_STATUS );
2559    } 
2560    while ( status ); 
2561
2562    // desactivates the NIC channel
2563    _nic_channel_stop( nic_channel, is_rx );
2564
2565    return SYSCALL_OK;
2566}  // end _sys_nic_stop()
2567
2568////////////////////////////////////////
2569int _sys_nic_clear( unsigned int is_rx )
2570{
2571    unsigned int trdid  = _get_context_slot( CTX_TRDID_ID );
2572
2573    unsigned int channel;
2574
2575    // get NIC channel
2576    if ( is_rx )  channel = _get_context_slot( CTX_NIC_RX_ID );
2577    else          channel = _get_context_slot( CTX_NIC_TX_ID );
2578
2579    if ( channel >= NB_NIC_CHANNELS )
2580    {
2581        _printf("\n[GIET_ERROR] in _sys_nic_clear() : "
2582                "NIC channel non allocated for thread %x\n", trdid );
2583
2584        return SYSCALL_CHANNEL_NON_ALLOCATED;
2585    }
2586
2587    if ( is_rx )
2588    {
2589        _nic_set_global_register( NIC_G_NPKT_RX_G2S_RECEIVED       , 0 );
2590        _nic_set_global_register( NIC_G_NPKT_RX_DES_TOO_SMALL      , 0 );
2591        _nic_set_global_register( NIC_G_NPKT_RX_DES_TOO_BIG        , 0 );
2592        _nic_set_global_register( NIC_G_NPKT_RX_DES_MFIFO_FULL     , 0 );
2593        _nic_set_global_register( NIC_G_NPKT_RX_DES_CRC_FAIL       , 0 );
2594        _nic_set_global_register( NIC_G_NPKT_RX_DISPATCH_RECEIVED  , 0 );
2595        _nic_set_global_register( NIC_G_NPKT_RX_DISPATCH_BROADCAST , 0 );
2596        _nic_set_global_register( NIC_G_NPKT_RX_DISPATCH_DST_FAIL  , 0 );
2597        _nic_set_global_register( NIC_G_NPKT_RX_DISPATCH_CH_FULL   , 0 );
2598    } 
2599    else
2600    {
2601        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_RECEIVED  , 0 );
2602        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_TRANSMIT  , 0 );
2603        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_TOO_BIG   , 0 );
2604        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_TOO_SMALL , 0 );
2605        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_SRC_FAIL  , 0 );
2606        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_BYPASS    , 0 );
2607        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_BROADCAST , 0 );
2608    }
2609    return SYSCALL_OK;
2610}  // en _sys_nic_clear()
2611
2612////////////////////////////////////////
2613int _sys_nic_stats( unsigned int is_rx )
2614{
2615    unsigned int trdid  = _get_context_slot( CTX_TRDID_ID );
2616
2617    unsigned int nic_channel;
2618
2619    // get NIC channel
2620    if ( is_rx )  nic_channel = _get_context_slot( CTX_NIC_RX_ID );
2621    else          nic_channel = _get_context_slot( CTX_NIC_TX_ID );
2622
2623    if ( nic_channel >= NB_NIC_CHANNELS )
2624    {
2625        _printf("\n[GIET_ERROR] in _sys_nic_stats() : "
2626                "NIC channel non allocated for thread %x\n", trdid );
2627
2628        return SYSCALL_CHANNEL_NON_ALLOCATED;
2629    }
2630
2631    if ( is_rx )
2632    {
2633        unsigned int received   = _nic_get_global_register( NIC_G_NPKT_RX_G2S_RECEIVED       );
2634        unsigned int too_small  = _nic_get_global_register( NIC_G_NPKT_RX_DES_TOO_SMALL      );
2635        unsigned int too_big    = _nic_get_global_register( NIC_G_NPKT_RX_DES_TOO_BIG        );
2636        unsigned int fifo_full  = _nic_get_global_register( NIC_G_NPKT_RX_DES_MFIFO_FULL     );
2637        unsigned int crc_fail   = _nic_get_global_register( NIC_G_NPKT_RX_DES_CRC_FAIL       );
2638        unsigned int broadcast  = _nic_get_global_register( NIC_G_NPKT_RX_DISPATCH_BROADCAST );
2639        unsigned int dst_fail   = _nic_get_global_register( NIC_G_NPKT_RX_DISPATCH_DST_FAIL  );
2640        unsigned int ch_full    = _nic_get_global_register( NIC_G_NPKT_RX_DISPATCH_CH_FULL   );
2641
2642        _printf("\n### Network Controller RX Statistics ###\n"
2643                "- packets received : %d\n"
2644                "- too small        : %d\n"
2645                "- too big          : %d\n"
2646                "- fifo full        : %d\n" 
2647                "- crc fail         : %d\n" 
2648                "- dst mac fail     : %d\n" 
2649                "- channel full     : %d\n" 
2650                "- broadcast        : %d\n",
2651                received,
2652                too_small,
2653                too_big,
2654                fifo_full,
2655                crc_fail,
2656                dst_fail,
2657                ch_full,
2658                broadcast );
2659    } 
2660    else
2661    {
2662        unsigned int received   = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_RECEIVED  );
2663        unsigned int too_big    = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_TOO_BIG   );
2664        unsigned int too_small  = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_TOO_SMALL );
2665        unsigned int src_fail   = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_SRC_FAIL  );
2666        unsigned int bypass     = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_BYPASS    );
2667        unsigned int broadcast  = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_BROADCAST );
2668
2669        _printf("\n### Network Controller TX Statistics ###\n"
2670                "- packets received : %d\n"
2671                "- too small        : %d\n"
2672                "- too big          : %d\n"
2673                "- src mac fail     : %d\n" 
2674                "- bypass           : %d\n" 
2675                "- broadcast        : %d\n",
2676                received,
2677                too_big,
2678                too_small,
2679                src_fail,
2680                bypass,
2681                broadcast );
2682    }
2683    return SYSCALL_OK;
2684}  // end _sys_nic_stats()
2685
2686#endif
2687
2688/////////////////////////////////////////////////////////////////////////////////////////
2689//    FBF related syscall handlers
2690/////////////////////////////////////////////////////////////////////////////////////////
2691
2692//////////////////////////////////////
2693int _sys_fbf_size( unsigned int* width,
2694                   unsigned int* height )
2695{
2696    if ( USE_FBF == 0 )
2697    {
2698        *width  = 0;
2699        *height = 0;
2700    }
2701    else
2702    {
2703        *width  = FBUF_X_SIZE;
2704        *height = FBUF_Y_SIZE;
2705    }
2706
2707    return SYSCALL_OK;
2708}
2709
2710////////////////////
2711int _sys_fbf_alloc()
2712{
2713    mapping_header_t  *header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
2714    mapping_vspace_t  *vspace   = _get_vspace_base(header);
2715    mapping_thread_t  *thread   = _get_thread_base(header);
2716   
2717    // compute number of users
2718    unsigned int   vsid  = _get_context_slot(CTX_VSID_ID);
2719    unsigned int   users = vspace[vsid].threads;
2720
2721    // access FBF allocator
2722    // register it in all threads contexts
2723    if ( _atomic_test_and_set( &_fbf_alloc , users ) == 0 )     // FBF available   
2724    {
2725        unsigned int   min   = vspace[vsid].thread_offset;
2726        unsigned int   max   = min + users;
2727        unsigned int   tid;
2728        for ( tid = min ; tid < max ; tid++ )
2729        {
2730            unsigned int y_size        = header->y_size;
2731            unsigned int cid           = thread[tid].clusterid;
2732            unsigned int x             = cid / y_size;
2733            unsigned int y             = cid % y_size;
2734            unsigned int p             = thread[tid].proclocid;
2735            unsigned int ltid          = thread[tid].ltid;
2736            static_scheduler_t* psched = (static_scheduler_t*)_schedulers[x][y][p];
2737            _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FBF ); 
2738        }
2739        return SYSCALL_OK;
2740    }
2741    else                                                       // FBF already allocated
2742    {
2743        return SYSCALL_SHARED_PERIPHERAL_BUSY;
2744    }
2745}
2746
2747//////////////////////
2748int _sys_fbf_release()    // not a syscall: used by _ctx_kill_thread()
2749{
2750    // get calling thread scheduler, ltid and trdid
2751    static_scheduler_t*  psched = _get_sched();
2752    unsigned int         ltid   = _get_thread_ltid();
2753    unsigned int         trdid  = _get_thread_trdid();
2754
2755    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
2756    {
2757        _printf("\n[GIET ERROR] in _sys_fbf_release() : "
2758                "FBF not allocated to thread %x\n", trdid );
2759
2760        return SYSCALL_CHANNEL_NON_ALLOCATED;
2761    }
2762
2763    // decrement FBF allocator
2764    // reset the calling thread context
2765    _atomic_increment( &_fbf_alloc , 0xFFFFFFFF );
2766    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FBF ); 
2767
2768    return SYSCALL_OK;   
2769}
2770
2771/////////////////////////////////////////////
2772int _sys_fbf_sync_write( unsigned int offset,
2773                         void*        buffer,
2774                         unsigned int length )
2775{
2776    // get calling thread scheduler, ltid and trdid
2777    static_scheduler_t*  psched = _get_sched();
2778    unsigned int         ltid   = _get_thread_ltid();
2779    unsigned int         trdid  = _get_thread_trdid();
2780
2781    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
2782    {
2783        _printf("\n[GIET ERROR] in _sys_fbf_release() : "
2784                "FBF not allocated to thread %x\n", trdid );
2785
2786        return SYSCALL_CHANNEL_NON_ALLOCATED;
2787    }
2788
2789    char* fbf_address = (char *)SEG_FBF_BASE + offset;
2790    memcpy( fbf_address, buffer, length);
2791
2792    return SYSCALL_OK;
2793}
2794
2795/////////////////////////////////////////////
2796int _sys_fbf_sync_read(  unsigned int offset,
2797                         void*        buffer,
2798                         unsigned int length )
2799{
2800    // get calling thread scheduler, ltid and trdid
2801    static_scheduler_t*  psched = _get_sched();
2802    unsigned int         ltid   = _get_thread_ltid();
2803    unsigned int         trdid  = _get_thread_trdid();
2804
2805    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
2806    {
2807        _printf("\n[GIET ERROR] in _sys_fbf_release() : "
2808                "FBF not allocated to thread %x\n", trdid );
2809
2810        return SYSCALL_CHANNEL_NON_ALLOCATED;
2811    }
2812
2813    char* fbf_address = (char *)SEG_FBF_BASE + offset;
2814    memcpy( buffer, fbf_address, length);
2815
2816    return SYSCALL_OK;
2817}
2818
2819////////////////////////////////////////////
2820int _sys_fbf_cma_alloc( unsigned int nbufs )
2821{
2822    // compute trdid and vsid for the calling thread
2823    unsigned int vsid  = _get_context_slot( CTX_VSID_ID );
2824    unsigned int trdid = _get_thread_trdid();
2825
2826    if ( _get_context_slot( CTX_CMA_FB_ID ) < NB_CMA_CHANNELS )
2827    {
2828        _printf("\n[GIET ERROR] in _sys_fbf_cma_alloc() : "
2829                "CMA channel already allocated for thread %x\n", trdid );
2830        return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
2831    }
2832
2833    // compute number of threads in vspace from mapping
2834    mapping_header_t  *header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
2835    mapping_vspace_t  *vspace   = _get_vspace_base(header);
2836    mapping_thread_t  *thread   = _get_thread_base(header);
2837    unsigned int      first     = vspace[vsid].thread_offset;
2838    unsigned int      threads   = vspace[vsid].threads;
2839
2840    // get a CMA channel
2841    unsigned int channel;
2842    for ( channel = 0 ; channel < NB_CMA_CHANNELS ; channel++ )
2843    {
2844        unsigned int*  palloc = &_cma_channel_alloc[channel];
2845        if ( _atomic_test_and_set( palloc , threads ) == 0 ) break;
2846    }
2847
2848    if ( channel >= NB_CMA_CHANNELS )
2849    {
2850        _printf("\n[GIET ERROR] in _sys_fbf_cma_alloc() : no CMA channel available\n");
2851        return SYSCALL_NO_CHANNEL_AVAILABLE;
2852    }
2853
2854    // check nbufs argument
2855    if ( nbufs > 256 )
2856    {
2857        _printf("\n[GIET ERROR] in _sys_fbf_cma_alloc() : nbufs larger than 256\n");
2858        return SYSCALL_ILLEGAL_ARGUMENT;
2859    }
2860
2861    // loop on all threads to register channel in thread contexts
2862    unsigned int      tid;
2863    for ( tid = first ; tid < (first + threads) ; tid++ )
2864    {
2865        unsigned int         y_size = header->y_size;
2866        unsigned int         cid    = thread[tid].clusterid;
2867        unsigned int         x      = cid / y_size;
2868        unsigned int         y      = cid % y_size;
2869        unsigned int         p      = thread[tid].proclocid;
2870        unsigned int         ltid   = thread[tid].ltid;
2871        static_scheduler_t* psched  = (static_scheduler_t*)_schedulers[x][y][p];
2872        psched->context[ltid].slot[CTX_CMA_FB_ID] = channel; 
2873    }
2874
2875    unsigned int vaddr;
2876    unsigned int flags;
2877
2878    // compute frame buffer physical addresses
2879    vaddr = (unsigned int)SEG_FBF_BASE;
2880    unsigned long long fbf_buf_paddr = _v2p_translate( vaddr , &flags );
2881
2882    // initialize the FBF chbuf
2883    // we don't register a status address in the fbf_desc, because
2884    // the CMA does not test the status for the frame buffer (no synchro)
2885    _fbf_ker_chbuf.nbufs    = nbufs;
2886    _fbf_ker_chbuf.fbf_desc = (((fbf_buf_paddr & 0xFFFFFFFFFFFULL) >> 6 ) << 26);
2887
2888    // register FBF chbuf physical address
2889    vaddr = (unsigned int)(&_fbf_ker_chbuf);
2890    _fbf_chbuf_paddr = _v2p_translate( vaddr , &flags );
2891
2892#if GIET_DEBUG_FBF_CMA
2893_printf("\n[FBF_CMA DEBUG] _sys_fbf_cma_alloc()\n"
2894        " - channel               = %d\n"
2895        " - vaddr(_ker_fbf_chbuf) = %x\n"
2896        " - paddr(_ker_fbf_chbuf) = %l\n"
2897        " - nbufs                 = %d\n" 
2898        " - fbf_desc              = %l\n",
2899        channel , vaddr , _fbf_chbuf_paddr , nbufs , _fbf_ker_chbuf.fbf_desc );
2900#endif
2901
2902    return SYSCALL_OK;
2903} // end sys_fbf_cma_alloc()
2904
2905//////////////////////////
2906int _sys_fbf_cma_release()  // Not a syscall : used by _ctx_kill_thread()
2907{
2908    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
2909    unsigned int trdid   = _get_thread_trdid();
2910
2911    if ( channel >= NB_CMA_CHANNELS )
2912    {
2913        _printf("\n[GIET_ERROR] in _sys_fbf_cma_release() : "
2914                "CMA_FB channel already released for thread %x\n", trdid );
2915
2916        return SYSCALL_CHANNEL_NON_ALLOCATED;
2917    }
2918
2919    if ( _cma_channel_alloc[channel] == 1 )  // the calling thread is the last user
2920    {
2921        // stop the CMA transfer
2922        _sys_fbf_cma_stop();
2923
2924        // reset the CMA channel allocator
2925        _cma_channel_alloc[channel] = 0;
2926    }
2927    else                                     // not the last user
2928    {
2929        // atomically decrement the CMA channel allocator
2930        _atomic_increment( &_cma_channel_alloc[channel] , -1 );
2931    }
2932
2933    // reset CTX_CMA_FB_ID slot in calling thread context
2934    _set_context_slot( CTX_CMA_FB_ID, 0xFFFFFFFF );
2935
2936    return SYSCALL_OK;
2937} // end _sys_fbf_cma_release()
2938
2939///////////////////////////////////////////////////
2940int _sys_fbf_cma_init_buf( unsigned int index,
2941                           void*        buf_vaddr, 
2942                           void*        sts_vaddr )
2943{
2944    unsigned int       vaddr;           // virtual address
2945    unsigned int       flags;           // for _v2p_translate()
2946    unsigned long long buf_paddr;       // user buffer physical address
2947    unsigned long long sts_paddr;       // user status physical address
2948
2949    // get calling thread scheduler, ltid and trdid
2950    static_scheduler_t*  psched = _get_sched();
2951    unsigned int         ltid   = _get_thread_ltid();
2952    unsigned int         trdid  = _get_thread_trdid();
2953
2954    // check FBF allocated
2955    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
2956    {
2957        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
2958                "FBF not allocated to thread %x\n", trdid );
2959
2960        return SYSCALL_CHANNEL_NON_ALLOCATED;
2961    }
2962
2963    // get channel index
2964    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
2965
2966    if ( channel >= NB_CMA_CHANNELS )
2967    {
2968        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
2969                "CMA channel non allocated to thread %x\n", trdid );
2970
2971        return SYSCALL_CHANNEL_NON_ALLOCATED;
2972    }
2973
2974#if GIET_DEBUG_FBF_CMA
2975_printf("\n[FBF_CMA DEBUG] _sys_fbf_cma_init_buf()\n"
2976        " - channel     = %d / index = %d\n"
2977        " - buf vaddr   = %x\n"
2978        " - sts vaddr   = %x\n",
2979        channel, index,
2980        (unsigned int)buf_vaddr,
2981        (unsigned int)sts_vaddr );
2982#endif
2983
2984    // checking index argument
2985    if ( index >= _fbf_ker_chbuf.nbufs )
2986    {
2987        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
2988                "user buffer index too large %x\n", trdid );
2989
2990        return SYSCALL_CHANNEL_NON_ALLOCATED;
2991    }
2992
2993    // checking user buffer and status addresses alignment
2994    if ( ((unsigned int)buf_vaddr & 0x3F) || ((unsigned int)sts_vaddr & 0x3F) )
2995    {
2996        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
2997                "user buffer or status not aligned for thread %x\n", trdid );
2998
2999        return SYSCALL_ADDRESS_NON_ALIGNED;
3000    }
3001
3002    // Compute user buffer and status physical addresses
3003    vaddr = (unsigned int)buf_vaddr;
3004    buf_paddr = _v2p_translate( vaddr , &flags );
3005    if ((flags & PTE_U) == 0) 
3006    {
3007        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
3008                "buffer not in user space for thread %x\n", trdid );
3009
3010        return SYSCALL_ADDRESS_NON_USER_ACCESSIBLE;
3011    }
3012
3013    vaddr = (unsigned int)sts_vaddr;
3014    sts_paddr = _v2p_translate( vaddr , &flags );
3015    if ((flags & PTE_U) == 0) 
3016    {
3017        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
3018                "status not in user space for thread %x\n", trdid);
3019
3020        return SYSCALL_ADDRESS_NON_USER_ACCESSIBLE;
3021    }
3022
3023    // check user buffer and user status in same cluster
3024    if ( (buf_paddr & 0xFF00000000ULL) != (sts_paddr & 0xFF00000000ULL) ) 
3025    {
3026        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
3027                "user status and buffer not in same cluster for thread %x\n", trdid);
3028
3029        return SYSCALL_ADDRESS_NON_USER_ACCESSIBLE;
3030    }
3031
3032    // initialize _fbf_ker_chbuf.usr_desc[index]
3033    _fbf_ker_chbuf.usr_desc[index] = ((sts_paddr & 0xFFFFFFFFULL) >> 6) +
3034                                     (((buf_paddr & 0xFFFFFFFFFFULL) >> 6 ) << 26);
3035
3036#if GIET_DEBUG_FBF_CMA
3037_printf(" - buf paddr   = %l\n"
3038        " - sts paddr   = %l\n"
3039        " - usr_desc[%d] = %l\n",
3040        buf_paddr,
3041        sts_paddr,
3042        index , _fbf_ker_chbuf.usr_desc[index] );
3043#endif
3044
3045    return SYSCALL_OK;
3046
3047} // end sys_fbf_cma_init_buf()
3048
3049////////////////////////
3050int _sys_fbf_cma_start() 
3051{
3052    // get calling thread scheduler, ltid and trdid
3053    static_scheduler_t*  psched = _get_sched();
3054    unsigned int         ltid   = _get_thread_ltid();
3055    unsigned int         trdid  = _get_thread_trdid();
3056
3057    // check FBF allocated
3058    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
3059    {
3060        _printf("\n[GIET ERROR] in _sys_fbf_release() : "
3061                "FBF not allocated to thread %x\n", trdid );
3062
3063        return SYSCALL_CHANNEL_NON_ALLOCATED;
3064    }
3065
3066    // get CMA channel index
3067    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
3068
3069    if ( channel >= NB_CMA_CHANNELS )
3070    {
3071        _printf("\n[GIET ERROR] in _fbf_cma_start() : "
3072                "CMA channel non allocated\n");
3073
3074        return SYSCALL_CHANNEL_NON_ALLOCATED;
3075    }
3076
3077    // check buffers initialization
3078    if ( _fbf_ker_chbuf.nbufs == 0 )
3079    {
3080        _printf("\n[GIET ERROR] in _sys_fbf_cma_start(): "
3081                "FBF chbuf not initialized for thread %x\n", trdid );
3082
3083        return SYSCALL_MISSING_INITIALISATION;
3084    }
3085
3086    // synchronize FBF chbuf that will be read by CMA peripheral
3087    if ( USE_IOB )
3088    {
3089        // SYNC request for fbf_chbuf descriptor
3090        _mmc_sync( _fbf_chbuf_paddr , sizeof( fbf_chbuf_t ) );
3091    }
3092
3093    // start CMA transfer
3094    unsigned long long paddr = _fbf_chbuf_paddr;
3095    unsigned int dst_chbuf_paddr_lsb = (unsigned int)(paddr & 0xFFFFFFFF);
3096    unsigned int dst_chbuf_paddr_ext = (unsigned int)(paddr >> 32);
3097    unsigned int src_chbuf_paddr_lsb = dst_chbuf_paddr_lsb + 8;
3098    unsigned int src_chbuf_paddr_ext = dst_chbuf_paddr_ext;
3099
3100#if GIET_DEBUG_FBF_CMA
3101_printf("\n[FBF_CMA DEBUG] _sys_fbf_cma_start()\n"
3102        " - src_chbuf_paddr_lsb = %x\n"
3103        " - src_chbuf_paddr_ext = %x\n"
3104        " - src_chbuf_nbufs     = %d\n"
3105        " - dst_chbuf_paddr_lsb = %x\n"
3106        " - dst_chbuf_paddr_ext = %x\n"
3107        " - dst_chbuf_nbufs     = 1 \n"
3108        " - buffer_size         = %d\n",
3109        src_chbuf_paddr_lsb,
3110        src_chbuf_paddr_ext,
3111        _fbf_ker_chbuf.nbufs,
3112        dst_chbuf_paddr_lsb,
3113        dst_chbuf_paddr_ext,
3114        FBUF_X_SIZE * FBUF_Y_SIZE );
3115#endif
3116
3117    _cma_set_register( channel, CHBUF_SRC_DESC , src_chbuf_paddr_lsb );
3118    _cma_set_register( channel, CHBUF_SRC_EXT  , src_chbuf_paddr_ext );
3119    _cma_set_register( channel, CHBUF_SRC_NBUFS, _fbf_ker_chbuf.nbufs );
3120    _cma_set_register( channel, CHBUF_DST_DESC , dst_chbuf_paddr_lsb );
3121    _cma_set_register( channel, CHBUF_DST_EXT  , dst_chbuf_paddr_ext );
3122    _cma_set_register( channel, CHBUF_DST_NBUFS, 1 );
3123    _cma_set_register( channel, CHBUF_BUF_SIZE , FBUF_X_SIZE*FBUF_Y_SIZE );
3124    _cma_set_register( channel, CHBUF_PERIOD   , 1000 );
3125    _cma_set_register( channel, CHBUF_RUN      , MODE_NO_DST_SYNC );
3126
3127    return SYSCALL_OK;
3128
3129} // end _sys_fbf_cma_start()
3130
3131////////////////////////////////////////////
3132int _sys_fbf_cma_check( unsigned int index )
3133{
3134    // get calling thread scheduler, ltid and trdid
3135    static_scheduler_t*  psched = _get_sched();
3136    unsigned int         ltid   = _get_thread_ltid();
3137    unsigned int         trdid  = _get_thread_trdid();
3138
3139    // check FBF allocated
3140    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
3141    {
3142        _printf("\n[GIET ERROR] in _sys_fbf_cma_check() : "
3143                "FBF not allocated to thread %x\n", trdid );
3144
3145        return SYSCALL_CHANNEL_NON_ALLOCATED;
3146    }
3147
3148    // get channel index
3149    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
3150
3151    if ( channel >= NB_CMA_CHANNELS )
3152    {
3153        _printf("\n[GIET ERROR] in _sys_fbf_cma_check() : "
3154                "CMA channel non allocated to thread %x\n", trdid );
3155
3156        return SYSCALL_CHANNEL_NON_ALLOCATED;
3157    }
3158
3159    // check buffer index
3160    if ( index >= _fbf_ker_chbuf.nbufs )
3161    {
3162        _printf("\n[GIET ERROR] in _sys_fbf_cma_check() : "
3163                "buffer index too large for thread %x\n", trdid );
3164
3165        return SYSCALL_CHANNEL_NON_ALLOCATED;
3166    }
3167
3168    // compute user buffer status physical addresses
3169    unsigned long long usr_sts_paddr;
3170    fbf_chbuf_t* pdesc = &_fbf_ker_chbuf;     
3171    usr_sts_paddr = ((pdesc->usr_desc[index] & 0xFFF0000000000000ULL) >> 20) + 
3172                    ((pdesc->usr_desc[index] & 0x3FFFFFFULL) << 6);         
3173
3174#if GIET_DEBUG_FBF_CMA
3175_printf("\n[FBF_CMA DEBUG] enters _sys_fbf_cma_check()\n"
3176        " - cma channel      = %d\n"
3177        " - buffer index     = %d\n"
3178        " - usr_desc value   = %l\n"
3179        " - fbf_desc value   = %l\n"
3180        " - usr status paddr = %l\n",
3181        channel,
3182        index,
3183        _fbf_ker_chbuf.usr_desc[index],
3184        _fbf_ker_chbuf.fbf_desc,
3185        usr_sts_paddr );
3186#endif
3187
3188    // waiting user buffer released by the CMA component)
3189    unsigned int full;
3190    do
3191    { 
3192        // INVAL L2 cache copy of user buffer status     
3193        // because it is modified in RAM by the CMA component
3194        _mmc_inval( usr_sts_paddr , 4 );       
3195
3196        full = _physical_read( usr_sts_paddr );
3197    }
3198    while ( full );
3199
3200    return SYSCALL_OK;
3201
3202}  // end _sys_fbf_cma_check()
3203
3204//////////////////////////////////////////////
3205int _sys_fbf_cma_display( unsigned int index )
3206{
3207    // get calling thread scheduler, ltid and trdid
3208    static_scheduler_t*  psched = _get_sched();
3209    unsigned int         ltid   = _get_thread_ltid();
3210    unsigned int         trdid  = _get_thread_trdid();
3211
3212    // check FBF allocated
3213    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
3214    {
3215        _printf("\n[GIET ERROR] in _sys_fbf_cma_display() : "
3216                "FBF not allocated to thread %x\n", trdid );
3217
3218        return SYSCALL_CHANNEL_NON_ALLOCATED;
3219    }
3220
3221    // get channel index
3222    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
3223
3224    if ( channel >= NB_CMA_CHANNELS )
3225    {
3226        _printf("\n[GIET ERROR] in _sys_fbf_cma_display() : "
3227                "CMA channel non allocated to thread %x\n", trdid );
3228
3229        return SYSCALL_CHANNEL_NON_ALLOCATED;
3230    }
3231
3232    // check buffer index
3233    if ( index >= _fbf_ker_chbuf.nbufs )
3234    {
3235        _printf("\n[GIET ERROR] in _sys_fbf_cma_display() : "
3236                "buffer index too large for thread %x\n", trdid );
3237
3238        return SYSCALL_CHANNEL_NON_ALLOCATED;
3239    }
3240
3241    // compute user buffer and status physical addresses
3242    unsigned long long usr_sts_paddr;
3243    unsigned long long usr_buf_paddr;
3244
3245    fbf_chbuf_t* pdesc = &_fbf_ker_chbuf;     
3246
3247    usr_sts_paddr = ((pdesc->usr_desc[index] & 0xFFF0000000000000ULL) >> 20) + 
3248                    ((pdesc->usr_desc[index] & 0x3FFFFFFULL) << 6);         
3249
3250    usr_buf_paddr = ((pdesc->usr_desc[index] & 0xFFFFFFFFFC000000ULL) >> 20); 
3251
3252#if GIET_DEBUG_FBF_CMA
3253_printf("\n[FBF_CMA DEBUG] enters _sys_fbf_cma_display()\n"
3254        " - cma channel      = %d\n"
3255        " - buffer index     = %d\n"
3256        " - usr buffer paddr = %l\n"
3257        " - usr status paddr = %l\n",
3258        channel,
3259        index,
3260        usr_buf_paddr, 
3261        usr_sts_paddr ); 
3262#endif
3263       
3264    // SYNC request, because this buffer will be read from XRAM by the CMA component
3265    _mmc_sync( usr_buf_paddr , FBUF_X_SIZE * FBUF_Y_SIZE );
3266
3267    // set user buffer status
3268    _physical_write( usr_sts_paddr, 0x1 );
3269
3270    // SYNC request, because this status will be read from XRAM by the CMA component
3271    _mmc_sync( usr_sts_paddr, 4 );
3272
3273    return SYSCALL_OK;
3274
3275} // end _sys_fbf_cma_display()
3276
3277///////////////////////
3278int _sys_fbf_cma_stop()
3279{
3280    // get channel index
3281    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
3282
3283    if ( channel >= NB_CMA_CHANNELS )
3284    {
3285        _printf("\n[GIET ERROR] in _sys_fbf_cma_stop() : CMA channel non allocated\n");
3286
3287        return SYSCALL_CHANNEL_NON_ALLOCATED;
3288    }
3289
3290    // Desactivate CMA channel
3291    _cma_set_register( channel, CHBUF_RUN, MODE_IDLE );
3292
3293    return SYSCALL_OK;
3294
3295} // end _sys_fbf_cma_stop()
3296
3297
3298//////////////////////////////////////////////////////////////////////////////
3299//           Miscelaneous syscall handlers
3300//////////////////////////////////////////////////////////////////////////////
3301
3302///////////////
3303int _sys_ukn() 
3304{
3305    _printf("\n[GIET ERROR] Undefined System Call / EPC = %x\n", _get_epc() );
3306
3307    return SYSCALL_UNDEFINED_SYSTEM_CALL;
3308}
3309
3310////////////////////////////////////
3311int _sys_proc_xyp( unsigned int* x,
3312                   unsigned int* y,
3313                   unsigned int* p )
3314{
3315    unsigned int gpid = _get_procid();  // global processor index from CPO register
3316
3317    *x = (gpid >> (Y_WIDTH + P_WIDTH)) & ((1<<X_WIDTH)-1);
3318    *y = (gpid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
3319    *p = gpid & ((1<<P_WIDTH)-1);
3320
3321    return SYSCALL_OK;
3322}
3323
3324////////////////////////////////////////////
3325int _sys_procs_number( unsigned int* x_size,
3326                       unsigned int* y_size,
3327                       unsigned int* nprocs )
3328{
3329    mapping_header_t * header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
3330    mapping_cluster_t * cluster = _get_cluster_base(header);
3331
3332    unsigned int x;
3333    unsigned int y;
3334    unsigned int okmin = 1;
3335    unsigned int okmax = 1;
3336
3337    // compute max values
3338    unsigned int xmax  = header->x_size;
3339    unsigned int ymax  = header->y_size;
3340    unsigned int procs = cluster[0].procs;
3341
3342    // check the (ymax-1) lower rows
3343    for ( y = 0 ; y < ymax-1 ; y++ )
3344    {
3345        for ( x = 0 ; x < xmax ; x++ )
3346        {
3347            if (cluster[x*ymax+y].procs != procs ) okmin = 0;
3348        }
3349    }
3350
3351    // check the upper row
3352    for ( x = 0 ; x < xmax ; x++ )
3353    {
3354        if (cluster[x*ymax+ymax-1].procs != procs ) okmax = 0;
3355    }
3356
3357    // return values
3358    if ( okmin && okmax )
3359    {
3360        *x_size = xmax;
3361        *y_size = ymax;
3362        *nprocs = procs;
3363    }
3364    else if ( okmin )
3365    {
3366        *x_size = xmax;
3367        *y_size = ymax-1;
3368        *nprocs = procs;
3369    }
3370    else
3371    {
3372        *x_size = 0;
3373        *y_size = 0;
3374        *nprocs = 0;
3375    }
3376    return SYSCALL_OK;
3377}
3378
3379///////////////////////////////////////////////////////
3380int _sys_vseg_get_vbase( char*             vspace_name, 
3381                         char*             vseg_name, 
3382                         unsigned int*     vbase ) 
3383{
3384    mapping_header_t * header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
3385    mapping_vspace_t * vspace = _get_vspace_base(header);
3386    mapping_vseg_t * vseg     = _get_vseg_base(header);
3387
3388    unsigned int vspace_id;
3389    unsigned int vseg_id;
3390
3391    // scan vspaces
3392    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
3393    {
3394        if (_strncmp( vspace[vspace_id].name, vspace_name, 31) == 0) 
3395        {
3396            // scan vsegs
3397            for (vseg_id = vspace[vspace_id].vseg_offset; 
3398                 vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs); 
3399                 vseg_id++) 
3400            {
3401                if (_strncmp(vseg[vseg_id].name, vseg_name, 31) == 0) 
3402                {
3403                    *vbase = vseg[vseg_id].vbase;
3404                    return SYSCALL_OK;
3405                }
3406            } 
3407        }
3408    } 
3409    return SYSCALL_VSEG_NOT_FOUND;
3410}
3411
3412/////////////////////////////////////////////////////////
3413int _sys_vseg_get_length( char*         vspace_name, 
3414                          char*         vseg_name,
3415                          unsigned int* length ) 
3416{
3417    mapping_header_t * header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
3418    mapping_vspace_t * vspace = _get_vspace_base(header);
3419    mapping_vseg_t * vseg     = _get_vseg_base(header);
3420
3421    unsigned int vspace_id;
3422    unsigned int vseg_id;
3423
3424    // scan vspaces
3425    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
3426    {
3427        if (_strncmp( vspace[vspace_id].name, vspace_name, 31) == 0) 
3428        {
3429            // scan vsegs
3430            for (vseg_id = vspace[vspace_id].vseg_offset; 
3431                 vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs); 
3432                 vseg_id++) 
3433            {
3434                if (_strncmp(vseg[vseg_id].name, vseg_name, 31) == 0) 
3435                {
3436                    *length = vseg[vseg_id].length;
3437                    return SYSCALL_OK;
3438                }
3439            } 
3440        }
3441    } 
3442    return SYSCALL_VSEG_NOT_FOUND;
3443}
3444
3445////////////////////////////////////////
3446int _sys_xy_from_ptr( void*         ptr,
3447                      unsigned int* x,
3448                      unsigned int* y )
3449{
3450    unsigned int flags;
3451    unsigned long long paddr = _v2p_translate( (unsigned int)ptr , &flags );
3452   
3453    *x = (paddr>>36) & 0xF;
3454    *y = (paddr>>32) & 0xF;
3455
3456    return SYSCALL_OK;
3457}
3458
3459/////////////////////////////////////////
3460int _sys_heap_info( unsigned int* vaddr, 
3461                    unsigned int* length,
3462                    unsigned int  x,
3463                    unsigned int  y ) 
3464{
3465    // checking parameters
3466    if ( (x >= X_SIZE) || (y >= Y_SIZE) ) 
3467    {
3468        *vaddr  = 0;
3469        *length = 0;
3470        _printf("\n[GIET ERROR] in _sys_heap_info() : "
3471                "illegal (%d,%d) coordinates\n", x , y );
3472        return SYSCALL_ILLEGAL_CLUSTER_COORDINATES;
3473    }
3474
3475    mapping_header_t * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
3476    mapping_thread_t * thread  = _get_thread_base(header);
3477    mapping_vseg_t *   vseg    = _get_vseg_base(header);
3478    mapping_vspace_t * vspace  = _get_vspace_base(header);
3479
3480    unsigned int thread_id;
3481    unsigned int vspace_id;
3482    unsigned int vseg_id = 0xFFFFFFFF;
3483
3484    // get calling thread vspace index
3485    vspace_id = _get_context_slot(CTX_VSID_ID);
3486
3487    // scan all threads in vspace to find one in clyster[x,y]
3488    unsigned int min = vspace[vspace_id].thread_offset ;
3489    unsigned int max = min + vspace[vspace_id].threads ;
3490    for ( thread_id = min ; thread_id < max ; thread_id++ )
3491    {
3492        if ( thread[thread_id].clusterid == (x * Y_SIZE + y) )
3493        {
3494            vseg_id = thread[thread_id].heap_vseg_id;
3495            break;
3496        }
3497    }
3498
3499    // analysing the vseg_id
3500    if ( vseg_id != 0xFFFFFFFF ) 
3501    {
3502        *vaddr  = vseg[vseg_id].vbase;
3503        *length = vseg[vseg_id].length;
3504    }
3505    else 
3506    {
3507        *vaddr  = 0;
3508        *length = 0;
3509        _printf("error in _sys_heap_info() : no heap in cluster (%d,%d)\n", x , y );
3510    }
3511    return SYSCALL_OK;
3512}  // end _sys_heap_info()
3513
3514
3515// Local Variables:
3516// tab-width: 4
3517// c-basic-offset: 4
3518// c-file-offsets:((innamespace . 0)(inline-open . 0))
3519// indent-tabs-mode: nil
3520// End:
3521// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
3522
Note: See TracBrowser for help on using the repository browser.