Index: trunk/kernel/mm/vmm.c
===================================================================
--- trunk/kernel/mm/vmm.c	(revision 407)
+++ trunk/kernel/mm/vmm.c	(revision 408)
@@ -32,4 +32,5 @@
 #include <rwlock.h>
 #include <list.h>
+#include <xlist.h>
 #include <bits.h>
 #include <process.h>
@@ -69,6 +70,6 @@
     // initialize local list of vsegs 
     vmm->vsegs_nr = 0;
-	list_root_init( &vmm->vsegs_root );
-	rwlock_init( &vmm->vsegs_lock );
+	xlist_root_init( XPTR( local_cxy , &vmm->vsegs_root ) );
+	remote_rwlock_init( XPTR( local_cxy , &vmm->vsegs_lock ) );
 
     assert( ((CONFIG_VMM_KENTRY_SIZE + CONFIG_VMM_ARGS_SIZE + CONFIG_VMM_ENVS_SIZE) 
@@ -154,6 +155,4 @@
     // initialize instrumentation counters
 	vmm->pgfault_nr          = 0;
-	vmm->u_err_nr            = 0;
-	vmm->m_err_nr            = 0;
 
     hal_fence();
@@ -176,12 +175,16 @@
 
     // get lock protecting the vseg list
-    rwlock_rd_lock( &vmm->vsegs_lock );
+    remote_rwlock_rd_lock( XPTR( local_cxy , &vmm->vsegs_lock ) );
 
     // scan the list of vsegs
-    list_entry_t * iter;
+    xptr_t         root_xp = XPTR( local_cxy , &vmm->vsegs_root );
+    xptr_t         iter_xp;
+    xptr_t         vseg_xp;
     vseg_t       * vseg;
-    LIST_FOREACH( &vmm->vsegs_root , iter )
-    {
-        vseg = LIST_ELEMENT( iter , vseg_t , list );
+    XLIST_FOREACH( root_xp , iter_xp )
+    {
+        vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
+        vseg    = (vseg_t *)GET_PTR( vseg_xp );
+
         printk(" - %s : base = %X / size = %X / npages = %d\n",
         vseg_type_str( vseg->type ) , vseg->min , vseg->max - vseg->min , vseg->vpn_size );
@@ -206,108 +209,313 @@
 
     // release the lock
-    rwlock_rd_unlock( &vmm->vsegs_lock );
-}
-
-//////////////////////////////////////////
-error_t vmm_copy( process_t * dst_process,
-                  process_t * src_process )
-{
-    error_t error;
-
-    vmm_t * src_vmm = &src_process->vmm;
-    vmm_t * dst_vmm = &dst_process->vmm;
-
-    // take the src_vmm vsegs_lock
-    rwlock_wr_lock( &src_vmm->vsegs_lock );
-
-    // initialize dst_vmm vsegs_lock
-    rwlock_init( &dst_vmm->vsegs_lock );
-
-    // initialize the dst_vmm vsegs list
-    dst_vmm->vsegs_nr = 0;
-    list_root_init( &dst_vmm->vsegs_root );
-
-    // initialize generic page table
-    error = hal_gpt_create( &dst_vmm->gpt );
-
+    remote_rwlock_rd_unlock( XPTR( local_cxy , &vmm->vsegs_lock ) );
+
+}  // vmm_display()
+
+/////////////////////i////////////////////
+void vmm_update_pte( process_t * process,
+                     vpn_t       vpn,
+                     uint32_t    attr,
+                     ppn_t       ppn )
+{
+
+    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;
+
+    pid_t           pid;
+    cxy_t           owner_cxy;
+    lpid_t          owner_lpid;
+
+    // get extended pointer on root of process copies xlist in owner cluster
+    pid              = process->pid;
+    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 );
+
+    // loop on destination 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 = (process_t *)GET_PTR( remote_process_xp );
+        remote_process_cxy = GET_CXY( remote_process_xp );
+
+        // get extended pointer on remote gpt
+        remote_gpt_xp = XPTR( remote_process_cxy , &remote_process_ptr->vmm.gpt );
+
+        hal_gpt_update_pte( remote_gpt_xp,
+                            vpn,
+                            attr,
+                            ppn );
+    }  
+}  // end vmm_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;
+
+vmm_dmsg("\n[DBG] %s : core[%x,%d] enters for process %x\n",
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , process->pid );
+
+    // check cluster is reference
+    assert( (GET_CXY( process->ref_xp ) == local_cxy) , __FUNCTION__,
+    "local cluster is not process reference cluster\n");
+
+    // get pointer on reference VMM
+    vmm = &process->vmm;
+
+    // get extended pointer on root of process copies xlist in owner cluster
+    pid              = process->pid;
+    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 destination 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 = (process_t *)GET_PTR( remote_process_xp );
+        remote_process_cxy = GET_CXY( remote_process_xp );
+
+vmm_dmsg("\n[DBG] %s : core[%x,%d] handling process %x in cluster %x\n",
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , process->pid , remote_process_cxy );
+
+        // 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     = (vseg_t *)GET_PTR( vseg_xp );
+
+            assert( (GET_CXY( vseg_xp ) == local_cxy) , __FUNCTION__,
+            "all vsegs in reference VSL must be local\n" );
+
+            // 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;
+
+vmm_dmsg("\n[DBG] %s : core[%x,%d] handling vseg %s / vpn_base = %x / vpn_size = %x\n",
+__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, vseg_type_str(type), vpn_base, vpn_size );
+
+            // set COW flag on the remote GPT depending on vseg type
+            if( (type == VSEG_TYPE_DATA)  ||
+                (type == VSEG_TYPE_ANON)  ||
+                (type == VSEG_TYPE_REMOTE) )
+            {
+                hal_gpt_flip_cow( true,             // set_cow
+                                  remote_gpt_xp,
+                                  vpn_base,
+                                  vpn_size );
+            }
+        }    // en loop on vsegs
+    }   // end loop on process copies
+ 
+vmm_dmsg("\n[DBG] %s : core[%x,%d] exit for process %x\n",
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , process->pid );
+
+}  // 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;
+    bool_t      cow;
+    vpn_t       vpn;            
+    vpn_t       vpn_base;
+    vpn_t       vpn_size;
+    xptr_t      page_xp;
+    page_t    * page_ptr;
+    cxy_t       page_cxy;
+    xptr_t      parent_root_xp;
+    bool_t      mapped; 
+    ppn_t       ppn;
+
+vmm_dmsg("\n[DBG] %s : core[%x,%d] enter\n",
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid );
+
+    // get parent process cluster and local pointer
+    parent_cxy     = GET_CXY( parent_process_xp );
+    parent_process = (process_t *)GET_PTR( parent_process_xp );
+
+    // get local pointers on parent and child VMM
+    parent_vmm = &parent_process->vmm; 
+    child_vmm  = &child_process->vmm;
+
+    // get extended pointer on lock protecting the parent VSL
+    parent_lock_xp = XPTR( parent_cxy , &parent_vmm->vsegs_lock );
+
+    // take the lock protecting the parent VSL
+    remote_rwlock_rd_lock( parent_lock_xp );
+
+    // initialize the lock protecting the child VSL
+    remote_rwlock_init( XPTR( local_cxy , &child_vmm->vsegs_lock ) );
+
+    // initialize the child VSL as empty
+    xlist_root_init( XPTR( local_cxy, &child_vmm->vsegs_root ) );
+    child_vmm->vsegs_nr = 0;
+
+    // create & initialize the child GPT as empty
+    error = hal_gpt_create( &child_vmm->gpt );
     if( error )
     {
-        printk("\n[ERROR] in %s : cannot initialize page table\n", __FUNCTION__ );
-        return ENOMEM;
-    }
-
-    // loop on SRC VSL to register vsegs copies in DST VSL
-    // and copy valid PTEs from SRC GPT to DST GPT
-    list_entry_t * iter;
-    vseg_t       * src_vseg;
-    vseg_t       * dst_vseg;
-    LIST_FOREACH( &src_vmm->vsegs_root , iter )
-    {
-        // get pointer on current src_vseg
-        src_vseg = LIST_ELEMENT( iter , vseg_t , list );
-
-        // allocate memory for a new dst_vseg
-        dst_vseg = vseg_alloc();
-
-        if( dst_vseg == NULL )
+        printk("\n[ERROR] in %s : cannot create GPT\n", __FUNCTION__ );
+        return -1;
+    }
+
+    // build extended pointer on parent VSL
+    parent_root_xp = XPTR( parent_cxy , &parent_vmm->vsegs_root );
+
+    // loop on parent VSL xlist
+    XLIST_FOREACH( parent_root_xp , iter_xp )
+    {
+        // get local and extended pointers on current parent vseg
+        parent_vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
+        parent_vseg    = (vseg_t *)GET_PTR( parent_vseg_xp );
+
+        // get vseg type
+        type = hal_remote_lw( XPTR( parent_cxy , &parent_vseg->type ) );
+        
+
+vmm_dmsg("\n[DBG] %s : core[%x,%d] found parent vseg %s / vpn_base = %x\n",
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vseg_type_str(type),
+hal_remote_lw( XPTR( parent_cxy , &parent_vseg->vpn_base ) ) );
+
+        // all parent vsegs - but STACK - must be copied in child VSL
+        if( type != VSEG_TYPE_STACK )
         {
-            // release all allocated vsegs
-            LIST_FOREACH( &dst_vmm->vsegs_root , iter )
+            // allocate memory for a new child vseg
+            child_vseg = vseg_alloc();
+            if( child_vseg == NULL )   // release all allocated vsegs
             {
-                dst_vseg = LIST_ELEMENT( iter , vseg_t , list );
-                vseg_free( dst_vseg );
+                vmm_destroy( child_process );
+                printk("\n[ERROR] in %s : cannot create vseg for child\n", __FUNCTION__ );
+                return -1;
             }
-            return ENOMEM;
-        }
-
-        // copy src_vseg to dst_vseg
-        vseg_init_from_ref( dst_vseg , XPTR( local_cxy , src_vseg ) );
-
-        // register dst_vseg in DST VSL
-        vseg_attach( dst_vmm , dst_vseg );
-
-        // copy SRC GPT to DST GPT / set COW for all writable vsegs, but the FILE type
-        bool_t cow = (src_vseg->type != VSEG_TYPE_FILE) && (src_vseg->flags & VSEG_WRITE); 
-        error = hal_gpt_copy( &dst_vmm->gpt, 
-                              &src_vmm->gpt,
-                              src_vseg->vpn_base,
-                              src_vseg->vpn_size,
-                              cow );
-        if( error )
-        {
-            printk("\n[ERROR] in %s : cannot copy page GPT\n", __FUNCTION__ );
-            hal_gpt_destroy( &dst_vmm->gpt );
-            return ENOMEM;
-        }
-    }
-
-    // release the src_vmm vsegs_lock
-    rwlock_wr_unlock( &src_vmm->vsegs_lock );
-
-    // initialize STACK allocator
-    dst_vmm->stack_mgr.bitmap   = 0;
-    dst_vmm->stack_mgr.vpn_base = CONFIG_VMM_STACK_BASE;
-
-    // initialize MMAP allocator
-    dst_vmm->mmap_mgr.vpn_base        = CONFIG_VMM_HEAP_BASE;
-    dst_vmm->mmap_mgr.vpn_size        = CONFIG_VMM_STACK_BASE - CONFIG_VMM_HEAP_BASE;
-    dst_vmm->mmap_mgr.first_free_vpn  = CONFIG_VMM_HEAP_BASE;
+
+            // copy parent vseg to child vseg
+            vseg_init_from_ref( child_vseg , parent_vseg_xp );
+
+            // register child vseg in child VSL
+            vseg_attach( child_vmm , child_vseg );
+
+vmm_dmsg("\n[DBG] %s : core[%x,%d] copied to child VSL : vseg %s / vpn_base = %x\n",
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vseg_type_str(type),
+hal_remote_lw( XPTR( parent_cxy , &parent_vseg->vpn_base ) ) );
+
+            // copy DATA, MMAP, REMOTE, FILE parent GPT entries to child GPT
+            if( type != VSEG_TYPE_CODE )
+            {
+                // activate the COW for DATA, MMAP, 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,
+                                              XPTR( parent_cxy , &parent_vmm->gpt ),
+                                              vpn,
+                                              cow,
+                                              &ppn,
+                                              &mapped );
+                    if( error )
+                    {
+                        vmm_destroy( child_process );
+                        printk("\n[ERROR] in %s : cannot copy GPT\n", __FUNCTION__ );
+                        return -1;
+                    }
+
+                    // increment page descriptor fork_nr for the referenced page if mapped
+                    if( mapped )
+                    {
+                        page_xp = ppm_ppn2page( ppn );
+                        page_cxy = GET_CXY( page_xp );
+                        page_ptr = (page_t *)GET_PTR( page_xp );
+                        hal_remote_atomic_add( XPTR( page_cxy , &page_ptr->fork_nr ) , 1 );
+
+vmm_dmsg("\n[DBG] %s : core[%x,%d] copied to child GPT : vpn %x\n",
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn );
+
+                    }
+                }
+            }   // end if no code & no stack
+        }   // end if no stack
+    }   // end loop on vsegs
+
+    // release the parent vsegs lock
+    remote_rwlock_rd_unlock( parent_lock_xp );
+
+    // initialize the child VMM STACK allocator
+    child_vmm->stack_mgr.bitmap   = 0;
+    child_vmm->stack_mgr.vpn_base = CONFIG_VMM_STACK_BASE;
+
+    // initialize the child VMM MMAP allocator
     uint32_t i;
