Index: /soft/giet_vm/giet_kernel/ctx_handler.c
===================================================================
--- /soft/giet_vm/giet_kernel/ctx_handler.c	(revision 724)
+++ /soft/giet_vm/giet_kernel/ctx_handler.c	(revision 725)
@@ -29,10 +29,11 @@
 extern fat_desc_t  _fat;
 
-//////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
 // This function is called by the _ctx_switch() function.
 // It desactivates a thread that received a KILL signal.
 // We must release all ressources allocated to the thread
-// before the actual desactivation, that uses NORUN_MASK_THREAD.
-//////////////////////////////////////////////////////////////////
+// before the actual desactivation, that set the NORUN_MASK_THREAD
+// bit in the thread context.
+//////////////////////////////////////////////////////////////////////////////////
 static void _ctx_kill_thread( unsigned int x,
                               unsigned int y,
Index: /soft/giet_vm/giet_kernel/kernel_init.c
===================================================================
--- /soft/giet_vm/giet_kernel/kernel_init.c	(revision 724)
+++ /soft/giet_vm/giet_kernel/kernel_init.c	(revision 725)
@@ -379,7 +379,4 @@
     ////////////////////////////////////////////////////////////////////////////
 
-    if (threads == 0) _printf("\n[GIET WARNING] No thread allocated to P[%d,%d,%d]\n",
-                            x, y, p );
-
     // default value for ltid
     ltid = IDLE_THREAD_INDEX;
Index: /soft/giet_vm/giet_kernel/sys_handler.c
===================================================================
--- /soft/giet_vm/giet_kernel/sys_handler.c	(revision 724)
+++ /soft/giet_vm/giet_kernel/sys_handler.c	(revision 725)
@@ -160,23 +160,19 @@
 
 __attribute__((section(".kdata")))
-ker_chbuf_t  _nic_ker_rx_chbuf[NB_NIC_CHANNELS] __attribute__((aligned(64)));
+nic_chbuf_t  _nic_ker_rx_chbuf[NB_NIC_CHANNELS] __attribute__((aligned(64)));
 
 __attribute__((section(".kdata")))
-ker_chbuf_t  _nic_ker_tx_chbuf[NB_NIC_CHANNELS] __attribute__((aligned(64)));
+nic_chbuf_t  _nic_ker_tx_chbuf[NB_NIC_CHANNELS] __attribute__((aligned(64)));
 
 ////////////////////////////////////////////////////////////////////////////
-// FBF related chbuf descriptors array, indexed by the CMA channel index.
-// Physical addresses of these chbuf descriptors required for L2 cache sync.
-// FBF status
+//     FBF related chbuf
+// The physical address of this chbuf is required for L2 cache sync.
 ////////////////////////////////////////////////////////////////////////////
 
 __attribute__((section(".kdata")))
-fbf_chbuf_t _fbf_chbuf[NB_CMA_CHANNELS] __attribute__((aligned(64)));
+fbf_chbuf_t          _fbf_ker_chbuf  __attribute__((aligned(64)));
 
 __attribute__((section(".kdata")))
-unsigned long long _fbf_chbuf_paddr[NB_CMA_CHANNELS];
-
-__attribute__((section(".kdata")))
-buffer_status_t _fbf_status[NB_CMA_CHANNELS] __attribute__((aligned(64)));
+unsigned long long   _fbf_chbuf_paddr;
 
 ////////////////////////////////////////////////////////////////////////////
@@ -203,5 +199,5 @@
     &_sys_fbf_cma_display,           /* 0x0D */
     &_sys_fbf_cma_stop,              /* 0x0E */
-    &_sys_ukn,                       /* 0x0F */
+    &_sys_fbf_cma_check,             /* 0x0F */
 
     &_sys_applications_status,       /* 0x10 */
@@ -1574,12 +1570,4 @@
     unsigned int trdid = _get_thread_trdid();
 
-    // check no TTY already allocated to calling thread
-    if ( _get_context_slot( CTX_TTY_ID ) < NB_TTY_CHANNELS )
-    {
-        _printf("\n[GIET_ERROR] in _sys_tty_alloc() : "
-                "TTY channel already allocated to thread %x\n", trdid );
-        return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
-    }
-
     mapping_header_t  *header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
     mapping_vspace_t  *vspace   = _get_vspace_base(header);
@@ -1963,5 +1951,5 @@
                 "xmax or ymax argument too large for thread %x\n", trdid );
 
-        return SYSCALL_ILLEGAL_XY_ARGUMENTS;
+        return SYSCALL_ILLEGAL_ARGUMENT;
     }
 
@@ -2201,5 +2189,5 @@
 
     // sync the kernel chbuf in L2 after write in L2
-    _mmc_sync( ker_chbuf_pbase, sizeof( ker_chbuf_t ) );
+    _mmc_sync( ker_chbuf_pbase, sizeof( nic_chbuf_t ) );
 
     ///////////////////////////////////////////////////////////////
@@ -2372,6 +2360,6 @@
     // start CMA transfer
     _cma_set_register( cma_channel, CHBUF_BUF_SIZE , NIC_CONTAINER_SIZE );
