Index: trunk/kernel/mm/vmm.c
===================================================================
--- trunk/kernel/mm/vmm.c	(revision 624)
+++ trunk/kernel/mm/vmm.c	(revision 625)
@@ -4,5 +4,5 @@
  * Authors   Ghassan Almaless (2008,2009,2010,2011, 2012)
  *           Mohamed Lamine Karaoui (2015)
- *           Alain Greiner (2016,2017,2018)
+ *           Alain Greiner (2016,2017,2018,2019)
  *
  * Copyright (c) UPMC Sorbonne Universites
@@ -55,8 +55,241 @@
 extern  process_t  process_zero;      // allocated in cluster.c 
 
-///////////////////////////////////////
-error_t vmm_init( process_t * process )
+////////////////////////////////////////////////////////////////////////////////////////////
+// This static function is called by the vmm_create_vseg() function, and implements
+// the VMM STACK specific allocator.
+////////////////////////////////////////////////////////////////////////////////////////////
+// @ vmm      : [in]  pointer on VMM.
+// @ ltid     : [in]  requested slot == local user thread identifier.
+// @ vpn_base : [out] first allocated page
+// @ vpn_size : [out] number of allocated pages
+////////////////////////////////////////////////////////////////////////////////////////////
+static void vmm_stack_alloc( vmm_t  * vmm,
+                             ltid_t   ltid,
+                             vpn_t  * vpn_base,
+                             vpn_t  * vpn_size )
 {
-    error_t   error;
+
+// check ltid argument
+assert( (ltid <= ((CONFIG_VMM_VSPACE_SIZE - CONFIG_VMM_STACK_BASE) / CONFIG_VMM_STACK_SIZE)),
+"slot index %d too large for an user stack vseg", ltid );
+
+    // get stack allocator pointer
+    stack_mgr_t * mgr = &vmm->stack_mgr;
+
+    // get lock on stack allocator
+    busylock_acquire( &mgr->lock );
+
+// check requested slot is available
+assert( (bitmap_state( &mgr->bitmap , ltid ) == false),
+"slot index %d already allocated", ltid );
+
+    // update bitmap
+    bitmap_set( &mgr->bitmap , ltid );
+
+    // release lock on stack allocator
+    busylock_release( &mgr->lock );
+
+    // returns vpn_base, vpn_size (first page non allocated)
+    *vpn_base = mgr->vpn_base + ltid * CONFIG_VMM_STACK_SIZE + 1;
+    *vpn_size = CONFIG_VMM_STACK_SIZE - 1;
+
+} // end vmm_stack_alloc()
+
+////////////////////////////////////////////////////////////////////////////////////////////
+// This static function is called by the vmm_remove_vseg() function, and implements
+// the VMM STACK specific desallocator.
+////////////////////////////////////////////////////////////////////////////////////////////
+// @ 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( (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( (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 );
+
+}  // end vmm_stack_free()
+
+////////////////////////////////////////////////////////////////////////////////////////////
+// This static function is called by the vmm_create_vseg() function, and implements
+// the VMM MMAP specific allocator.
+////////////////////////////////////////////////////////////////////////////////////////////
+// @ vmm      : [in] pointer on VMM.
+// @ npages   : [in] requested number of pages.
+// @ vpn_base : [out] first allocated page.
+// @ vpn_size : [out] actual number of allocated pages.
+////////////////////////////////////////////////////////////////////////////////////////////
+static error_t vmm_mmap_alloc( vmm_t * vmm,
+                               vpn_t   npages,
+                               vpn_t * vpn_base,
+                               vpn_t * vpn_size )
+{
+    uint32_t   order;
+    xptr_t     vseg_xp;
+    vseg_t   * vseg;
+    vpn_t      base;
+    vpn_t      size;
+    vpn_t      free;
+
+#if DEBUG_VMM_MMAP_ALLOC
+thread_t * this = CURRENT_THREAD;
+uint32_t cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_VMM_MMAP_ALLOC < cycle )
+printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, cycle );
+#endif
+
+    // number of allocated pages must be power of 2
+    // compute actual size and order 
+    size  = POW2_ROUNDUP( npages );
+    order = bits_log2( size );
+
+    // get mmap allocator pointer
+    mmap_mgr_t * mgr = &vmm->mmap_mgr;
+
+    // build extended pointer on root of zombi_list[order]
+    xptr_t root_xp = XPTR( local_cxy , &mgr->zombi_list[order] );
+
+    // take lock protecting zombi_lists
+    busylock_acquire( &mgr->lock );
+
+    // get vseg from zombi_list or from mmap zone
+    if( xlist_is_empty( root_xp ) )                   // from mmap zone
+    {
+        // check overflow
+        free = mgr->first_free_vpn;
+        if( (free + size) > mgr->vpn_size ) return -1;
+
+        // update MMAP allocator
+        mgr->first_free_vpn += size;
+
+        // compute base
+        base = free;
+    }
+    else                                              // from zombi_list
+    {
+        // get pointer on zombi vseg from zombi_list
+        vseg_xp = XLIST_FIRST( root_xp , vseg_t , xlist );
+        vseg    = GET_PTR( vseg_xp );
+
+        // remove vseg from free-list
+        xlist_unlink( XPTR( local_cxy , &vseg->xlist ) );
+
+        // compute base
+        base = vseg->vpn_base;
+    }
+
+    // release lock 
+    busylock_release( &mgr->lock );
+
+#if DEBUG_VMM_MMAP_ALLOC
+cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_VMM_DESTROY < cycle )
+printk("\n[%s] thread[%x,%x] exit / vpn_base %x / vpn_size %x / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, base, size, cycle );
+#endif
+
+    // returns vpn_base, vpn_size
+    *vpn_base = base;
+    *vpn_size = size;
+    return 0;
+
+}  // end vmm_mmap_alloc()
+
+////////////////////////////////////////////////////////////////////////////////////////////
+// This static function is called by the vmm_remove_vseg() function, and implements
+// the VMM MMAP specific desallocator.
+////////////////////////////////////////////////////////////////////////////////////////////
+// @ vmm      : [in] pointer on VMM.
+// @ vseg     : [in] pointer on released vseg.
+////////////////////////////////////////////////////////////////////////////////////////////
+static void vmm_mmap_free( vmm_t  * vmm,
+                           vseg_t * vseg )
+{
+    // get pointer on mmap allocator
+    mmap_mgr_t * mgr = &vmm->mmap_mgr;
+
+    // compute zombi_list order
+    uint32_t order = bits_log2( vseg->vpn_size );
+
+    // take lock protecting zombi lists
+    busylock_acquire( &mgr->lock );
+
+    // update relevant zombi_list
+    xlist_add_first( XPTR( local_cxy , &mgr->zombi_list[order] ),
+                     XPTR( local_cxy , &vseg->xlist ) );
+
+    // release lock
+    busylock_release( &mgr->lock );
+
+}  // end of 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_from_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_from_vsl()
+
+
+
+
+////////////////////////////////////////////
+error_t vmm_user_init( process_t * process )
+{
     vseg_t  * vseg_args;
     vseg_t  * vseg_envs;
@@ -65,8 +298,8 @@
     uint32_t  i;
 
-#if DEBUG_VMM_INIT
+#if DEBUG_VMM_USER_INIT
 thread_t * this = CURRENT_THREAD;
 uint32_t cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_INIT )