-    for( i = 0 ; i < 32 ; i++ ) list_root_init( &dst_vmm->mmap_mgr.zombi_list[i] );
+    child_vmm->mmap_mgr.vpn_base        = CONFIG_VMM_HEAP_BASE;
+    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] );
 
     // initialize instrumentation counters
-	dst_vmm->pgfault_nr    = 0;
-	dst_vmm->u_err_nr      = 0;
-	dst_vmm->m_err_nr      = 0;
-
-    // copy base addresses
-    dst_vmm->kent_vpn_base = src_vmm->kent_vpn_base;
-    dst_vmm->args_vpn_base = src_vmm->args_vpn_base;
-    dst_vmm->envs_vpn_base = src_vmm->envs_vpn_base;
-    dst_vmm->heap_vpn_base = src_vmm->heap_vpn_base;
-    dst_vmm->code_vpn_base = src_vmm->code_vpn_base;
-    dst_vmm->data_vpn_base = src_vmm->data_vpn_base;
-
-    dst_vmm->entry_point   = src_vmm->entry_point;
+	child_vmm->pgfault_nr    = 0;
+
+    // copy base addresses from parent VMM to child VMM
+    child_vmm->kent_vpn_base = (vpn_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->kent_vpn_base));
+    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();
@@ -315,9 +523,10 @@
     return 0;
 