-    _cma_set_register( cma_channel, CHBUF_PERIOD   , 0 );     // OUT_OF_ORDER 
-    _cma_set_register( cma_channel, CHBUF_RUN      , 1 );
+    _cma_set_register( cma_channel, CHBUF_PERIOD   , 0 );                  // OUT_OF_ORDER 
+    _cma_set_register( cma_channel, CHBUF_RUN      , MODE_NORMAL );
 
     // activates NIC channel
@@ -2416,5 +2404,5 @@
 
     // get kernel chbuf virtual address
-    ker_chbuf_t* ker_chbuf;
+    nic_chbuf_t* ker_chbuf;
     if ( is_rx )  ker_chbuf = &_nic_ker_rx_chbuf[channel];
     else          ker_chbuf = &_nic_ker_tx_chbuf[channel];
@@ -2436,5 +2424,5 @@
          cx , cy , xmax , ymax );
 
-        return SYSCALL_ILLEGAL_XY_ARGUMENTS;
+        return SYSCALL_ILLEGAL_ARGUMENT;
     }
     
@@ -2586,5 +2574,5 @@
 
     // desactivates the CMA channel
-    _cma_set_register( cma_channel, CHBUF_RUN , 0 );
+    _cma_set_register( cma_channel, CHBUF_RUN , MODE_IDLE );
 
     // wait until CMA channel IDLE
@@ -2853,7 +2841,9 @@
 }
 
-////////////////////////
-int _sys_fbf_cma_alloc()
-{
+////////////////////////////////////////////
+int _sys_fbf_cma_alloc( unsigned int nbufs )
+{
+    // compute trdid and vsid for the calling thread
+    unsigned int vsid  = _get_context_slot( CTX_VSID_ID );
     unsigned int trdid = _get_thread_trdid();
 
@@ -2862,7 +2852,13 @@
         _printf("\n[GIET ERROR] in _sys_fbf_cma_alloc() : "
                 "CMA channel already allocated for thread %x\n", trdid );
-
         return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
     }
+
+    // compute number of threads in vspace from mapping
+    mapping_header_t  *header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
+    mapping_vspace_t  *vspace   = _get_vspace_base(header);
+    mapping_thread_t  *thread   = _get_thread_base(header);
+    unsigned int      first     = vspace[vsid].thread_offset;
+    unsigned int      threads   = vspace[vsid].threads;
 
     // get a CMA channel
@@ -2871,22 +2867,66 @@
     {
         unsigned int*  palloc = &_cma_channel_alloc[channel];
-        if ( _atomic_test_and_set( palloc , 1 ) == 0 ) break;
-    }
+        if ( _atomic_test_and_set( palloc , threads ) == 0 ) break;
+    }
+
     if ( channel >= NB_CMA_CHANNELS )
     {
         _printf("\n[GIET ERROR] in _sys_fbf_cma_alloc() : no CMA channel available\n");
-
         return SYSCALL_NO_CHANNEL_AVAILABLE;
     }
-    else
-    {
-        _set_context_slot( CTX_CMA_FB_ID, channel );
-
-        return SYSCALL_OK;
-    }
+
+    // check nbufs argument
+    if ( nbufs > 256 )
+    {
+        _printf("\n[GIET ERROR] in _sys_fbf_cma_alloc() : nbufs larger than 256\n");
+        return SYSCALL_ILLEGAL_ARGUMENT;
+    }
+
+    // loop on all threads to register channel in thread contexts
+    unsigned int      tid;
+    for ( tid = first ; tid < (first + threads) ; tid++ )
+    {
+        unsigned int         y_size = header->y_size;
+        unsigned int         cid    = thread[tid].clusterid;
+        unsigned int         x      = cid / y_size;
+        unsigned int         y      = cid % y_size;
+        unsigned int         p      = thread[tid].proclocid;
+        unsigned int         ltid   = thread[tid].ltid;
+        static_scheduler_t* psched  = (static_scheduler_t*)_schedulers[x][y][p];
+        psched->context[ltid].slot[CTX_CMA_FB_ID] = channel; 
+    }
+
+    unsigned int vaddr;
+    unsigned int flags;
+
+    // compute frame buffer physical addresses
+    vaddr = (unsigned int)SEG_FBF_BASE;
+    unsigned long long fbf_buf_paddr = _v2p_translate( vaddr , &flags );
+
+    // initialize the FBF chbuf 
+    // we don't register a status address in the fbf_desc, because
+    // the CMA does not test the status for the frame buffer (no synchro) 
+    _fbf_ker_chbuf.nbufs    = nbufs;
+    _fbf_ker_chbuf.fbf_desc = (((fbf_buf_paddr & 0xFFFFFFFFFFFULL) >> 6 ) << 26);
+
+    // register FBF chbuf physical address
+    vaddr = (unsigned int)(&_fbf_ker_chbuf);
+    _fbf_chbuf_paddr = _v2p_translate( vaddr , &flags );
+
+#if GIET_DEBUG_FBF_CMA
+_printf("\n[FBF_CMA DEBUG] _sys_fbf_cma_alloc()\n"
+        " - channel               = %d\n"
+        " - vaddr(_ker_fbf_chbuf) = %x\n"
+        " - paddr(_ker_fbf_chbuf) = %l\n"
+        " - nbufs                 = %d\n" 
+        " - fbf_desc              = %l\n",
+        channel , vaddr , _fbf_chbuf_paddr , nbufs , _fbf_ker_chbuf.fbf_desc );
+#endif
+
+    return SYSCALL_OK;
 } // end sys_fbf_cma_alloc()
 
 //////////////////////////