+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 );
@@ -76,18 +309,15 @@
     vmm_t   * vmm = &process->vmm;
 
-    // initialize VSL (empty)
-    vmm->vsegs_nr = 0;
-	xlist_root_init( XPTR( local_cxy , &vmm->vsegs_root ) );
-	remote_rwlock_init( XPTR( local_cxy , &vmm->vsegs_lock ) , LOCK_VMM_VSL );
-
+// check UTILS zone 
 assert( ((CONFIG_VMM_ARGS_SIZE + CONFIG_VMM_ENVS_SIZE) <= 
          (CONFIG_VMM_ELF_BASE - CONFIG_VMM_UTILS_BASE)) ,
          "UTILS zone too small\n" );
 
+// check STACK zone
 assert( ((CONFIG_VMM_STACK_SIZE * CONFIG_THREADS_MAX_PER_CLUSTER) <=
 (CONFIG_VMM_VSPACE_SIZE - CONFIG_VMM_STACK_BASE)) ,
 "STACK zone too small\n");
 
-    // register args vseg in VSL
+    // register "args" vseg in VSL
     base = CONFIG_VMM_UTILS_BASE << CONFIG_PPM_PAGE_SHIFT;
     size = CONFIG_VMM_ARGS_SIZE << CONFIG_PPM_PAGE_SHIFT;
@@ -101,5 +331,4 @@
                                  XPTR_NULL,     // mapper_xp unused
                                  local_cxy );
-
     if( vseg_args == NULL )
     {
@@ -110,5 +339,5 @@
     vmm->args_vpn_base = base;
 
-    // register the envs vseg in VSL
+    // register "envs" vseg in VSL
     base = (CONFIG_VMM_UTILS_BASE + CONFIG_VMM_ARGS_SIZE) << CONFIG_PPM_PAGE_SHIFT;
     size = CONFIG_VMM_ENVS_SIZE << CONFIG_PPM_PAGE_SHIFT;
@@ -122,5 +351,4 @@
                                  XPTR_NULL,     // mapper_xp unused
                                  local_cxy );
