Index: trunk/kernel/mm/vmm.c
===================================================================
--- trunk/kernel/mm/vmm.c	(revision 429)
+++ trunk/kernel/mm/vmm.c	(revision 433)
@@ -63,6 +63,10 @@
     intptr_t  size;
 
-vmm_dmsg("\n[DBG] %s : core[%x,%d] enters for process %x\n", 
-__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , process->pid );
+#if CONFIG_DEBUG_VMM_INIT
+uint32_t cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_INIT )
+printk("\n[DBG] %s : thread %x enter for process %x / cycle %d\n", 
+__FUNCTION__ , CURRENT_THREAD , process->pid , cycle );
+#endif
 
     // get pointer on VMM
@@ -179,7 +183,10 @@
     hal_fence();
 
-vmm_dmsg("\n[DBG] %s : core[%x,%d] exit for process %x / entry_point = %x\n",
-__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , 
-process->pid , process->vmm.entry_point );
+#if CONFIG_DEBUG_VMM_INIT
+cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_INIT )
+printk("\n[DBG] %s : thread %x exit for process %x / entry_point = %x / cycle %d\n", 
+__FUNCTION__ , CURRENT_THREAD , process->pid , process->vmm.entry_point , cycle );
+#endif
 
     return 0;
@@ -211,5 +218,5 @@
     {
         vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
-        vseg    = (vseg_t *)GET_PTR( vseg_xp );
+        vseg    = GET_PTR( vseg_xp );
 
         printk(" - %s : base = %X / size = %X / npages = %d\n",
@@ -239,9 +246,9 @@
 }  // vmm_display()
 
-/////////////////////i////////////////////
-void vmm_update_pte( process_t * process,
-                     vpn_t       vpn,
-                     uint32_t    attr,
-                     ppn_t       ppn )
+/////////////////////i//////////////////////////
+void vmm_global_update_pte( process_t * process,
+                            vpn_t       vpn,
+                            uint32_t    attr,
+                            ppn_t       ppn )
 {
 
@@ -258,4 +265,15 @@
     cxy_t           owner_cxy;
     lpid_t          owner_lpid;
+
+#if CONFIG_DEBUG_VMM_UPDATE_PTE
+uint32_t cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_UPDATE_PTE < cycle )
+printk("\n[DBG] %s : thread %x enter for process %x / vpn %x / cycle %d\n",
+__FUNCTION__ , CURRENT_THREAD , process->pid , vpn , cycle );
+#endif
+
+    // check cluster is reference
+    assert( (GET_CXY( process->ref_xp ) == local_cxy) , __FUNCTION__,
+    "not called in reference cluster\n");
 
     // get extended pointer on root of process copies xlist in owner cluster
@@ -271,16 +289,28 @@
         // 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_ptr = GET_PTR( remote_process_xp );
         remote_process_cxy = GET_CXY( remote_process_xp );
+
+#if (CONFIG_DEBUG_VMM_UPDATE_PTE & 0x1)
+if( CONFIG_DEBUG_VMM_UPDATE_PTE < cycle )
+printk("\n[DBG] %s : thread %x handling process %x in cluster %x\n",
+__FUNCTION__ , CURRENT_THREAD , process->pid , remote_process_cxy );
+#endif
 
         // 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 );
+        // update remote GPT
+        hal_gpt_update_pte( remote_gpt_xp, vpn, attr, ppn );
     }  
-}  // end vmm_update_pte()
+
+#if CONFIG_DEBUG_VMM_UPDATE_PTE
+cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_UPDATE_PTE < cycle )
+printk("\n[DBG] %s : thread %x exit for process %x / vpn %x / cycle %d\n",
+__FUNCTION__ , CURRENT_THREAD , process->pid , vpn , cycle );
+#endif
+
+}  // end vmm_global_update_pte()
 
 ///////////////////////////////////////
@@ -308,6 +338,10 @@
     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 );
+#if CONFIG_DEBUG_VMM_SET_COW
+uint32_t cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_SET_COW < cycle )
+printk("\n[DBG] %s : thread %x enter for process %x / cycle %d\n",
+__FUNCTION__ , CURRENT_THREAD , process->pid , cycle );
+#endif
 
     // check cluster is reference
@@ -333,9 +367,12 @@
         // 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_ptr = 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 );
