Index: trunk/kernel/mm/vmm.c
===================================================================
--- trunk/kernel/mm/vmm.c	(revision 690)
+++ trunk/kernel/mm/vmm.c	(revision 1)
@@ -1,8 +1,9 @@
 /*
- * vmm.c - virtual memory manager related operations implementation.
+ * vmm.c - virtual memory manager related operations interface.
  *
- * Authors   Ghassan Almaless (2008,2009,2010,2011,2012)
- *           Alain Greiner    (2016,2017,2018,2019,2020)
- *
+ * Authors   Ghassan Almaless (2008,2009,2010,2011, 2012)
+ *           Mohamed Lamine Karaoui (2015)
+ *           Alain Greiner (2016)
+ * 
  * Copyright (c) UPMC Sorbonne Universites
  *
@@ -23,16 +24,11 @@
  */
 
-#include <kernel_config.h>
-#include <hal_kernel_types.h>
+#include <almos_config.h>
+#include <hal_types.h>
 #include <hal_special.h>
 #include <hal_gpt.h>
-#include <hal_vmm.h>
-#include <hal_irqmask.h>
-#include <hal_macros.h>
 #include <printk.h>
-#include <memcpy.h>
-#include <remote_queuelock.h>
+#include <rwlock.h>
 #include <list.h>
-#include <xlist.h>
 #include <bits.h>
 #include <process.h>
@@ -46,2909 +42,1379 @@
 #include <kmem.h>
 #include <vmm.h>
-#include <hal_exception.h>
-
-////////////////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////////////
 //   Extern global variables
-////////////////////////////////////////////////////////////////////////////////////////////
-
-extern  process_t  process_zero;      // allocated in cluster.c 
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// This static function is called by the vmm_user_init() function.
-// It initialises the free lists of vsegs used by the VMM MMAP allocator.
-// It makes the assumption that HEAP_BASE == 1 Gbytes and HEAP_SIZE == 2 Gbytes.
-////////////////////////////////////////////////////////////////////////////////////////////
-static void vmm_stack_init( vmm_t * vmm )
-{
-
-// check STACK zone
-assert( __FUNCTION__, ((CONFIG_VMM_STACK_SIZE * CONFIG_THREADS_MAX_PER_CLUSTER) <=
-(CONFIG_VMM_VSPACE_SIZE - CONFIG_VMM_STACK_BASE)) , "STACK zone too small\n");
-
-    // get pointer on STACK allocator 
-    stack_mgr_t * mgr = &vmm->stack_mgr;
-
-    mgr->bitmap   = 0;
-    mgr->vpn_base = CONFIG_VMM_STACK_BASE;
-    busylock_init( &mgr->lock , LOCK_VMM_STACK );
-
-}
+//////////////////////////////////////////////////////////////////////////////////
+
+extern  process_t  process_zero;   // defined in cluster.c file
+
+
+////////////////////////////////////
+void vmm_init( process_t * process )
+{  
+    error_t   error;
+    vseg_t  * vseg_kentry;
+    vseg_t  * vseg_args;
+    vseg_t  * vseg_envs;
+    vseg_t  * vseg_heap;
+    intptr_t  base;
+    intptr_t  size;
+
+    // get pointer on VMM
+    vmm_t   * vmm = &process->vmm;
+
+    // check UTILS zone size
+    if( (CONFIG_VMM_KENTRY_SIZE + CONFIG_VMM_ARGS_SIZE + CONFIG_VMM_ENVS_SIZE ) >
+        CONFIG_VMM_ELF_BASE )
+    {
+        printk("\n[PANIC] in %s : UTILS zone too small for process %x\n",
+               __FUNCTION__ , process->pid );
+        hal_core_sleep();
+    }
+    
+    // check max number of stacks slots
+    if( CONFIG_THREAD_MAX_PER_CLUSTER > 32 )
+    {
+        printk("\n[PANIC] in %s : max number ot threads per cluster for a sihgle process"
+               " cannot be larger than 32\n", __FUNCTION__ );
+        hal_core_sleep();
+    }
+
+    // check STACK zone size
+    if( (CONFIG_VMM_STACK_SIZE * CONFIG_THREAD_MAX_PER_CLUSTER) > 
+        (CONFIG_VMM_VSPACE_SIZE - CONFIG_VMM_STACK_BASE) )
+    {
+        printk("\n[PANIC] in %s : STACK zone too small for process %x\n",
+               __FUNCTION__ , process->pid );
+        hal_core_sleep();
+    }
+
+    // initialise the rwlock protecting the vsegs list
+	rwlock_init( &vmm->vsegs_lock );
+
+    // initialize local list of vsegs and radix-tree
+	list_root_init( &vmm->vsegs_root );
+    vmm->vsegs_nr = 0;
+    error = grdxt_init( &vmm->grdxt,
+                        CONFIG_VMM_GRDXT_W1,
+                        CONFIG_VMM_GRDXT_W2,
+                        CONFIG_VMM_GRDXT_W3 );
+    if( error )
+    {
+        printk("\n[PANIC] in %s : cannot initialise radix tree for process %x\n",
+               __FUNCTION__ , process->pid );
+        hal_core_sleep();
+    }
+
+    // register kentry vseg in VMM
+    base = 1 << CONFIG_PPM_PAGE_SHIFT;
+    size = CONFIG_VMM_KENTRY_SIZE << CONFIG_PPM_PAGE_SHIFT;
+    vseg_kentry = vmm_create_vseg( process , base , size , VSEG_TYPE_CODE );
+    if( vseg_kentry == NULL ) 
+    {
+        printk("\n[PANIC] in %s : cannot register kent vseg for process %x\n",
+               __FUNCTION__ , process->pid );
+        hal_core_sleep();
+    }
+    vmm->kent_vpn_base = 1;
+
+    // register the args vseg in VMM
+    base = (CONFIG_VMM_KENTRY_SIZE + 1 )<<CONFIG_PPM_PAGE_SHIFT;
+    size = CONFIG_VMM_ARGS_SIZE << CONFIG_PPM_PAGE_SHIFT;
+    vseg_args = vmm_create_vseg( process , base , size , VSEG_TYPE_DATA );
+    if( vseg_args == NULL ) 
+    {
+        printk("\n[PANIC] in %s : cannot register args vseg for process %x\n",
+               __FUNCTION__ , process->pid );
+        hal_core_sleep();
+    }
+    vmm->args_vpn_base = CONFIG_VMM_KENTRY_SIZE + 1;
+
+    // register the envs vseg in VMM
+    base = (CONFIG_VMM_KENTRY_SIZE + CONFIG_VMM_ARGS_SIZE + 1 )<<CONFIG_PPM_PAGE_SHIFT;
+    size = CONFIG_VMM_ENVS_SIZE << CONFIG_PPM_PAGE_SHIFT;
+    vseg_envs = vmm_create_vseg( process , base , size , VSEG_TYPE_DATA );
+    if( vseg_envs == NULL ) 
+    {
+        printk("\n[PANIC] in %s : cannot register envs vseg for process %x\n",
+               __FUNCTION__ , process->pid );
+        hal_core_sleep();
+    }
+    vmm->envs_vpn_base = CONFIG_VMM_KENTRY_SIZE + CONFIG_VMM_ARGS_SIZE + 1;
+
+    // register the heap vseg in VMM
+    base = CONFIG_VMM_HEAP_BASE << CONFIG_PPM_PAGE_SHIFT;
+    size = (CONFIG_VMM_MMAP_BASE-CONFIG_VMM_HEAP_BASE) << CONFIG_PPM_PAGE_SHIFT;
+    vseg_heap = vmm_create_vseg( process , base , size , VSEG_TYPE_HEAP );
+    if( vseg_heap == NULL ) 
+    {
+        printk("\n[PANIC] in %s : cannot register heap vseg in for process %x\n",
+               __FUNCTION__ , process->pid );
+        hal_core_sleep();
+    }
+    vmm->heap_vpn_base = CONFIG_VMM_HEAP_BASE;
+
+    // initialize generic page table
+    error = hal_gpt_create( &vmm->gpt );
+    if( error )
+    {
+        printk("PANIC in %s : cannot initialize page table\n", __FUNCTION__ );
+        hal_core_sleep();
+    }
+
+    // initialize STACK allocator
+    vmm->stack_mgr.bitmap   = 0;
+    vmm->stack_mgr.vpn_base = CONFIG_VMM_STACK_BASE;
+
+    // initialize MMAP allocator
+    vmm->mmap_mgr.vpn_base        = CONFIG_VMM_MMAP_BASE;
+    vmm->mmap_mgr.vpn_size        = CONFIG_VMM_STACK_BASE - CONFIG_VMM_MMAP_BASE;
+    vmm->mmap_mgr.first_free_vpn  = CONFIG_VMM_MMAP_BASE;
+    uint32_t i;
+    for( i = 0 ; i < 32 ; i++ ) list_root_init( &vmm->mmap_mgr.zombi_list[i] );
+
+    // initialise instrumentation counters
+	vmm->pgfault_nr          = 0;
+	vmm->u_err_nr            = 0;
+	vmm->m_err_nr            = 0;
+
+    hal_wbflush();
+
+}  // end vmm_init()
+
+///////////////////////////////////////
+void vmm_destroy( process_t * process )
+{
+	vseg_t * vseg;
+
+    // get pointer on VMM
+    vmm_t  * vmm = &process->vmm;
+
+    // get lock protecting vseg list
+	rwlock_wr_lock( &vmm->vsegs_lock );
+
+    // remove all vsegs registered in vmm
+	while( !list_is_empty( &vmm->vsegs_root ) )
+	{
+		vseg = LIST_FIRST( &vmm->vsegs_root ,  vseg_t , list );
+		vseg_detach( vmm , vseg );
+        vseg_free( vseg );
+	}
+
+    // delete vsegs radix_tree
+    grdxt_destroy( &vmm->grdxt );
+
+    // release lock
+	rwlock_wr_unlock(&vmm->vsegs_lock);
+
+    // remove all vsegs from zombi_lists in MMAP allocator
+    uint32_t i;
+    for( i = 0 ; i<32 ; i++ )
+    {
+	    while( !list_is_empty( &vmm->mmap_mgr.zombi_list[i] ) )
+	    {
+		    vseg = LIST_FIRST( &vmm->mmap_mgr.zombi_list[i] , vseg_t , list );
+		    vseg_detach( vmm , vseg );
+            vseg_free( vseg );
+	    }
+    }
+
+    // release memory allocated to the local page table
+    hal_gpt_destroy( &vmm->gpt );
+
+} // end vmm_destroy()
+
+/////////////////////////////////////////////////
+vseg_t * vmm_check_conflict( process_t * process,
+                             vpn_t       vpn_base, 
+                             vpn_t       vpn_size )
+{
+    vmm_t        * vmm = &process->vmm;
+	vseg_t       * vseg;
+    list_entry_t * iter;
+
+    // scan the list of registered vsegs
+	LIST_FOREACH( &vmm->vsegs_root , iter )
+	{
+		vseg = LIST_ELEMENT( iter , vseg_t , list );
+		if( ((vpn_base + vpn_size) > vseg->vpn_base) && 
+             (vpn_base < (vseg->vpn_base + vseg->vpn_size)) ) return vseg; 
+	}
+    return NULL;
+}  // vmm_check_conflict()
 
 ////////////////////////////////////////////////////////////////////////////////////////////
 // This static function is called by the vmm_create_vseg() function, and implements
-// the VMM STACK specific allocator. Depending on the local thread index <ltid>,
-// it ckeks availability of the corresponding slot in the process STACKS region,
-// allocates a vseg descriptor, and initializes the "vpn_base" and "vpn_size" fields.
+// the VMM stack_vseg specific allocator.
 ////////////////////////////////////////////////////////////////////////////////////////////
-// @ vmm      : [in]  pointer on VMM.
-// @ ltid     : [in]  requested slot == local user thread identifier.
+// @ vmm      : pointer on VMM.
+// @ vpn_base : (return value) first alocated page 
+// @ vpn_size : (return value) number of allocated pages
 ////////////////////////////////////////////////////////////////////////////////////////////