-
     if( vseg_envs == NULL )
     {
@@ -130,25 +358,4 @@
 
     vmm->envs_vpn_base = base;
-
-    // create GPT (empty)
-    error = hal_gpt_create( &vmm->gpt );
-
-    if( error ) 
-    {
-        printk("\n[ERROR] in %s : cannot create GPT\n", __FUNCTION__ );
-        return -1;
-    }
-
-    // initialize GPT lock
-    remote_rwlock_init( XPTR( local_cxy , &vmm->gpt_lock ) , LOCK_VMM_GPT );
-
-    // update process VMM with kernel vsegs as required by the hardware architecture
-    error = hal_vmm_kernel_update( process );
-
-    if( error )
-    { 
-        printk("\n[ERROR] in %s : cannot update GPT for kernel vsegs\n", __FUNCTION__ );
-        return -1;
-    }
 
     // initialize STACK allocator
@@ -162,5 +369,8 @@
     vmm->mmap_mgr.first_free_vpn  = CONFIG_VMM_HEAP_BASE;
     busylock_init( &vmm->mmap_mgr.lock , LOCK_VMM_MMAP );
-    for( i = 0 ; i < 32 ; i++ ) list_root_init( &vmm->mmap_mgr.zombi_list[i] );
+    for( i = 0 ; i < 32 ; i++ )
+    {
+        xlist_root_init( XPTR( local_cxy , &vmm->mmap_mgr.zombi_list[i] ) );
+    }
 
     // initialize instrumentation counters
@@ -169,7 +379,7 @@
     hal_fence();
 
-#if DEBUG_VMM_INIT
+#if DEBUG_VMM_USER_INIT
 cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_INIT )
+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 );
@@ -178,91 +388,95 @@
     return 0;
 
-}  // end vmm_init()
-
+}  // end vmm_user_init()
 
 //////////////////////////////////////////
-void vmm_attach_vseg_to_vsl( vmm_t  * vmm,
-                             vseg_t * vseg )
+void vmm_user_reset( process_t * process )
 {
-    // build extended pointer on rwlock protecting VSL
-    xptr_t lock_xp = XPTR( local_cxy , &vmm->vsegs_lock );
-
-    // get rwlock in write mode
-    remote_rwlock_wr_acquire( lock_xp );
-
-    // 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 ) );
-
-    // release rwlock in write mode
-    remote_rwlock_wr_release( lock_xp );
-}
-
-////////////////////////////////////////////
-void vmm_detach_vseg_from_vsl( vmm_t  * vmm,
-                               vseg_t * vseg )
-{
-    // get vseg type
-    uint32_t type = vseg->type;
-
-    // build extended pointer on rwlock protecting VSL
-    xptr_t lock_xp = XPTR( local_cxy , &vmm->vsegs_lock );
-
-    // get rwlock in write mode
-    remote_rwlock_wr_acquire( lock_xp );
-
-    // update vseg descriptor
-    vseg->vmm = NULL;
-
-    // remove vseg from VSL
-    xlist_unlink( XPTR( local_cxy , &vseg->xlist ) );
-
-    // release rwlock in write mode
-    remote_rwlock_wr_release( lock_xp );
-
-    // 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
-        busylock_acquire( &mgr->lock );
-        bitmap_clear( &mgr->bitmap , index );
-        busylock_release( &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
-        busylock_acquire( &mgr->lock );
-        list_add_first( &mgr->zombi_list[index] , &vseg->zlist );
-        busylock_release( &mgr->lock );
-    }
-
-    // release physical memory allocated for vseg if no MMAP and no kernel type
-    if( (type != VSEG_TYPE_ANON) && (type != VSEG_TYPE_FILE) && (type != VSEG_TYPE_REMOTE) &&
-        (type != VSEG_TYPE_KCODE) && (type != VSEG_TYPE_KDATA) && (type != VSEG_TYPE_KDEV) )
-    {
-        vseg_free( vseg );
-    }
-
-}  // end vmm_remove_vseg_from_vsl()
+    xptr_t       vseg_xp;
+	vseg_t     * vseg;
+    vseg_type_t  vseg_type;
+
+#if DEBUG_VMM_USER_RESET
+uint32_t cycle = (uint32_t)hal_get_cycles();
+thread_t * this = CURRENT_THREAD;
+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( 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_rwlock_wr_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_rwlock_wr_release( lock_xp );
+
+// FIXME il faut gérer les process copies...
+
+#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
+
+}  // end vmm_user_reset()
 
 ////////////////////////////////////////////////
@@ -507,5 +721,4 @@
     cxy_t       page_cxy;
     xptr_t      forks_xp;       // extended pointer on forks counter in page descriptor
-    xptr_t      lock_xp;        // extended pointer on lock protecting the forks counter
     xptr_t      parent_root_xp;
     bool_t      mapped; 
@@ -528,9 +741,7 @@
     child_vmm  = &child_process->vmm;
 