+#if (CONFIG_DEBUG_VMM_SET_COW &0x1)
+if( CONFIG_DEBUG_VMM_SET_COW < cycle )
+printk("\n[DBG] %s : thread %x handling process %x in cluster %x\n",
+__FUNCTION__ , CURRENT_THREAD , process->pid , remote_process_cxy );
+#endif
 
         // get extended pointer on remote gpt
@@ -347,5 +384,5 @@
             // get pointer on vseg
             vseg_xp  = XLIST_ELEMENT( vseg_iter_xp , vseg_t , xlist );
-            vseg     = (vseg_t *)GET_PTR( vseg_xp );
+            vseg     = GET_PTR( vseg_xp );
 
             assert( (GET_CXY( vseg_xp ) == local_cxy) , __FUNCTION__,
@@ -357,22 +394,61 @@
             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 (CONFIG_DEBUG_VMM_SET_COW & 0x1)
+if( CONFIG_DEBUG_VMM_SET_COW < cycle )
+printk("\n[DBG] %s : thread %x handling vseg %s / vpn_base = %x / vpn_size = %x\n",
+__FUNCTION__, CURRENT_THREAD , 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) )
             {
-                hal_gpt_flip_cow( true,             // set_cow
-                                  remote_gpt_xp,
-                                  vpn_base,
-                                  vpn_size );
-            }
-        }    // en loop on vsegs
+                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;
+
+                // update flags in remote GPT 
+                hal_gpt_set_cow( remote_gpt_xp,
+                                 vpn_base,
+                                 vpn_size ); 
+
+                // atomically increment pending forks counter in physical pages,
+                // for all vseg pages that are mapped in reference cluster 
+                if( remote_process_cxy == local_cxy )
+                {
+                    // the reference GPT is the local GPT
+                    gpt_t * gpt = GET_PTR( remote_gpt_xp );
+
+                    // 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( gpt , vpn , &attr , &ppn ); 
+
+                        // atomically update pending forks counter if page is mapped
+                        if( attr & GPT_MAPPED )
+                        {
+                            page_xp  = ppm_ppn2page( ppn );
+                            page_cxy = GET_CXY( page_xp );
+                            page_ptr = GET_PTR( page_xp );
+                            forks_xp = XPTR( page_cxy , &page_ptr->forks );
+                            hal_remote_atomic_add( forks_xp , 1 );
+                        }
+                    }   // end loop on vpn
+                }   // end if local
+            }   // end if vseg type
+        }   // end 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 );
+#if CONFIG_DEBUG_VMM_SET_COW
+cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_SET_COW < cycle )
+printk("\n[DBG] %s : thread %x exit for process %x / cycle %d\n",
+__FUNCTION__ , CURRENT_THREAD , process->pid , cycle );
+#endif
 
 }  // end vmm_set-cow()
@@ -404,10 +480,14 @@
     ppn_t       ppn;
 
-vmm_dmsg("\n[DBG] %s : core[%x,%d] enter\n",
-__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid );
+#if CONFIG_DEBUG_VMM_FORK_COPY
+uint32_t cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_FORK_COPY < cycle )
+printk("\n[DBG] %s : thread %x enter / cycle %d\n",
+__FUNCTION__ , CURRENT_THREAD, cycle );
+#endif
 
     // get parent process cluster and local pointer
     parent_cxy     = GET_CXY( parent_process_xp );
-    parent_process = (process_t *)GET_PTR( parent_process_xp );
+    parent_process = GET_PTR( parent_process_xp );
 
     // get local pointers on parent and child VMM
@@ -445,13 +525,16 @@
         // 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 );
+        parent_vseg    = 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 ) ) );
+#if CONFIG_DEBUG_VMM_FORK_COPY
+cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_FORK_COPY < cycle )
+printk("\n[DBG] %s : thread %x found parent vseg %s / vpn_base = %x / cycle %d\n",
+__FUNCTION__ , CURRENT_THREAD, vseg_type_str(type),
+hal_remote_lw( XPTR( parent_cxy , &parent_vseg->vpn_base ) ) , cycle );
+#endif
 
         // all parent vsegs - but STACK - must be copied in child VSL
@@ -473,7 +556,11 @@
             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 ) ) );