-static vseg_t * vmm_stack_alloc( vmm_t  * vmm,
-                                 ltid_t   ltid )
-{
-
-// check ltid argument
-assert( __FUNCTION__, 
-(ltid <= ((CONFIG_VMM_VSPACE_SIZE - CONFIG_VMM_STACK_BASE) / CONFIG_VMM_STACK_SIZE)),
-"slot index %d too large for an user stack vseg", ltid );
-
+static error_t vmm_stack_alloc( vmm_t * vmm,
+                                vpn_t * vpn_base,
+                                vpn_t * vpn_size )
+{
     // get stack allocator pointer
     stack_mgr_t * mgr = &vmm->stack_mgr;
 
-    // get lock protecting stack allocator
-    busylock_acquire( &mgr->lock );
-
-// check requested slot is available
-assert( __FUNCTION__, (bitmap_state( &mgr->bitmap , ltid ) == false),
-"slot index %d already allocated", ltid );
-
-    // allocate a vseg descriptor
-    vseg_t * vseg = vseg_alloc();
-
-    if( vseg == NULL )
-   	{
- 
-#if DEBUG_VMM_ERROR
-printk("\n[ERROR] %s cannot allocate memory for vseg in cluster %x\n",
-__FUNCTION__ , local_cxy );
-#endif
-        busylock_release( &mgr->lock );
-        return NULL;
-    }
+    // get lock on stack allocator
+    spinlock_lock( &mgr->lock );
+
+    // get first free slot index in bitmap
+    int32_t index = bitmap_ffc( &mgr->bitmap , 4 );
+    if( (index < 0) || (index > 31) ) return ENOMEM;
 
     // update bitmap
-    bitmap_set( &mgr->bitmap , ltid );
-
+    bitmap_set( &mgr->bitmap , index );
+            
     // release lock on stack allocator
-    busylock_release( &mgr->lock );
-
-    // set "vpn_base" & "vpn_size" fields (first page non allocated)
-    vseg->vpn_base = mgr->vpn_base + (ltid * CONFIG_VMM_STACK_SIZE) + 1;
-    vseg->vpn_size = CONFIG_VMM_STACK_SIZE - 1;
-
-    return vseg;
-
-} // end vmm_stack_alloc()
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// This static function is called by the vmm_remove_vseg() function, and implements
-// the VMM STACK specific desallocator.
-// It updates the bitmap to release the corresponding slot in the process STACKS region,
-// and releases memory allocated to vseg descriptor.
-////////////////////////////////////////////////////////////////////////////////////////////
-// @ vmm      : [in] pointer on VMM.
-// @ vseg     : [in] pointer on released vseg.
-////////////////////////////////////////////////////////////////////////////////////////////
-static void vmm_stack_free( vmm_t  * vmm,
-                            vseg_t * vseg )
-{
-    // get stack allocator pointer
-    stack_mgr_t * mgr = &vmm->stack_mgr;
-
-    // compute slot index
-    uint32_t index = (vseg->vpn_base - 1 - mgr->vpn_base) / CONFIG_VMM_STACK_SIZE;
-
-// check index
-assert( __FUNCTION__, (index <= ((CONFIG_VMM_VSPACE_SIZE - CONFIG_VMM_STACK_BASE) / CONFIG_VMM_STACK_SIZE)),
-"slot index %d too large for an user stack vseg", index );
-
-// check released slot is allocated
-assert( __FUNCTION__, (bitmap_state( &mgr->bitmap , index ) == true),
-"released slot index %d non allocated", index );
-
-    // get lock on stack allocator
-    busylock_acquire( &mgr->lock );
-
-    // update stacks_bitmap
-    bitmap_clear( &mgr->bitmap , index );
-
-    // release lock on stack allocator
-    busylock_release( &mgr->lock );
-
-    // release memory allocated to vseg descriptor
-    vseg_free( vseg );
-
-}  // end vmm_stack_free()
-
-
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// This function display the current state of the VMM MMAP allocator of a process VMM
-// identified by the <vmm> argument.
-////////////////////////////////////////////////////////////////////////////////////////////
-void vmm_mmap_display( vmm_t * vmm )
-{
-    uint32_t  order;
-    xptr_t    root_xp;
-    xptr_t    iter_xp;
-
-    // get pointer on process
-    process_t * process = (process_t *)(((char*)vmm) - OFFSETOF( process_t , vmm ));
-
-    // get process PID
-    pid_t pid = process->pid;
-
-    // get pointer on VMM MMAP allocator
-    mmap_mgr_t * mgr = &vmm->mmap_mgr;
-
-    // display header
-    printk("***** VMM MMAP allocator / process %x *****\n", pid );
-
-    // scan the array of free lists of vsegs
-    for( order = 0 ; order <= CONFIG_VMM_HEAP_MAX_ORDER ; order++ )
-    {
-        root_xp = XPTR( local_cxy , &mgr->free_list_root[order] );
-
-        if( !xlist_is_empty( root_xp ) )
-        {
-            printk(" - %d (%x pages) : ", order , 1<<order );
-
-            XLIST_FOREACH( root_xp , iter_xp )
-            {
-                xptr_t   vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
-                vseg_t * vseg    = GET_PTR( vseg_xp );
-
-                printk("%x | ", vseg->vpn_base );
-            }
-
-            printk("\n");
-        }
-    }
-}  // end vmm_mmap_display()
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// This static function is called by the vmm_user_init() function.
-// It initialises the free lists of vsegs used by the VMM MMAP allocator.
-// TODO this function is only valid for 32 bits cores, and makes three assumptions:
-// HEAP_BASE == 1 Gbytes / HEAP_SIZE == 2 Gbytes / MMAP_MAX_SIZE == 1 Gbytes
-////////////////////////////////////////////////////////////////////////////////////////////
-void vmm_mmap_init( vmm_t * vmm )
-{
-
-// check HEAP base and size 
-assert( __FUNCTION__, (CONFIG_VMM_HEAP_BASE == 0x40000) & (CONFIG_VMM_STACK_BASE == 0xc0000),
-"CONFIG_VMM_HEAP_BASE != 0x40000 or CONFIG_VMM_STACK_BASE != 0xc0000" );
-
-// check  MMAP vseg max order 
-assert( __FUNCTION__, (CONFIG_VMM_HEAP_MAX_ORDER == 18), "max mmap vseg size is 256K pages" );
-
-    // get pointer on MMAP allocator 
-    mmap_mgr_t * mgr = &vmm->mmap_mgr;
-
-    // initialize HEAP base and size
-    mgr->vpn_base        = CONFIG_VMM_HEAP_BASE;
-    mgr->vpn_size        = CONFIG_VMM_STACK_BASE - CONFIG_VMM_HEAP_BASE;
-
-    // initialize lock
-    busylock_init( &mgr->lock , LOCK_VMM_MMAP );
-
-    // initialize free lists
-    uint32_t   i;
-    for( i = 0 ; i <= CONFIG_VMM_HEAP_MAX_ORDER ; i++ )
-    {
-        xlist_root_init( XPTR( local_cxy , &mgr->free_list_root[i] ) );
-    }
-
-    // allocate and register first 1 Gbytes vseg
-    vseg_t * vseg0 = vseg_alloc();
-
-assert( __FUNCTION__, (vseg0 != NULL) , "cannot allocate vseg" );
-
-    vseg0->vpn_base = CONFIG_VMM_HEAP_BASE;
-    vseg0->vpn_size = CONFIG_VMM_HEAP_BASE;
-
-    xlist_add_first( XPTR( local_cxy , &mgr->free_list_root[CONFIG_VMM_HEAP_MAX_ORDER] ),
-                     XPTR( local_cxy , &vseg0->xlist ) );
-
-    // allocate and register second 1 Gbytes vseg
-    vseg_t * vseg1 = vseg_alloc();
-
-assert( __FUNCTION__, (vseg1 != NULL) , "cannot allocate vseg" );
-
-    vseg1->vpn_base = CONFIG_VMM_HEAP_BASE << 1;
-    vseg1->vpn_size = CONFIG_VMM_HEAP_BASE;
-
-    xlist_add_first( XPTR( local_cxy , &mgr->free_list_root[CONFIG_VMM_HEAP_MAX_ORDER] ),
-                     XPTR( local_cxy , &vseg1->xlist ) );
-
-#if DEBUG_VMM_MMAP
-thread_t * this = CURRENT_THREAD;
-uint32_t cycle = (uint32_t)hal_get_cycles();
-printk("\n[%s] thread[%x,%x] / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, cycle );
-vmm_mmap_display( vmm );
-#endif
-
-}  // end vmm_mmap_init()
+    spinlock_unlock( &mgr->lock );
+
+    // returns vpn_base, vpn_size (one page non allocated) 
+    *vpn_base = mgr->vpn_base + index * CONFIG_VMM_STACK_SIZE + 1;
+    *vpn_size = CONFIG_VMM_STACK_SIZE - 1;
+    return 0;
+
+}  // end vmm_stack_alloc()
 
 ////////////////////////////////////////////////////////////////////////////////////////////
 // This static function is called by the vmm_create_vseg() function, and implements
-// the VMM MMAP specific allocator.  Depending on the requested number of pages <npages>,
-// it get a free vseg from the relevant free_list, and initializes the "vpn_base" and
-// "vpn_size" fields.
+// the VMM MMAP specific allocator.
 ////////////////////////////////////////////////////////////////////////////////////////////
 // @ vmm      : [in] pointer on VMM.
 // @ npages   : [in] requested number of pages.
-// @ returns local pointer on vseg if success / returns NULL if failure.
+// @ vpn_base : [out] first allocated page. 
+// @ vpn_size : [out] actual number of allocated pages.
 ////////////////////////////////////////////////////////////////////////////////////////////
-static vseg_t * vmm_mmap_alloc( vmm_t * vmm,
-                                vpn_t   npages )
-{
-
-#if DEBUG_VMM_MMAP
-thread_t * this = CURRENT_THREAD;
-uint32_t cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_MMAP < cycle )
-printk("\n[%s] thread[%x,%x] for %x pages / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, npages, cycle );
-#endif
-
-    // number of allocated pages must be power of 2
-    // compute actual size and order 
-    vpn_t    required_vpn_size = POW2_ROUNDUP( npages );
-    uint32_t required_order    = bits_log2( required_vpn_size );
+static error_t vmm_mmap_alloc( vmm_t * vmm,
+                               vpn_t   npages,
+                               vpn_t * vpn_base,
+                               vpn_t * vpn_size )
+{
+    uint32_t   index;
+    vseg_t   * vseg;
+    vpn_t      base;
+    vpn_t      size;
+    vpn_t      free;    
+
+    // mmap vseg size must be power of 2 
+    // compute actual size and index in zombi_list array
+    size  = POW2_ROUNDUP( npages );
+    index = bits_log2( size );
 
     // get mmap allocator pointer
     mmap_mgr_t * mgr = &vmm->mmap_mgr;
 
-    // take lock protecting free lists in MMAP allocator
-    busylock_acquire( &mgr->lock );
-
-    // initialises the while loop variables
-    uint32_t   current_order = required_order;
-    vseg_t   * current_vseg  = NULL;
-
-    // search a free vseg equal or larger than requested size
-	while( current_order <= CONFIG_VMM_HEAP_MAX_ORDER )
-	{
-        // build extended pointer on free_pages_root[current_order]
-        xptr_t root_xp = XPTR( local_cxy , &mgr->free_list_root[current_order] );
-
-		if( !xlist_is_empty( root_xp ) )
-		{
-            // get extended pointer on first vseg in this free_list
-			xptr_t current_vseg_xp = XLIST_FIRST( root_xp , vseg_t , xlist );
-            current_vseg = GET_PTR( current_vseg_xp );
-
-            // build extended pointer on xlist field in vseg descriptor
-            xptr_t list_entry_xp = XPTR( local_cxy , &current_vseg->xlist );
-
-            // remove this vseg from the free_list
-			xlist_unlink( list_entry_xp );
-
-			break;	
-		}
-
-        // increment loop index
-        current_order++;
-
-    }  // end while loop 
-
-    if( current_vseg == NULL )  // return failure 
-    {
-
-#if DEBUG_VMM_ERROR
-printk("\n[ERROR] %s cannot allocate ) %d page(s) in cluster %x\n",
-__FUNCTION__, npages , local_cxy );
-#endif
-        busylock_release( &mgr->lock );
-        return NULL;
-    }
-
-	// split recursively the found vseg in smaller vsegs
-    // if required, and update the free-lists accordingly
-	while( current_order > required_order )
-	{
-        // get found vseg base and size
-        vpn_t  vpn_base = current_vseg->vpn_base;
-        vpn_t  vpn_size = current_vseg->vpn_size;
-        
-        // allocate a new vseg for the upper half of current vseg
-	    vseg_t * new_vseg = vseg_alloc();
-
-	    if( new_vseg == NULL )
-    	{
-
-#if DEBUG_VMM_ERROR
-printk("\n[ERROR] %s cannot allocate memory for vseg in cluster %x\n",
-__FUNCTION__ , local_cxy );
-#endif
-            busylock_release( &mgr->lock );
-            return NULL;
-	    }
-
-        // initialise new vseg (upper half of found vseg)
-        new_vseg->vmm      = vmm;
-        new_vseg->vpn_base = vpn_base + (vpn_size >> 1);
-        new_vseg->vpn_size = vpn_size >> 1;
-
-        // insert new vseg in relevant free_list
-		xlist_add_first( XPTR( local_cxy , &mgr->free_list_root[current_order-1] ),
-                         XPTR( local_cxy , &new_vseg->xlist ) );
-
-        // update found vseg
-        current_vseg->vpn_size = vpn_size>>1; 
-
-        // update order
-		current_order --;
-	}
-
-	// release lock protecting free lists
-	busylock_release( &mgr->lock );
-
-#if DEBUG_VMM_MMAP
-vmm_mmap_display( vmm );
-#endif
-
-    return current_vseg;
-
-}  // end vmm_mmap_alloc()
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// This static function implements the VMM MMAP specific desallocator.
-// It is called by the vmm_remove_vseg() function.
-// It releases the vseg to the relevant free_list, after trying (recursively) to
-// merge it to the buddy vseg.
-////////////////////////////////////////////////////////////////////////////////////////////
-// @ vmm      : [in] pointer on VMM.
-// @ vseg     : [in] pointer on released vseg.
-////////////////////////////////////////////////////////////////////////////////////////////
-static void vmm_mmap_free( vmm_t  * vmm,
-                           vseg_t * vseg )
-{
-
-#if DEBUG_VMM_MMAP
-thread_t * this = CURRENT_THREAD;
-uint32_t cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_MMAP < cycle )
-printk("\n[%s] thread[%x,%x] for vpn_base %x / vpn_size %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, vseg->vpn_base, vseg->vpn_size, cycle );
-#endif
-
-    vseg_t * buddy_vseg;
-
-    // get mmap allocator pointer
-    mmap_mgr_t * mgr = &vmm->mmap_mgr;
-
-    // take lock protecting free lists
-    busylock_acquire( &mgr->lock );
-
-    // initialise loop variables 
-    // released_vseg is the currently released vseg
-    vseg_t * released_vseg     = vseg;
-    uint32_t released_order    = bits_log2( vseg->vpn_size );
-
-	// iteratively merge the released vseg to the buddy vseg
-	// release the current page and exit when buddy not found
-    while( released_order <= CONFIG_VMM_HEAP_MAX_ORDER )
-    {
-        // compute buddy_vseg vpn_base 
-		vpn_t buddy_vpn_base = released_vseg->vpn_base ^ (1 << released_order);
-        
-        // build extended pointer on free_pages_root[current_order]
-        xptr_t root_xp = XPTR( local_cxy , &mgr->free_list_root[released_order] );
-
-        // scan this free list to find the buddy vseg
-        xptr_t   iter_xp;
-        buddy_vseg = NULL;
-        XLIST_FOREACH( root_xp , iter_xp )
+    // get lock on mmap allocator
+    spinlock_lock( &mgr->lock );
+
+    // get vseg from zombi_list or from mmap zone
+    if( list_is_empty( &mgr->zombi_list[index] ) )     // from mmap zone
+    {
+        // check overflow
+        free = mgr->first_free_vpn;
+        if( (free + size) > mgr->vpn_size ) return ENOMEM;
+
+        // update STACK allocator
+        mgr->first_free_vpn += size;
+
+        // compute base
+        base = free;
+    }
+    else                                             // from zombi_list
+    {
+        // get pointer on zombi vseg from zombi_list
+        vseg = LIST_FIRST( &mgr->zombi_list[index] , vseg_t , list );
+
+        // remove vseg from free-list
+        list_unlink( &vseg->list );
+
+        // compute base
+        base = vseg->vpn_base;
+    }    
+            
+    // release lock on mmap allocator
+    spinlock_unlock( &mgr->lock );
+
+    // returns vpn_base, vpn_size
+    *vpn_base = base;
+    *vpn_size = size;
+    return 0;
+
+}  // end vmm_mmap_allocator()
+
+//////////////////////////////////////////////
+vseg_t * vmm_create_vseg( process_t * process,
+                          intptr_t    base, 
+	                      intptr_t    size, 
+	                      uint32_t    type )
+{
+    vseg_t     * vseg;          // created vseg pointer
+    vpn_t        vpn_base;      // vseg first page 
+    vpn_t        vpn_size;      // number of pages
+	error_t      error;
+
+    // get pointer on VMM
+	vmm_t * vmm = &process->vmm;
+  
+	vmm_dmsg("\n[INFO] %s enter for process %x / base = %x / size = %x / type = %s\n",
+		     __FUNCTION__ , process->pid , base , size , vseg_type_name[type] );
+   
+    // compute base, size, vpn_base, vpn_size, depending on type
+    // we use the VMM specific allocators for STACK and MMAP vsegs
+    if( type == VSEG_TYPE_STACK )
+    {
+        // get vpn_base and vpn_size from STACK allocator
+        error = vmm_stack_alloc( vmm , &vpn_base , &vpn_size );
+        if( error )
         {
-            xptr_t   current_vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
-            vseg_t * current_vseg    = GET_PTR( current_vseg_xp );
-
-            if( current_vseg->vpn_base == buddy_vpn_base )
-            {
-                buddy_vseg = current_vseg;
-                break;
-            }
-        }
-        
-        if( buddy_vseg != NULL )     // buddy found => merge released & buddy
-        {
-            // update released vseg fields
-            released_vseg->vpn_size = buddy_vseg->vpn_size<<1;
-            if( released_vseg->vpn_base > buddy_vseg->vpn_base) 
-                released_vseg->vpn_base = buddy_vseg->vpn_base;
-
-            // remove buddy vseg from free_list
-            xlist_unlink( XPTR( local_cxy , &buddy_vseg->xlist ) );
-
-            // release memory allocated to buddy descriptor
-            vseg_free( buddy_vseg );
-        }
-        else                         // buddy not found => register & exit
-        {
-            // register released vseg in free list
-            xlist_add_first( root_xp , XPTR( local_cxy , &released_vseg->xlist ) );
-
-            // exit while loop
-            break;
-        }
-
-        // increment released_order
-        released_order++;
-    }
-
-    // release lock
-    busylock_release( &mgr->lock );
-
-#if DEBUG_VMM_MMAP
-vmm_mmap_display( vmm );
-#endif
-
-}  // end vmm_mmap_free()
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// This static function registers one vseg in the VSL of a local process descriptor.
-////////////////////////////////////////////////////////////////////////////////////////////
-// vmm       : [in] pointer on VMM.
-// vseg      : [in] pointer on vseg.
-////////////////////////////////////////////////////////////////////////////////////////////
-void vmm_attach_vseg_to_vsl( vmm_t  * vmm,
-                             vseg_t * vseg )
-{
-    // update vseg descriptor
-    vseg->vmm = vmm;
-
-    // increment vsegs number
-    vmm->vsegs_nr++;
-
-    // add vseg in vmm list
-    xlist_add_last( XPTR( local_cxy , &vmm->vsegs_root ),
-                    XPTR( local_cxy , &vseg->xlist ) );
-
-}  // end vmm_attach_vseg_to_vsl()
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// This static function removes one vseg from the VSL of a local process descriptor.
-////////////////////////////////////////////////////////////////////////////////////////////
-// vmm       : [in] pointer on VMM.
-// vseg      : [in] pointer on vseg.
-////////////////////////////////////////////////////////////////////////////////////////////
-void vmm_detach_vseg_from_vsl( vmm_t  * vmm,
-                               vseg_t * vseg )
-{
-    // update vseg descriptor
-    vseg->vmm = NULL;
-
-    // decrement vsegs number
-    vmm->vsegs_nr--;
-
-    // remove vseg from VSL
-    xlist_unlink( XPTR( local_cxy , &vseg->xlist ) );
-
-}  // end vmm_detach_vseg_from_vsl()
-
-////////////////////////////////////////////
-error_t vmm_user_init( process_t * process )
-{
-
-#if DEBUG_VMM_USER_INIT
-thread_t * this = CURRENT_THREAD;
-uint32_t cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_USER_INIT )
-printk("\n[%s] thread[%x,%x] enter for process %x in cluster %x / cycle %d\n", 
-__FUNCTION__ , this->process->pid, this->trdid, process->pid, local_cxy, cycle );
-#endif
-
-    // get pointer on VMM
-    vmm_t   * vmm = &process->vmm;
-
-// check UTILS zone 
-assert( __FUNCTION__ , ((CONFIG_VMM_ARGS_SIZE + CONFIG_VMM_ENVS_SIZE) <= 
-(CONFIG_VMM_ELF_BASE - CONFIG_VMM_UTILS_BASE)) , "UTILS zone too small\n" );
-
-    // initialize lock protecting the VSL 
-	remote_queuelock_init( XPTR( local_cxy , &vmm->vsl_lock ) , LOCK_VMM_VSL );
-
-    // initialize STACK allocator
-    vmm_stack_init( vmm );
-
-    // initialize MMAP allocator
-    vmm_mmap_init( vmm );
-
-    // initialize instrumentation counters
-	vmm->false_pgfault_nr    = 0;
-	vmm->local_pgfault_nr    = 0;
-	vmm->global_pgfault_nr   = 0;
-	vmm->false_pgfault_cost  = 0;
-	vmm->local_pgfault_cost  = 0;
-	vmm->global_pgfault_cost = 0;
-
-    hal_fence();
-
-#if DEBUG_VMM_USER_INIT
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_USER_INIT )
-printk("\n[%s] thread[%x,%x] exit for process %x in cluster %x / cycle %d\n", 
-__FUNCTION__, this->process->pid, this->trdid, process->pid, local_cxy, cycle );
-#endif
-
-    return 0;
-
-}  // end vmm_user_init()
-
-//////////////////////////////////////////
-void vmm_user_reset( process_t * process )
-{
-    xptr_t       vseg_xp;
-	vseg_t     * vseg;
-    vseg_type_t  vseg_type;
-
-#if DEBUG_VMM_USER_RESET
-uint32_t   cycle;
-thread_t * this = CURRENT_THREAD;
-#endif
-
-#if (DEBUG_VMM_USER_RESET & 1 )
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_USER_RESET < cycle )
-printk("\n[%s] thread[%x,%x] enter for process %x in cluster %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, process->pid, local_cxy, cycle );
-#endif
-
-#if (DEBUG_VMM_USER_RESET & 1 )
-if( DEBUG_VMM_USER_RESET < cycle )
-hal_vmm_display( XPTR( local_cxy , process ) , true );
-#endif
-
-    // get pointer on local VMM
-    vmm_t * vmm = &process->vmm;
-
-    // build extended pointer on VSL root and VSL lock
-    xptr_t   root_xp = XPTR( local_cxy , &vmm->vsegs_root );
-    xptr_t   lock_xp = XPTR( local_cxy , &vmm->vsl_lock );
-
-    // take the VSL lock
-	remote_queuelock_acquire( lock_xp );
-
-    // scan the VSL to delete all non kernel vsegs
-    // (we don't use a FOREACH in case of item deletion)
-    xptr_t   iter_xp;
-    xptr_t   next_xp;
-	for( iter_xp = hal_remote_l64( root_xp ) ; 
-         iter_xp != root_xp ;
-         iter_xp = next_xp )
-	{
-        // save extended pointer on next item in xlist
-        next_xp = hal_remote_l64( iter_xp );
-
-        // get pointers on current vseg in VSL
-        vseg_xp   = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
-        vseg      = GET_PTR( vseg_xp );
-        vseg_type = vseg->type;
-
-#if( DEBUG_VMM_USER_RESET & 1 )
-if( DEBUG_VMM_USER_RESET < cycle )
-printk("\n[%s] found %s vseg / vpn_base %x / vpn_size %d\n",
-__FUNCTION__ , vseg_type_str( vseg->type ), vseg->vpn_base, vseg->vpn_size );
-#endif
-        // delete non kernel vseg  
-        if( (vseg_type != VSEG_TYPE_KCODE) && 
-            (vseg_type != VSEG_TYPE_KDATA) && 
-            (vseg_type != VSEG_TYPE_KDEV ) )
-        {
-            // remove vseg from VSL
-            vmm_remove_vseg( process , vseg );
-
-#if( DEBUG_VMM_USER_RESET & 1 )
-if( DEBUG_VMM_USER_RESET < cycle )
-printk("\n[%s] %s vseg deleted / vpn_base %x / vpn_size %d\n",
-__FUNCTION__ , vseg_type_str( vseg->type ), vseg->vpn_base, vseg->vpn_size );
-#endif
-        }
-        else
-        {
-
-#if( DEBUG_VMM_USER_RESET & 1 )
-if( DEBUG_VMM_USER_RESET < cycle )
-printk("\n[%s] keep %s vseg / vpn_base %x / vpn_size %d\n",
-__FUNCTION__ , vseg_type_str( vseg->type ), vseg->vpn_base, vseg->vpn_size );
-#endif
-        }
-	}  // end loop on vsegs in VSL
-
-    // release the VSL lock
-	remote_queuelock_release( lock_xp );
-
-// FIXME il faut gérer les process copies...
-
-    // re-initialise VMM
-    vmm_user_init( process );
-
-#if DEBUG_VMM_USER_RESET
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_USER_RESET < cycle )
-printk("\n[%s] thread[%x,%x] exit for process %x in cluster %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, process->pid, local_cxy , cycle );
-#endif
-
-#if (DEBUG_VMM_USER_RESET & 1 )
-if( DEBUG_VMM_USER_RESET < cycle )
-hal_vmm_display( XPTR( local_cxy , process ) , true );
-#endif
-
-}  // end vmm_user_reset()
-
-/////////////////////////////////////////////////
-void vmm_global_delete_vseg( process_t * process,
-                             intptr_t    base )
-{
-    cxy_t           owner_cxy;
-    lpid_t          owner_lpid;
-    reg_t           save_sr;
-
-    xptr_t          process_lock_xp;
-    xptr_t          process_root_xp;
-    xptr_t          process_iter_xp;
-
-    xptr_t          remote_process_xp;
-    cxy_t           remote_process_cxy;
-    process_t     * remote_process_ptr;
-
-    xptr_t          vsl_root_xp;
-    xptr_t          vsl_lock_xp;
-    xptr_t          vsl_iter_xp;
-
-    rpc_desc_t      rpc;                  // shared rpc descriptor for parallel RPCs
-    uint32_t        responses;            // RPC responses counter
-
-    thread_t      * this    = CURRENT_THREAD;
-    pid_t           pid     = process->pid;
-    cluster_t     * cluster = LOCAL_CLUSTER;
-
-#if DEBUG_VMM_GLOBAL_DELETE_VSEG
-uint32_t cycle = (uint32_t)hal_get_cycles();
-#endif
-
-#if (DEBUG_VMM_GLOBAL_DELETE_VSEG & 1)
-if( DEBUG_VMM_GLOBAL_DELETE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] enters / process %x / base %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, process->pid, base, cycle );
-#endif
-
-    // initialize a shared RPC descriptor
-    rpc.rsp       = &responses;
-    rpc.blocking  = false;                  // non blocking behaviour for rpc_send()
-    rpc.index     = RPC_VMM_REMOVE_VSEG;
-    rpc.thread    = this;
-    rpc.lid       = this->core->lid;
-    rpc.args[0]   = this->process->pid;
-    rpc.args[1]   = base;
-
-    // get owner process cluster and local index 
-    owner_cxy        = CXY_FROM_PID( pid );
-    owner_lpid       = LPID_FROM_PID( pid );
-
-    // get extended pointer on root and lock of process copies xlist in owner cluster
-    process_root_xp  = XPTR( owner_cxy , &cluster->pmgr.copies_root[owner_lpid] );
-    process_lock_xp  = XPTR( owner_cxy , &cluster->pmgr.copies_lock[owner_lpid] );
-
-    // mask IRQs
-    hal_disable_irq( &save_sr );
-
-    // client thread blocks itself
-    thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_RPC );
-
-    // take the lock protecting process copies
-    remote_queuelock_acquire( process_lock_xp );
-
-    // initialize responses counter
-    responses = 0;
-
-    // loop on process copies
-    XLIST_FOREACH( process_root_xp , process_iter_xp )
-    {
-        // get cluster and local pointer on remote process
-        remote_process_xp  = XLIST_ELEMENT( process_iter_xp , process_t , copies_list );
-        remote_process_ptr = GET_PTR( remote_process_xp );
-        remote_process_cxy = GET_CXY( remote_process_xp );
-
-        // build extended pointers on remote VSL root and lock
-        vsl_root_xp = XPTR( remote_process_cxy , &remote_process_ptr->vmm.vsegs_root );
-        vsl_lock_xp = XPTR( remote_process_cxy , &remote_process_ptr->vmm.vsl_lock );
-
-        // get lock on remote VSL
-        remote_queuelock_acquire( vsl_lock_xp );
-
-        // loop on vsegs in remote process VSL
-        XLIST_FOREACH( vsl_root_xp , vsl_iter_xp )
-        {
-            // get pointers on current vseg 
-            xptr_t   vseg_xp  = XLIST_ELEMENT( vsl_iter_xp , vseg_t , xlist );
-            vseg_t * vseg_ptr = GET_PTR( vseg_xp );
-
-            // get current vseg base address
-            intptr_t vseg_base = (intptr_t)hal_remote_lpt( XPTR( remote_process_cxy,
-                                                                 &vseg_ptr->min ) );
-
-            if( vseg_base == base )   // found searched vseg
-            {
-                // atomically increment responses counter
-                hal_atomic_add( &responses , 1 );
-
-#if (DEBUG_VMM_GLOBAL_DELETE_VSEG & 1)
-if( DEBUG_VMM_GLOBAL_DELETE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] register RPC request in cluster %x\n",
-__FUNCTION__, this->process->pid, this->trdid, remote_process_cxy );
-#endif
-                // send RPC to remote cluster
-                rpc_send( remote_process_cxy , &rpc );
-
-                // exit loop on vsegs
-                break;
-            }
-        }  // end of loop on vsegs
-
-        // release lock on remote VSL
-        remote_queuelock_release( vsl_lock_xp );
-
-    }  // end of loop on process copies
-
-    // release the lock protecting process copies
-    remote_queuelock_release( process_lock_xp );
-
-#if (DEBUG_VMM_GLOBAL_DELETE_VSEG & 1)
-if( DEBUG_VMM_GLOBAL_DELETE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] deschedule / process %x / base %x\n",
-__FUNCTION__, this->process->pid, this->trdid, process->pid, base );
-#endif
-
-    // client thread deschedule
-    sched_yield("blocked on rpc_vmm_delete_vseg");
- 
-    // restore IRQs
-    hal_restore_irq( save_sr );
-
-#if DEBUG_VMM_GLOBAL_DELETE_VSEG
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_GLOBAL_DELETE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] exit / process %x / base %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, process->pid, base, cycle );
-#endif
-
-}  // end vmm_global_delete_vseg()
-
-////////////////////////////////////////////////
-void vmm_global_resize_vseg( process_t * process,
-                             intptr_t    base,
-                             intptr_t    new_base,
-                             intptr_t    new_size )
-{
-    cxy_t           owner_cxy;
-    lpid_t          owner_lpid;
-    reg_t           save_sr;
-
-    xptr_t          process_lock_xp;
-    xptr_t          process_root_xp;
-    xptr_t          process_iter_xp;
-
-    xptr_t          remote_process_xp;
-    cxy_t           remote_process_cxy;
-    process_t     * remote_process_ptr;
-
-    xptr_t          vsl_root_xp;
-    xptr_t          vsl_lock_xp;
-    xptr_t          vsl_iter_xp;
-
-    rpc_desc_t      rpc;                  // shared rpc descriptor for parallel RPCs
-    uint32_t        responses;            // RPC responses counter
-
-    thread_t      * this    = CURRENT_THREAD; 
-    pid_t           pid     = process->pid;
-    cluster_t     * cluster = LOCAL_CLUSTER;
-
-#if DEBUG_VMM_GLOBAL_RESIZE_VSEG
-uint32_t cycle = (uint32_t)hal_get_cycles();
-#endif
-
-#if (DEBUG_VMM_GLOBAL_RESIZE_VSEG & 1)
-if( DEBUG_VMM_GLOBAL_RESIZE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] : process %x / base %x / new_base %x / new_size %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, process->pid, base, new_base, new_size, cycle );
-#endif
-
-    // initialize a shared RPC descriptor
-    rpc.rsp       = &responses;
-    rpc.blocking  = false;                  // non blocking behaviour for rpc_send()
-    rpc.index     = RPC_VMM_REMOVE_VSEG;
-    rpc.thread    = this;
-    rpc.lid       = this->core->lid;
-    rpc.args[0]   = this->process->pid;
-    rpc.args[1]   = base;
-    rpc.args[2]   = new_base;
-    rpc.args[3]   = new_size;
-
-    // get owner process cluster and local index
-    owner_cxy        = CXY_FROM_PID( pid );
-    owner_lpid       = LPID_FROM_PID( pid );
-
-    // get extended pointer on root and lock of process copies xlist in owner cluster
-    process_root_xp  = XPTR( owner_cxy , &cluster->pmgr.copies_root[owner_lpid] );
-    process_lock_xp  = XPTR( owner_cxy , &cluster->pmgr.copies_lock[owner_lpid] );
-
-    // mask IRQs
-    hal_disable_irq( &save_sr );
-
-    // client thread blocks itself
-    thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_RPC );
-
-    // take the lock protecting process copies
-    remote_queuelock_acquire( process_lock_xp );
-
-    // initialize responses counter
-    responses = 0;
-
-    // loop on process copies
-    XLIST_FOREACH( process_root_xp , process_iter_xp )
-    {
-        // get cluster and local pointer on remote process
-        remote_process_xp  = XLIST_ELEMENT( process_iter_xp , process_t , copies_list );
-        remote_process_ptr = GET_PTR( remote_process_xp );
-        remote_process_cxy = GET_CXY( remote_process_xp );
-
-        // build extended pointers on remote VSL root and lock
-        vsl_root_xp = XPTR( remote_process_cxy , &remote_process_ptr->vmm.vsegs_root );
-        vsl_lock_xp = XPTR( remote_process_cxy , &remote_process_ptr->vmm.vsl_lock );
-
-        // get lock on remote VSL
-        remote_queuelock_acquire( vsl_lock_xp );
-
-        // loop on vsegs in remote process VSL
-        XLIST_FOREACH( vsl_root_xp , vsl_iter_xp )
-        {
-            // get pointers on current vseg 
-            xptr_t   vseg_xp  = XLIST_ELEMENT( vsl_iter_xp , vseg_t , xlist );
-            vseg_t * vseg_ptr = GET_PTR( vseg_xp );
-
-            // get current vseg base address
-            intptr_t vseg_base = (intptr_t)hal_remote_lpt( XPTR( remote_process_cxy,
-                                                                 &vseg_ptr->min ) );
-
-            if( vseg_base == base )   // found searched vseg
-            {
-                // atomically increment responses counter
-                hal_atomic_add( &responses , 1 );
-
-#if (DEBUG_VMM_GLOBAL_RESIZE_VSEG & 1)
-if( DEBUG_VMM_GLOBAL_RESIZE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] register RPC request in cluster %x\n",
-__FUNCTION__, this->process->pid, this->trdid, remote_process_cxy );
-#endif
-                // send RPC to remote cluster
-                rpc_send( remote_process_cxy , & rpc );
-
-                // exit loop on vsegs
-                break;
-            }
-
-        }  // end of loop on vsegs
-
-#if (DEBUG_VMM_GLOBAL_RESIZE_VSEG & 1)
-if( DEBUG_VMM_GLOBAL_RESIZE_VSEG < cycle )
-hal_vmm_display( remote_process_xp , false );
-#endif
-
-        // release lock on remote VSL
-        remote_queuelock_release( vsl_lock_xp );
-
-    }  // end of loop on process copies
-
-    // release the lock protecting process copies
-    remote_queuelock_release( process_lock_xp );
-
-#if (DEBUG_VMM_GLOBAL_RESIZE_VSEG & 1)
-if( DEBUG_VMM_GLOBAL_RESIZE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] deschedule / process %x / base %x\n",
-__FUNCTION__, this->process->pid, this->trdid, process->pid, base );
-#endif
-
-    // client thread deschedule
-    sched_yield("blocked on rpc_vmm_delete_vseg");
-
-    // restore IRQs
-    hal_restore_irq( save_sr );
-
-#if DEBUG_VMM_GLOBAL_RESIZE_VSEG
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_GLOBAL_RESIZE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] exit for process %x / base %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, process->pid , base, cycle );
-#endif
-
-}  // end vmm_global_resize_vseg()
-
-////////////////////////////////////////////////
-void vmm_global_update_pte( process_t * process,
-                            vpn_t       vpn,
-                            uint32_t    attr,
-                            ppn_t       ppn )
-{
-    pid_t           pid;
-    cxy_t           owner_cxy;
-    lpid_t          owner_lpid;
-
-    xlist_entry_t * process_root_ptr;
-    xptr_t          process_root_xp;
-    xptr_t          process_iter_xp;
-
-    xptr_t          remote_process_xp;
-    cxy_t           remote_process_cxy;
-    process_t     * remote_process_ptr;
-    xptr_t          remote_gpt_xp;
-
-#if DEBUG_VMM_GLOBAL_UPDATE_PTE
-uint32_t cycle = (uint32_t)hal_get_cycles();
-thread_t * this = CURRENT_THREAD;
-#endif
-
-
-#if (DEBUG_VMM_GLOBAL_UPDATE_PTE & 1)
-if( DEBUG_VMM_GLOBAL_UPDATE_PTE < cycle )
-printk("\n[%s] thread[%x,%x] enter for process %x / vpn %x / attr %x / ppn %x / ycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, process->pid, vpn, attr, ppn, cycle );
-#endif
-
-    // get owner process cluster and local index
-    pid              = process->pid;
-    owner_cxy        = CXY_FROM_PID( pid );
-    owner_lpid       = LPID_FROM_PID( pid );
-
-    // get extended pointer on root of process copies xlist in owner cluster
-    process_root_ptr = &LOCAL_CLUSTER->pmgr.copies_root[owner_lpid];
-    process_root_xp  = XPTR( owner_cxy , process_root_ptr );
-
-    // loop on process copies
-    XLIST_FOREACH( process_root_xp , process_iter_xp )
-    {
-        // get cluster and local pointer on remote process
-        remote_process_xp  = XLIST_ELEMENT( process_iter_xp , process_t , copies_list );
-        remote_process_ptr = GET_PTR( remote_process_xp );
-        remote_process_cxy = GET_CXY( remote_process_xp );
-
-#if (DEBUG_VMM_GLOBAL_UPDATE_PTE & 1)
-if( DEBUG_VMM_GLOBAL_UPDATE_PTE < cycle )
-printk("\n[%s] thread[%x,%x] handling vpn %x for process %x in cluster %x\n",
-__FUNCTION__, this->process->pid, this->trdid, vpn, process->pid, remote_process_cxy );
-#endif
-
-        // get extended pointer on remote gpt
-        remote_gpt_xp = XPTR( remote_process_cxy , &remote_process_ptr->vmm.gpt );
-
-        // update remote GPT
-        hal_gpt_update_pte( remote_gpt_xp, vpn, attr, ppn );
-    }  
-
-#if DEBUG_VMM_GLOBAL_UPDATE_PTE
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_GLOBAL_UPDATE_PTE < cycle )
-printk("\n[%s] thread[%x,%x] exit for process %x / vpn %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, process->pid , vpn , cycle );
-#endif
-
-#if (DEBUG_VMM_GLOBAL_UPDATE_PTE & 1)
-hal_vmm_display( process , true );
-#endif
-
-}  // end vmm_global_update_pte()
-
-///////////////////////////////////////
-void vmm_set_cow( process_t * process )
-{
-    vmm_t         * vmm;
-
-    xlist_entry_t * process_root_ptr;
-    xptr_t          process_root_xp;
-    xptr_t          process_iter_xp;
-
-    xptr_t          remote_process_xp;
-    cxy_t           remote_process_cxy;
-    process_t     * remote_process_ptr;
-    xptr_t          remote_gpt_xp;
-
-    xptr_t          vseg_root_xp;
-    xptr_t          vseg_iter_xp;
-
-    xptr_t          vseg_xp;
-    vseg_t        * vseg;
-
-    pid_t           pid;
-    cxy_t           owner_cxy;
-    lpid_t          owner_lpid;
-
-    // get target process PID
-    pid = process->pid;
-
-#if DEBUG_VMM_SET_COW
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-thread_t * this  = CURRENT_THREAD;
-if( DEBUG_VMM_SET_COW < cycle )
-printk("\n[%s] thread[%x,%x] enter for process %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, pid , cycle );
-#endif
-
-#if (DEBUG_VMM_SET_COW & 1)
-if( DEBUG_VMM_SET_COW < cycle )
-hal_vmm_display( process , true );
-#endif
-
-// check cluster is reference
-assert( __FUNCTION__, (XPTR( local_cxy , process ) == process->ref_xp),
-"local cluster must be process reference cluster\n");
-
-    // get pointer on reference VMM
-    vmm = &process->vmm;
-
-    // get extended pointer on root of process copies xlist in owner cluster
-    owner_cxy        = CXY_FROM_PID( pid );
-    owner_lpid       = LPID_FROM_PID( pid );
-    process_root_ptr = &LOCAL_CLUSTER->pmgr.copies_root[owner_lpid];
-    process_root_xp  = XPTR( owner_cxy , process_root_ptr );
-
-    // get extended pointer on root of vsegs xlist from reference VMM
-    vseg_root_xp  = XPTR( local_cxy , &vmm->vsegs_root ); 
-
-    // loop on target process copies
-    XLIST_FOREACH( process_root_xp , process_iter_xp )
-    {
-        // get cluster and local pointer on remote process copy
-        remote_process_xp  = XLIST_ELEMENT( process_iter_xp , process_t , copies_list );
-        remote_process_ptr = GET_PTR( remote_process_xp );
-        remote_process_cxy = GET_CXY( remote_process_xp );
-
-#if (DEBUG_VMM_SET_COW & 1)
-if( DEBUG_VMM_SET_COW < cycle )
-printk("\n[%s] thread[%x,%x] (%x) handles process %x in cluster %x\n",
-__FUNCTION__, this->process->pid, this->trdid, this, pid, remote_process_cxy );
-#endif
-
-        // get extended pointer on remote gpt
-        remote_gpt_xp = XPTR( remote_process_cxy , &remote_process_ptr->vmm.gpt );
-
-        // loop on vsegs in (local) reference process VSL
-        XLIST_FOREACH( vseg_root_xp , vseg_iter_xp )
-        {
-            // get pointer on vseg
-            vseg_xp  = XLIST_ELEMENT( vseg_iter_xp , vseg_t , xlist );
-            vseg     = GET_PTR( vseg_xp );
-
-            // get vseg type, base and size
-            uint32_t type     = vseg->type;
-            vpn_t    vpn_base = vseg->vpn_base;
-            vpn_t    vpn_size = vseg->vpn_size;
-
-#if (DEBUG_VMM_SET_COW & 1)
-if( DEBUG_VMM_SET_COW < cycle )
-printk("\n[%s] thread[%x,%x] found vseg %s / vpn_base = %x / vpn_size = %x\n",
-__FUNCTION__, this->process->pid, this->trdid, vseg_type_str(type), vpn_base, vpn_size );
-#endif
-            // only DATA, ANON and REMOTE vsegs
-            if( (type == VSEG_TYPE_DATA)  ||
-                (type == VSEG_TYPE_ANON)  ||
-                (type == VSEG_TYPE_REMOTE) )
-            {
-                vpn_t      vpn;
-                uint32_t   attr;
-                ppn_t      ppn;
-                xptr_t     page_xp;
-                cxy_t      page_cxy;
-                page_t   * page_ptr;
-                xptr_t     forks_xp;
-                xptr_t     lock_xp;
-
-                // update flags in remote GPT 
-                hal_gpt_set_cow( remote_gpt_xp,
-                                 vpn_base,
-                                 vpn_size ); 
-
-                // atomically increment pending forks counter in physical pages,
-                // this is only done once, when handling the reference copy 
-                if( remote_process_cxy == local_cxy )
-                {
-
-#if (DEBUG_VMM_SET_COW & 1)
-if( DEBUG_VMM_SET_COW < cycle )
-printk("\n[%s] thread[%x,%x] handles vseg %s / vpn_base = %x / vpn_size = %x\n",
-__FUNCTION__, this->process->pid, this->trdid, vseg_type_str(type), vpn_base, vpn_size );
-#endif
-                    // scan all pages in vseg 
-                    for( vpn = vpn_base ; vpn < (vpn_base + vpn_size) ; vpn++ )
-                    {
-                        // get page attributes and PPN from reference GPT
-                        hal_gpt_get_pte( remote_gpt_xp , vpn , &attr , &ppn ); 
-
-                        // atomically update pending forks counter if page is mapped
-                        if( attr & GPT_MAPPED )
-                        {
-                            // get pointers and cluster on page descriptor
-                            page_xp  = ppm_ppn2page( ppn );
-                            page_cxy = GET_CXY( page_xp );
-                            page_ptr = GET_PTR( page_xp );
-
-                            // get extended pointers on "forks" and "lock"
-                            forks_xp = XPTR( page_cxy , &page_ptr->forks );
-                            lock_xp  = XPTR( page_cxy , &page_ptr->lock );
-
-                            // take lock protecting "forks" counter
-                            remote_busylock_acquire( lock_xp );
-
-                            // increment "forks"
-                            hal_remote_atomic_add( forks_xp , 1 );
-
-                            // release lock protecting "forks" counter
-                            remote_busylock_release( lock_xp );
-                        }
-                    }   // end loop on vpn
-
-#if (DEBUG_VMM_SET_COW & 1)
-if( DEBUG_VMM_SET_COW < cycle )
-printk("\n[%s] thread[%x,%x] completes vseg %s / vpn_base = %x / vpn_size = %x\n",
-__FUNCTION__, this->process->pid, this->trdid, vseg_type_str(type), vpn_base, vpn_size );
-#endif
-                }   // end if local
-            }   // end if vseg type
-        }   // end loop on vsegs
-    }   // end loop on process copies
- 
-#if DEBUG_VMM_SET_COW
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_SET_COW < cycle )
-printk("\n[%s] thread[%x,%x] exit for process %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, process->pid , cycle );
-#endif
-
-}  // end vmm_set-cow()
-
-/////////////////////////////////////////////////
-error_t vmm_fork_copy( process_t * child_process,
-                       xptr_t      parent_process_xp )
-{
-    error_t     error;
-    cxy_t       parent_cxy;
-    process_t * parent_process;
-    vmm_t     * parent_vmm;
-    xptr_t      parent_lock_xp;
-    vmm_t     * child_vmm;
-    xptr_t      iter_xp;
-    xptr_t      parent_vseg_xp;
-    vseg_t    * parent_vseg;
-    vseg_t    * child_vseg;
-    uint32_t    type;
-    vpn_t       vpn;            
-    vpn_t       vpn_base;
-    vpn_t       vpn_size;
-    xptr_t      parent_root_xp;
-    bool_t      mapped; 
-    ppn_t       ppn;
-
-#if DEBUG_VMM_FORK_COPY
-uint32_t cycle = (uint32_t)hal_get_cycles();
-thread_t * this = CURRENT_THREAD;
-if( DEBUG_VMM_FORK_COPY < cycle )
-printk("\n[%s] thread %x enter / cycle %d\n",
-__FUNCTION__ , this->process->pid, this->trdid, cycle );
-#endif
-
-    // get parent process cluster and local pointer
-    parent_cxy     = GET_CXY( parent_process_xp );
-    parent_process = GET_PTR( parent_process_xp );
-
-    // get local pointers on parent and child VMM
-    parent_vmm = &parent_process->vmm; 
-    child_vmm  = &child_process->vmm;
-
-    // build extended pointer on parent VSL root and lock
-    parent_root_xp = XPTR( parent_cxy , &parent_vmm->vsegs_root );
-    parent_lock_xp = XPTR( parent_cxy , &parent_vmm->vsl_lock );
-
-    // take the lock protecting the parent VSL 
-    remote_queuelock_acquire( parent_lock_xp );
-
-    // loop on parent VSL xlist
-    XLIST_FOREACH( parent_root_xp , iter_xp )
-    {
-        // get pointers on current parent vseg
-        parent_vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
-        parent_vseg    = GET_PTR( parent_vseg_xp );
-
-        // get vseg type
-        type = hal_remote_l32( XPTR( parent_cxy , &parent_vseg->type ) );
-        
-#if DEBUG_VMM_FORK_COPY
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_FORK_COPY < cycle )
-printk("\n[%s] thread[%x,%x] found parent vseg %s / vpn_base = %x / cycle %d\n",
-__FUNCTION__ , this->process->pid, this->trdid, vseg_type_str(type),
-hal_remote_l32( XPTR( parent_cxy , &parent_vseg->vpn_base ) ) , cycle );
-#endif
-
-        // all parent vsegs - but STACK and kernel vsegs - must be copied in child VSL
-        if( (type != VSEG_TYPE_STACK) && (type != VSEG_TYPE_KCODE) &&
-            (type != VSEG_TYPE_KDATA) && (type != VSEG_TYPE_KDEV) )
-        {
-            // allocate memory for a new child vseg
-            child_vseg = vseg_alloc();
-            if( child_vseg == NULL )   // release all allocated vsegs
-            {
-
-#if DEBUG_VMM_ERROR
-printk("\n[ERROR] in %s : cannot create vseg for child in cluster %x\n",
-__FUNCTION__, local_cxy );
-#endif
-                vmm_destroy( child_process );
-                return -1;
-            }
-
-            // copy parent vseg to child vseg
-            vseg_init_from_ref( child_vseg , parent_vseg_xp );
-
-            // build extended pointer on child VSL lock
-            xptr_t child_lock_xp = XPTR( local_cxy , &child_vmm->vsl_lock );
- 
-            // take the child VSL lock 
-            remote_queuelock_acquire( child_lock_xp );
-
-            // register child vseg in child VSL
-            vmm_attach_vseg_to_vsl( child_vmm , child_vseg );
-
-            // release the child VSL lock
-            remote_queuelock_release( child_lock_xp );
-
-#if DEBUG_VMM_FORK_COPY
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_FORK_COPY < cycle )
-printk("\n[%s] thread[%x,%x] copied vseg %s / vpn_base = %x to child VSL / cycle %d\n",
-__FUNCTION__ , this->process->pid, this->trdid, vseg_type_str(type),
-hal_remote_l32( XPTR( parent_cxy , &parent_vseg->vpn_base ) ) , cycle );
-#endif
-            // copy DATA, ANON, REMOTE, FILE parent GPT entries to child GPT
-            if( type != VSEG_TYPE_CODE )
-            {
-                // activate the COW for DATA, ANON, REMOTE vsegs only
-                // cow = ( type != VSEG_TYPE_FILE );
-
-                vpn_base = child_vseg->vpn_base;
-                vpn_size = child_vseg->vpn_size;
-
-                // scan pages in parent vseg
-                for( vpn = vpn_base ; vpn < (vpn_base + vpn_size) ; vpn++ )
-                {
-                    error = hal_gpt_pte_copy( &child_vmm->gpt,
-                                              vpn,
-                                              XPTR( parent_cxy , &parent_vmm->gpt ),
-                                              vpn,
-                                              false,      // does not handle COW flag
-                                              &ppn,       // unused
-                                              &mapped );  // unused
-                    if( error )
-                    {
-
-#if DEBUG_VMM_ERROR
-printk("\n[ERROR] in %s : cannot copy GPT\n",
-__FUNCTION__ );
-#endif
-                        vmm_destroy( child_process );
-                        return -1;
-                    }
-
-#if DEBUG_VMM_FORK_COPY
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_FORK_COPY < cycle )
-printk("\n[%s] thread[%x,%x] copied vpn %x to child GPT / cycle %d\n",
-__FUNCTION__ , this->process->pid, this->trdid , vpn , cycle );
-#endif
-                }
-            }   // end if no code & no stack
-        }   // end if no stack
-    }   // end loop on vsegs
-
-    // release the parent VSL lock in read mode
-    remote_queuelock_release( parent_lock_xp );
-
-    // copy base addresses from parent VMM to child VMM
-    child_vmm->args_vpn_base = (vpn_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->args_vpn_base));
-    child_vmm->envs_vpn_base = (vpn_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->envs_vpn_base));
-    child_vmm->heap_vpn_base = (vpn_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->heap_vpn_base));
-    child_vmm->code_vpn_base = (vpn_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->code_vpn_base));
-    child_vmm->data_vpn_base = (vpn_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->data_vpn_base));
-
-    child_vmm->entry_point = (intptr_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->entry_point));
-
-    hal_fence();
-
-#if DEBUG_VMM_FORK_COPY
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_FORK_COPY < cycle )
-printk("\n[%s] thread[%x,%x] exit successfully / cycle %d\n",
-__FUNCTION__ , this->process->pid, this->trdid , cycle );
-#endif
-
-    return 0;
-
-}  // vmm_fork_copy()
-
-///////////////////////////////////////
-void vmm_destroy( process_t * process )
-{
-    xptr_t   vseg_xp;
-	vseg_t * vseg;
-
-#if DEBUG_VMM_DESTROY
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-thread_t * this  = CURRENT_THREAD;
-if( DEBUG_VMM_DESTROY < cycle )
-printk("\n[%s] thread[%x,%x] enter for process %x in cluster %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, process->pid, local_cxy, cycle );
-#endif
-
-#if (DEBUG_VMM_DESTROY & 1 )
-if( DEBUG_VMM_DESTROY < cycle )
-hal_vmm_display( XPTR( local_cxy, process ) , true );
-#endif
-
-    // get pointer on local VMM
-    vmm_t  * vmm = &process->vmm;
-
-    // build extended pointer on VSL root, VSL lock and GPT lock
-    xptr_t   vsl_root_xp = XPTR( local_cxy , &vmm->vsegs_root );
-    xptr_t   vsl_lock_xp = XPTR( local_cxy , &vmm->vsl_lock );
-
-    // take the VSL lock
-    remote_queuelock_acquire( vsl_lock_xp );
-
-    // scan the VSL to delete all registered vsegs
-    // (we don't use a FOREACH in case of item deletion)
-    xptr_t  iter_xp;
-    xptr_t  next_xp;
-	for( iter_xp = hal_remote_l64( vsl_root_xp ) ; 
-         iter_xp != vsl_root_xp ;
-         iter_xp = next_xp )
-	{
-        // save extended pointer on next item in xlist
-        next_xp = hal_remote_l64( iter_xp );
-
-        // get pointers on current vseg in VSL
-        vseg_xp   = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
-        vseg      = GET_PTR( vseg_xp );
-
-        // delete vseg and release physical pages 
-        vmm_remove_vseg( process , vseg );
-
-#if( DEBUG_VMM_DESTROY & 1 )
-if( DEBUG_VMM_DESTROY < cycle )
-printk("\n[%s] %s vseg deleted / vpn_base %x / vpn_size %d\n",
-__FUNCTION__ , vseg_type_str( vseg->type ), vseg->vpn_base, vseg->vpn_size );
-#endif
-
-	}
-
-    // release the VSL lock
-    remote_queuelock_release( vsl_lock_xp );
-
-    // remove all registered MMAP vsegs from free_lists in MMAP allocator
-    uint32_t i;
-    for( i = 0 ; i <= CONFIG_VMM_HEAP_MAX_ORDER ; i++ )
-    {
-        // build extended pointer on free list root
-        xptr_t root_xp = XPTR( local_cxy , &vmm->mmap_mgr.free_list_root[i] );
-  
-        // scan zombi_list[i]
-	    while( !xlist_is_empty( root_xp ) )
-	    {
-		    vseg_xp = XLIST_FIRST( root_xp , vseg_t , xlist );
-            vseg    = GET_PTR( vseg_xp );
-
-#if( DEBUG_VMM_DESTROY & 1 )
-if( DEBUG_VMM_DESTROY < cycle )
-printk("\n[%s] found zombi vseg / vpn_base %x / vpn_size %d\n",
-__FUNCTION__ , vseg_type_str( vseg->type ), vseg->vpn_base, vseg->vpn_size );
-#endif
-            // clean vseg descriptor
-            vseg->vmm = NULL;
-
-            // remove vseg from  zombi_list
-            xlist_unlink( XPTR( local_cxy , &vseg->xlist ) );
-
-		    // release vseg descriptor
-            vseg_free( vseg );
-
-#if( DEBUG_VMM_DESTROY & 1 )
-if( DEBUG_VMM_DESTROY < cycle )
-printk("\n[%s] zombi vseg released / vpn_base %x / vpn_size %d\n",
-__FUNCTION__ , vseg_type_str( vseg->type ), vseg->vpn_base, vseg->vpn_size );
-#endif
-	    }
-    }
-
-    // release memory allocated to the GPT itself
-    hal_gpt_destroy( &vmm->gpt );
-
-#if DEBUG_VMM_DESTROY
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_DESTROY < cycle )
-printk("\n[%s] thread[%x,%x] exit for process %x in cluster %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, process->pid, local_cxy , cycle );
-#endif
-
-}  // end vmm_destroy()
-
-/////////////////////////////////////////////////
-vseg_t * vmm_check_conflict( process_t * process,
-                             vpn_t       vpn_base,
-                             vpn_t       vpn_size )
-{
-    vmm_t        * vmm = &process->vmm;
-
-    // scan the VSL
-	vseg_t       * vseg;
-    xptr_t         iter_xp;
-    xptr_t         vseg_xp;
-    xptr_t         root_xp = XPTR( local_cxy , &vmm->vsegs_root );
-
-	XLIST_FOREACH( root_xp , iter_xp )
-	{
-		vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
-        vseg    = GET_PTR( vseg_xp );
-
-		if( ((vpn_base + vpn_size) > vseg->vpn_base) &&
-             (vpn_base < (vseg->vpn_base + vseg->vpn_size)) ) return vseg;
-	}
-    return NULL;
-
-}  // end vmm_check_conflict()
-
-////////////////////////////////////////////////
-vseg_t * vmm_create_vseg( process_t   * process,
-	                      vseg_type_t   type,
-                          intptr_t      base,         // ltid for VSEG_TYPE_STACK
-	                      uint32_t      size,
-                          uint32_t      file_offset,
-                          uint32_t      file_size,
-                          xptr_t        mapper_xp,
-                          cxy_t         cxy )
-{
-    vseg_t     * vseg;          // pointer on allocated vseg descriptor 
-
-#if DEBUG_VMM_CREATE_VSEG
-thread_t * this  = CURRENT_THREAD;
-uint32_t   cycle;
-#endif
-
-#if (DEBUG_VMM_CREATE_VSEG & 1)
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_CREATE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] enter / process %x / %s / base %x / cxy %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid,
-process->pid, vseg_type_str(type), base, cxy, cycle );
-#endif
-
-    // get pointer on VMM 
-	vmm_t * vmm    = &process->vmm;
-
-    // allocate a vseg descriptor and initialize it, depending on type
-    // we use specific allocators for "stack" and "mmap" types
-
-    /////////////////////////////
-    if( type == VSEG_TYPE_STACK )
-    {
-        // get vseg from STACK allocator
-        vseg = vmm_stack_alloc( vmm , base );    // base == ltid
-       
-        if( vseg == NULL )
-        {
-
-#if DEBUG_VMM_ERROR
-printk("\n[ERROR] %s cannot create %s vseg for process %x in cluster %x\n",
-__FUNCTION__ , vseg_type_str( type ) , process->pid , local_cxy );
-#endif
+            printk("\n[ERROR] in %s : no vspace for stack vseg / process %x in cluster %x\n",
+                   __FUNCTION__ , process->pid , local_cxy );
             return NULL;
         }
 
-        // initialize vseg
-        vseg->type = type;
-        vseg->vmm  = vmm;
-        vseg->min  = vseg->vpn_base << CONFIG_PPM_PAGE_ORDER;
-        vseg->max  = vseg->min + (vseg->vpn_size << CONFIG_PPM_PAGE_ORDER);
-        vseg->cxy  = cxy;
-
-        vseg_init_flags( vseg , type );
-    }
-    /////////////////////////////////
-    else if( type == VSEG_TYPE_FILE )
-    {
-        // compute page index (in mapper) for first and last byte
-        vpn_t    vpn_min    = file_offset >> CONFIG_PPM_PAGE_ORDER;
-        vpn_t    vpn_max    = (file_offset + size - 1) >> CONFIG_PPM_PAGE_ORDER;
-
-        // compute offset in first page and number of pages
-        uint32_t offset = file_offset & CONFIG_PPM_PAGE_MASK;
-        vpn_t    npages      = vpn_max - vpn_min + 1;
-
-        // get vseg from MMAP allocator
-        vseg = vmm_mmap_alloc( vmm , npages );
-
-        if( vseg == NULL )
+        // compute vseg base and size from vpn_base and vpn_size
+        base = vpn_base << CONFIG_PPM_PAGE_SHIFT;
+        size = vpn_size << CONFIG_PPM_PAGE_SHIFT;
+    }
+    else if( (type == VSEG_TYPE_ANON) || 
+             (type == VSEG_TYPE_FILE) || 
+             (type == VSEG_TYPE_REMOTE) )
+    {
+        // get vpn_base and vpn_size from MMAP allocator
+        vpn_t npages = size >> CONFIG_PPM_PAGE_SHIFT;
+        error = vmm_mmap_alloc( vmm , npages , &vpn_base , &vpn_size );
+        if( error )
         {
-
-#if DEBUG_VMM_ERROR
-printk("\n[ERROR] %s cannot create %s vseg for process %x in cluster %x\n",
-__FUNCTION__ , vseg_type_str( type ) , process->pid , local_cxy );
-#endif
+            printk("\n[ERROR] in %s : no vspace for mmap vseg / process %x in cluster %x\n",
+                   __FUNCTION__ , process->pid , local_cxy );
             return NULL;
         }
 
-        // initialize vseg 
-        vseg->type        = type;
-        vseg->vmm         = vmm;
-        vseg->min         = (vseg->vpn_base << CONFIG_PPM_PAGE_ORDER) + offset; 
-        vseg->max         = vseg->min + size;
-        vseg->file_offset = file_offset;
-        vseg->file_size   = file_size;
-        vseg->mapper_xp   = mapper_xp;
-        vseg->cxy         = cxy;
-
-        vseg_init_flags( vseg , type );
-    }
-    /////////////////////////////////////////////////////////////////
-    else if( (type == VSEG_TYPE_ANON) || (type == VSEG_TYPE_REMOTE) )
-    {
-        // compute number of required pages in virtual space
-        vpn_t npages = size >> CONFIG_PPM_PAGE_ORDER;
-        if( size & CONFIG_PPM_PAGE_MASK) npages++;
-        
-        // allocate vseg from MMAP allocator
-        vseg = vmm_mmap_alloc( vmm , npages );
-
-        if( vseg == NULL )
+        // compute vseg base and size from vpn_base and vpn_size
+        base = vpn_base << CONFIG_PPM_PAGE_SHIFT;
+        size = vpn_size << CONFIG_PPM_PAGE_SHIFT;
+    }
+    else
+    {
+        vpn_base = ARROUND_DOWN( base , CONFIG_PPM_PAGE_SIZE ) >> CONFIG_PPM_PAGE_SHIFT;
+	    vpn_size = ARROUND_UP( base + size , CONFIG_PPM_PAGE_SIZE ) >> CONFIG_PPM_PAGE_SHIFT;
+    }
+
+    // check collisions
+    vseg = vmm_check_conflict( process , vpn_base , vpn_size );
+    if( vseg != NULL )
+    {
+        printk("\n[ERROR] in %s for process %x : new vseg [vpn_base = %x / vpn_size = %x]\n" 
+               "  overlap existing vseg [vpn_base = %x / vpn_size = %x]\n",
+               __FUNCTION__ , process->pid, vpn_base, vpn_size, 
+               vseg->vpn_base, vseg->vpn_size ); 
+        return NULL;
+    }
+
+    // allocate physical memory for vseg descriptor
+	vseg = vseg_alloc();
+	if( vseg == NULL )
+	{
+	    printk("\n[ERROR] in %s for process %x : cannot allocate memory for vseg\n",
+             __FUNCTION__ , process->pid );
+        return NULL;
+	}
+
+    // initialize vseg descriptor
+	vseg_init( vseg , base, size , vpn_base , vpn_size , type , local_cxy , 0 , 0 );
+
+    // update "heap_vseg" in VMM
+	process->vmm.heap_vseg = vseg;
+
+    // attach vseg to vmm
+	rwlock_wr_lock( &vmm->vsegs_lock );
+	vseg_attach( vmm , vseg );
+	rwlock_wr_unlock( &vmm->vsegs_lock );
+
+	vmm_dmsg("\n[INFO] : %s exit for process %x, vseg [%x, %x] has been mapped\n", 
+		     __FUNCTION__ , process->pid , vseg->min , vseg->max );
+  
+	return vseg;
+
+}  // end vmm_create_vseg()
+
+/////////////////////////////////////
+void vmm_remove_vseg( vseg_t * vseg )
+{
+    // get pointers on calling process and VMM
+    thread_t   * this    = CURRENT_THREAD;
+    process_t  * process = this->process;
+    vmm_t      * vmm     = &this->process->vmm;
+    uint32_t     type    = vseg->type;
+
+    // detach vseg from VMM
+	rwlock_wr_lock( &vmm->vsegs_lock );
+    vseg_detach( &process->vmm , vseg );
+	rwlock_wr_unlock( &vmm->vsegs_lock );
+
+    // release the stack slot to VMM stack allocator if STACK type
+    if( type == VSEG_TYPE_STACK )
+    {
+        // get pointer on stack allocator
+        stack_mgr_t * mgr = &vmm->stack_mgr;
+
+        // compute slot index
+        uint32_t index = ((vseg->vpn_base - mgr->vpn_base - 1) / CONFIG_VMM_STACK_SIZE);
+
+        // update stacks_bitmap
+        spinlock_lock( &mgr->lock );
+        bitmap_clear( &mgr->bitmap , index );
+        spinlock_unlock( &mgr->lock );
+    }
+
+    // release the vseg to VMM mmap allocator if MMAP type
+    if( (type == VSEG_TYPE_ANON) || (type == VSEG_TYPE_FILE) || (type == VSEG_TYPE_REMOTE) )
+    {
+        // get pointer on mmap allocator
+        mmap_mgr_t * mgr = &vmm->mmap_mgr;
+
+        // compute zombi_list index
+        uint32_t index = bits_log2( vseg->vpn_size );
+
+        // update zombi_list
+        spinlock_lock( &mgr->lock );
+        list_add_first( &mgr->zombi_list[index] , &vseg->list );
+        spinlock_unlock( &mgr->lock );
+    }
+
+    // release physical memory allocated for vseg descriptor if no MMAP type
+    if( (type != VSEG_TYPE_ANON) && (type != VSEG_TYPE_FILE) && (type != VSEG_TYPE_REMOTE) )
+    {
+        vseg_free( vseg );
+    }
+
+}  // end vmm_remove_vseg()
+
+
+//////////////////////////////////////////
+error_t vmm_map_vseg( vseg_t    * vseg,
+                      uint32_t    attr )
+{
+    vpn_t       vpn;        // VPN of PTE to be set
+    vpn_t       vpn_min;    // VPN of first PTE to be set
+    vpn_t       vpn_max;    // VPN of last PTE to be set (excluded)
+	ppn_t       ppn;        // PPN of allocated physical page
+	uint32_t    order;      // ln( number of small pages for one single PTE )
+	page_t    * page;
+    error_t     error;
+
+    // check vseg type
+    uint32_t type = vseg->type;
+    if( (type != VSEG_TYPE_KCODE) && (type != VSEG_TYPE_KDATA) && (type != VSEG_TYPE_KDEV) )
+    {
+        printk("\n[PANIC] in %s : not a kernel vseg\n", __FUNCTION__ );
+        hal_core_sleep();
+    }
+
+    // get pointer on page table
+    gpt_t * gpt = &process_zero.vmm.gpt;
+
+    // define number of small pages per PTE 
+	if( attr & GPT_SMALL ) order = 0;   // 1 small page
+	else                   order = 9;   // 512 small pages
+
+    // loop on pages in vseg
+    vpn_min = vseg->vpn_base;
+    vpn_max = vpn_min + vseg->vpn_size;
+	for( vpn = vpn_min ; vpn < vpn_max ; vpn++ )
+	{
+	    kmem_req_t req;
+	    req.type  = KMEM_PAGE;
+	    req.size  = order;
+	    req.flags = AF_KERNEL | AF_ZERO;
+	    page      = (page_t *)kmem_alloc( &req );
+		if( page == NULL ) 
         {
-
-#if DEBUG_VMM_ERROR
-printk("\n[ERROR] %s cannot create %s vseg for process %x in cluster %x\n",
-__FUNCTION__ , vseg_type_str( type ) , process->pid , local_cxy );
-#endif
-            return NULL;
+            printk("\n[ERROR] in %s : cannot allocate physical memory\n", __FUNCTION__ );
+            return ENOMEM;
         }
 
-        // initialize vseg
-        vseg->type = type;
-        vseg->vmm  = vmm;
-        vseg->min  = vseg->vpn_base << CONFIG_PPM_PAGE_ORDER;
-        vseg->max  = vseg->min + (vseg->vpn_size << CONFIG_PPM_PAGE_ORDER);
-        vseg->cxy  = cxy;
-
-        vseg_init_flags( vseg , type );
-    }
-    /////////////////////////////////////////////////////////////////
-    else    // VSEG_TYPE_DATA, VSEG_TYPE_CODE or KERNEL vseg
-    {
-        uint32_t vpn_min = base >> CONFIG_PPM_PAGE_ORDER;
-        uint32_t vpn_max = (base + size - 1) >> CONFIG_PPM_PAGE_ORDER;
-
-        // allocate vseg descriptor
-	    vseg = vseg_alloc();
-
-	    if( vseg == NULL )
-	    {
-
-#if DEBUG_VMM_ERROR
-printk("\n[ERROR] %s cannot create %s vseg for process %x in cluster %x\n",
-__FUNCTION__ , vseg_type_str( type ) , process->pid , local_cxy );
-#endif
-            return NULL;
-	    }
-
-        // initialize vseg
-        vseg->type        = type;
-        vseg->vmm         = vmm;
-        vseg->min         = base;
-        vseg->max         = base + size;
-        vseg->vpn_base    = base >> CONFIG_PPM_PAGE_ORDER;
-        vseg->vpn_size    = vpn_max - vpn_min + 1;
-        vseg->file_offset = file_offset;
-        vseg->file_size   = file_size;
-        vseg->mapper_xp   = mapper_xp;
-        vseg->cxy         = cxy;
-
-        vseg_init_flags( vseg , type );
-    }
-
-    // check collisions
-    vseg_t * existing_vseg = vmm_check_conflict( process , vseg->vpn_base , vseg->vpn_size );
-
-    if( existing_vseg != NULL )
-    {
-
-#if DEBUG_VMM_ERROR
-printk("\n[ERROR] in %s for process %x : new vseg %s [vpn_base %x / vpn_size %x]\n"
-       "        overlap existing vseg %s [vpn_base %x / vpn_size %x]\n",
-__FUNCTION__ , process->pid, vseg_type_str(vseg->type), vseg->vpn_base, vseg->vpn_size, 
-vseg_type_str(existing_vseg->type), existing_vseg->vpn_base, existing_vseg->vpn_size );
-#endif
-        vseg_free( vseg );
-        return NULL;
-    }
-
-    // build extended pointer on VSL lock
-    xptr_t lock_xp = XPTR( local_cxy , &vmm->vsl_lock );
+        // set page table entry
+        ppn = ppm_page2ppn( page );
+        error = hal_gpt_set_pte( gpt , vpn , ppn , attr );
+		if( error ) 
+        {
+            printk("\n[ERROR] in %s : cannot register PPE\n", __FUNCTION__ );
+            return ENOMEM;
+        }
+	}
  