-    // get extended pointer on lock protecting the parent VSL
-    parent_lock_xp = XPTR( parent_cxy , &parent_vmm->vsegs_lock );
-
-    // initialize the lock protecting the child VSL
-    remote_rwlock_init( XPTR( local_cxy , &child_vmm->vsegs_lock ), LOCK_VMM_STACK );
+    // initialize the locks protecting the child VSL and GPT
+    remote_rwlock_init( XPTR( local_cxy , &child_vmm->gpt_lock ) , LOCK_VMM_GPT );
+	remote_rwlock_init( XPTR( local_cxy , &child_vmm->vsl_lock ) , LOCK_VMM_VSL );
 
     // initialize the child VSL as empty
@@ -538,7 +749,6 @@
     child_vmm->vsegs_nr = 0;
 
-    // create the child GPT
+    // create an empty child GPT
     error = hal_gpt_create( &child_vmm->gpt );
-
     if( error )
     {
@@ -547,6 +757,7 @@
     }
 
-    // build extended pointer on parent VSL
+    // 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 in read mode
@@ -556,5 +767,5 @@
     XLIST_FOREACH( parent_root_xp , iter_xp )
     {
-        // get local and extended pointers on current parent vseg
+        // get pointers on current parent vseg
         parent_vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
         parent_vseg    = GET_PTR( parent_vseg_xp );
@@ -587,6 +798,15 @@
             vseg_init_from_ref( child_vseg , parent_vseg_xp );
 
+            // build extended pointer on VSL lock
+            xptr_t lock_xp = XPTR( local_cxy , &child_vmm->vsl_lock );
+ 
+            // take the VSL lock in write mode
+            remote_rwlock_wr_acquire( lock_xp );
+
             // register child vseg in child VSL
             vmm_attach_vseg_to_vsl( child_vmm , child_vseg );
+
+            // release the VSL lock
+            remote_rwlock_wr_release( lock_xp );
 
 #if DEBUG_VMM_FORK_COPY
@@ -597,9 +817,8 @@
 hal_remote_l32( XPTR( parent_cxy , &parent_vseg->vpn_base ) ) , cycle );
 #endif