-}  // vmm_copy()
+}  // vmm_fork_copy()
 
 ///////////////////////////////////////
 void vmm_destroy( process_t * process )
 {
+    xptr_t   vseg_xp;
 	vseg_t * vseg;
 
@@ -325,11 +534,16 @@
     vmm_t  * vmm = &process->vmm;
 
+    // get 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->vsegs_lock );
+
     // get lock protecting vseg list
-	rwlock_wr_lock( &vmm->vsegs_lock );
-
-    // remove all vsegs registered in vmm
-	while( !list_is_empty( &vmm->vsegs_root ) )
+	remote_rwlock_wr_lock( lock_xp );
+
+    // remove all vsegs registered in VSL
+	while( !xlist_is_empty( root_xp ) )
 	{
-		vseg = LIST_FIRST( &vmm->vsegs_root ,  vseg_t , list );
+		vseg_xp = XLIST_FIRST_ELEMENT( root_xp , vseg_t , xlist );
+        vseg = (vseg_t *)GET_PTR( vseg_xp );
 		vseg_detach( vmm , vseg );
         vseg_free( vseg );
@@ -337,5 +551,5 @@
 
     // release lock
-	rwlock_wr_unlock(&vmm->vsegs_lock);
+	remote_rwlock_wr_unlock( lock_xp );
 
     // remove all vsegs from zombi_lists in MMAP allocator
@@ -345,5 +559,5 @@
 	    while( !list_is_empty( &vmm->mmap_mgr.zombi_list[i] ) )
 	    {
-		    vseg = LIST_FIRST( &vmm->mmap_mgr.zombi_list[i] , vseg_t , list );
+		    vseg = LIST_FIRST( &vmm->mmap_mgr.zombi_list[i] , vseg_t , zlist );
 		    vseg_detach( vmm , vseg );
             vseg_free( vseg );
@@ -362,11 +576,15 @@
 {
     vmm_t        * vmm = &process->vmm;
+
+    // scan the VSL
 	vseg_t       * vseg;
-    list_entry_t * iter;
-
-    // scan the list of registered vsegs
-	LIST_FOREACH( &vmm->vsegs_root , iter )
+    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 = LIST_ELEMENT( iter , vseg_t , list );
+		vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
+        vseg    = (vseg_t *)GET_PTR( vseg_xp );
 
 		if( ((vpn_base + vpn_size) > vseg->vpn_base) &&
@@ -463,8 +681,8 @@
     {
         // get pointer on zombi vseg from zombi_list
-        vseg = LIST_FIRST( &mgr->zombi_list[index] , vseg_t , list );
+        vseg = LIST_FIRST( &mgr->zombi_list[index] , vseg_t , zlist );
 
         // remove vseg from free-list
-        list_unlink( &vseg->list );
+        list_unlink( &vseg->zlist );
 
         // compute base
@@ -579,8 +797,9 @@
                cxy );
 
-    // attach vseg to vmm
-	rwlock_wr_lock( &vmm->vsegs_lock );
+    // attach vseg to VSL
+    xptr_t lock_xp = XPTR( local_cxy , &vmm->vsegs_lock );
+	remote_rwlock_wr_lock( lock_xp );
 	vseg_attach( vmm , vseg );
-	rwlock_wr_unlock( &vmm->vsegs_lock );
+	remote_rwlock_wr_unlock( lock_xp );
 
 vmm_dmsg("\n[DBG] %s : core[%x,%d] exit / process %x / base %x / size %x / type %s\n",
@@ -601,8 +820,9 @@
     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 );
+    // detach vseg from VSL
+    xptr_t lock_xp = XPTR( local_cxy , &vmm->vsegs_lock );
+	remote_rwlock_wr_lock( lock_xp );
+	vseg_detach( &process->vmm , vseg );
+	remote_rwlock_wr_unlock( lock_xp );
 
     // release the stack slot to VMM stack allocator if STACK type
@@ -632,5 +852,5 @@
         // update zombi_list
         spinlock_lock( &mgr->lock );
-        list_add_first( &mgr->zombi_list[index] , &vseg->list );
+        list_add_first( &mgr->zombi_list[index] , &vseg->zlist );
         spinlock_unlock( &mgr->lock );
     }
@@ -686,5 +906,8 @@
         // set page table entry
         ppn = ppm_page2ppn( XPTR( local_cxy , page ) );
-        error = hal_gpt_set_pte( gpt , vpn , ppn , attr );
+        error = hal_gpt_set_pte( gpt,
+                                 vpn,
+                                 attr,
+                                 ppn );
 		if( error )
         {
@@ -695,5 +918,6 @@
 
 	return 0;
-}
+
+}  // end vmm_map_kernel_vseg()
 
 /////////////////////////////////////////
@@ -729,22 +953,33 @@
                                  intptr_t   vaddr )
 {
-    list_entry_t * iter;
-    vseg_t       * vseg = NULL;
-
-    // get lock protecting the vseg list
-    rwlock_rd_lock( &vmm->vsegs_lock );
-
-    // scan the list of vsegs
-    LIST_FOREACH( &vmm->vsegs_root , iter )
-    {
-        vseg = LIST_ELEMENT( iter , vseg_t , list );
-        if( (vaddr >= vseg->min) && (vaddr < vseg->max) ) break;
-    }
-
-    // release the lock
-    rwlock_rd_unlock( &vmm->vsegs_lock );
-
-    return vseg;
-}
+    xptr_t   iter_xp;
+    xptr_t   vseg_xp;
+    vseg_t * vseg;
+
+    // get extended pointers on VSL lock and root
+    xptr_t lock_xp = XPTR( local_cxy , &vmm->vsegs_lock );
+    xptr_t root_xp = XPTR( local_cxy , &vmm->vsegs_root );
+
+    // get lock protecting the VSL
+    remote_rwlock_rd_lock( lock_xp );
+
+    // scan the list of vsegs in VSL
+    XLIST_FOREACH( root_xp , iter_xp )
+    {
+        vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
+        vseg    = (vseg_t *)GET_PTR( vseg_xp );
+        if( (vaddr >= vseg->min) && (vaddr < vseg->max) )
+        {
+            // return success
+            remote_rwlock_rd_unlock( lock_xp );
+            return vseg;
+        }
+    }
+
+    // return failure
+    remote_rwlock_rd_unlock( lock_xp );
+    return NULL;
+
+}  // end vseg_from_vaddr()
 
 /////////////////////////////////////////////
@@ -769,6 +1004,9 @@
 	if( vseg == NULL)  return EINVAL;
 
-    // get VMM lock protecting vsegs list
-	rwlock_wr_lock( &vmm->vsegs_lock );
+    // get extended pointer on VSL lock
+    xptr_t lock_xp = XPTR( local_cxy , &vmm->vsegs_lock );
+
+    // get lock protecting VSL
+	remote_rwlock_wr_lock( lock_xp );
 
 	if( (vseg->min > addr_min) || (vseg->max < addr_max) )   // region not included in vseg
@@ -831,5 +1069,5 @@
 
     // release VMM lock
-	rwlock_wr_unlock( &vmm->vsegs_lock );
+	remote_rwlock_wr_unlock( lock_xp );
 
 	return error;
@@ -1129,5 +1367,4 @@
     ppn_t     new_ppn;    // new PTE_PPN
     uint32_t  new_attr;   // new PTE_ATTR
-    xptr_t    page_xp;    // extended pointer on allocated page descriptor
     error_t   error;
 
@@ -1137,5 +1374,5 @@
 
 vmm_dmsg("\n[DBG] %s : core[%x,%d] enter for vpn = %x in process %x / cow = %d\n",
-__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , process->pid , %d);
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , process->pid , cow );
 
     // get VMM pointer