-int _sys_fbf_cma_release()  // Not a syscall
+int _sys_fbf_cma_release()  // Not a syscall : used by _ctx_kill_thread()
 {
     unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
@@ -2901,30 +2941,33 @@
     }
 
-    // stop CMA transfer
-    _sys_fbf_cma_stop();
-
-    // reset CTX_CMA_FB_ID for thread
+    if ( _cma_channel_alloc[channel] == 1 )  // the calling thread is the last user
+    {
+        // stop the CMA transfer
+        _sys_fbf_cma_stop();
+
+        // reset the CMA channel allocator
+        _cma_channel_alloc[channel] = 0;
+    }
+    else                                     // not the last user
+    {
+        // atomically decrement the CMA channel allocator
+        _atomic_increment( &_cma_channel_alloc[channel] , -1 );
+    }
+
+    // reset CTX_CMA_FB_ID slot in calling thread context
     _set_context_slot( CTX_CMA_FB_ID, 0xFFFFFFFF );
 
-    // release CMA channel
-    _cma_channel_alloc[channel] = 0;
-
     return SYSCALL_OK;
-}
+} // end _sys_fbf_cma_release()
 
 ///////////////////////////////////////////////////
-int _sys_fbf_cma_init_buf( void*        buf0_vbase, 
-                           void*        buf1_vbase, 
-                           void*        sts0_vaddr,
-                           void*        sts1_vaddr )
+int _sys_fbf_cma_init_buf( unsigned int index,
+                           void*        buf_vaddr, 
+                           void*        sts_vaddr )
 {
     unsigned int       vaddr;           // virtual address
     unsigned int       flags;           // for _v2p_translate()
-    unsigned long long fbf_paddr;       // fbf physical address
-    unsigned long long fbf_sts_paddr;   // fbf status physical address
-    unsigned long long buf0_pbase;      // buffer 0 base physical address
-    unsigned long long sts0_paddr;      // buffer 0 status physical address
-    unsigned long long buf1_pbase;      // buffer 1 base physical address
-    unsigned long long sts1_paddr;      // buffer 1 status physical address
+    unsigned long long buf_paddr;       // user buffer physical address
+    unsigned long long sts_paddr;       // user status physical address
 
     // get calling thread scheduler, ltid and trdid
@@ -2955,115 +2998,71 @@
 #if GIET_DEBUG_FBF_CMA
 _printf("\n[FBF_CMA DEBUG] _sys_fbf_cma_init_buf()\n"
-        " - channel           = %d\n"
-        " - buf0        vbase = %x\n"
-        " - buf1        vbase = %x\n"
-        " - sts0        vaddr = %x\n"
-        " - sts1        vaddr = %x\n",
-        channel,
-        (unsigned int)buf0_vbase,
-        (unsigned int)buf1_vbase,
-        (unsigned int)sts0_vaddr,
-        (unsigned int)sts1_vaddr );
-#endif
-
-    // checking user buffers virtual addresses alignment
-    if ( ((unsigned int)buf0_vbase & 0x3F) || 
-         ((unsigned int)buf1_vbase & 0x3F) ) 
+        " - channel     = %d / index = %d\n"
+        " - buf vaddr   = %x\n"
+        " - sts vaddr   = %x\n",
+        channel, index,
+        (unsigned int)buf_vaddr,
+        (unsigned int)sts_vaddr );
+#endif
+
+    // checking index argument
+    if ( index >= _fbf_ker_chbuf.nbufs )
     {
         _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
-                "user buffer not aligned for thread %x\n", trdid );
+                "user buffer index too large %x\n", trdid );
+
+        return SYSCALL_CHANNEL_NON_ALLOCATED;
+    }
+
+    // checking user buffer and status addresses alignment
+    if ( ((unsigned int)buf_vaddr & 0x3F) || ((unsigned int)sts_vaddr & 0x3F) )
+    {
+        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
+                "user buffer or status not aligned for thread %x\n", trdid );
 
         return SYSCALL_ADDRESS_NON_ALIGNED;
     }
 