-
-            // copy DATA, MMAP, REMOTE, FILE parent GPT entries to child GPT
+            // copy DATA, ANON, REMOTE, FILE parent GPT entries to child GPT
             if( type != VSEG_TYPE_CODE )
             {
-                // activate the COW for DATA, MMAP, REMOTE vsegs only
+                // activate the COW for DATA, ANON, REMOTE vsegs only
                 cow = ( type != VSEG_TYPE_FILE );
 
@@ -611,4 +830,5 @@
                 {
                     error = hal_gpt_pte_copy( &child_vmm->gpt,
+                                              vpn,
                                               XPTR( parent_cxy , &parent_vmm->gpt ),
                                               vpn,
@@ -677,5 +897,8 @@
     child_vmm->mmap_mgr.vpn_size        = CONFIG_VMM_STACK_BASE - CONFIG_VMM_HEAP_BASE;
     child_vmm->mmap_mgr.first_free_vpn  = CONFIG_VMM_HEAP_BASE;
-    for( i = 0 ; i < 32 ; i++ ) list_root_init( &child_vmm->mmap_mgr.zombi_list[i] );
+    for( i = 0 ; i < 32 ; i++ ) 
+    {
+        xlist_root_init( XPTR( local_cxy , &child_vmm->mmap_mgr.zombi_list[i] ) );
+    }
 
     // initialize instrumentation counters
@@ -726,18 +949,29 @@
     vmm_t  * vmm = &process->vmm;
 
-    // get extended pointer on VSL root and VSL lock
-    xptr_t   root_xp = XPTR( local_cxy , &vmm->vsegs_root );
+    // 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 );
+    xptr_t   gpt_lock_xp = XPTR( local_cxy , &vmm->gpt_lock );
+
+    // take the VSL lock
+    remote_rwlock_wr_acquire( vsl_lock_xp );
 
     // scan the VSL to delete all registered vsegs
-    // (don't use a FOREACH for item deletion in xlist)
-
-	while( !xlist_is_empty( root_xp ) )
+    // (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 )
 	{
-        // get pointer on first vseg in VSL
-		vseg_xp = XLIST_FIRST( root_xp , vseg_t , xlist );
-        vseg    = GET_PTR( vseg_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_delete_vseg( process->pid , vseg->min );
+        vmm_remove_vseg( process , vseg );
 
 #if( DEBUG_VMM_DESTROY & 1 )
@@ -749,11 +983,20 @@
 	}
 
-    // remove all vsegs from zombi_lists in MMAP allocator
+    // release the VSL lock
+    remote_rwlock_wr_release( vsl_lock_xp );
+
+    // remove all registered MMAP 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] ) )
+        // build extended pointer on zombi_list[i]
+        xptr_t root_xp = XPTR( local_cxy , &vmm->mmap_mgr.zombi_list[i] );
+  
+        // scan zombi_list[i]
+	    while( !xlist_is_empty( root_xp ) )
 	    {
-		    vseg = LIST_FIRST( &vmm->mmap_mgr.zombi_list[i] , vseg_t , zlist );
+		    vseg_xp = XLIST_FIRST( root_xp , vseg_t , xlist );
+            vseg    = GET_PTR( vseg_xp );
 
 #if( DEBUG_VMM_DESTROY & 1 )
@@ -765,5 +1008,5 @@
             vseg->vmm = NULL;
 
-            // remove vseg from  xlist
+            // remove vseg from  zombi_list
             xlist_unlink( XPTR( local_cxy , &vseg->xlist ) );
 
@@ -779,6 +1022,12 @@
     }
 
+    // take the GPT lock
+    remote_rwlock_wr_acquire( gpt_lock_xp );
+
     // release memory allocated to the GPT itself
     hal_gpt_destroy( &vmm->gpt );
+
+    // release the GPT lock
+    remote_rwlock_wr_release( gpt_lock_xp );
 
 #if DEBUG_VMM_DESTROY
@@ -816,123 +1065,5 @@
 }  // end vmm_check_conflict()
 
-////////////////////////////////////////////////////////////////////////////////////////////
-// This static function is called by the vmm_create_vseg() function, and implements
-// the VMM stack_vseg specific allocator.
-////////////////////////////////////////////////////////////////////////////////////////////
-// @ vmm      : pointer on VMM.
-// @ vpn_base : (return value) first allocated page
-// @ vpn_size : (return value) number of allocated pages
-////////////////////////////////////////////////////////////////////////////////////////////
-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 on stack allocator
-    busylock_acquire( &mgr->lock );
-
-    // get first free slot index in bitmap
-    int32_t index = bitmap_ffc( &mgr->bitmap , 4 );
-    if( (index < 0) || (index > 31) )
-    {
-        busylock_release( &mgr->lock );
-        return 0xFFFFFFFF;
-    }
-
-    // update bitmap
-    bitmap_set( &mgr->bitmap , index );
-
-    // release lock on stack allocator
-    busylock_release( &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.
-////////////////////////////////////////////////////////////////////////////////////////////
-// @ vmm      : [in] pointer on VMM.
-// @ npages   : [in] requested number of pages.
-// @ vpn_base : [out] first allocated page.
-// @ vpn_size : [out] actual number of allocated pages.
-////////////////////////////////////////////////////////////////////////////////////////////
-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;
-
-#if DEBUG_VMM_MMAP_ALLOC
-thread_t * this = CURRENT_THREAD;
-uint32_t cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_MMAP_ALLOC < cycle )
-printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, cycle );
-#endif
-
-    // 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;
-
-    // get lock on mmap allocator
-    busylock_acquire( &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 -1;
-
-        // update MMAP 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 , zlist );
-
-        // remove vseg from free-list
-        list_unlink( &vseg->zlist );
-
-        // compute base
-        base = vseg->vpn_base;
-    }
-
-    // release lock on mmap allocator
-    busylock_release( &mgr->lock );
-
-#if DEBUG_VMM_MMAP_ALLOC
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_DESTROY < cycle )
-printk("\n[%s] thread[%x,%x] exit / vpn_base %x / vpn_size %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, base, size, cycle );
-#endif
-
-    // returns vpn_base, vpn_size
-    *vpn_base = base;
-    *vpn_size = size;
-    return 0;
-
-}  // end vmm_mmap_alloc()
+
 
 ////////////////////////////////////////////////
@@ -968,11 +1099,5 @@
     {
         // get vpn_base and vpn_size from STACK allocator
-        error = vmm_stack_alloc( vmm , &vpn_base , &vpn_size );
-        if( error )
-        {
-            printk("\n[ERROR] in %s : no space for stack vseg / process %x in cluster %x\n",
-            __FUNCTION__ , process->pid , local_cxy );
-            return NULL;
-        }
+        vmm_stack_alloc( vmm , base , &vpn_base , &vpn_size );
 
         // compute vseg base and size from vpn_base and vpn_size
@@ -1072,6 +1197,15 @@
                cxy );
 
+    // build extended pointer on VSL lock
+    xptr_t lock_xp = XPTR( local_cxy , &vmm->vsl_lock );
+ 
+    // take the VSL lock in write mode
+    remote_rwlock_wr_acquire( lock_xp );
+
     // attach vseg to VSL
 	vmm_attach_vseg_to_vsl( vmm , vseg );
+
+    // release the VSL lock
+    remote_rwlock_wr_release( lock_xp );
 
 #if DEBUG_VMM_CREATE_VSEG
@@ -1086,12 +1220,12 @@
 }  // vmm_create_vseg()
 