+#if CONFIG_DEBUG_VMM_FORK_COPY
+cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_FORK_COPY < cycle )
+printk("\n[DBG] %s : thread %x copied vseg %s / vpn_base = %x to child VSL / cycle %d\n",
+__FUNCTION__ , CURRENT_THREAD , vseg_type_str(type),
+hal_remote_lw( XPTR( parent_cxy , &parent_vseg->vpn_base ) ) , cycle );
+#endif
 
             // copy DATA, MMAP, REMOTE, FILE parent GPT entries to child GPT
@@ -502,14 +589,18 @@
                     }
 
-                    // increment page descriptor fork_nr for the referenced page if mapped
+                    // increment pending forks counter in 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 );
+                        page_ptr = GET_PTR( page_xp );
+                        hal_remote_atomic_add( XPTR( page_cxy , &page_ptr->forks ) , 1 );
+
+#if CONFIG_DEBUG_VMM_FORK_COPY
+cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_FORK_COPY < cycle )
+printk("\n[DBG] %s : thread %x copied vpn %x to child GPT / cycle %d\n",
+__FUNCTION__ , CURRENT_THREAD , vpn , cycle );
+#endif
 
                     }
@@ -558,4 +649,11 @@
     hal_fence();
 
+#if CONFIG_DEBUG_VMM_FORK_COPY
+cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_FORK_COPY < cycle )
+printk("\n[DBG] %s : thread %x exit successfully / cycle %d\n",
+__FUNCTION__ , CURRENT_THREAD , cycle );
+#endif
+
     return 0;
 
@@ -568,8 +666,12 @@
 	vseg_t * vseg;
 
-vmm_dmsg("\n[DBG] %s : core[%x,%d] enter\n",
-__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid );
-
-    // get pointer on VMM
+#if CONFIG_DEBUG_VMM_DESTROY
+uint32_t cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_DESTROY < cycle )
+printk("\n[DBG] %s : thread %x enter for process %x / cycle %d\n",
+__FUNCTION__ , CURRENT_THREAD , process->pid , cycle );
+#endif
+
+    // get pointer on local VMM
     vmm_t  * vmm = &process->vmm;
 
@@ -586,7 +688,7 @@
         // get pointer on first vseg in VSL
 		vseg_xp = XLIST_FIRST_ELEMENT( root_xp , vseg_t , xlist );
-        vseg = (vseg_t *)GET_PTR( vseg_xp );
-
-        // unmap and release all pages
+        vseg    = GET_PTR( vseg_xp );
+
+        // unmap rand release physical pages if required)
         vmm_unmap_vseg( process , vseg );
 
@@ -598,5 +700,5 @@
 	}
 
-    // release lock
+    // release lock protecting VSL
 	remote_rwlock_wr_unlock( lock_xp );
 
@@ -616,6 +718,10 @@
     hal_gpt_destroy( &vmm->gpt );
 
-vmm_dmsg("\n[DBG] %s : core[%x,%d] exit\n",
-__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid );
+#if CONFIG_DEBUG_VMM_DESTROY
+cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_DESTROY < cycle )
+printk("\n[DBG] %s : thread %x exit / cycle %d\n",
+__FUNCTION__ , CURRENT_THREAD , cycle );
+#endif
 
 }  // end vmm_destroy()
@@ -637,5 +743,5 @@
 	{
 		vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
-        vseg    = (vseg_t *)GET_PTR( vseg_xp );
+        vseg    = GET_PTR( vseg_xp );
 
 		if( ((vpn_base + vpn_size) > vseg->vpn_base) &&
@@ -766,7 +872,10 @@
 	error_t      error;
 
-vmm_dmsg("\n[DBG] %s : core[%x,%d] enters / process %x / base %x / size %x / %s / cxy = %x\n",
-__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid ,
-process->pid , base , size , vseg_type_str(type) , cxy );
+#if CONFIG_DEBUG_VMM_CREATE_VSEG
+uint32_t cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_CREATE_VSEG < cycle )
+printk("\n[DBG] %s : thread %x enter / process %x / base %x / size %x / %s / cxy %x / cycle %d\n",
+__FUNCTION__, CURRENT_THREAD, process->pid, base, size, vseg_type_str(type), cxy, cycle );
+#endif
 
     // get pointer on VMM 
@@ -854,7 +963,10 @@
 	remote_rwlock_wr_unlock( lock_xp );
 
-vmm_dmsg("\n[DBG] %s : core[%x,%d] exit / process %x / base %x / size %x / type %s\n",
-__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid ,
-process->pid , base , size , vseg_type_str(type) );
+#if CONFIG_DEBUG_VMM_CREATE_VSEG
+cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_CREATE_VSEG < cycle )
+printk("\n[DBG] %s : thread %x exit / process %x / %s / cxy %x / cycle %d\n",
+__FUNCTION__, CURRENT_THREAD, process->pid, vseg_type_str(type), cxy, cycle );
+#endif
 
 	return vseg;