-    // checking user buffers status virtual addresses alignment
-    if ( ((unsigned int)sts0_vaddr & 0x3F) ||
-         ((unsigned int)sts1_vaddr & 0x3F) )
+    // Compute user buffer and status physical addresses 
+    vaddr = (unsigned int)buf_vaddr;
+    buf_paddr = _v2p_translate( vaddr , &flags );
+    if ((flags & PTE_U) == 0) 
     {
         _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
-                "user status not aligned for thread %x\n", trdid );
-
-        return SYSCALL_ADDRESS_NON_ALIGNED;
-    }
-
-    // compute frame buffer physical address and initialize _fbf_chbuf[channel]
-    vaddr = (unsigned int)SEG_FBF_BASE;
-    fbf_paddr = _v2p_translate( vaddr , &flags );
-    vaddr = (unsigned int)&_fbf_status[channel];
-    fbf_sts_paddr = _v2p_translate( vaddr , &flags );
-
-    _fbf_chbuf[channel].fbf_desc =
-        (unsigned long long) ((fbf_sts_paddr & 0xFFFFFFFFULL) >> 6) +
-        (((fbf_paddr & 0xFFFFFFFFULL) >> 6 ) << 26);
-
-    // Compute user buffer 0 physical addresses and intialize _fbf_chbuf[channel]
-    vaddr = (unsigned int)buf0_vbase;
-    buf0_pbase = _v2p_translate( vaddr , &flags );
+                "buffer not in user space for thread %x\n", trdid );
+
+        return SYSCALL_ADDRESS_NON_USER_ACCESSIBLE;
+    }
+
+    vaddr = (unsigned int)sts_vaddr;
+    sts_paddr = _v2p_translate( vaddr , &flags );
     if ((flags & PTE_U) == 0) 
     {
         _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
-                "buf0 not in user space for thread %x\n", trdid );
+                "status not in user space for thread %x\n", trdid);
 
         return SYSCALL_ADDRESS_NON_USER_ACCESSIBLE;
     }
 
-    vaddr = (unsigned int)sts0_vaddr;
-    sts0_paddr = _v2p_translate( vaddr , &flags );
-    if ((flags & PTE_U) == 0) 
+    // check user buffer and user status in same cluster
+    if ( (buf_paddr & 0xFF00000000ULL) != (sts_paddr & 0xFF00000000ULL) ) 
     {
         _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
-                "sts0 not in user space for thread %x\n", trdid);
+                "user status and buffer not in same cluster for thread %x\n", trdid);
 
         return SYSCALL_ADDRESS_NON_USER_ACCESSIBLE;
     }
 
-    _fbf_chbuf[channel].buf0_desc = 
-        (unsigned long long) ((sts0_paddr & 0xFFFFFFFFULL) >> 6) +
-        (((buf0_pbase & 0xFFFFFFFFULL) >> 6 ) << 26);
-
-    // Compute user buffer 1 physical addresses and intialize _fbf_chbuf[channel]
-    vaddr = (unsigned int)buf1_vbase;
-    buf1_pbase = _v2p_translate( vaddr , &flags );
-    if ((flags & PTE_U) == 0) 
-    {
-        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
-                "buf1 not in user space for thread %x\n", trdid );
-
-        return SYSCALL_ADDRESS_NON_USER_ACCESSIBLE;
-    }
-
-    vaddr = (unsigned int)sts1_vaddr;
-    sts1_paddr = _v2p_translate( vaddr , &flags );
-    if ((flags & PTE_U) == 0) 
-    {
-        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
-                "sts1 not in user space for thread %x\n", trdid);
-
-        return SYSCALL_ADDRESS_NON_USER_ACCESSIBLE;
-    }
-
-    _fbf_chbuf[channel].buf1_desc = 
-        (unsigned long long) ((sts1_paddr & 0xFFFFFFFFULL) >> 6) +
-        (((buf1_pbase & 0xFFFFFFFFULL) >> 6 ) << 26);
-
-    // Compute and register physical adress of the fbf_chbuf descriptor
-    vaddr = (unsigned int)&_fbf_chbuf[channel];
-    _fbf_chbuf_paddr[channel] = _v2p_translate( vaddr , &flags );
- 
+    // initialize _fbf_ker_chbuf.usr_desc[index]
+    _fbf_ker_chbuf.usr_desc[index] = ((sts_paddr & 0xFFFFFFFFULL) >> 6) +
+                                     (((buf_paddr & 0xFFFFFFFFFFULL) >> 6 ) << 26);
+
 #if GIET_DEBUG_FBF_CMA
-_printf(" - fbf         pbase = %l\n"
-        " - fbf status  paddr = %l\n"
-        " - buf0        pbase = %l\n"
-        " - buf0 status paddr = %l\n" 
-        " - buf1        pbase = %l\n"
-        " - buf0 status paddr = %l\n" 
-        " - chbuf       pbase = %l\n",
-        fbf_paddr,
-        fbf_sts_paddr,
-        buf0_pbase,
-        sts0_paddr,
-        buf1_pbase,
-        sts1_paddr,
-        _fbf_chbuf_paddr[channel] );
+_printf(" - buf paddr   = %l\n"
+        " - sts paddr   = %l\n"
+        " - usr_desc[%d] = %l\n",
+        buf_paddr,
+        sts_paddr,
+        index , _fbf_ker_chbuf.usr_desc[index] );
 #endif
 
@@ -3072,6 +3071,6 @@
 } // end sys_fbf_cma_init_buf()
 
-////////////////////////////////////////////
-int _sys_fbf_cma_start( unsigned int length ) 
+////////////////////////
+int _sys_fbf_cma_start() 
 {
     // get calling thread scheduler, ltid and trdid
@@ -3089,5 +3088,5 @@
     }
 
-    // get channel index
+    // get CMA channel index
     unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
 
@@ -3101,38 +3100,52 @@
 
     // check buffers initialization