-///////////////////////////////////
-void vmm_delete_vseg( pid_t    pid,
-                      intptr_t vaddr )
+
+//////////////////////////////////////////
+void vmm_remove_vseg( process_t * process,
+                      vseg_t    * vseg )
 {
-    process_t * process;    // local pointer on local process 
-    vmm_t     * vmm;        // local pointer on local process VMM
-    vseg_t    * vseg;       // local pointer on local vseg containing vaddr
-    gpt_t     * gpt;        // local pointer on local process GPT
+    vmm_t     * vmm;        // local pointer on process VMM
+    bool_t      is_ref;     // local process is reference process
+    uint32_t    vseg_type;  // vseg type
     vpn_t       vpn;        // VPN of current PTE
     vpn_t       vpn_min;    // VPN of first PTE
@@ -1103,40 +1237,16 @@
     cxy_t       page_cxy;   // page descriptor cluster
     page_t    * page_ptr;   // page descriptor pointer
-    xptr_t      forks_xp;   // extended pointer on pending forks counter
-    xptr_t      lock_xp;    // extended pointer on lock protecting forks counter
-    uint32_t    forks;      // actual number of pendinf forks
-    uint32_t    vseg_type;  // vseg type
-
-#if DEBUG_VMM_DELETE_VSEG
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-thread_t * this  = CURRENT_THREAD;
-if( DEBUG_VMM_DELETE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] enter / process %x / vaddr %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, vaddr, cycle );
-#endif
-
-    // get local pointer on local process descriptor
-    process = cluster_get_local_process_from_pid( pid );
-
-    if( process == NULL )
-    {
-        printk("\n[ERRORR] in %s : cannot get local process descriptor\n",
-        __FUNCTION__ );
-        return;
-    }
-
-    // get pointers on local process VMM an GPT
+    xptr_t      count_xp;   // extended pointer on page refcount
+    uint32_t    count;      // current value of page refcount
+
+// check arguments
+assert( (process != NULL), "process argument is NULL" );
+assert( (vseg    != NULL), "vseg argument is NULL" );
+
+    // compute is_ref
+    is_ref = (GET_CXY( process->ref_xp ) == local_cxy);
+
+    // get pointers on local process VMM 
     vmm = &process->vmm;
-    gpt = &process->vmm.gpt;
-
-    // get local pointer on vseg containing vaddr
-    vseg = vmm_vseg_from_vaddr( vmm , vaddr );
-
-    if( vseg == NULL )
-    {
-        printk("\n[ERRORR] in %s : cannot get vseg descriptor\n",
-        __FUNCTION__ );
-        return;
-    }
 
     // get relevant vseg infos
@@ -1145,89 +1255,180 @@
     vpn_max   = vpn_min + vseg->vpn_size;
 