@@ -985,10 +1097,15 @@
     cxy_t       page_cxy;   // page descriptor cluster
     page_t    * page_ptr;   // page descriptor pointer
-
-vmm_dmsg("\n[DBG] %s : core[%x, %d] enter / process %x / vseg %s / base %x / cycle %d\n",
-__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, process->pid ,
-vseg_type_str( vseg->type ), vseg->vpn_base, (uint32_t)hal_get_cycles() );
-
-    // get pointer on process GPT
+    xptr_t      forks_xp;   // extended pointer on pending forks counter
+    uint32_t    count;      // actual number of pendinf forks
+
+#if CONFIG_DEBUG_VMM_UNMAP_VSEG
+uint32_t cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_UNMAP_VSEG < cycle )
+printk("\n[DBG] %s : thread %x enter / process %x / vseg %s / base %x / cycle %d\n",
+__FUNCTION__, CURRENT_THREAD, process->pid, vseg_type_str( vseg->type ), vseg->vpn_base, cycle );
+#endif
+
+    // get pointer on local GPT
     gpt_t     * gpt = &process->vmm.gpt;
 
@@ -1007,29 +1124,56 @@
             "an user vseg must use small pages" );
 
-            // unmap GPT entry
+            // unmap GPT entry in all GPT copies
             hal_gpt_reset_pte( gpt , vpn );
 
-            // release memory if not identity mapped
-            if( (vseg->flags & VSEG_IDENT)  == 0 )
+            // handle pending forks counter if
+            // 1) not identity mapped
+            // 2) running in reference cluster
+            if( ((vseg->flags & VSEG_IDENT)  == 0) &&
+                (GET_CXY( process->ref_xp ) == local_cxy) )
             {
-                // get extended pointer on page descriptor
+                // get extended pointer on physical page descriptor
                 page_xp  = ppm_ppn2page( ppn );
                 page_cxy = GET_CXY( page_xp );
-                page_ptr = (page_t *)GET_PTR( page_xp );
-
-                // release physical page to relevant cluster
-                if( page_cxy == local_cxy )                   // local cluster
+                page_ptr = GET_PTR( page_xp );
+
+                // FIXME lock the physical page
+
+                // get extended pointer on pending forks counter
+                forks_xp = XPTR( page_cxy , &page_ptr->forks );
+
+                // get pending forks counter
+                count = hal_remote_lw( forks_xp );
+                
+                if( count )  // decrement pending forks counter
                 {
-                    req.type = KMEM_PAGE;
-                    req.ptr  = page_ptr; 
-                    kmem_free( &req );
+                    hal_remote_atomic_add( forks_xp , -1 );
+                }  
+                else         // release physical page to relevant cluster
+                {
+                    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 );
+                    }
                 }
-                else                                          // remote cluster
-                {
-                    rpc_pmem_release_pages_client( page_cxy , page_ptr );
-                }
+
+                // FIXME unlock the physical page
             }
         }
     }
+
+#if CONFIG_DEBUG_VMM_UNMAP_VSEG
+cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_UNMAP_VSEG < cycle )
+printk("\n[DBG] %s : thread %x exit / process %x / vseg %s / base %x / cycle %d\n",
+__FUNCTION__, CURRENT_THREAD, process->pid, vseg_type_str( vseg->type ), vseg->vpn_base, cycle );
+#endif
+
 }  // end vmm_unmap_vseg()
 