-    if ( ( _fbf_chbuf[channel].buf0_desc == 0x0ULL ) &&
-         ( _fbf_chbuf[channel].buf1_desc == 0x0ULL) &&
-         ( _fbf_chbuf[channel].fbf_desc == 0x0ULL) )
-    {
-        _printf("\n[GIET ERROR] in _sys_fbf_cma_start(): initialization not done\n");
+    if ( _fbf_ker_chbuf.nbufs == 0 )
+    {
+        _printf("\n[GIET ERROR] in _sys_fbf_cma_start(): "
+                "FBF chbuf not initialized for thread %x\n", trdid );
 
         return SYSCALL_MISSING_INITIALISATION;
     }
 
-    // initializes buffer length
-    _fbf_chbuf[channel].length = length;
-
+    // synchronize FBF chbuf that will be read by CMA peripheral
     if ( USE_IOB )
     {
         // SYNC request for fbf_chbuf descriptor
-        _mmc_sync( _fbf_chbuf_paddr[channel] , sizeof( fbf_chbuf_t ) );
+        _mmc_sync( _fbf_chbuf_paddr , sizeof( fbf_chbuf_t ) );
     }
 
     // start CMA transfer
-    unsigned long long paddr = _fbf_chbuf_paddr[channel];
-    unsigned int src_chbuf_paddr_lsb = (unsigned int)(paddr & 0xFFFFFFFF);
-    unsigned int src_chbuf_paddr_ext = (unsigned int)(paddr >> 32);
-    unsigned int dst_chbuf_paddr_lsb = src_chbuf_paddr_lsb + 16;
-    unsigned int dst_chbuf_paddr_ext = src_chbuf_paddr_ext;
+    unsigned long long paddr = _fbf_chbuf_paddr;
+    unsigned int dst_chbuf_paddr_lsb = (unsigned int)(paddr & 0xFFFFFFFF);
+    unsigned int dst_chbuf_paddr_ext = (unsigned int)(paddr >> 32);
+    unsigned int src_chbuf_paddr_lsb = dst_chbuf_paddr_lsb + 8;
+    unsigned int src_chbuf_paddr_ext = dst_chbuf_paddr_ext;
+
+#if GIET_DEBUG_FBF_CMA
+_printf("\n[FBF_CMA DEBUG] _sys_fbf_cma_start()\n"
+        " - src_chbuf_paddr_lsb = %x\n"
+        " - src_chbuf_paddr_ext = %x\n"
+        " - src_chbuf_nbufs     = %d\n"
+        " - dst_chbuf_paddr_lsb = %x\n"
+        " - dst_chbuf_paddr_ext = %x\n"
+        " - dst_chbuf_nbufs     = 1 \n"
+        " - buffer_size         = %d\n",
+        src_chbuf_paddr_lsb,
+        src_chbuf_paddr_ext,
+        _fbf_ker_chbuf.nbufs,
+        dst_chbuf_paddr_lsb,
+        dst_chbuf_paddr_ext,
+        FBUF_X_SIZE * FBUF_Y_SIZE );
+#endif
 
     _cma_set_register( channel, CHBUF_SRC_DESC , src_chbuf_paddr_lsb );
     _cma_set_register( channel, CHBUF_SRC_EXT  , src_chbuf_paddr_ext );
-    _cma_set_register( channel, CHBUF_SRC_NBUFS, 2 );
+    _cma_set_register( channel, CHBUF_SRC_NBUFS, _fbf_ker_chbuf.nbufs );
     _cma_set_register( channel, CHBUF_DST_DESC , dst_chbuf_paddr_lsb );
     _cma_set_register( channel, CHBUF_DST_EXT  , dst_chbuf_paddr_ext );
     _cma_set_register( channel, CHBUF_DST_NBUFS, 1 );
-    _cma_set_register( channel, CHBUF_BUF_SIZE , length );
+    _cma_set_register( channel, CHBUF_BUF_SIZE , FBUF_X_SIZE*FBUF_Y_SIZE );
     _cma_set_register( channel, CHBUF_PERIOD   , 300 );
-    _cma_set_register( channel, CHBUF_RUN      , 1 );
+    _cma_set_register( channel, CHBUF_RUN      , MODE_NO_DST_SYNC );
 
     return SYSCALL_OK;
@@ -3140,9 +3153,7 @@
 } // end _sys_fbf_cma_start()
 