@@ -1159,68 +1396,81 @@
     hal_gpt_get_pte( &vmm->gpt , vpn , &old_attr , &old_ppn );
 
-    // for both copy_on_write and page_fault events, we allocate a physical page,
-    // initialize it, register it in the GPT, and return the new_ppn and new_attr
+    // for both "copy_on_write" and "page_fault" events, allocate a physical page,
+    // initialize it, register it in the reference GPT, update GPT copies in all
+    // clusters containing a copy, and return the new_ppn and new_attr
 
     if( cow )               ////////////// copy_on_write request ///////////
     {
-        assert( (*attr & GPT_MAPPED) , __FUNCTION__ , 
-        "PTE must be mapped for a copy-on-write\n" );
-
-vmm_dmsg("\n[DBG] %s : core[%x,%d] page %x must be copied => do it\n",
+        assert( (old_attr & GPT_MAPPED) , __FUNCTION__ , 
+        "PTE must be mapped for a copy-on-write exception\n" );
+
+excp_dmsg("\n[DBG] %s : core[%x,%d] handling COW for vpn %x\n",
 __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn );
 
-        // allocate a physical page depending on vseg type
-        page_xp = vmm_page_allocate( vseg , vpn );
-
-        if( page_xp == XPTR_NULL ) 
+        // get extended pointer, cluster and local pointer on page descriptor
+        xptr_t   page_xp  = ppm_ppn2page( old_ppn );
+        cxy_t    page_cxy = GET_CXY( page_xp );
+        page_t * page_ptr = (page_t *)GET_PTR( page_xp );
+
+        // get number of pending forks in page descriptor
+        uint32_t count = hal_remote_lw( XPTR( page_cxy , &page_ptr->fork_nr ) );
+
+        if( count )        // pending fork => allocate a new page, copy it, reset COW
         {
-            printk("\n[ERROR] in %s : no memory / process = %x / vpn = %x\n",
-            __FUNCTION__ , process->pid , vpn );
-            return ENOMEM;
+            // allocate a new physical page
+            page_xp = vmm_page_allocate( vseg , vpn );
+            if( page_xp == XPTR_NULL ) 
+            {
+                printk("\n[ERROR] in %s : no memory / process = %x / vpn = %x\n",
+                __FUNCTION__ , process->pid , vpn );
+                return -1;
+            }
+
+            // compute allocated page PPN 
+            new_ppn = ppm_page2ppn( page_xp );
+
+            // copy old page content to new page
+            xptr_t  old_base_xp = ppm_ppn2base( old_ppn );
+            xptr_t  new_base_xp = ppm_ppn2base( new_ppn );
+            memcpy( GET_PTR( new_base_xp ),
+                    GET_PTR( old_base_xp ),
+                    CONFIG_PPM_PAGE_SIZE );
+        }             
+        else               // no pending fork => keep the existing page, reset COW
+        {
+            new_ppn = old_ppn;
         }
 
-        // compute allocated page PPN
-        new_ppn = ppm_page2ppn( page_xp );
-
-        // copy old page content to new page
-        xptr_t  old_base_xp = ppm_ppn2base( old_ppn );
-        xptr_t  new_base_xp = ppm_ppn2base( new_ppn );
-        memcpy( GET_PTR( new_base_xp ),
-                GET_PTR( old_base_xp ),
-                CONFIG_PPM_PAGE_SIZE );
-
-        // update attributes: reset COW and set WRITABLE
-        new_attr = old_attr & ~GPT_COW;  
-        new_attr = new_attr | GPT_WRITABLE;
-
-        // register PTE in GPT
-        error = hal_gpt_set_pte( &vmm->gpt , vpn , new_ppn , new_attr );
-
-        if( error )
+        // build new_attr : reset COW and set WRITABLE,
+        new_attr = (old_attr | GPT_WRITABLE) & (~GPT_COW);
+
+        // update GPT[vpn] for all GPT copies
+        // to maintain coherence of copies
+        vmm_update_pte( process,
+                        vpn,
+                        new_attr,
+                        new_ppn );
+
+        // decrement fork_nr in page descriptor
+        hal_remote_atomic_add( XPTR( page_cxy , &page_ptr->fork_nr ) , -1 );
+    }
+    else                         /////////////// page_fault request ///////////
+    {  
+        if( (old_attr & GPT_MAPPED) == 0 )   // true page_fault => map it
         {
-            printk("\n[ERROR] in %s : cannot update GPT / process = %x / vpn = %x\n",
-            __FUNCTION__ , process->pid , vpn );
-            return error;
-        }
-    }
-    else                    //////////////////// page_fault request ///////////
-    {  
-        if( (old_attr & GPT_MAPPED) == 0 )    // PTE unmapped in ref GPT
-        {
-
-vmm_dmsg("\n[DBG] %s : core[%x,%d] page %x unmapped => try to map it\n",
+
+excp_dmsg("\n[DBG] %s : core[%x,%d] handling page fault for vpn %x\n",
 __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn );
 
-            // allocate one physical page, depending on vseg type
+            // allocate new_ppn, depending on vseg type
             error = vmm_get_one_ppn( vseg , vpn , &new_ppn );
-
             if( error )
             {
                 printk("\n[ERROR] in %s : no memory / process = %x / vpn = %x\n",
                 __FUNCTION__ , process->pid , vpn );
-                return error;
+                return -1;
             }
 
-            // define attributes from vseg flags 
+            // define new_attr from vseg flags 
             new_attr = GPT_MAPPED | GPT_SMALL;
             if( vseg->flags & VSEG_USER  ) new_attr |= GPT_USER;
@@ -1229,24 +1479,28 @@
             if( vseg->flags & VSEG_CACHE ) new_attr |= GPT_CACHABLE;
 
-            // register PTE in GPT
-            error = hal_gpt_set_pte( &vmm->gpt , vpn , new_ppn , new_attr );
-
+            // register new PTE in reference GPT
+            // on demand policy => no update of GPT copies
+            error = hal_gpt_set_pte( &vmm->gpt,
+                                     vpn,
+                                     new_attr,
+                                     new_ppn );
             if( error )
             {
                 printk("\n[ERROR] in %s : cannot update GPT / process = %x / vpn = %x\n",
                 __FUNCTION__ , process->pid , vpn );
-                return error;
+                return -1;
             }
         }
-        else
+        else                                  // mapped in reference GPT => get it
         {
+            new_ppn  = old_ppn;
             new_attr = old_attr;
-            new_ppn  = old_ppn;
         }
     }
 
-vmm_dmsg("\n[DBG] %s : core[%x,%d] exit for vpn = %x / ppn = %x / attr = %x\n",
+excp_dmsg("\n[DBG] %s : core[%x,%d] update GPT for vpn %x / ppn = %x / attr = %x\n",
 __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , new_ppn , new_attr );
 
+    // retur success
     *ppn  = new_ppn;
     *attr = new_attr;
@@ -1282,5 +1536,8 @@
 
         // update local GPT
-        error |= hal_gpt_set_pte( &vmm->gpt , vpn , ppn , attr );
+        error |= hal_gpt_set_pte( &vmm->gpt,
+                                  vpn,
+                                  attr,
+                                  ppn );
     }
     else   // local cluster is the reference cluster
@@ -1297,7 +1554,7 @@
 }  // end vmm_handle_page_fault()
 
-///////////////////////////////////////////////
-error_t vmm_copy_on_write( process_t * process,
-                           vpn_t       vpn )
+////////////////////////////////////////////
+error_t vmm_handle_cow( process_t * process,
+                        vpn_t       vpn )
 {
     uint32_t         attr;          // missing page attributes
@@ -1324,5 +1581,8 @@
 
         // update local GPT
-        error |= hal_gpt_set_pte( &vmm->gpt , vpn , ppn , attr );
+        error |= hal_gpt_set_pte( &vmm->gpt,
+                                  vpn,
+                                  attr,
+                                  ppn );
     }
     else   // local cluster is the reference cluster
@@ -1337,5 +1597,5 @@
     return error;
 
-}  // end vmm_copy_on_write()
+}  // end vmm_handle_cow()
 
 ///////////////////////////////////////////