@@ -1061,5 +1205,5 @@
     {
         vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
-        vseg    = (vseg_t *)GET_PTR( vseg_xp );
+        vseg    = GET_PTR( vseg_xp );
         if( (vaddr >= vseg->min) && (vaddr < vseg->max) )
         {
@@ -1185,5 +1329,5 @@
         // get cluster and local pointer on reference process 
         cxy_t       ref_cxy = GET_CXY( ref_xp );
-        process_t * ref_ptr = (process_t *)GET_PTR( ref_xp );
+        process_t * ref_ptr = GET_PTR( ref_xp );
 
         if( local_cxy == ref_cxy )  return -1;   // local cluster is the reference
@@ -1224,4 +1368,11 @@
                                  vpn_t    vpn )
 {
+
+#if CONFIG_DEBUG_VMM_ALLOCATE_PAGE
+if( CONFIG_DEBUG_VMM_ALLOCATE_PAGE < (uint32_t)hal_get_cycles() )
+printk("\n[DBG] in %s : thread %x enter for vpn %x\n",
+__FUNCTION__ , CURRENT_THREAD, vpn );
+#endif
+
     // compute target cluster
     page_t     * page_ptr;
@@ -1262,4 +1413,10 @@
     }
 
+#if CONFIG_DEBUG_VMM_ALLOCATE_PAGE
+if( CONFIG_DEBUG_VMM_ALLOCATE_PAGE < (uint32_t)hal_get_cycles() )
+printk("\n[DBG] in %s : thread %x exit for vpn = %d / ppn = %x\n",
+__FUNCTION__ , CURRENT_THREAD, vpn, ppm_page2ppn( XPTR( page_cxy , page_ptr ) ) );
+#endif
+
     if( page_ptr == NULL ) return XPTR_NULL;
     else                   return XPTR( page_cxy , page_ptr );
@@ -1281,6 +1438,9 @@
     index     = vpn - vseg->vpn_base;
 
-vmm_dmsg("\n[DBG] %s : core[%x,%d] enter for vpn = %x / type = %s / index = %d\n",
-__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, vpn, vseg_type_str(type), index );
+#if CONFIG_DEBUG_VMM_GET_ONE_PPN 
+if( CONFIG_DEBUG_VMM_GET_ONE_PPN < (uint32_t)hal_get_cycles() )
+printk("\n[DBG] %s : thread %x enter for vpn = %x / type = %s / index = %d\n",
+__FUNCTION__, CURRENT_THREAD, vpn, vseg_type_str(type), index );
+#endif
 
     // FILE type : get the physical page from the file mapper
@@ -1295,5 +1455,5 @@
         // get mapper cluster and local pointer
         cxy_t      mapper_cxy = GET_CXY( mapper_xp );
-        mapper_t * mapper_ptr = (mapper_t *)GET_PTR( mapper_xp );
+        mapper_t * mapper_ptr = GET_PTR( mapper_xp );
 
         // get page descriptor from mapper
@@ -1316,5 +1476,5 @@
     else
     {
-        // allocate physical page 
+        // allocate one physical page 
         page_xp = vmm_page_allocate( vseg , vpn );
 
@@ -1322,5 +1482,5 @@
 
         // initialise missing page from .elf file mapper for DATA and CODE types
-        // => the mapper_xp field is an extended pointer on the .elf file mapper
+        // (the vseg->mapper_xp field is an extended pointer on the .elf file mapper)
         if( (type == VSEG_TYPE_CODE) || (type == VSEG_TYPE_DATA) )
         {
@@ -1333,5 +1493,5 @@
             // get mapper cluster and local pointer
             cxy_t      mapper_cxy = GET_CXY( mapper_xp );
-            mapper_t * mapper_ptr = (mapper_t *)GET_PTR( mapper_xp );
+            mapper_t * mapper_ptr = GET_PTR( mapper_xp );
 
             // compute missing page offset in vseg
@@ -1341,6 +1501,9 @@
             uint32_t elf_offset = vseg->file_offset + offset;
 
-vmm_dmsg("\n[DBG] %s : core[%x,%d] for vpn = %x / elf_offset = %x\n",
-__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, vpn, elf_offset );
+#if (CONFIG_DEBUG_VMM_GET_ONE_PPN & 0x1)
+if( CONFIG_DEBUG_VMM_GET_ONE_PPN < (uint32_t)hal_get_cycles() )
+printk("\n[DBG] %s : thread %x for vpn = %x / elf_offset = %x\n",
+__FUNCTION__, CURRENT_THREAD, vpn, elf_offset );
+#endif
 
             // compute extended pointer on page base 
@@ -1352,6 +1515,10 @@
             if( file_size < offset )                 // missing page fully in  BSS 
             {
-vmm_dmsg("\n[DBG] %s : core[%x,%d] for vpn = %x / fully in BSS\n",
-__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, vpn );
+
+#if (CONFIG_DEBUG_VMM_GET_ONE_PPN & 0x1)
+if( CONFIG_DEBUG_VMM_GET_ONE_PPN < (uint32_t)hal_get_cycles() )
+printk("\n[DBG] %s : thread%x for vpn = %x / fully in BSS\n",
+__FUNCTION__, CURRENT_THREAD, vpn );
+#endif
 
                 if( GET_CXY( page_xp ) == local_cxy )
@@ -1367,6 +1534,9 @@
             {
 
-vmm_dmsg("\n[DBG] %s : core[%x,%d] for vpn = %x / fully in mapper\n",
-__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, vpn );
+#if (CONFIG_DEBUG_VMM_GET_ONE_PPN & 0x1)
+if( CONFIG_DEBUG_VMM_GET_ONE_PPN < (uint32_t)hal_get_cycles() )
+printk("\n[DBG] %s : thread %x, for vpn = %x / fully in mapper\n",
+__FUNCTION__, CURRENT_THREAD, vpn );
+#endif
 
                 if( mapper_cxy == local_cxy ) 
@@ -1396,9 +1566,11 @@
             {
 
-vmm_dmsg("\n[DBG] %s : core[%x,%d] for vpn = %x / both mapper & BSS\n"
-         "      %d bytes from mapper / %d bytes from BSS\n",
-__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, vpn,
+#if (CONFIG_DEBUG_VMM_GET_ONE_PPN & 0x1)
+if( CONFIG_DEBUG_VMM_GET_ONE_PPN < (uint32_t)hal_get_cycles() )
+printk("\n[DBG] %s : thread %x for vpn = %x / both mapper & BSS\n"
+"      %d bytes from mapper / %d bytes from BSS\n",
+__FUNCTION__, CURRENT_THREAD, vpn,
 file_size - offset , offset + CONFIG_PPM_PAGE_SIZE - file_size  );
-
+#endif
                 // initialize mapper part
                 if( mapper_cxy == local_cxy )
@@ -1441,6 +1613,9 @@
     *ppn = ppm_page2ppn( page_xp );
 
-vmm_dmsg("\n[DBG] %s : core[%x,%d] exit for vpn = %x / ppn = %x\n",
-__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , *ppn );
+#if CONFIG_DEBUG_VMM_GET_ONE_PPN
+if( CONFIG_DEBUG_VMM_GET_ONE_PPN < (uint32_t)hal_get_cycles() )
+printk("\n[DBG] %s : thread %x exit for vpn = %x / ppn = %x\n",
+__FUNCTION__ , CURRENT_THREAD , vpn , *ppn );
+#endif
 
     return 0;
@@ -1455,5 +1630,5 @@
                      ppn_t     * ppn )
 {
-    vseg_t  * vseg;       // pointer on vseg containing VPN
+    vseg_t  * vseg;       // vseg containing VPN
     ppn_t     old_ppn;    // current PTE_PPN
     uint32_t  old_attr;   // current PTE_ATTR
@@ -1466,11 +1641,15 @@
     "not called in the reference cluster\n" );
 
-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 , cow );
+#if CONFIG_DEBUG_VMM_GET_PTE
+uint32_t cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_GET_PTE > cycle )
+printk("\n[DBG] %s : thread %x enter for vpn = %x / process %x / cow = %d / cycle %d\n",
+__FUNCTION__ , CURRENT_THREAD , vpn , process->pid , cow , cycle );
+#endif
 
     // get VMM pointer
     vmm_t * vmm = &process->vmm;
 
-    // get vseg pointer from ref VSL
+    // get vseg pointer from reference VSL
     error = vmm_get_vseg( process , vpn<<CONFIG_PPM_PAGE_SHIFT , &vseg );
 
@@ -1482,7 +1661,10 @@
     }
 
-vmm_dmsg("\n[DBG] %s : core[%x,%d] found vseg %s / vpn_base = %x / vpn_size = %x\n",
-__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid ,
-vseg_type_str(vseg->type) , vseg->vpn_base , vseg->vpn_size );
+#if CONFIG_DEBUG_VMM_GET_PTE
+cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_GET_PTE < cycle )
+printk("\n[DBG] %s : thread %x found vseg %s / vpn_base = %x / vpn_size = %x\n",
+__FUNCTION__, CURRENT_THREAD, vseg_type_str(vseg->type), vseg->vpn_base, vseg->vpn_size );
+#endif
 
     // access GPT to get current PTE attributes and PPN
@@ -1493,21 +1675,25 @@
     // clusters containing a copy, and return the new_ppn and new_attr
 
-    if( cow )               ////////////// copy_on_write request ///////////
+    if( cow )  /////////////////////////// copy_on_write request //////////////////////
     {
         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 );
-
-        // get extended pointer, cluster and local pointer on page descriptor
+#if CONFIG_DEBUG_VMM_GET_PTE
+cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_GET_PTE < cycle )
+printk("\n[DBG] %s : thread %x handling COW for vpn %x in process %x\n",
+__FUNCTION__, CURRENT_THREAD, vpn, process->pid );
+#endif
+
+        // get extended pointer, cluster and local pointer on physical 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 );
+        page_t * page_ptr = 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
+        uint32_t forks = hal_remote_lw( XPTR( page_cxy , &page_ptr->forks ) );
+
+        if( forks )        // pending fork => allocate a new page, copy old to new
         {
             // allocate a new physical page
@@ -1539,20 +1725,20 @@
 
         // 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 ///////////
+        vmm_global_update_pte( process, vpn, new_attr, new_ppn );
+
+        // decrement pending forks counter in page descriptor
+        hal_remote_atomic_add( XPTR( page_cxy , &page_ptr->forks ) , -1 );
+    }
+    else  ////////////////////////////////// page_fault request ////////////////////////
     {  
         if( (old_attr & GPT_MAPPED) == 0 )   // true page_fault => map it
         {
 
-excp_dmsg("\n[DBG] %s : core[%x,%d] handling page fault for vpn %x\n",
-__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn );
+#if CONFIG_DEBUG_VMM_GET_PTE
+cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_GET_PTE < cycle )
+printk("\n[DBG] %s : thread %x handling page fault for vpn %x in process %x\n",
+__FUNCTION__, CURRENT_THREAD, vpn, process->pid );
+#endif
 
             // allocate new_ppn, depending on vseg type
@@ -1592,8 +1778,12 @@
     }
 
-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
+#if CONFIG_DEBUG_VMM_GET_PTE
+cycle = (uint32_t)hal_get_cycles();
+if( CONFIG_DEBUG_VMM_GET_PTE < cycle )
+printk("\n[DBG] %s : thread,%x exit for vpn %x in process %x / ppn = %x / attr = %x / cycle %d\n",
+__FUNCTION__, CURRENT_THREAD, vpn, process->pid, new_ppn, new_attr, cycle );
+#endif
+
+    // return success
     *ppn  = new_ppn;
     *attr = new_attr;
@@ -1612,5 +1802,5 @@
     // 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 );
+    process_t * ref_ptr = GET_PTR( process->ref_xp );
 
     // get missing PTE attributes and PPN from reference cluster
@@ -1651,11 +1841,12 @@
                         vpn_t       vpn )
 {
-    uint32_t         attr;          // missing page attributes
-    ppn_t            ppn;           // missing page PPN
+    uint32_t         attr;          // page attributes
+    ppn_t            ppn;           // page PPN
     error_t          error;
 
+    
     // 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 );
+    process_t * ref_ptr = GET_PTR( process->ref_xp );
 
     // get new PTE attributes and PPN from reference cluster
@@ -1722,5 +1913,5 @@
     {
         cxy_t       ref_cxy = GET_CXY( process->ref_xp );
-        process_t * ref_ptr = (process_t *)GET_PTR( process->ref_xp );
+        process_t * ref_ptr = GET_PTR( process->ref_xp );
         rpc_vmm_get_pte_client( ref_cxy , ref_ptr , vpn , false , &attr , &ppn , &error );
     }