-/////////////////////////////////////////////////////
-int _sys_fbf_cma_display( unsigned int buffer_index )
-{
-    volatile unsigned int full = 1;
-
+////////////////////////////////////////////
+int _sys_fbf_cma_check( unsigned int index )
+{
     // get calling thread scheduler, ltid and trdid
     static_scheduler_t*  psched = _get_sched();
@@ -3153,5 +3164,5 @@
     if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
     {
-        _printf("\n[GIET ERROR] in _sys_fbf_release() : "
+        _printf("\n[GIET ERROR] in _sys_fbf_cma_check() : "
                 "FBF not allocated to thread %x\n", trdid );
 
@@ -3164,86 +3175,123 @@
     if ( channel >= NB_CMA_CHANNELS )
     {
-        _printf("\n[GIET ERROR] in _sys_fbf_cma_display() : "
-                "CMA channel non allocated\n");
+        _printf("\n[GIET ERROR] in _sys_fbf_cma_check() : "
+                "CMA channel non allocated to thread %x\n", trdid );
 
         return SYSCALL_CHANNEL_NON_ALLOCATED;
     }
 
-    // get fbf_chbuf descriptor pointer
-    fbf_chbuf_t* pdesc = &_fbf_chbuf[channel];     
+    // check buffer index
+    if ( index >= _fbf_ker_chbuf.nbufs )
+    {
+        _printf("\n[GIET ERROR] in _sys_fbf_cma_check() : "
+                "buffer index too large for thread %x\n", trdid );
+
+        return SYSCALL_CHANNEL_NON_ALLOCATED;
+    }
+
+    // compute user buffer status physical addresses
+    unsigned long long usr_sts_paddr;
+    fbf_chbuf_t* pdesc = &_fbf_ker_chbuf;     
+    usr_sts_paddr = ((pdesc->usr_desc[index] & 0xFFF0000000000000ULL) >> 20) +  
+                    ((pdesc->usr_desc[index] & 0x3FFFFFFULL) << 6);          
 
 #if GIET_DEBUG_FBF_CMA
-_printf("\n[FBF_CMA DEBUG] enters _sys_fb_cma_display()\n"
+_printf("\n[FBF_CMA DEBUG] enters _sys_fbf_cma_check()\n"
         " - cma channel      = %d\n"
         " - buffer index     = %d\n"
-        " - buf0_desc value  = %l\n"
-        " - buf1_desc value  = %l\n"
-        " - fbf_desc  value  = %l\n",
-        channel , buffer_index,
-        _fbf_chbuf[channel].buf0_desc,
-        _fbf_chbuf[channel].buf1_desc,
-        _fbf_chbuf[channel].fbf_desc );
-#endif
-
-    unsigned long long buf_sts_paddr;
-    unsigned long long buf_paddr;
-    unsigned long long fbf_sts_paddr;
-
-    if ( buffer_index == 0 )    // user buffer 0
-    {
-        buf_sts_paddr =
-            ((pdesc->buf0_desc & 0xFFF0000000000000ULL) >> 20) + // compute address extension
-            ((pdesc->buf0_desc & 0x3FFFFFFULL) << 6);            // compute 32 LSB of the address
-
-        buf_paddr =
-            (pdesc->buf0_desc & 0xFFFFFFFFFC000000ULL) >> 20;  // compute the entire address
-    }
-    else                        // user buffer 1
-    {
-        buf_sts_paddr =
-            ((pdesc->buf1_desc & 0xFFF0000000000000ULL) >> 20) +
-            ((pdesc->buf1_desc & 0x3FFFFFFULL) << 6);
-
-        buf_paddr =
-            (pdesc->buf1_desc & 0xFFFFFFFFFC000000ULL) >> 20;
-    }
-
-    fbf_sts_paddr =
-        ((pdesc->fbf_desc & 0xFFF0000000000000ULL) >> 20) +
-        ((pdesc->fbf_desc & 0x3FFFFFFULL) << 6);
-
-#if GIET_DEBUG_FBF_CMA
-_printf(" - fbf status paddr = %l\n"
-        " - buf        pbase = %l\n"
-        " - buf status paddr = %l\n",
-        fbf_sts_paddr,
-        buf_paddr,
-        buf_sts_paddr );
-#endif
-        
+        " - usr_desc value   = %l\n"
+        " - fbf_desc value   = %l\n"
+        " - usr status paddr = %l\n",
+        channel,
+        index,
+        _fbf_ker_chbuf.usr_desc[index],
+        _fbf_ker_chbuf.fbf_desc,
+        usr_sts_paddr );
+#endif
+
     // waiting user buffer released by the CMA component)
-    while ( full )
+    unsigned int full;
+    do
     {  
         // INVAL L2 cache copy of user buffer status     
-        // because it has been modified in RAM by the CMA component 
-        _mmc_inval( buf_sts_paddr , 4 );        
-
-        full = _physical_read( buf_sts_paddr );
-    }
-
-    // SYNC request for the user buffer, because 
-    // it will be read from XRAM by the CMA component
-    _mmc_sync( buf_paddr , pdesc->length );
+        // because it is modified in RAM by the CMA component 
+        _mmc_inval( usr_sts_paddr , 4 );        
+
+        full = _physical_read( usr_sts_paddr );
+    }
+    while ( full );
+
+    return SYSCALL_OK;
+
+}  // end _sys_fbf_cma_check()
+
+//////////////////////////////////////////////
+int _sys_fbf_cma_display( unsigned int index )
+{
+    // get calling thread scheduler, ltid and trdid
+    static_scheduler_t*  psched = _get_sched();
+    unsigned int         ltid   = _get_thread_ltid();
+    unsigned int         trdid  = _get_thread_trdid();
+
+    // check FBF allocated
+    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
+    {
+        _printf("\n[GIET ERROR] in _sys_fbf_cma_display() : "
+                "FBF not allocated to thread %x\n", trdid );
+
+        return SYSCALL_CHANNEL_NON_ALLOCATED;
+    }
+
+    // get channel index
+    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
+
+    if ( channel >= NB_CMA_CHANNELS )
+    {
+        _printf("\n[GIET ERROR] in _sys_fbf_cma_display() : "
+                "CMA channel non allocated to thread %x\n", trdid );
+
+        return SYSCALL_CHANNEL_NON_ALLOCATED;
+    }
+
+    // check buffer index
+    if ( index >= _fbf_ker_chbuf.nbufs )
+    {
+        _printf("\n[GIET ERROR] in _sys_fbf_cma_display() : "
+                "buffer index too large for thread %x\n", trdid );
+
+        return SYSCALL_CHANNEL_NON_ALLOCATED;
+    }
+
+    // compute user buffer and status physical addresses
+    unsigned long long usr_sts_paddr;
+    unsigned long long usr_buf_paddr;
+
+    fbf_chbuf_t* pdesc = &_fbf_ker_chbuf;     
+
+    usr_sts_paddr = ((pdesc->usr_desc[index] & 0xFFF0000000000000ULL) >> 20) +  
+                    ((pdesc->usr_desc[index] & 0x3FFFFFFULL) << 6);          
+
+    usr_buf_paddr = ((pdesc->usr_desc[index] & 0xFFFFFFFFFC000000ULL) >> 20); 
+
+#if GIET_DEBUG_FBF_CMA
+_printf("\n[FBF_CMA DEBUG] enters _sys_fbf_cma_display()\n"
+        " - cma channel      = %d\n"
+        " - buffer index     = %d\n"
+        " - usr buffer paddr = %l\n"
+        " - usr status paddr = %l\n",
+        channel,
+        index,
+        usr_buf_paddr, 
+        usr_sts_paddr ); 
+#endif
+        
+    // SYNC request, because this buffer will be read from XRAM by the CMA component
+    _mmc_sync( usr_buf_paddr , FBUF_X_SIZE * FBUF_Y_SIZE );
 
     // set user buffer status
-    _physical_write( buf_sts_paddr, 0x1 );
-
-    // reset fbf buffer status
-    _physical_write( fbf_sts_paddr, 0x0 );
-    
-    // SYNC request, because these buffer descriptors
-    // will be read from XRAM by the CMA component
-    _mmc_sync( buf_sts_paddr, 4 );
-    _mmc_sync( fbf_sts_paddr, 4 );
+    _physical_write( usr_sts_paddr, 0x1 );
+
+    // SYNC request, because this status will be read from XRAM by the CMA component
+    _mmc_sync( usr_sts_paddr, 4 );
 
     return SYSCALL_OK;
@@ -3265,5 +3313,5 @@
 
     // Desactivate CMA channel
-    _cma_set_register( channel, CHBUF_RUN, 0 );
+    _cma_set_register( channel, CHBUF_RUN, MODE_IDLE );
 
     return SYSCALL_OK;
Index: /soft/giet_vm/giet_kernel/sys_handler.h
===================================================================
--- /soft/giet_vm/giet_kernel/sys_handler.h	(revision 724)
+++ /soft/giet_vm/giet_kernel/sys_handler.h	(revision 725)
@@ -51,5 +51,5 @@
 #define SYSCALL_NO_CHANNEL_AVAILABLE             (-18)
 #define SYSCALL_CHANNEL_NON_ALLOCATED            (-19)
-#define SYSCALL_ILLEGAL_XY_ARGUMENTS             (-20)
+#define SYSCALL_ILLEGAL_ARGUMENT                 (-20)
 #define SYSCALL_OUT_OF_KERNEL_HEAP_MEMORY        (-21)
 #define SYSCALL_ADDRESS_NON_ALIGNED              (-22)
@@ -64,30 +64,18 @@
 
 ///////////////////////////////////////////////////////////////////////////////
-// This structure is used by the CMA component to store the status of the
-// frame buffer (full or empty). The useful information is contained in the
-// "status" integer (1 for full and 0 for empty).
-// This structure must be aligned on a cache line (64 bytes) to simplify 
-// the software L2/L3 cache coherence when the IO bridge is used. 
-///////////////////////////////////////////////////////////////////////////////
-
-typedef struct buffer_status_s
-{
-    unsigned int status;
-    unsigned int padding[15];
-} buffer_status_t;
-
-///////////////////////////////////////////////////////////////////////////////
-// This structure is used by the CMA component to move a stream 
-// of images from two user buffers to the frame buffer in kernel space.
+// This structure is used by the CMA component to move a stream of images 
+// from a set of user buffers to the frame buffer in kernel space.
 // It contains two chbuf arrays:
-// - The SRC chbuf contains two buffers (buf0 & buf1), in user space.
-// - The DST cbuf contains one single buffer (fbf), that is the frame buffer.
+// - The SRC chbuf contains <nbufs> buffer descriptors, in user space,
+//   that can be distributed (one buffer per cluster) or not.
+// - The DST cbuf contains one single buffer, that is the frame buffer.
 // Each buffer is described with a 64 bits buffer descriptor:
-// - the 26 LSB bits contain bits[6:31] of the buffer physical address
-// - the 26 following bits contain bits[6:31] of the physical address where the
-//   buffer status is located
-// - the 12 MSB bits contain the common address extension of the buffer and its
-//   status
-// The length field define the buffer size (bytes)
+// - the 26 LSB bits contain bits[31:6] of the status physical address.
+// - the 26 following bits contain bits[31:6] of the buffer physical address.
+// - the 12 MSB bits contain the common address extension.
+// The actual number of user buffers cannot be larger than 256 (at most
+// one user buffer per cluster for a 16*16 mesh).
+// NB: The user buffers are mapped in user space, but the chbuf descriptor
+// contained in this structure is a protected kernel variable.
 // This structure must be 64 bytes aligned.
 ///////////////////////////////////////////////////////////////////////////////
@@ -95,9 +83,7 @@
 typedef struct fbf_chbuf_s
 {
-    unsigned long long  buf0_desc;     // first user buffer descriptor 
-    unsigned long long  buf1_desc;     // second user buffer descriptor
-    unsigned long long  fbf_desc;      // frame buffer descriptor 
-    unsigned int        length;        // buffer length (bytes)
-    unsigned int        padding[9];    // padding for 64 bytes alignment
+    unsigned long long  fbf_desc;                    // frame buffer descriptor 
+    unsigned long long  usr_desc[256];               // user chbuf descriptor 
+    unsigned int        nbufs;                       // number of user buffers
 } fbf_chbuf_t;   
 
@@ -110,18 +96,17 @@
 // The actual number of buffers used in the chbuf is defined by (xmax * ymax).
 // Each buffer is described with a 64 bits buffer descriptor:
-// - the 26 LSB bits contain bits[6:31] of the buffer physical address
-// - the 26 following bits contain bits[6:31] of the physical address where the
-//   buffer status is located
-// - the 12 MSB bits contain the common address extension of the buffer and its
-//   status
+// - the 26 LSB bits contain bits[31:6] of the status physical address.
+// - the 26 following bits contain bits[31:6] of the buffer physical address.
+// - the 12 MSB bits contain the common address extension.
+// The <xmax> and <ymax> fields define the actual mesh size.
 // This structure must be 64 bytes aligned.
 ///////////////////////////////////////////////////////////////////////////////
 
-typedef struct ker_chbuf_s
+typedef struct nic_chbuf_s
 {
-    unsigned long long   buf_desc[X_SIZE*Y_SIZE]; // kernel chbuf descriptor
+    unsigned long long   buf_desc[X_SIZE*Y_SIZE];     // kernel chbuf descriptor
     unsigned int         xmax;                        // nb clusters in a row
     unsigned int         ymax;                        // nb clusters in a column
-} ker_chbuf_t;
+} nic_chbuf_t;
 
 
@@ -236,23 +221,24 @@
 
 extern int _sys_fbf_sync_write( unsigned int offset,
-                         void*        buffer,
-                         unsigned int length );
+                                void*        buffer,
+                                unsigned int length );
 
 extern int _sys_fbf_sync_read(  unsigned int offset,
-                         void*        buffer,
-                         unsigned int length );
-
-extern int _sys_fbf_cma_alloc();
+                                void*        buffer,
+                                unsigned int length );
+
+extern int _sys_fbf_cma_alloc( unsigned int nbufs );
 
 extern int _sys_fbf_cma_release();
 