-    // loop to invalidate all vseg PTEs in GPT
+#if DEBUG_VMM_REMOVE_VSEG
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+thread_t * this  = CURRENT_THREAD;
+if( DEBUG_VMM_REMOVE_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), vseg->min, cycle );
+#endif
+
+    // loop on PTEs in GPT
 	for( vpn = vpn_min ; vpn < vpn_max ; vpn++ )
     {
-        // get ppn and attr from GPT entry
-        hal_gpt_get_pte( XPTR( local_cxy , gpt ) , vpn , &attr , &ppn );
-
-        if( attr & GPT_MAPPED )  // entry is mapped
+        // get ppn and attr
+        hal_gpt_get_pte( XPTR( local_cxy , &vmm->gpt ) , vpn , &attr , &ppn );
+
+        if( attr & GPT_MAPPED )  // PTE is mapped
         { 
 
-#if( DEBUG_VMM_DELETE_VSEG & 1 )
-if( DEBUG_VMM_DELETE_VSEG < cycle )
-printk("- unmap vpn %x / ppn %x / vseg %s \n" , vpn , ppn, vseg_type_str(vseg->type) );
+#if( DEBUG_VMM_REMOVE_VSEG & 1 )
+if( DEBUG_VMM_REMOVE_VSEG < cycle )
+printk("- unmap vpn %x / ppn %x / %s" , vpn , ppn, vseg_type_str(vseg_type) );
 #endif
             // unmap GPT entry in local GPT
-            hal_gpt_reset_pte( gpt , vpn );
-
-            // the allocated page is not released to for kernel vseg
-            if( (vseg_type != VSEG_TYPE_KCODE) && 
-                (vseg_type != VSEG_TYPE_KDATA) && 
-                (vseg_type != VSEG_TYPE_KDEV ) )
+            hal_gpt_reset_pte( &vmm->gpt , vpn );
+
+            // get pointers on physical page descriptor
+            page_xp  = ppm_ppn2page( ppn );
+            page_cxy = GET_CXY( page_xp );
+            page_ptr = GET_PTR( page_xp );
+
+            // decrement page refcount
+            count_xp = XPTR( page_cxy , &page_ptr->refcount );
+            count    = hal_remote_atomic_add( count_xp , -1 );
+
+            // compute the ppn_release condition depending on vseg type
+            bool_t ppn_release;
+            if( (vseg_type == VSEG_TYPE_FILE)  ||
+                (vseg_type == VSEG_TYPE_KCODE) || 
+                (vseg_type == VSEG_TYPE_KDATA) || 
+                (vseg_type == VSEG_TYPE_KDEV) )            
             {
-                // get extended pointer on physical page descriptor
-                page_xp  = ppm_ppn2page( ppn );
-                page_cxy = GET_CXY( page_xp );
-                page_ptr = GET_PTR( page_xp );
-
-// FIXME This code must be re-written, as the actual release depends on vseg type,
-// the reference cluster, the page refcount and/or the forks counter...
-
-                // get extended pointers on forks and lock fields
-                forks_xp = XPTR( page_cxy , &page_ptr->forks );
-                lock_xp  = XPTR( page_cxy , &page_ptr->lock );
-
-                // get the lock protecting the page
+                // no physical page release for FILE and KERNEL 
+                ppn_release = false;
+            }
+            else if( (vseg_type == VSEG_TYPE_CODE)  ||
+                     (vseg_type == VSEG_TYPE_STACK) ) 
+            {
+                // always release physical page for private vsegs
+                ppn_release = true;
+            }
+            else if( (vseg_type == VSEG_TYPE_ANON)  ||
+                     (vseg_type == VSEG_TYPE_REMOTE) )
+            {
+                // release physical page if reference cluster
+                ppn_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 pending forks counter
-                forks = hal_remote_l32( forks_xp );
-
-                if( forks )  // decrement pending forks counter
+                // 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
+                ppn_release = (forks == 0); 
+            }
+            else              // vseg_type == DATA not in reference cluster
+            {
+                // no physical page release if not in reference cluster 
+                ppn_release = false;
+            }
+
+            // release physical page to relevant kmem when required
+            if( ppn_release )
+            {
+                if( page_cxy == local_cxy )
                 {
-                    // update forks counter
-                    hal_remote_atomic_add( forks_xp , -1 );
-
-                    // release the lock protecting the page
-                    remote_busylock_release( lock_xp );
-                }  
-                else         // release physical page to relevant cluster
+                    req.type = KMEM_PAGE;
+                    req.ptr  = page_ptr; 
+                    kmem_free( &req );
+                }
+                else
                 {
-                    // release the lock protecting the page
-                    remote_busylock_release( lock_xp );
-
-                    // release the page to kmem
-                    if( page_cxy == local_cxy )   // local cluster
-                    {
-                        req.type = KMEM_PAGE;
-                        req.ptr  = page_ptr; 
-                        kmem_free( &req );
-                    }
-                    else                          // remote cluster
-                    {
-                        rpc_pmem_release_pages_client( page_cxy , page_ptr );
-                    }
-
-#if( DEBUG_VMM_DELETE_VSEG & 1 )
-if( DEBUG_VMM_DELETE_VSEG < cycle )
-printk("- release ppn %x\n", ppn );
-#endif
+                    rpc_pmem_release_pages_client( page_cxy , page_ptr );
                 }
-
             }
+
+#if( DEBUG_VMM_REMOVE_VSEG & 1 )
+if( DEBUG_VMM_REMOVE_VSEG < cycle )
+{
+    if( ppn_release ) printk(" / released to kmem\n" );
+    else              printk("\n");
+}
+#endif
         }
     }
 
-    // remove vseg from VSL and release vseg descriptor (if not MMAP)
+    // remove vseg from VSL 
     vmm_detach_vseg_from_vsl( vmm , vseg );
 