-    // take the VSL lock in write mode
-    remote_queuelock_acquire( lock_xp );
-
-    // attach vseg to VSL
-	vmm_attach_vseg_to_vsl( vmm , vseg );
-
-    // release the VSL lock
-    remote_queuelock_release( lock_xp );
-
-#if DEBUG_VMM_CREATE_VSEG 
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_CREATE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] exit / %s / vpn_base %x / vpn_size %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid,
-vseg_type_str(type), vseg->vpn_base, vseg->vpn_size, cycle );
-#endif
-
-	return vseg;
-
-}  // vmm_create_vseg()
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// This static function is called by the vmm_remove_vseg() and vmm_resize_vseg() functions
-// to update the physical page descriptor identified by the <ppn> argument. 
-// It decrements the refcount, set the dirty bit when required, and releases the physical
-// page to kmem depending on the vseg type.
-// - KERNEL : refcount decremented / not released to kmem    / dirty bit not set
-// - FILE   : refcount decremented / not released to kmem    / dirty bit set when required.
-// - CODE   : refcount decremented / released to kmem        / dirty bit not set.
-// - STAK   : refcount decremented / released to kmem        / dirty bit not set.
-// - DATA   : refcount decremented / released to kmem if ref / dirty bit not set.
-// - MMAP   : refcount decremented / released to kmem if ref / dirty bit not set.
-////////////////////////////////////////////////////////////////////////////////////////////
-// @ process  : local pointer on process.
-// @ vseg     : local pointer on vseg.
-// @ ppn      : released pysical page index. 
-// @ dirty    : set the dirty bit in page descriptor when non zero.
-////////////////////////////////////////////////////////////////////////////////////////////
-static void vmm_ppn_release( process_t * process,
-                             vseg_t    * vseg,
-                             ppn_t       ppn,
-                             uint32_t    dirty )
-{
-    bool_t do_kmem_release;
-
-    // get vseg type
-    vseg_type_t type = vseg->type;
-
-    // compute is_ref <=> this vseg is the reference vseg
-    bool_t is_ref = (GET_CXY( process->ref_xp ) == local_cxy);
-
-    // get pointers on physical page descriptor
-    xptr_t   page_xp  = ppm_ppn2page( ppn );
-    cxy_t    page_cxy = GET_CXY( page_xp );
-    page_t * page_ptr = GET_PTR( page_xp );
-
-    // decrement page refcount
-    xptr_t count_xp = XPTR( page_cxy , &page_ptr->refcount );
-    hal_remote_atomic_add( count_xp , -1 );
-
-    // compute the do_kmem_release condition depending on vseg type
-    if( (type == VSEG_TYPE_KCODE) || 
-        (type == VSEG_TYPE_KDATA) || 
-        (type == VSEG_TYPE_KDEV) )            
-    {
-        // no physical page release for KERNEL 
-        do_kmem_release = false;
-    }
-    else if( type == VSEG_TYPE_FILE )
-    {
-        // no physical page release for KERNEL 
-        do_kmem_release = false;
-
-        // set dirty bit if required
-        if( dirty ) ppm_page_do_dirty( page_xp );
-    }   
-    else if( (type == VSEG_TYPE_CODE)  ||
-             (type == VSEG_TYPE_STACK) ) 
-    {
-        // always release physical page for private vsegs
-        do_kmem_release = true;
-    }
-    else if( (type == VSEG_TYPE_ANON)  ||
-             (type == VSEG_TYPE_REMOTE) )
-    {
-        // release physical page if reference cluster
-        do_kmem_release = is_ref;
-    }
-    else if( is_ref )  // vseg_type == DATA in reference cluster
-    {
-        // get extended pointers on forks and lock field in page descriptor
-        xptr_t forks_xp = XPTR( page_cxy , &page_ptr->forks );
-        xptr_t lock_xp  = XPTR( page_cxy , &page_ptr->lock );
-
-        // take lock protecting "forks" counter
-        remote_busylock_acquire( lock_xp );
-
-        // get number of pending forks from page descriptor
-        uint32_t forks = hal_remote_l32( forks_xp );
-
-        // decrement pending forks counter if required
-        if( forks )  hal_remote_atomic_add( forks_xp , -1 );
-
-        // release lock protecting "forks" counter
-        remote_busylock_release( lock_xp );
-
-        // release physical page if forks == 0
-        do_kmem_release = (forks == 0); 
-    }
-    else              // vseg_type == DATA not in reference cluster
-    {
-        // no physical page release if not in reference cluster 
-        do_kmem_release = false;
-    }
-
-    // release physical page to relevant kmem when required
-    if( do_kmem_release )
-    {
-        // get physical page order
-        uint32_t order = CONFIG_PPM_PAGE_ORDER +
-                         hal_remote_l32( XPTR( page_cxy , &page_ptr->order ));
-
-        // get physical page base 
-        void * base = GET_PTR( ppm_ppn2base( ppn ) );
-
-        // release physical page
-        kmem_remote_free( page_cxy , base , order );
-
-#if DEBUG_VMM_PPN_RELEASE
-thread_t * this = CURRENT_THREAD;
-if( DEBUG_VMM_PPN_RELEASE < cycle )
-printk("\n[%s] thread[%x,%x] released ppn %x to kmem\n",
-__FUNCTION__, this->process->pid, this->trdid, ppn );
-#endif
-
-    }
-} // end vmm_ppn_release()
-
-//////////////////////////////////////////
-void vmm_remove_vseg( process_t * process,
-                      vseg_t    * vseg )
-{
-    uint32_t    vseg_type;  // vseg type
-    vpn_t       vpn;        // VPN of current PTE
-    vpn_t       vpn_min;    // VPN of first PTE
+	return 0;
+} // end vmm_map_vseg()
+
+/////////////////////////////////////////
+void vmm_unmap_vseg( process_t * process,
+                     vseg_t    * vseg )
+{
+    vpn_t       vpn;        // VPN of current PTE 
+    vpn_t       vpn_min;    // VPN of first PTE 
     vpn_t       vpn_max;    // VPN of last PTE (excluded)
-    ppn_t       ppn;        // current PTE ppn value
-    uint32_t    attr;       // current PTE attributes
-
-// check arguments
-assert( __FUNCTION__, (process != NULL), "process argument is NULL" );
-assert( __FUNCTION__, (vseg    != NULL), "vseg argument is NULL" );
-
-    // get pointers on local process VMM 
+
+    // get pointer on process page table
+    gpt_t     * gpt = &process->vmm.gpt;
+
+    // loop on pages in vseg
+    vpn_min = vseg->vpn_base;
+    vpn_max = vpn_min + vseg->vpn_size;
+	for( vpn = vpn_min ; vpn < vpn_max ; vpn++ )
+    {
+        hal_gpt_reset_pte( gpt , vpn );
+    }
+} // end vmm_unmap_vseg()
+
+
+/////////////////////////////////////////////
+error_t vmm_resize_vseg( process_t * process,
+                         intptr_t    base,
+                         intptr_t    size )
+{
+	error_t error;
+
+    // get pointer on process VMM
     vmm_t * vmm = &process->vmm;
 
-    // build extended pointer on GPT
-    xptr_t gpt_xp = XPTR( local_cxy , &vmm->gpt );
-
-    // get relevant vseg infos
-    vseg_type = vseg->type;
-    vpn_min   = vseg->vpn_base;
-    vpn_max   = vpn_min + vseg->vpn_size;
-
-#if DEBUG_VMM_REMOVE_VSEG
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-thread_t * this  = CURRENT_THREAD;
-#endif
-
-#if (DEBUG_VMM_REMOVE_VSEG & 1 )
-if( DEBUG_VMM_REMOVE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] enters / process %x / type %s / base %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, 
-process->pid, vseg_type_str(vseg->type), vseg->min, cycle );
-#endif
-
-    // the loop on PTEs in GPT to unmap all mapped PTEs 
-    for( vpn = vpn_min ; vpn < vpn_max ; vpn++ )
-    {
-        // get ppn and attr
-        hal_gpt_get_pte( gpt_xp , vpn , &attr , &ppn );
-
-        if( attr & GPT_MAPPED )  // PTE is mapped
+    intptr_t addr_min = base;
+	intptr_t addr_max = base + size;
+    uint32_t shift    = CONFIG_PPM_PAGE_SHIFT;       
+
+    // get pointer on vseg
+	vseg_t * vseg = grdxt_lookup( &vmm->grdxt , (uint32_t)(base >> shift) );
+
+	if( vseg == NULL)  return EINVAL;
+  
+    // get VMM lock protecting vsegs list
+	rwlock_wr_lock( &vmm->vsegs_lock );
+  
+	if( (vseg->min > addr_min) || (vseg->max < addr_max) )   // region not included in vseg
+    {
+        error = EINVAL;
+    }
+	else if( (vseg->min == addr_min) && (vseg->max == addr_max) ) // vseg must be removed
+    {
+        vmm_remove_vseg( vseg );
+        error = 0;
+    }
+	else if( vseg->min == addr_min )                              // vseg must be resized
+    {
+        printk("\n[PANIC] in %s : resize not implemented yet\n", __FUNCTION__ );
+        hal_core_sleep();
+		error = 0;
+    }
+	else if( vseg->max == addr_max )                              // vseg must be resized
+    {
+        printk("\n[PANIC] in %s : resize not implemented yet\n", __FUNCTION__ );
+        hal_core_sleep();
+		error = 0;
+    }
+    else            // vseg cut in three regions => vseg must be resized & new vseg created
+    {
+        printk("\n[PANIC] in %s : resize not implemented yet\n", __FUNCTION__ );
+        hal_core_sleep();
+		error = 0;
+    }
+
+    // release VMM lock
+	rwlock_wr_unlock( &vmm->vsegs_lock );
+
+	return error;
+} // end vmm_resize_vseg()
+
+///////////////////////////////////////////
+vseg_t * vmm_get_vseg( process_t * process,
+                       intptr_t    vaddr )
+{
+
+    // get pointer on process VMM
+    vmm_t * vmm = &process->vmm;
+
+    // get lock protecting the vseg list
+    rwlock_rd_lock( &vmm->vsegs_lock );
+
+    // get pointer on vseg from radix tree
+	vseg_t * vseg = grdxt_lookup( &vmm->grdxt, (uint32_t)(vaddr >> CONFIG_PPM_PAGE_SHIFT) );
+
+    // release the lock
+    rwlock_rd_unlock( &vmm->vsegs_lock );
+
+    return vseg;
+
+} // end vmm_get_vseg()
+
+/////////////////////////////////////////
+error_t vmm_get_pte( process_t * process,
+                     vpn_t       vpn,
+                     uint32_t  * ret_attr,
+                     ppn_t     * ret_ppn )
+{
+    vseg_t  * vseg;   // pointer on vseg containing VPN
+    ppn_t     ppn;    // PPN from GPT entry
+    uint32_t  attr;   // attributes from GPT entry
+    error_t   error;
+
+    // this function must be called by in the reference cluster 
+    if( process->is_ref == false );
+    {
+        printk("\n[PANIC] in %s : not called in the reference cluster\n", __FUNCTION__ );
+        hal_core_sleep();
+    }
+
+    // get VMM pointer
+    vmm_t * vmm = &process->vmm;
+
+    // access GPT to get PTE attributes and PPN
+    hal_gpt_get_pte( &vmm->gpt , vpn , &attr , &ppn );
+
+    // if PTE unmapped => allocate one small physical page to map it
+    if( (attr & GPT_MAPPED) == 0 )  
+    {
+        // get vseg pointer
+        vseg = vmm_get_vseg( process , vpn<<CONFIG_PPM_PAGE_SHIFT );
+
+        if( vseg == NULL );
+        {
+            printk("\n[ERROR] in %s : out of segment / process = %x / vpn = %x\n",
+                   __FUNCTION__ , process->pid , vpn );
+            return EINVAL;
+        }
+
+        // select the target cluster for physical mapping
+        uint32_t target_cxy;
+        if( vseg->flags & VSEG_DISTRIB ) // depends on VPN LSB
+        {
+            uint32_t x_width = LOCAL_CLUSTER->x_width;
+            uint32_t y_width = LOCAL_CLUSTER->y_width;
+            target_cxy = vpn & ((1<<(x_width + y_width)) - 1);
+        }
+        else                             // defined in vseg descriptor
+        {
+            target_cxy = vseg->cxy;
+        }
+
+        // allocate memory for page fault
+        kmem_req_t   req;
+        page_t     * page;
+        if( target_cxy == local_cxy )        // target cluster is the local cluster
         { 
-
-#if( DEBUG_VMM_REMOVE_VSEG & 1 )
-if( DEBUG_VMM_REMOVE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] unmap vpn %x / ppn %x / type %s\n",
-__FUNCTION__, this->process->pid, this->trdid, vpn , ppn, vseg_type_str(vseg_type) );
-#endif
-            // unmap GPT entry in local GPT
-            hal_gpt_reset_pte( gpt_xp , vpn );
-
-            // release physical page depending on vseg type
-            vmm_ppn_release( process , vseg , ppn , attr & GPT_DIRTY );
+            req.type  = KMEM_PAGE;
+            req.size  = 0;
+            req.flags = AF_NONE;
+            page      = (page_t *)kmem_alloc( &req );
+
+            error = ( page == NULL ) ? 1 : 0;
+            ppn   = ppm_page2ppn( page );
         }
-    }
-
-    // remove vseg from VSL 
-    vmm_detach_vseg_from_vsl( vmm , vseg );
-
-    // release vseg descriptor depending on vseg type
-    if( vseg_type == VSEG_TYPE_STACK )
-    {
-        // release slot to local stack allocator
-        vmm_stack_free( vmm , vseg );
-    }
-    else if( (vseg_type == VSEG_TYPE_ANON) || 
-             (vseg_type == VSEG_TYPE_FILE) || 
-             (vseg_type == VSEG_TYPE_REMOTE) )  
-    {
-        // release vseg to local mmap allocator
-        vmm_mmap_free( vmm , vseg );
-    }
-    else
-    {
-        // release vseg descriptor to local kmem
-        vseg_free( vseg );
-    }
-
-#if DEBUG_VMM_REMOVE_VSEG
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_REMOVE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] exit / process %x / type %s / base %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, 
-process->pid, vseg_type_str(vseg->type), vseg->min, cycle );
-#endif
-
-}  // end vmm_remove_vseg()
-
-/////////////////////////////////////////////
-void vmm_resize_vseg( process_t * process,
-                      vseg_t    * vseg,
-                      intptr_t    new_base,
-                      intptr_t    new_size )
-{
-    vpn_t     vpn;
-    ppn_t     ppn;
-    uint32_t  attr;
-
-// check arguments
-assert( __FUNCTION__, (process != NULL), "process argument is NULL" );
-assert( __FUNCTION__, (vseg    != NULL), "vseg argument is NULL" );
-
-#if DEBUG_VMM_RESIZE_VSEG
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-thread_t * this  = CURRENT_THREAD;
-#endif
-
-#if (DEBUG_VMM_RESIZE_VSEG & 1)
-if( DEBUG_VMM_RESIZE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] enter / process %x / %s / base %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, 
-process->pid, vseg_type_str(vseg->type), old_base, cycle );
-#endif
-
-    // get existing vseg vpn_min and vpn_max
-    vpn_t     old_vpn_min = vseg->vpn_base;
-    vpn_t     old_vpn_max = old_vpn_min + vseg->vpn_size - 1;
-
-    // compute new vseg vpn_min & vpn_max  
-    intptr_t min          = new_base;
-    intptr_t max          = new_base + new_size;
-    vpn_t    new_vpn_min  = min >> CONFIG_PPM_PAGE_ORDER;
-    vpn_t    new_vpn_max  = (max - 1) >> CONFIG_PPM_PAGE_ORDER;
-
-    // build extended pointer on GPT
-    xptr_t gpt_xp = XPTR( local_cxy , &process->vmm.gpt );
-
-    // loop on PTEs in GPT to unmap PTE if (old_vpn_min <= vpn < new_vpn_min)
-	for( vpn = old_vpn_min ; vpn < new_vpn_min ; vpn++ )
-    {
-        // get ppn and attr
-        hal_gpt_get_pte( gpt_xp , vpn , &attr , &ppn );
-
-        if( attr & GPT_MAPPED )  // PTE is mapped
-        { 
-
-#if( DEBUG_VMM_RESIZE_VSEG & 1 )
-if( DEBUG_VMM_RESIZE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] unmap vpn %x / ppn %x / %s",
-__FUNCTION__, this->process->pid, this->trdid, vpn , ppn, vseg_type_str(vseg_type) );
-#endif
-            // unmap GPT entry 
-            hal_gpt_reset_pte( gpt_xp , vpn );
-
-            // release physical page when required
-            vmm_ppn_release( process , vseg , ppn , attr & GPT_DIRTY );
+        else                                 // target cluster is not the local cluster
+        {
+            rpc_pmem_get_pages_client( target_cxy , 0 , &error , &ppn );
         }
-    }
-
-    // loop on PTEs in GPT to unmap PTE if (new vpn_max <= vpn < old_vpn_max)
-	for( vpn = new_vpn_max ; vpn < old_vpn_max ; vpn++ )
-    {
-        // get ppn and attr
-        hal_gpt_get_pte( gpt_xp , vpn , &attr , &ppn );
-
-        if( attr & GPT_MAPPED )  // PTE is mapped
-        { 
-
-#if( DEBUG_VMM_RESIZE_VSEG & 1 )
-if( DEBUG_VMM_RESIZE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] unmap vpn %x / ppn %x / %s",
-__FUNCTION__, this->process->pid, this->trdid, vpn , ppn, vseg_type_str(vseg_type) );
-#endif
-            // unmap GPT entry in local GPT
-            hal_gpt_reset_pte( gpt_xp , vpn );
-
-            // release physical page when required
-            vmm_ppn_release( process , vseg , ppn , attr & GPT_DIRTY );
+
+        if( error )
+        {
+            printk("\n[ERROR] in %s : cannot allocate memory / process = %x / vpn = %x\n",
+                   __FUNCTION__ , process->pid , vpn );
+            return ENOMEM;
         }
-    }
-
-    // resize vseg in VSL
-    vseg->min      = min;
-    vseg->max      = max;
-    vseg->vpn_base = new_vpn_min;
-    vseg->vpn_size = new_vpn_max - new_vpn_min + 1;
-
-#if DEBUG_VMM_RESIZE_VSEG
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_RESIZE_VSEG < cycle )
-printk("[%s] thread[%x,%x] exit / process %x / %s / base %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, 
-process->pid, vseg_type_str(vseg->type), vseg->min, cycle );
-#endif
-
-}  // end vmm_resize_vseg
-
-/////////////////////////////////////////////////////////////////////////////////////////////
-// This static function is called twice by the vmm_get_vseg() function.
-// It scan the - possibly remote - VSL defined by the <vmm_xp> argument to find the vseg
-// containing a given virtual address <vaddr>. It uses remote accesses to access the remote
-// VSL if required. The VSL lock protecting the VSL must be taken by the caller.
-/////////////////////////////////////////////////////////////////////////////////////////////
-// @ vmm_xp  : extended pointer on the process VMM.
-// @ vaddr   : virtual address.
-// @ return local pointer on remote vseg if success / return NULL if not found.
-/////////////////////////////////////////////////////////////////////////////////////////////
-static vseg_t * vmm_vseg_from_vaddr( xptr_t     vmm_xp,
-                                     intptr_t   vaddr )
-{
-    xptr_t   iter_xp;
-    xptr_t   vseg_xp;
-    vseg_t * vseg;
-    intptr_t min;
-    intptr_t max;
-
-    // get cluster and local pointer on target VMM
-    vmm_t * vmm_ptr = GET_PTR( vmm_xp );
-    cxy_t   vmm_cxy = GET_CXY( vmm_xp );
-
-    // build extended pointer on VSL root
-    xptr_t root_xp = XPTR( vmm_cxy , &vmm_ptr->vsegs_root );
-
-    // scan the list of vsegs in VSL
-    XLIST_FOREACH( root_xp , iter_xp )
-    {
-        vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
-        vseg    = GET_PTR( vseg_xp );
-
-        min = hal_remote_l32( XPTR( vmm_cxy , &vseg->min ) );
-        max = hal_remote_l32( XPTR( vmm_cxy , &vseg->max ) );
-
-        // return success when match
-        if( (vaddr >= min) && (vaddr < max) ) return vseg;
-    }
-
-    // return failure
-    return NULL;
-
-}  // end vmm_vseg_from_vaddr()
-
-///////////////////////////////////////////
-error_t  vmm_get_vseg( process_t * process,
-                       intptr_t    vaddr,
-                       vseg_t   ** found_vseg )
-{
-    xptr_t    loc_lock_xp;     // extended pointer on local VSL lock
-    xptr_t    ref_lock_xp;     // extended pointer on reference VSL lock
-    vseg_t  * loc_vseg;        // local pointer on local vseg
-    vseg_t  * ref_vseg;        // local pointer on reference vseg
-
-    // build extended pointer on local VSL lock
-    loc_lock_xp = XPTR( local_cxy , &process->vmm.vsl_lock );
-     
-    // get local VSL lock 
-    remote_queuelock_acquire( loc_lock_xp );
-
-    // try to get vseg from local VSL
-    loc_vseg = vmm_vseg_from_vaddr( XPTR( local_cxy, &process->vmm ) , vaddr );
-
-    if (loc_vseg == NULL)   // vseg not found => access reference VSL
-    {
-        // get extended pointer on reference process
-        xptr_t ref_xp = process->ref_xp;
-
-        // get cluster and local pointer on reference process
-        cxy_t       ref_cxy = GET_CXY( ref_xp );
-        process_t * ref_ptr = GET_PTR( ref_xp );
-
-        if( ref_cxy == local_cxy )    // local is ref => return error
+
+        // defineg GPT attributes from vseg flags
+        attr = GPT_MAPPED | GPT_SMALL;
+        if( vseg->flags & VSEG_USER  ) attr |= GPT_USER;
+        if( vseg->flags & VSEG_WRITE ) attr |= GPT_WRITABLE;
+        if( vseg->flags & VSEG_EXEC  ) attr |= GPT_EXECUTABLE;
+        if( vseg->flags & VSEG_CACHE ) attr |= GPT_CACHABLE;
+
+        // set the missing PTE in local VMM
+        error = hal_gpt_set_pte( &vmm->gpt , vpn , ppn , attr );
+        if( error )
         {
-
-#if DEBUG_VMM_ERROR
-printk("\n[ERROR] in %s : vaddr %x in process %x out of segment\n",
-__FUNCTION__, vaddr, process->pid );
-#endif
-            remote_queuelock_release( loc_lock_xp );
-            return -1;
+            printk("\n[ERROR] in %s : cannot register PTE / process = %x / vpn = %x\n",
+                   __FUNCTION__ , process->pid , vpn );
+            return ENOMEM;
         }
-        else                          // ref != local => access ref VSL                     
-        {
-            // build extended pointer on reference VSL lock
-            ref_lock_xp = XPTR( ref_cxy , &ref_ptr->vmm.vsl_lock );
-     
-            // get reference VSL lock 
-            remote_queuelock_acquire( ref_lock_xp );
-
-            // try to get vseg from reference VSL
-            ref_vseg = vmm_vseg_from_vaddr( XPTR( ref_cxy , &ref_ptr->vmm ) , vaddr );
-
-            if( ref_vseg == NULL )  // vseg not found => return error
-            {
-
-#if DEBUG_VMM_ERROR
-printk("\n[ERROR] in %s : vaddr %x in process %x out of segment\n",
-__FUNCTION__, vaddr, process->pid );
-#endif
-                remote_queuelock_release( loc_lock_xp );
-                remote_queuelock_release( ref_lock_xp );
-                return -1;
-            }
-            else                    // vseg found => try to update local VSL 
-            {
-                // allocate a local vseg descriptor
-                loc_vseg = vseg_alloc();
-
-                if( loc_vseg == NULL )   // no memory => return error
-                {
-
-#if DEBUG_VMM_ERROR
-printk("\n[ERROR] in %s : vaddr %x in process %x / no memory\n",
-__FUNCTION__, vaddr, process->pid );
-#endif
-                    remote_queuelock_release( ref_lock_xp );
-                    remote_queuelock_release( loc_lock_xp );
-                    return -1;
-                }
-                else                     // update local VSL and return success
-                {
-                    // initialize local vseg
-                    vseg_init_from_ref( loc_vseg , XPTR( ref_cxy , ref_vseg ) );
-
-                    // register local vseg in local VSL
-                    vmm_attach_vseg_to_vsl( &process->vmm , loc_vseg );
-
-                    // release both VSL locks
-                    remote_queuelock_release( ref_lock_xp );
-                    remote_queuelock_release( loc_lock_xp );
-
-                    *found_vseg = loc_vseg;
-                    return 0;
-                }
-            }
-        }
-    }
-    else                        // vseg found in local VSL => return success
-    {
-        // release local VSL lock
-        remote_queuelock_release( loc_lock_xp );
-
-        *found_vseg = loc_vseg;
-        return 0;
-    }
-}  // end vmm_get_vseg()
-
-//////////////////////////////////////////////////////////////////////////////////////
-// This static function compute the target cluster to allocate a physical page
-// for a given <vpn> in a given <vseg>, allocates the physical page from a local
-// or remote cluster (depending on the vseg type), and returns an extended pointer
-// on the allocated page descriptor.
-// The vseg cannot have the FILE type.
-//////////////////////////////////////////////////////////////////////////////////////
-// @ vseg   : local pointer on vseg.
-// @ vpn    : unmapped vpn.
-// @ return xptr on page descriptor if success / return XPTR_NULL if failure
-//////////////////////////////////////////////////////////////////////////////////////
-static xptr_t vmm_page_allocate( vseg_t * vseg,
-                                 vpn_t    vpn )
-{
-
-#if DEBUG_VMM_PAGE_ALLOCATE
-uint32_t   cycle   = (uint32_t)hal_get_cycles();
-thread_t * this    = CURRENT_THREAD;
-if( DEBUG_VMM_PAGE_ALLOCATE < cycle )
-printk("\n[%s] thread[%x,%x] enter for vpn %x / cycle %d\n",
-__FUNCTION__ , this->process->pid, this->trdid, vpn, cycle );
-#endif
-
-    xptr_t       page_xp;
-    cxy_t        page_cxy;
-    uint32_t     index;
-
-    uint32_t     type   = vseg->type;
-    uint32_t     flags  = vseg->flags;
-    uint32_t     x_size = LOCAL_CLUSTER->x_size;
-    uint32_t     y_size = LOCAL_CLUSTER->y_size;
-
-// check vseg type
-assert( __FUNCTION__, ( type != VSEG_TYPE_FILE ) , "illegal vseg type\n" );
-
-    // compute target cluster identifier
-    if( flags & VSEG_DISTRIB )    // distributed => cxy depends on vpn LSB
-    {
-        index    = vpn & ((x_size * y_size) - 1);
-        page_cxy = HAL_CXY_FROM_XY( (index / y_size) , (index % y_size) );
-
-        // If the cluster selected from VPN's LSBs is empty, we select one randomly
-        if ( cluster_is_active( page_cxy ) == false )
-        {
-            page_cxy = cluster_random_select();
-        }
-    }
-    else                          // other cases => cxy specified in vseg
-    {
-        page_cxy = vseg->cxy;
-    }
-
-    // get local pointer on page base
-    void * ptr = kmem_remote_alloc( page_cxy , CONFIG_PPM_PAGE_ORDER , AF_ZERO );
-
-    if( ptr == NULL )
-    {
-
-#if DEBUG_VMM_ERROR
-printk("\n[ERROR] in %s : cannot allocate memory from cluster %x\n",
-__FUNCTION__, page_cxy );
-#endif
-        return XPTR_NULL;
-    }     
-    // get extended pointer on page descriptor
-    page_xp = ppm_base2page( XPTR( page_cxy , ptr ) );
-
-#if DEBUG_VMM_PAGE_ALLOCATE
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_PAGE_ALLOCATE < cycle )
-printk("\n[%s] thread[%x,%x] exit for vpn %x / ppn %x / cycle %d\n",
-__FUNCTION__ , this->process->pid, this->trdid, vpn, ppm_page2ppn(page_xp), cycle );
-#endif
-
-    return page_xp;
-
-}  // end vmm_page_allocate()  
-
-////////////////////////////////////////
-error_t vmm_get_one_ppn( vseg_t * vseg,
-                         vpn_t    vpn,
-                         ppn_t  * ppn )
-{
-    error_t    error;
-    xptr_t     page_xp;           // extended pointer on physical page descriptor
-    uint32_t   page_id;           // missing page index in vseg mapper
-    uint32_t   type;              // vseg type;
-
-    type      = vseg->type;
-    page_id   = vpn - vseg->vpn_base;
-
-#if DEBUG_VMM_GET_ONE_PPN 
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-thread_t * this  = CURRENT_THREAD;
-if( DEBUG_VMM_GET_ONE_PPN < cycle )
-printk("\n[%s] thread[%x,%x] enter for vpn %x / vseg %s / page_id  %d / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, vpn, vseg_type_str(type), page_id, cycle );
-#endif
-
-#if (DEBUG_VMM_GET_ONE_PPN & 2)
-if( DEBUG_VMM_GET_ONE_PPN < cycle )
-hal_vmm_display( XPTR( local_cxy , this->process ) , true );
-#endif
-
-    // FILE type : get the physical page from the file mapper
-    if( type == VSEG_TYPE_FILE )
-    {
-        // get extended pointer on mapper
-        xptr_t mapper_xp = vseg->mapper_xp;
-
-assert( __FUNCTION__, (mapper_xp != XPTR_NULL),
-"mapper not defined for a FILE vseg\n" );
-        
-        // get extended pointer on page descriptor
-        page_xp = mapper_get_page( mapper_xp , page_id );
-
-        if ( page_xp == XPTR_NULL ) return EINVAL;
-    }
-
-    // Other types : allocate a physical page from target cluster,
-    // as defined by vseg type and vpn value
-    else
-    {
-        // allocate one physical page 
-        page_xp = vmm_page_allocate( vseg , vpn );
-
-        if( page_xp == XPTR_NULL ) return -1;
-
-        // initialise missing page from .elf file mapper for DATA and CODE types
-        // the vseg->mapper_xp field is an extended pointer on the .elf file mapper
-        if( (type == VSEG_TYPE_CODE) || (type == VSEG_TYPE_DATA) )
-        {
-            // get extended pointer on mapper
-            xptr_t     mapper_xp = vseg->mapper_xp;
-
-assert( __FUNCTION__, (mapper_xp != XPTR_NULL),
-"mapper not defined for a CODE or DATA vseg\n" );
-        
-            // compute missing page offset in vseg
-            uint32_t offset = page_id << CONFIG_PPM_PAGE_ORDER;
-
-            // compute missing page offset in .elf file
-            uint32_t elf_offset = vseg->file_offset + offset;
-
-#if (DEBUG_VMM_GET_ONE_PPN & 0x1)
-if( DEBUG_VMM_GET_ONE_PPN < cycle )
-printk("\n[%s] thread[%x,%x] for vpn = %x / elf_offset = %x\n",
-__FUNCTION__, this->process->pid, this->trdid, vpn, elf_offset );
-#endif
-            // compute extended pointer on page base 
-            xptr_t base_xp  = ppm_page2base( page_xp );
-
-            // file_size (in .elf mapper) can be smaller than vseg_size (BSS)
-            uint32_t file_size = vseg->file_size;
-
-            if( file_size < offset )                 // missing page fully in  BSS 
-            {
-
-#if (DEBUG_VMM_GET_ONE_PPN & 0x1)
-if( DEBUG_VMM_GET_ONE_PPN < cycle )
-printk("\n[%s] thread[%x,%x] for vpn  %x / fully in BSS\n",
-__FUNCTION__, this->process->pid, this->trdid, vpn );
-#endif
-                if( GET_CXY( page_xp ) == local_cxy )
-                {
-                    memset( GET_PTR( base_xp ) , 0 , CONFIG_PPM_PAGE_SIZE );
-                }
-                else
-                {
-                   hal_remote_memset( base_xp , 0 , CONFIG_PPM_PAGE_SIZE );       
-                }
-            }
-            else if( file_size >= (offset + CONFIG_PPM_PAGE_SIZE) )  // fully in  mapper
-            {
-
-#if (DEBUG_VMM_GET_ONE_PPN & 0x1)
-if( DEBUG_VMM_GET_ONE_PPN < cycle )
-printk("\n[%s] thread[%x,%x] for vpn  %x / fully in mapper\n",
-__FUNCTION__, this->process->pid, this->trdid, vpn );
-#endif
-                error = mapper_move_kernel( mapper_xp,
-                                            true,             // to_buffer
-                                            elf_offset,
-                                            base_xp,
-                                            CONFIG_PPM_PAGE_SIZE ); 
-                if( error ) return EINVAL;
-            }
-            else  // both in mapper and in BSS :
-                  // - (file_size - offset)             bytes from mapper
-                  // - (page_size + offset - file_size) bytes from BSS
-            {
-
-#if (DEBUG_VMM_GET_ONE_PPN & 0x1)
-if( DEBUG_VMM_GET_ONE_PPN < cycle )
-printk("\n[%s] thread[%x,%x] for vpn  %x / both mapper & BSS\n"
-"      %d bytes from mapper / %d bytes from BSS\n",
-__FUNCTION__, this->process->pid, this->trdid, vpn,
-file_size - offset , offset + CONFIG_PPM_PAGE_SIZE - file_size  );
-#endif
-                // initialize mapper part
-                error = mapper_move_kernel( mapper_xp,
-                                            true,         // to buffer
-                                            elf_offset,
-                                            base_xp,
-                                            file_size - offset ); 
-                if( error ) return EINVAL;
-
-                // initialize BSS part
-                if( GET_CXY( page_xp ) == local_cxy )
-                {
-                    memset( GET_PTR( base_xp ) + file_size - offset , 0 , 
-                            offset + CONFIG_PPM_PAGE_SIZE - file_size );
-                }
-                else
-                {
-                   hal_remote_memset( base_xp + file_size - offset , 0 , 
-                                      offset + CONFIG_PPM_PAGE_SIZE - file_size );
-                }
-            }    
-
-        }  // end if CODE or DATA types   
-    } 
-
-    // return ppn
-    *ppn = ppm_page2ppn( page_xp );
-
-#if DEBUG_VMM_GET_ONE_PPN
-if( DEBUG_VMM_GET_ONE_PPN < cycle )
-printk("\n[%s] thread[%x,%x] exit for vpn %x / ppn %x / cycle %d\n",
-__FUNCTION__ , this->process->pid, this->trdid , vpn , *ppn, cycle );
-#endif
-
-#if (DEBUG_VMM_GET_ONE_PPN & 2)
-if( DEBUG_VMM_GET_ONE_PPN < cycle )
-hal_vmm_display( XPTR( local_cxy , this->process ) , true );
-#endif
-
+    }
+
+    *ret_ppn  = ppn;
+    *ret_attr = attr;  
     return 0;
-
-}  // end vmm_get_one_ppn()
+}  // end vmm_get_pte()
 
 ///////////////////////////////////////////////////
 error_t vmm_handle_page_fault( process_t * process,
+                               vseg_t    * vseg,
                                vpn_t       vpn )
 {
-    vseg_t         * vseg;            // vseg containing vpn
-    uint32_t         attr;            // PTE_ATTR value
-    ppn_t            ppn;             // PTE_PPN value
-    uint32_t         ref_attr;        // PTE_ATTR value in reference GPT
-    ppn_t            ref_ppn;         // PTE_PPN value in reference GPT
-    cxy_t            ref_cxy;         // reference cluster for missing vpn
-    process_t      * ref_ptr;         // reference process for missing vpn
-    xptr_t           local_gpt_xp;    // extended pointer on local GPT
-    xptr_t           ref_gpt_xp;      // extended pointer on reference GPT
-    error_t          error;           // value returned by called functions
-
-    thread_t * this  = CURRENT_THREAD;
-
-#if (CONFIG_INSTRUMENTATION_PGFAULTS || DEBUG_VMM_HANDLE_PAGE_FAULT)
-uint32_t start_cycle = (uint32_t)hal_get_cycles();
+    uint32_t         attr;          // missing page attributes
+    ppn_t            ppn;           // missing page PPN 
+    error_t          error;         // return value
+
+    // get local VMM pointer
+	vmm_t * vmm = &process->vmm;
+
+    // get reference process cluster and local pointer
+    cxy_t       ref_cxy = GET_CXY( process->ref_xp );
+    process_t * ref_ptr = (process_t *)GET_PTR( process->ref_xp );
+
+    // get missing PTE attributes and PPN
+    if( local_cxy != ref_cxy )   // local cluster is not the reference cluster
+    {
+        rpc_vmm_get_pte_client( ref_cxy , ref_ptr , vpn , &attr , &ppn , &error );
+    }
+    else                              // local cluster is the reference cluster       
+    {
+        error = vmm_get_pte( process , vpn , &attr , &ppn );
+    }
+
+    // check page allocation error
+    if( error )
+    {
+        printk("\n[ERROR] in %s : cannot allocate memory / process = %x / vpn = %x\n",
+               __FUNCTION__ , process->pid , vpn ); 
+	    return ENOMEM;
+    }
+
+    // set the missing PTE in local VMM
+    error = hal_gpt_set_pte( &vmm->gpt , vpn , attr , ppn );
+    if( error )
+    {
+        printk("\n[ERROR] in %s : cannot register PTE / process = %x / vpn = %x\n",
+               __FUNCTION__ , process->pid , vpn ); 
+        return ENOMEM;
+    }
+ 
+    return 0;
+}  // end vmm_handle_page_fault()
+
+///////////////////////////////////////////
+error_t vmm_v2p_translate( bool_t    ident,
+                           void    * ptr,
+                           paddr_t * paddr )
+{
+    uint32_t vaddr = (uint32_t)ptr;
+
+    thread_t  * this    = CURRENT_THREAD;
+    process_t * process = this->process;
+
+    if( ident )  // identity mapping
+    {
+        *paddr = (paddr_t)PADDR( local_cxy , vaddr );
+        return 0;
+    }
+
+    // access page table 
+    error_t  error;
+    vpn_t    vpn;
+    uint32_t attr;
+    ppn_t    ppn;
+    uint32_t offset;
+
+    vpn    = (vpn_t)( vaddr >> CONFIG_PPM_PAGE_SHIFT );
+    offset = (uint32_t)( vaddr & CONFIG_PPM_PAGE_MASK );
+
+    if( process->is_ref )   // calling process is reference process
+    {
+        error = vmm_get_pte( process, vpn , &attr , &ppn );
+    }
+    else                    // use a RPC
+    {
+        cxy_t       ref_cxy = GET_CXY( process->ref_xp );
+        process_t * ref_ptr = (process_t *)GET_PTR( process->ref_xp );
+        rpc_vmm_get_pte_client( ref_cxy , ref_ptr , vpn , &attr , &ppn , &error );
+    }
+
+    if( error )
+    {
+        printk("\n[ERROR] in %s : cannot get physical address for vaddr = %x\n",
+               __FUNCTION__ , vaddr );
+        return error;
+    }
+  
+    // return paddr
+    *paddr = (((paddr_t)ppn) << CONFIG_PPM_PAGE_SHIFT) | offset;
+    return 0;
+ 
+}  // end vmm_v2p_translate()
+
+
+
+
+/*
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+error_t vmm_inval_shared_page( vseg_t *vseg, vma_t vaddr, ppn_t ppn)
+{
+	pmm_page_info_t current;
+	error_t err;
+
+	error= pmm_get_page(&vseg->vmm->pmm, vaddr, &current);
+
+	if((err) || (current.ppn != ppn))
+		goto ended;
+
+	current.ppn     = 0;
+	current.attr    = 0;
+	current.cluster = NULL;	
+
+	error= pmm_set_page(&vseg->vmm->pmm, vaddr, &current);
+
+ended:
+	return err;
+}
+
+error_t vmm_update_shared_page( vseg_t *vseg, vma_t vaddr, ppn_t ppn)
+{
+	pmm_page_info_t current;
+	error_t err;
+
+	error= pmm_get_page(&vseg->vmm->pmm, vaddr, &current);
+
+	if((err) || (current.attr != 0))
+		goto ended;
+
+	current.ppn     = ppn;
+	current.attr    = vseg->vm_pgprot;
+	current.cluster = NULL;	// this function is called after invalidate one 
+
+	error= pmm_set_page(&vseg->vmm->pmm, vaddr , &current);
+
+ended:
+	return err;
+}
+
+// Hypothesis: the vseg is shared-anon, mapper list is rdlocked, page is locked 
+error_t vmm_migrate_shared_page_seq( vseg_t *vseg, struct page_s *page, struct page_s **new)
+{
+	register  vseg_t *reg;
+	register struct process_s *process;
+	register struct process_s *this_process;
+	struct page_s *new_pg;
+	struct list_entry *iter;
+	kmem_req_t req;
+	vma_t vaddr;
+	ppn_t ppn;
+	error_t err;
+
+	vaddr     = (page->index << PMM_PAGE_SHIFT) + vseg->vm_start + vseg->vm_offset;
+	ppn       = ppm_page2ppn(page);
+	this_process = (new == NULL) ? NULL : current_process;
+	iter      = &vseg->vm_shared_list;
+	error      = ECANCELED;
+
+	// Invalidate All 
+	do
+	{
+		reg  = list_element(iter,  vseg_t, vm_shared_list);
+
+		process = vmm_get_process(reg->vmm);
+
+		if(process != this_process)
+		{
+			error= vmm_inval_shared_page(reg, vaddr, ppn);
+
+			if(err) goto fail_inval;
+		}
+
+		assert(vseg->vm_mapper.m_home_cid == current_cid);
+		iter = list_next(&vseg->vm_mapper.m_reg_root, iter);
+
+	}while(iter != NULL);
+
+	req.type  = KMEM_PAGE;
+	req.size  = 0;
+	req.excep_code = AF_USER;
+
+	new_pg    = kmem_alloc(&req);
+	*new      = new_pg;
+
+	if(new_pg == NULL)
+	{
+		error= ENOMEM;
+		goto fail_alloc;
+	}
+
+	page_copy(new_pg, page);
+
+	page_lock(new_pg);
+
+	new_pg->mapper = page->mapper;
+	new_pg->index  = page->index;
+
+	// TODO: do the complet job regading dirty page 
+	if(PAGE_IS(page, PG_DIRTY))
+		PAGE_SET(new_pg, PG_DIRTY);
+
+	ppn  = ppm_page2ppn(new_pg);
+	iter = &vseg->vm_shared_list;
+
+	// Update All
+	do
+	{
+		reg  = list_element(iter,  vseg_t, vm_shared_list);
+
+		process = vmm_get_process(reg->vmm);
+
+		if(process != this_process)
+			(void) vmm_update_shared_page(reg, vaddr, ppn);
+
+		assert(vseg->vm_mapper.m_home_cid == current_cid);
+		iter = list_next(&vseg->vm_mapper.m_reg_root, iter);
+
+
+	}while(iter != NULL);
+
+	page_unlock(new_pg);
+
+fail_alloc:
+fail_inval:
+	return err;
+}
+
+//TODO: revisit all manipulation of the page->refcount
+///////////////////////////////////////////////////////////////
+static inline error_t vmm_do_migrate( vseg_t     * vseg, 
+                                      pmm_page_info_t * pinfo,
+                                      uint32_t          vaddr )
+{
+	kmem_req_t        req;
+	pmm_page_info_t   current;
+	page_t          * newpage;
+	cluster_t       * cluster;
+	thread_t        * this;
+	error_t           err;
+	ppn_t             ppn;
+ 
+	assert( pinfo->ppn != 0 );
+
+	ppn = pinfo->ppn;
+	this = current_thread;
+	newpage = NULL;
+	cluster = current_cluster;
+  
+	current.attr = 0;
+	current.ppn  = 0;
+
+	error= pmm_lock_page(&vseg->vmm->pmm, vaddr, &current);
+
+	if(error|| (current.isAtomic == false) || 
+              (current.ppn != ppn) || !(current.attr & PMM_MIGRATE))
+	{
+#if CONFIG_SHOW_SPURIOUS_PGFAULT
+		printk(INFO, "%s: pid %d, tid %d, cpu %d, nothing to do for vaddr %x\n", 
+		       __FUNCTION__, 
+		       this->process->pid, 
+		       this->info.order, 
+		       cpu_get_id(),
+		       vaddr);
 #endif
-
-#if DEBUG_VMM_HANDLE_PAGE_FAULT
-if( (start_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) & (vpn > 0) )
-printk("\n[%s] thread[%x,%x] enter for vpn %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, vpn, start_cycle );
+		this->info.spurious_pgfault_cntr ++;
+		pmm_unlock_page(&vseg->vmm->pmm, vaddr, &current);
+		pmm_tlb_flush_vaddr(vaddr, PMM_DATA);
+		return 0;
+	}
+  
+	if(!ppn_is_local(ppn))
+	{
+		req.type  = KMEM_PAGE;
+		req.size  = 0;
+		req.excep_code = AF_PGFAULT;
+
+		newpage = kmem_alloc(&req);
+
+		if(newpage)
+		{
+			newpage->mapper = NULL;//?
+			ppn_copy(ppm_page2ppn(newpage), ppn);
+
+			if(current.attr & PMM_COW)
+			{
+				current.attr |= PMM_WRITE;
+				current.attr &= ~(PMM_COW);
+			}
+
+			current.ppn = ppm_page2ppn(newpage);
+		}
+	}
+
+	current.attr   |= PMM_PRESENT;
+	current.attr   &= ~(PMM_MIGRATE);
+	current.attr   &= ~(PMM_LOCKED);
+	current.cluster = NULL;
+
+	//also unlock the table entry
+	error= pmm_set_page(&vseg->vmm->pmm, vaddr, &current);
+	
+	if(err)
+	{
+		// TODO: we should differ the kmem_free call 
+		//page_unlock(page);
+		(void)pmm_unlock_page(&vseg->vmm->pmm, vaddr, &current);
+		req.ptr = newpage;
+		kmem_free(&req);
+		return err;
+	} 
+
+
+	if(newpage)
+	{
+		ppn_refcount_down(ppn);
+		current_thread->info.remote_pages_cntr ++;
+#if CONFIG_SHOW_REMOTE_PGALLOC  
+		printk(INFO, "%s: pid %d, tid %x, cpu %d, cid %d: got new remote page from cluster %d (vaddr %x)\n",
+		       __FUNCTION__,
+		       current_process->pid,
+		       current_thread,
+		       cpu_get_id(),
+		       cluster->id,
+		       newpage->cid,
+		       vaddr);
 #endif
-
-#if (DEBUG_VMM_HANDLE_PAGE_FAULT & 2)
-if( (start_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) && (vpn > 0) )
-hal_vmm_display( XPTR( local_cxy , this->process ) , true );
+	}
+
+#if CONFIG_SHOW_VMMMGRT_MSG
+	printk(INFO, "%s: pid %d, tid %d, cpu %d: Asked to migrate page (vaddr %x) from cluster %d to cluster %d, error%d\n",
+	       __FUNCTION__,
+	       current_process->pid,
+	       current_thread->info.order,
+	       cpu_get_id(),
+	       vaddr,
+	       ppn_ppn2cid(ppn),
+	       cluster->id,
+	       err);
 #endif
 
-    // get local vseg (access to reference VSL can be required)
-    error = vmm_get_vseg( process, 
-                          (intptr_t)vpn<<CONFIG_PPM_PAGE_ORDER,
-                          &vseg );
-    if( error )
-    {
-        printk("\n[ERROR] in %s : vpn %x in thread[%x,%x] not in registered vseg\n",
-        __FUNCTION__ , vpn , process->pid, this->trdid );
-        
-        return EXCP_USER_ERROR;
-    }
-
-#if (DEBUG_VMM_HANDLE_PAGE_FAULT & 1)
-if( (start_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] found vseg %s\n",
-__FUNCTION__, this->process->pid, this->trdid, vseg_type_str(vseg->type) );
+	return err;
+}
+
+error_t vmm_do_cow( vseg_t *vseg, pmm_page_info_t *pinfo, uint32_t vaddr)
+{
+	register struct page_s *newpage;
+	register struct page_s *page;
+	register struct thread_s *this;
+	register error_t err;
+	register uint32_t count;
+	register bool_t isCountDown;
+	pmm_page_info_t old;
+	pmm_page_info_t new;
+	kmem_req_t req;
+
+	this       = current_thread;
+	old.attr  = 0;
+	newpage    = NULL;
+	isCountDown = true;
+
+	vmm_dmsg(2,"%s: pid %d, tid %d, cpu %d, vaddr %x\n",
+		 __FUNCTION__,
+		 this->process->pid,
+		 this->info.order,
+		 cpu_get_id(),
+		 vaddr);
+
+  
+	error= pmm_lock_page(&vseg->vmm->pmm, vaddr, &old);
+
+	//TODO: check this condition
+	if(error|| (old.isAtomic == false) || !(old.attr & PMM_COW))
+	{
+#if CONFIG_SHOW_SPURIOUS_PGFAULT
+		printk(INFO, "%s: pid %d, tid %d, cpu %d, nothing to do for vaddr %x\n", 
+		       __FUNCTION__, 
+		       this->process->pid, 
+		       this->info.order, 
+		       cpu_get_id(),
+		       vaddr);
 #endif
-
-    // build extended pointer on local GPT
-    local_gpt_xp  = XPTR( local_cxy , &process->vmm.gpt );
-
-    // lock PTE in local GPT and get current PPN and attributes
-    error = hal_gpt_lock_pte( local_gpt_xp,
-                              vpn,
-                              &attr,
-                              &ppn );
-    if( error )
-    {
-        printk("\n[PANIC] in %s : cannot lock PTE in local GPT / vpn %x / process %x\n",
-        __FUNCTION__ , vpn , process->pid );
-        
-        return EXCP_KERNEL_PANIC;
-    }
-
-#if (DEBUG_VMM_HANDLE_PAGE_FAULT & 1)
-if( (start_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] locked vpn %x in cluster %x\n",
-__FUNCTION__, this->process->pid, this->trdid, vpn, local_cxy );
+		this->info.spurious_pgfault_cntr ++;
+		pmm_tlb_flush_vaddr(vaddr, PMM_DATA);
+		pmm_unlock_page(&vseg->vmm->pmm, vaddr, &old);
+		return err;
+		//goto VMM_COW_END;
+	}
+
+	//if the ppn is local and the others (processus with wich we share the page) 
+	//has done cow, then use the old.ppn directly
+	if(ppn_is_local(old.ppn))
+	{
+		page = ppm_ppn2page(&current_cluster->ppm, old.ppn);
+
+		if(page->mapper == NULL)
+		{
+			count = page_refcount_get(page);
+			if(count == 1)
+			{
+				newpage = page;//don't copy the page. use it directly.
+				isCountDown = false;
+				vmm_dmsg(2, "%s: pid %d, tid %d, cpu %d, reuse same page for vaddr %x, pg_addr %x\n", 
+					 __FUNCTION__, 
+					 this->process->pid, 
+					 this->info.order, 
+					 cpu_get_id(), 
+					 vaddr, 
+					 ppm_page2addr(page));
+			}
+		}
+		//else: we need to do the cow even if it's local!
+
+	}
+
+	//else: alocate newpage and copy the data from the remote node
+	//also defcount down the ppn
+	if(newpage == NULL)
+	{    
+		req.type  = KMEM_PAGE;
+		req.size  = 0;
+		req.excep_code = AF_PGFAULT;
+
+		if((newpage = kmem_alloc(&req)) == NULL)
+		{
+			(void)pmm_unlock_page(&vseg->vmm->pmm, vaddr, &old);
+			return ENOMEM;
+		}	
+
+		newpage->mapper = NULL;
+
+		ppn_copy(ppm_page2ppn(newpage), old.ppn);
+		assert(isCountDown);
+		
+		vmm_dmsg(2, 
+			 "%s: pid %d, tid %d, cpu %d, newpage for vaddr %x, pg_addr %x\n", 
+			 __FUNCTION__, 
+			 this->process->pid, 
+			 this->info.order, 
+			 cpu_get_id(), 
+			 vaddr, 
+			 ppm_page2addr(newpage));
+
+		if(newpage->cid != current_cid)
+			this->info.remote_pages_cntr ++;
+	}
+
+	new.attr    = vseg->vm_pgprot | PMM_WRITE;
+	new.attr   &= ~(PMM_COW | PMM_MIGRATE);
+	new.ppn     = ppm_page2ppn(newpage);
+	new.cluster = NULL;
+
+	//this also unlock the table entry (if no error)
+	error= pmm_set_page(&vseg->vmm->pmm, vaddr, &new);
+
+	if(err)
+	{
+		(void)pmm_unlock_page(&vseg->vmm->pmm, vaddr, &old);
+		req.ptr = newpage;
+		kmem_free(&req);
+		vmm_dmsg(3, "%s: ended [ error%d ]\n", __FUNCTION__, err);
+		return err;
+	}
+	
+	if(isCountDown) ppn_refcount_down(old.ppn);
+	
+	vmm_dmsg(2, "%s, pid %d, tid %d, cpu %d, COW ended [vaddr %x]\n", 
+		 __FUNCTION__, 
+		 this->process->pid,
+		 this->info.order,
+		 cpu_get_id(),
+		 vaddr);
+  
+	return 0;
+}
+
+
+//refcount is taken on the file at mmap
+static inline error_t vmm_do_mapped( vseg_t *vseg, uint32_t vaddr, uint32_t excep_code)
+{
+	ppn_t ppn;
+	error_t err;
+	uint32_t index;
+	bool_t isDone;
+	pmm_page_info_t info;
+	pmm_page_info_t current;
+	struct thread_s *this;
+
+	this = current_thread;
+
+	current.attr = 1;
+	current.ppn  = 1;
+	isDone       = false;
+
+	error= pmm_lock_page(&vseg->vmm->pmm, vaddr, &current);
+	
+	if(err) return err;
+
+	if((current.isAtomic == false) || (current.attr != 0))
+	{
+#if CONFIG_SHOW_SPURIOUS_PGFAULT
+		printk(INFO, "%s: pid %d, tid %d, cpu %d, nothing to do for vaddr %x\n", 
+		       __FUNCTION__, 
+		       this->process->pid, 
+		       this->info.order, 
+		       cpu_get_id(),
+		       vaddr);
 #endif
-
-    // handle page fault only if local PTE still unmapped after lock
-    if( (attr & GPT_MAPPED) == 0 )
-    {
-        // get reference process cluster and local pointer
-        ref_cxy = GET_CXY( process->ref_xp );
-        ref_ptr = GET_PTR( process->ref_xp );
-
-        /////////////// private vseg or (local == reference)
-        /////////////// => access only the local GPT 
-        if( (vseg->type == VSEG_TYPE_STACK) ||
-            (vseg->type == VSEG_TYPE_CODE)  ||
-            (ref_cxy    == local_cxy ) )
-        {
-
-#if (DEBUG_VMM_HANDLE_PAGE_FAULT & 1)
-if( (start_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] access local gpt : cxy %x / ref_cxy %x / type %s / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid,
-local_cxy, ref_cxy, vseg_type_str(vseg->type), (uint32_t)hal_get_cycles() );
+		this->info.spurious_pgfault_cntr ++;
+		pmm_tlb_flush_vaddr(vaddr, PMM_DATA);
+		return 0;
+	}
+
+	index = ((vaddr - vseg->vm_start) + vseg->vm_offset) >> PMM_PAGE_SHIFT;
+
+	//also hold a refcount!
+	ppn = mapper_get_ppn(&vseg->vm_mapper, 
+			       index, 
+			       MAPPER_SYNC_OP);
+
+	if(!ppn)
+	{
+		error= pmm_unlock_page(&vseg->vmm->pmm, vaddr, &current);
+		assert(!err); //FIXME: liberate the ppn ...
+		return (VFS_FILE_IS_NULL(vseg->vm_file)) ? EIO : ENOMEM;
+	}
+
+	info.attr    = vseg->vm_pgprot;
+	info.ppn     = ppn;
+	info.cluster = NULL;
+
+	//also unlock the page
+	error= pmm_set_page(&vseg->vmm->pmm, vaddr, &info);
+
+	assert(!err);//FIXME: liberate the ppn and unlock the table entry ...
+	//error= pmm_unlock_page(&vseg->vmm->pmm, vaddr, &current);
+
+	return err;
+}
+
+/////////////////////////////////////////////////////
+static inline error_t vmm_do_aod( vseg_t *vseg, uint32_t vaddr)
+{
+	register error_t err;
+	register struct page_s *page;
+	register struct cluster_s *cluster;
+	struct thread_s *this;
+	pmm_page_info_t old;
+	pmm_page_info_t new;
+	kmem_req_t req;
+
+	page      = NULL;
+	old.attr  = 0;
+	this      = current_thread;
+  
+	error= pmm_lock_page(&vseg->vmm->pmm, vaddr, &old);
+
+	if(err) return err;
+
+	if(old.isAtomic == false)
+	{
+		this->info.spurious_pgfault_cntr ++;
+		pmm_tlb_flush_vaddr(vaddr, PMM_DATA);
+		return 0;
+	}
+
+	req.type  = KMEM_PAGE;
+	req.size  = 0;
+	req.excep_code = AF_PGFAULT | AF_ZERO;
+
+	if((page = kmem_alloc(&req)) == NULL)
+	{
+		(void)pmm_unlock_page(&vseg->vmm->pmm, vaddr, &old);
+		return ENOMEM;
+	}
+
+	page->mapper = NULL;
+
+	new.attr    = vseg->vm_pgprot;
+	new.ppn     = ppm_page2ppn(page);
+	new.cluster = NULL;
+
+	error= pmm_set_page(&vseg->vmm->pmm, vaddr, &new);
+	
+	if(err) goto fail_set_pg;
+
+	cluster = current_cluster;
+
+	if(page->cid != cluster->id)
+		this->info.remote_pages_cntr ++;
+
+	return 0;
+
+fail_set_pg:
+	(void)pmm_unlock_page(&vseg->vmm->pmm, vaddr, &old);
+	req.ptr = page;
+	kmem_free(&req);
+
+	vmm_dmsg(3, "%s: ended [ error%d ]\n", __FUNCTION__, err);
+	return err;
+}
+
+VSEGION_PAGE_FAULT(vmm_default_pagefault)
+{
+	register struct thread_s *this;
+	register error_t err;
+	pmm_page_info_t info;
+
+	if((error= pmm_get_page(&vseg->vmm->pmm, vaddr, &info)))
+		return err;
+
+	if((info.attr != 0) && (info.ppn != 0))
+	{
+		if((info.attr & PMM_COW) && pmm_except_isWrite(excep_code))
+		{
+			error= vmm_do_cow(vseg, &info, vaddr);
+			return err;
+		}
+
+		if(info.attr & PMM_MIGRATE)
+			return vmm_do_migrate(vseg, &info, vaddr);
+
+		if(info.attr & PMM_PRESENT)
+		{
+			this = current_thread;
+
+#if CONFIG_SHOW_SPURIOUS_PGFAULT
+			printk(WARNING, "WARNING: %s: pid %d, tid %d, cpu %d, excep_code %x but vaddr is valid %x, attr %x, ppn %x\n",
+			       __FUNCTION__,
+			       this->process->pid,
+			       this->info.order,
+			       cpu_get_id(),
+			       excep_code,
+			       vaddr,
+			       info.attr,
+			       info.ppn);
 #endif
-            // allocate and initialise a physical page 
-            error = vmm_get_one_ppn( vseg , vpn , &ppn );
-
-            if( error )
-            {
-                printk("\n[ERROR] in %s : no physical page / process = %x / vpn = %x\n",
-                __FUNCTION__ , process->pid , vpn );
-
-                // unlock PTE in local GPT 
-                hal_gpt_unlock_pte( local_gpt_xp , vpn );
-
-                return EXCP_KERNEL_PANIC;
-            }
-
-            // define attr from vseg flags 
-            attr = GPT_MAPPED | GPT_SMALL | GPT_READABLE;
-            if( vseg->flags & VSEG_USER  ) attr |= GPT_USER;
-            if( vseg->flags & VSEG_WRITE ) attr |= GPT_WRITABLE;
-            if( vseg->flags & VSEG_EXEC  ) attr |= GPT_EXECUTABLE;
-            if( vseg->flags & VSEG_CACHE ) attr |= GPT_CACHABLE;
-
-            // set PTE to local GPT 
-            // it unlocks this PTE
-            hal_gpt_set_pte( local_gpt_xp,
-                             vpn,
-                             attr,
-                             ppn );
-
-#if (CONFIG_INSTRUMENTATION_PGFAULTS || DEBUG_VMM_HANDLE_PAGE_FAULT)
-uint32_t end_cycle = (uint32_t)hal_get_cycles();
+
+			current_thread->info.spurious_pgfault_cntr ++;
+			pmm_tlb_flush_vaddr(vaddr, PMM_UNKNOWN);
+			return 0;
+		}
+
+		current_thread->info.spurious_pgfault_cntr ++;
+		pmm_tlb_flush_vaddr(vaddr, PMM_UNKNOWN);
+		return 0;
+#if 0
+#if CONFIG_SHOW_VMM_ERROR_MSG
+		printk(ERROR, 
+		       "ERROR: %s: pid %d, cpu %d, Unexpected page attributes configuration for vaddr %x, found: ppn %x, attr %x\n",
+		       __FUNCTION__,
+		       current_process->pid,
+		       cpu_get_id(), 
+		       vaddr, 
+		       info.ppn,
+		       info.attr);
 #endif
-
-#if DEBUG_VMM_HANDLE_PAGE_FAULT
-if( (end_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] handled local pgfault / ppn %x / attr %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, ppn, attr, end_cycle );
+    
+		return EPERM;
 #endif
-
-#if (DEBUG_VMM_HANDLE_PAGE_FAULT & 2)
-if( (end_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) && (vpn > 0) )
-hal_vmm_display( XPTR( local_cxy , this->process ) , true );
-#endif
-
-#if CONFIG_INSTRUMENTATION_PGFAULTS 
-uint32_t cost      = end_cycle - start_cycle;
-this->info.local_pgfault_nr++;
-this->info.local_pgfault_cost += cost;
-if( cost > this->info.local_pgfault_max ) this->info.local_pgfault_max = cost;
-#endif
-            return EXCP_NON_FATAL;
-
-        }   // end local GPT access 
-
-        /////////////////// public vseg and (local != reference) 
-        /////////////////// => access ref GPT to update local GPT
-        else                                
-        {
-
-#if (DEBUG_VMM_HANDLE_PAGE_FAULT & 1)
-if( (start_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] access ref gpt : cxy %x / ref_cxy %x / type %s / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, 
-local_cxy, ref_cxy, vseg_type_str(vseg->type), (uint32_t)hal_get_cycles() );
-#endif
-            // build extended pointer on reference GPT
-            ref_gpt_xp = XPTR( ref_cxy , &ref_ptr->vmm.gpt );
-
-            // lock PTE in reference GPT and get current PPN and attributes
-            error = hal_gpt_lock_pte( ref_gpt_xp,
-                                      vpn,
-                                      &ref_attr,
-                                      &ref_ppn );
-            if( error )
-            {
-                printk("\n[PANIC] in %s : cannot lock PTE in ref GPT / vpn %x / process %x\n",
-                __FUNCTION__ , vpn , process->pid );
-        
-                // unlock PTE in local GPT
-                hal_gpt_unlock_pte( local_gpt_xp , vpn );
-                    
-                return EXCP_KERNEL_PANIC;
-            }
-
-#if (DEBUG_VMM_HANDLE_PAGE_FAULT & 1)
-if( (start_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] get pte from ref gpt / attr %x / ppn %x\n",
-__FUNCTION__, this->process->pid, this->trdid, ref_attr, ref_ppn );
-#endif
-
-            if( ref_attr & GPT_MAPPED )        // false page fault 
-            {
-                // update local GPT from reference GPT values
-                // this unlocks the PTE in local GPT
-                hal_gpt_set_pte( local_gpt_xp,
-                                 vpn,
-                                 ref_attr,
-                                 ref_ppn );
-
-#if (DEBUG_VMM_HANDLE_PAGE_FAULT & 1)
-if( (start_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] updated local gpt for a false pgfault\n",
-__FUNCTION__, this->process->pid, this->trdid );
-#endif
-
-                // unlock the PTE in reference GPT
-                hal_gpt_unlock_pte( ref_gpt_xp, vpn );
-                             
-#if (DEBUG_VMM_HANDLE_PAGE_FAULT &1)
-if( (start_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] unlock the ref gpt after a false pgfault\n",
-__FUNCTION__, this->process->pid, this->trdid );
-#endif
-
-#if (CONFIG_INSTRUMENTATION_PGFAULTS || DEBUG_VMM_HANDLE_PAGE_FAULT)
-uint32_t end_cycle = (uint32_t)hal_get_cycles();
-#endif
-
-#if DEBUG_VMM_HANDLE_PAGE_FAULT
-if( (end_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] handled false pgfault / ppn %x / attr %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, ref_ppn, ref_attr, end_cycle );
-#endif
-
-#if (DEBUG_VMM_HANDLE_PAGE_FAULT & 2)
-if( (end_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) && (vpn > 0) )
-hal_vmm_display( XPTR( local_cxy , this->process ) , true );
-#endif
-
-#if CONFIG_INSTRUMENTATION_PGFAULTS 
-uint32_t cost      = end_cycle - start_cycle;
-this->info.false_pgfault_nr++;
-this->info.false_pgfault_cost += cost;
-if( cost > this->info.false_pgfault_max ) this->info.false_pgfault_max = cost;
-#endif
-                return EXCP_NON_FATAL;
-            }
-            else                            // true page fault 
-            {
-                // allocate and initialise a physical page depending on the vseg type
-                error = vmm_get_one_ppn( vseg , vpn , &ppn );
-
-                if( error )
-                {
-                    printk("\n[ERROR] in %s : no memory / process = %x / vpn = %x\n",
-                    __FUNCTION__ , process->pid , vpn );
-
-                    // unlock PTE in local GPT and in reference GPT
-                    hal_gpt_unlock_pte( local_gpt_xp , vpn );
-                    hal_gpt_unlock_pte( ref_gpt_xp   , vpn );
-                    
-                    return EXCP_KERNEL_PANIC;
-                }
-
-                // define attr from vseg flags 
-                attr = GPT_MAPPED | GPT_SMALL | GPT_READABLE;
-                if( vseg->flags & VSEG_USER  ) attr |= GPT_USER;
-                if( vseg->flags & VSEG_WRITE ) attr |= GPT_WRITABLE;
-                if( vseg->flags & VSEG_EXEC  ) attr |= GPT_EXECUTABLE;
-                if( vseg->flags & VSEG_CACHE ) attr |= GPT_CACHABLE;
-
-#if (DEBUG_VMM_HANDLE_PAGE_FAULT & 1)
-if( (start_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] build a new PTE for a true pgfault\n",
-__FUNCTION__, this->process->pid, this->trdid );
-#endif
-                // set PTE in reference GPT
-                // this unlock the PTE 
-                hal_gpt_set_pte( ref_gpt_xp,
-                                 vpn,
-                                 attr,
-                                 ppn );
-
-#if (DEBUG_VMM_HANDLE_PAGE_FAULT & 1)
-if( (start_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] set new PTE in ref gpt for a true page fault\n",
-__FUNCTION__, this->process->pid, this->trdid );
-#endif
-
-                // set PTE in local GPT 
-                // this unlock the PTE 
-                hal_gpt_set_pte( local_gpt_xp,
-                                 vpn,
-                                 attr,
-                                 ppn );
-
-#if (CONFIG_INSTRUMENTATION_PGFAULTS || DEBUG_VMM_HANDLE_PAGE_FAULT)
-uint32_t end_cycle = (uint32_t)hal_get_cycles();
-#endif
-
-#if DEBUG_VMM_HANDLE_PAGE_FAULT
-if( (end_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] handled global pgfault / ppn %x / attr %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, ppn, attr, end_cycle );
-#endif
-
-#if (DEBUG_VMM_HANDLE_PAGE_FAULT & 2)
-if( (end_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) && (vpn > 0) )
-hal_vmm_display( XPTR( local_cxy , this->process ) , true );
-#endif
-
-#if CONFIG_INSTRUMENTATION_PGFAULTS 
-uint32_t cost      = end_cycle - start_cycle;
-this->info.global_pgfault_nr++;
-this->info.global_pgfault_cost += cost;
-if( cost > this->info.global_pgfault_max ) this->info.global_pgfault_max = cost;
-#endif
-                return EXCP_NON_FATAL;
-            }
-        }
-    }
-    else   // page has been locally mapped by another concurrent thread
-    {
-        // unlock the PTE in local GPT
-        hal_gpt_unlock_pte( local_gpt_xp , vpn );
-
-#if (CONFIG_INSTRUMENTATION_PGFAULTS || DEBUG_VMM_HANDLE_PAGE_FAULT)
-uint32_t end_cycle = (uint32_t)hal_get_cycles();
-#endif
-
-#if DEBUG_VMM_HANDLE_PAGE_FAULT
-if( (end_cycle > DEBUG_VMM_HANDLE_PAGE_FAULT) && (vpn > 0) )
-printk("\n[%s] handled by another thread / vpn %x / ppn %x / attr %x / cycle %d\n",
-__FUNCTION__, vpn, ppn, attr, end_cycle );
-#endif
-
-#if CONFIG_INSTRUMENTATION_PGFAULTS 
-uint32_t cost      = end_cycle - start_cycle;
-this->info.false_pgfault_nr++;
-this->info.false_pgfault_cost += cost;
-if( cost > this->info.false_pgfault_max ) this->info.false_pgfault_max = cost;
-#endif
-        return EXCP_NON_FATAL;
-    }
-
-}   // end vmm_handle_page_fault()
-
-////////////////////////////////////////////
-error_t vmm_handle_cow( process_t * process,
-                        vpn_t       vpn )
-{
-    vseg_t         * vseg;            // vseg containing vpn
-    xptr_t           gpt_xp;          // extended pointer on GPT (local or reference)
-    gpt_t          * gpt_ptr;         // local pointer on GPT (local or reference)
-    cxy_t            gpt_cxy;         // GPT cluster identifier
-    uint32_t         old_attr;        // current PTE_ATTR value
-    ppn_t            old_ppn;         // current PTE_PPN value
-    uint32_t         new_attr;        // new PTE_ATTR value
-    ppn_t            new_ppn;         // new PTE_PPN value
-    cxy_t            ref_cxy;         // reference process cluster
-    process_t      * ref_ptr;         // local pointer on reference process
-    error_t          error;
-
-    thread_t * this  = CURRENT_THREAD;
-
-#if DEBUG_VMM_HANDLE_COW
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-if( (DEBUG_VMM_HANDLE_COW < cycle) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] enter for vpn %x / core[%x,%d] / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, vpn, local_cxy, this->core->lid, cycle );
-#endif
-
-#if (DEBUG_VMM_HANDLE_COW & 2)
-hal_vmm_display( XPTR( local_cxy , process ) , true );
-#endif
-
-    // get local vseg
-    error = vmm_get_vseg( process, 
-                          (intptr_t)vpn<<CONFIG_PPM_PAGE_ORDER,
-                          &vseg );
-    if( error )
-    {
-        printk("\n[ERROR] in %s : vpn %x in thread[%x,%x] not in a registered vseg\n",
-        __FUNCTION__, vpn, process->pid, this->trdid );
-
-        return EXCP_USER_ERROR;
-    }
-
-#if DEBUG_VMM_HANDLE_COW 
-if( (DEBUG_VMM_HANDLE_COW < cycle) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] get vseg %s\n",
-__FUNCTION__, this->process->pid, this->trdid, vseg_type_str(vseg->type) );
-#endif
-
-    // get reference process cluster and local pointer
-    ref_cxy = GET_CXY( process->ref_xp );
-    ref_ptr = GET_PTR( process->ref_xp );
-
-    // build pointers on relevant GPT
-    // - access only local GPT for a private vseg  
-    // - access reference GPT and all copies for a public vseg
-    if( (vseg->type == VSEG_TYPE_STACK) || (vseg->type == VSEG_TYPE_CODE) )
-    {
-        gpt_cxy = local_cxy;
-        gpt_ptr = &process->vmm.gpt;
-        gpt_xp  = XPTR( gpt_cxy , gpt_ptr );
-    }
-    else
-    {
-        gpt_cxy = ref_cxy;
-        gpt_ptr = &ref_ptr->vmm.gpt;
-        gpt_xp  = XPTR( gpt_cxy , gpt_ptr );
-    }
-
-    // lock target PTE in relevant GPT (local or reference) 
-    // and get current PTE value
-    error = hal_gpt_lock_pte( gpt_xp,
-                              vpn,
-                              &old_attr,
-                              &old_ppn );
-    if( error )
-    {
-        printk("\n[PANIC] in %s : cannot lock PTE in GPT / cxy %x / vpn %x / process %x\n",
-        __FUNCTION__ , gpt_cxy, vpn , process->pid );
-        
-        return EXCP_KERNEL_PANIC;
-    }
-
-#if DEBUG_VMM_HANDLE_COW 
-if( (DEBUG_VMM_HANDLE_COW < cycle) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] get pte for vpn %x : ppn %x / attr %x\n",
-__FUNCTION__, this->process->pid, this->trdid, vpn, old_ppn, old_attr );
-#endif
-
-    // return user error if COW attribute not set or PTE2 unmapped
-    if( ((old_attr & GPT_COW) == 0) || ((old_attr & GPT_MAPPED) == 0) )
-    {
-        hal_gpt_unlock_pte( gpt_xp , vpn );
-
-        return EXCP_USER_ERROR;
-    }
-
-    // get pointers on physical page descriptor
-    xptr_t   page_xp  = ppm_ppn2page( old_ppn );
-    cxy_t    page_cxy = GET_CXY( page_xp );
-    page_t * page_ptr = GET_PTR( page_xp );
-
-    // get extended pointers on forks and lock field in page descriptor
-    xptr_t forks_xp       = XPTR( page_cxy , &page_ptr->forks );
-    xptr_t forks_lock_xp  = XPTR( page_cxy , &page_ptr->lock );
-
-    // take lock protecting "forks" counter
-    remote_busylock_acquire( forks_lock_xp );
-
-    // get number of pending forks from page descriptor
-    uint32_t forks = hal_remote_l32( forks_xp );
-
-#if DEBUG_VMM_HANDLE_COW 
-if( (DEBUG_VMM_HANDLE_COW < cycle) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] get forks = %d for vpn %x\n",
-__FUNCTION__, this->process->pid, this->trdid, forks, vpn );
-#endif
-
-    if( forks )        // pending fork => allocate a new page, and copy old to new
-    {
-        // decrement pending forks counter in page descriptor
-        hal_remote_atomic_add( forks_xp , -1 );
-
-        // release lock protecting "forks" counter
-        remote_busylock_release( forks_lock_xp );
-
-        // allocate a new physical page depending on vseg type
-        page_xp = vmm_page_allocate( vseg , vpn );
-
-        if( page_xp == XPTR_NULL ) 
-        {
-            printk("\n[PANIC] in %s : no memory for vpn %x in process %x\n",
-            __FUNCTION__ , vpn, process->pid );
-
-            hal_gpt_unlock_pte( gpt_xp , vpn ); 
-
-            return EXCP_KERNEL_PANIC;
-        }
-
-        // compute allocated page PPN 
-        new_ppn = ppm_page2ppn( page_xp );
-
-#if DEBUG_VMM_HANDLE_COW 
-if( (DEBUG_VMM_HANDLE_COW < cycle) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] get new ppn %x for vpn %x\n",
-__FUNCTION__, this->process->pid, this->trdid, new_ppn, vpn );
-#endif
-
-        // copy old page content to new page
-        hal_remote_memcpy( ppm_ppn2base( new_ppn ),
-                           ppm_ppn2base( old_ppn ),
-                           CONFIG_PPM_PAGE_SIZE );
-
-#if DEBUG_VMM_HANDLE_COW
-if( (DEBUG_VMM_HANDLE_COW < cycle) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] copied old page to new page\n",
-__FUNCTION__, this->process->pid, this->trdid );
-#endif
-
-    }             
-    else               // no pending fork => keep the existing page
-    {
-        // release lock protecting "forks" counter
-        remote_busylock_release( forks_lock_xp );
-
-#if(DEBUG_VMM_HANDLE_COW & 1)
-if( (DEBUG_VMM_HANDLE_COW < cycle) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] no pending forks / keep existing PPN %x\n",
-__FUNCTION__, this->process->pid, this->trdid, old_ppn );
-#endif
-        new_ppn = old_ppn;
-    }
-
-    // build new_attr : set WRITABLE, reset COW, reset LOCKED
-    new_attr = (((old_attr | GPT_WRITABLE) & (~GPT_COW)) & (~GPT_LOCKED));
-
-#if(DEBUG_VMM_HANDLE_COW & 1)
-if( (DEBUG_VMM_HANDLE_COW < cycle) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] new_attr %x / new_ppn %x\n",
-__FUNCTION__, this->process->pid, this->trdid, new_attr, new_ppn );
-#endif
-
-    // update the relevant GPT(s)
-    // - private vseg => update only the local GPT 
-    // - public vseg => update the reference GPT AND all the GPT copies
-    if( (vseg->type == VSEG_TYPE_STACK) || (vseg->type == VSEG_TYPE_CODE) )
-    {
-        // set new PTE in local gpt
-        hal_gpt_set_pte( gpt_xp,
-                         vpn,
-                         new_attr,
-                         new_ppn );
-    }
-    else
-    {
-        // set new PTE in all GPT copies
-        vmm_global_update_pte( process,
-                               vpn,
-                               new_attr,
-                               new_ppn );
-    }
-
-#if DEBUG_VMM_HANDLE_COW
-cycle = (uint32_t)hal_get_cycles();
-if( (DEBUG_VMM_HANDLE_COW < cycle) && (vpn > 0) )
-printk("\n[%s] thread[%x,%x] exit for vpn %x / core[%x,%d] / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, vpn, local_cxy, this->core->lid, cycle );
-#endif
-
-#if (DEBUG_VMM_HANDLE_COW & 2)
-hal_vmm_display( XPTR( local_cxy , process ) , true );
-#endif
-
-     return EXCP_NON_FATAL;
-
-}   // end vmm_handle_cow()
-
+	}
+
+	if(!MAPPER_IS_NULL(vseg->vm_mapper))
+		return vmm_do_mapped(vseg, vaddr, excep_code);
+
+	return vmm_do_aod(vseg, vaddr);
+}
+
+*/
+
+