-extern int _sys_fbf_cma_init_buf(void*        buf0_vbase, 
-                                 void*        buf1_vbase, 
-                                 void*        sts0_vaddr,
-                                 void*        sts1_vaddr );
-
-extern int _sys_fbf_cma_start( unsigned int length );
-
-extern int _sys_fbf_cma_display( unsigned int buffer_index );
+extern int _sys_fbf_cma_init_buf( unsigned int index, 
+                                  void*        buf_vaddr, 
+                                  void*        sts_vaddr );
+
+extern int _sys_fbf_cma_start();
+
+extern int _sys_fbf_cma_display( unsigned int index );
+
+extern int _sys_fbf_cma_check( unsigned int index );
 
 extern int _sys_fbf_cma_stop();
@@ -265,27 +251,27 @@
 
 extern int _sys_proc_xyp( unsigned int* x,
-                   unsigned int* y,
-                   unsigned int* p );
+                          unsigned int* y,
+                          unsigned int* p );
 
 extern int _sys_procs_number( unsigned int* x_size,
-                       unsigned int* y_size, 
-                       unsigned int* nprocs );
+                              unsigned int* y_size, 
+                              unsigned int* nprocs );
 
 extern int _sys_vseg_get_vbase( char*         vspace_name,
-                         char*         vseg_name,
-                         unsigned int* vbase );
+                                char*         vseg_name,
+                                unsigned int* vbase );
 
 extern int _sys_vseg_get_length( char*         vspace_name, 
-                          char*         vseg_name,
-                          unsigned int* length );
+                                 char*         vseg_name,
+                                 unsigned int* length );
 
 extern int _sys_xy_from_ptr( void*          ptr,
-                      unsigned int*  x,
-                      unsigned int*  y );
+                             unsigned int*  x,
+                             unsigned int*  y );
 
 extern int _sys_heap_info( unsigned int* vaddr, 
-                    unsigned int* length,
-                    unsigned int  x,
-                    unsigned int  y ); 
+                           unsigned int* length,
+                           unsigned int  x,
+                           unsigned int  y ); 
 
 #endif