-#if DEBUG_VMM_DELETE_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 );
+
+        // release vseg descriptor to local kmem
+        vseg_free( 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_DELETE_VSEG < cycle )
-printk("\n[%s] thread[%x,%x] exit / process %x / vseg %s / base %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, vseg_type_str(vseg->type), vaddr, cycle );
-#endif
-
-}  // end vmm_delete_vseg()
+if( DEBUG_VMM_REMOVE_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_remove_vseg()
+
+
+///////////////////////////////////
+void vmm_delete_vseg( pid_t    pid,
+                      intptr_t vaddr )
+{
+    process_t * process;    // local pointer on local process 
+    vseg_t    * vseg;       // local pointer on local vseg containing vaddr
+
+    // get local pointer on local process descriptor
+    process = cluster_get_local_process_from_pid( pid );
+
+    if( process == NULL )
+    {
+        printk("\n[WARNING] in %s : cannot get local process descriptor\n",
+        __FUNCTION__ );
+        return;
+    }
+
+    // get local pointer on local vseg containing vaddr
+    vseg = vmm_vseg_from_vaddr( &process->vmm , vaddr );
+
+    if( vseg == NULL )
+    {
+        printk("\n[WARNING] in %s : cannot get vseg descriptor\n",
+        __FUNCTION__ );
+        return;
+    }
+
+    // call relevant function
+    vmm_remove_vseg( process , vseg );
+
+}  // end vmm_delete_vseg
+
 
 /////////////////////////////////////////////
@@ -1235,10 +1436,10 @@
                               intptr_t   vaddr )
 {
-    xptr_t   iter_xp;
     xptr_t   vseg_xp;
     vseg_t * vseg;
+    xptr_t   iter_xp;
 
     // get extended pointers on VSL lock and root
-    xptr_t lock_xp = XPTR( local_cxy , &vmm->vsegs_lock );
+    xptr_t lock_xp = XPTR( local_cxy , &vmm->vsl_lock );
     xptr_t root_xp = XPTR( local_cxy , &vmm->vsegs_root );
 
@@ -1249,7 +1450,9 @@
     XLIST_FOREACH( root_xp , iter_xp )
     {
+        // get pointers on vseg
         vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
         vseg    = GET_PTR( vseg_xp );
 
+        // return success when match
         if( (vaddr >= vseg->min) && (vaddr < vseg->max) )
         { 
@@ -1262,5 +1465,4 @@
     // return failure
     remote_rwlock_rd_release( lock_xp );
-
     return NULL;
 
@@ -1462,6 +1664,15 @@
         vseg_init_from_ref( vseg , vseg_xp );
 
+        // build extended pointer on VSL lock
+        xptr_t lock_xp = XPTR( local_cxy , &vmm->vsl_lock );
+ 
+        // take the VSL lock in write mode
+        remote_rwlock_wr_acquire( lock_xp );
+
         // register local vseg in local VSL
         vmm_attach_vseg_to_vsl( vmm , vseg );
+ 
+        // release the VSL lock
+        remote_rwlock_wr_release( lock_xp );
     }   
 
@@ -1486,5 +1697,4 @@
 uint32_t   cycle   = (uint32_t)hal_get_cycles();
 thread_t * this    = CURRENT_THREAD;
-xptr_t     this_xp = XPTR( local_cxy , this );
 if( DEBUG_VMM_ALLOCATE_PAGE < (uint32_t)hal_get_cycles() )
 printk("\n[%s] thread[%x,%x] enter for vpn %x / cycle %d\n",
@@ -1717,4 +1927,13 @@
     error_t          error;           // value returned by called functions
 
+#if DEBUG_VMM_HANDLE_PAGE_FAULT
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+thread_t * this  = CURRENT_THREAD;
+if( DEBUG_VMM_HANDLE_PAGE_FAULT < cycle )
+printk("\n[%s] thread[%x,%x] enter for vpn %x / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, vpn, cycle );
+hal_vmm_display( process , true );
+#endif
+
     // get local vseg (access to reference VSL can be required)
     error = vmm_get_vseg( process, 
@@ -1723,16 +1942,15 @@
     if( error )
     {
-        printk("\n[ERROR] in %s : vpn %x in process %x not in a registered vseg\n",
-        __FUNCTION__ , vpn , process->pid );
+        printk("\n[ERROR] in %s : vpn %x in process %x not in registered vseg / cycle %d\n",
+        __FUNCTION__ , vpn , process->pid, (uint32_t)hal_get_cycles() );
         
         return EXCP_USER_ERROR;
     }
 
- #if DEBUG_VMM_HANDLE_PAGE_FAULT
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-thread_t * this  = CURRENT_THREAD;
+#if DEBUG_VMM_HANDLE_PAGE_FAULT
+cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_VMM_HANDLE_PAGE_FAULT < cycle )
-printk("\n[%s] threadr[%x,%x] enter for vpn %x / %s / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, vpn, vseg_type_str(vseg->type), cycle );
+printk("\n[%s] threadr[%x,%x] found vseg %s / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, vseg_type_str(vseg->type), cycle );
 #endif
 
@@ -1971,11 +2189,12 @@
     error_t          error;
 
+    thread_t * this = CURRENT_THREAD;
+
 #if DEBUG_VMM_HANDLE_COW
 uint32_t   cycle   = (uint32_t)hal_get_cycles();
-thread_t * this    = CURRENT_THREAD;
-xptr_t     this_xp = XPTR( local_cxy , this );
 if( DEBUG_VMM_HANDLE_COW < cycle )
 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 );
+hal_vmm_display( process , true );
 #endif
 
@@ -1991,6 +2210,6 @@
     if( error )
     {
-        printk("\n[PANIC] in %s : vpn %x in process %x not in a registered vseg\n",
-        __FUNCTION__, vpn, process->pid );
+        printk("\n[PANIC] in %s vpn %x in thread[%x,%x] not in a registered vseg\n",
+        __FUNCTION__, vpn, process->pid, this->trdid );
 
         return EXCP_KERNEL_PANIC;
