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

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

Cosmetic.

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