Index: trunk/kernel/mm/vmm.c
===================================================================
--- trunk/kernel/mm/vmm.c	(revision 406)
+++ trunk/kernel/mm/vmm.c	(revision 407)
@@ -58,12 +58,17 @@
     vseg_t  * vseg_args;
     vseg_t  * vseg_envs;
-    vseg_t  * vseg_heap;
     intptr_t  base;
     intptr_t  size;
 
-    vmm_dmsg("\n[DMSG] %s : enter for process %x\n", __FUNCTION__ , process->pid );
+vmm_dmsg("\n[DBG] %s : core[%x,%d] enters for process %x\n", 
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , process->pid );
 
     // get pointer on VMM
     vmm_t   * vmm = &process->vmm;
+
+    // initialize local list of vsegs 
+    vmm->vsegs_nr = 0;
+	list_root_init( &vmm->vsegs_root );
+	rwlock_init( &vmm->vsegs_lock );
 
     assert( ((CONFIG_VMM_KENTRY_SIZE + CONFIG_VMM_ARGS_SIZE + CONFIG_VMM_ENVS_SIZE) 
@@ -77,16 +82,16 @@
              "STACK zone too small\n");
 
-    // initialize the rwlock protecting the vsegs list
-	rwlock_init( &vmm->vsegs_lock );
-
-    // initialize local list of vsegs and radix-tree
-    vmm->vsegs_nr = 0;
-	list_root_init( &vmm->vsegs_root );
-
     // register kentry vseg in VMM
     base = CONFIG_VMM_KENTRY_BASE << CONFIG_PPM_PAGE_SHIFT;
     size = CONFIG_VMM_KENTRY_SIZE << CONFIG_PPM_PAGE_SHIFT;
 
-    vseg_kentry = vmm_create_vseg( process , base , size , VSEG_TYPE_CODE );
+    vseg_kentry = vmm_create_vseg( process,
+                                   VSEG_TYPE_CODE,
+                                   base,
+                                   size,
+                                   0,             // file_offset unused
+                                   0,             // file_size unused
+                                   XPTR_NULL,     // mapper_xp unused
+                                   local_cxy );
 
     assert( (vseg_kentry != NULL) , __FUNCTION__ , "cannot register kentry vseg\n" );
@@ -99,7 +104,14 @@
     size = CONFIG_VMM_ARGS_SIZE << CONFIG_PPM_PAGE_SHIFT;
 
-    vseg_args = vmm_create_vseg( process , base , size , VSEG_TYPE_DATA );
-
-    assert( (vseg_args != NULL) , __FUNCTION__ , "cannot register args vseg\n" );
+    vseg_args = vmm_create_vseg( process,
+                                 VSEG_TYPE_DATA,
+                                 base,
+                                 size,
+                                 0,             // file_offset unused
+                                 0,             // file_size unused
+                                 XPTR_NULL,     // mapper_xp unused
+                                 local_cxy );
+
+    assert( (vseg_args != NULL) , __FUNCTION__ , "cannot create args vseg\n" );
 
     vmm->args_vpn_base = base;
@@ -111,19 +123,16 @@
     size = CONFIG_VMM_ENVS_SIZE << CONFIG_PPM_PAGE_SHIFT;
 
-    vseg_envs = vmm_create_vseg( process , base , size , VSEG_TYPE_DATA );
-
-    assert( (vseg_envs != NULL) , __FUNCTION__ , "cannot register envs vseg\n" );
+    vseg_envs = vmm_create_vseg( process,
+                                 VSEG_TYPE_DATA,
+                                 base,
+                                 size,
+                                 0,             // file_offset unused
+                                 0,             // file_size unused
+                                 XPTR_NULL,     // mapper_xp unused
+                                 local_cxy );
+
+    assert( (vseg_envs != NULL) , __FUNCTION__ , "cannot create envs vseg\n" );
 
     vmm->envs_vpn_base = base;
-
-    // register the heap vseg in VMM
-    base = CONFIG_VMM_HEAP_BASE << CONFIG_PPM_PAGE_SHIFT;
-    size = (CONFIG_VMM_MMAP_BASE-CONFIG_VMM_HEAP_BASE) << CONFIG_PPM_PAGE_SHIFT;
-
-    vseg_heap = vmm_create_vseg( process , base , size , VSEG_TYPE_HEAP );
-
-    assert( (vseg_heap != NULL) , __FUNCTION__ , "cannot register heap vseg\n" );
-
-    vmm->heap_vpn_base = base;
 
     // initialize generic page table
@@ -137,7 +146,7 @@
 
     // initialize MMAP allocator
-    vmm->mmap_mgr.vpn_base        = CONFIG_VMM_MMAP_BASE;
-    vmm->mmap_mgr.vpn_size        = CONFIG_VMM_STACK_BASE - CONFIG_VMM_MMAP_BASE;
-    vmm->mmap_mgr.first_free_vpn  = CONFIG_VMM_MMAP_BASE;
+    vmm->mmap_mgr.vpn_base        = CONFIG_VMM_HEAP_BASE;
+    vmm->mmap_mgr.vpn_size        = CONFIG_VMM_STACK_BASE - CONFIG_VMM_HEAP_BASE;
+    vmm->mmap_mgr.first_free_vpn  = CONFIG_VMM_HEAP_BASE;
     uint32_t i;
     for( i = 0 ; i < 32 ; i++ ) list_root_init( &vmm->mmap_mgr.zombi_list[i] );
@@ -150,8 +159,53 @@
     hal_fence();
 
-    vmm_dmsg("\n[DMSG] %s : exit for process %x / entry_point = %x\n",
-    __FUNCTION__ , process->pid , process->vmm.entry_point );
+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 );
 
 }  // end vmm_init()
+
+//////////////////////////////////////
+void vmm_display( process_t * process,
+                  bool_t      mapping )
+{
+    vmm_t * vmm = &process->vmm;
+    gpt_t * gpt = &vmm->gpt;
+
+    printk("\n***** VSL and GPT for process %x\n\n", 
+    process->pid );
+
+    // get lock protecting the vseg list
+    rwlock_rd_lock( &vmm->vsegs_lock );
+
+    // scan the list of vsegs
+    list_entry_t * iter;
+    vseg_t       * vseg;
+    LIST_FOREACH( &vmm->vsegs_root , iter )
+    {
+        vseg = LIST_ELEMENT( iter , vseg_t , list );
+        printk(" - %s : base = %X / size = %X / npages = %d\n",
+        vseg_type_str( vseg->type ) , vseg->min , vseg->max - vseg->min , vseg->vpn_size );
+
+        if( mapping )
+        {
+            vpn_t    vpn;
+            ppn_t    ppn;
+            uint32_t attr;
+            vpn_t    base = vseg->vpn_base;
+            vpn_t    size = vseg->vpn_size;
+            for( vpn = base ; vpn < (base+size) ; vpn++ )
+            {
+                hal_gpt_get_pte( gpt , vpn , &attr , &ppn );
+                if( attr & GPT_MAPPED )
+                {
+                    printk("    . vpn = %X / attr = %X / ppn = %X\n", vpn , attr , ppn );
+                }
+            }
+        }
+    }
+
+    // release the lock
+    rwlock_rd_unlock( &vmm->vsegs_lock );
+}
 
 //////////////////////////////////////////
@@ -170,10 +224,19 @@
     rwlock_init( &dst_vmm->vsegs_lock );
 
-    // initialize the dst_vmm vsegs list and the radix tree
+    // initialize the dst_vmm vsegs list
     dst_vmm->vsegs_nr = 0;
     list_root_init( &dst_vmm->vsegs_root );
 
-    // loop on src_vmm list of vsegs to create
-    // and register vsegs copies in dst_vmm
+    // initialize generic page table
+    error = hal_gpt_create( &dst_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;
@@ -201,19 +264,24 @@
         vseg_init_from_ref( dst_vseg , XPTR( local_cxy , src_vseg ) );
 
-        // register dst_vseg in dst_vmm
+        // 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 generic page table
-    error = hal_gpt_create( &dst_vmm->gpt );
-
-    if( error )
-    {
-        printk("\n[ERROR] in %s : cannot initialize page table\n", __FUNCTION__ );
-        return ENOMEM;
-    }
 
     // initialize STACK allocator
@@ -222,7 +290,7 @@
 
     // initialize MMAP allocator
-    dst_vmm->mmap_mgr.vpn_base        = CONFIG_VMM_MMAP_BASE;
-    dst_vmm->mmap_mgr.vpn_size        = CONFIG_VMM_STACK_BASE - CONFIG_VMM_MMAP_BASE;
-    dst_vmm->mmap_mgr.first_free_vpn  = CONFIG_VMM_MMAP_BASE;
+    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;
     uint32_t i;
     for( i = 0 ; i < 32 ; i++ ) list_root_init( &dst_vmm->mmap_mgr.zombi_list[i] );
@@ -242,21 +310,4 @@
 
     dst_vmm->entry_point   = src_vmm->entry_point;
-
-    // HEAP TODO : new heap for child ???
-    dst_vmm->heap_vseg     = src_vmm->heap_vseg;
-
-    // initialize generic page table
-    error = hal_gpt_create( &dst_vmm->gpt );
-
-    if( error )
-    {
-        printk("\n[ERROR] in %s : cannot initialize page table\n", __FUNCTION__ );
-        return ENOMEM;
-    }
-
-    // copy GPT content from src_vmm to dst_vmm, activating "Copy-On-Write"
-    // TODO register Copy-On_Write in page descriptors
-    bool_t cow = true;
-    hal_gpt_copy( &dst_vmm->gpt , &src_vmm->gpt , cow );
 
     hal_fence();
@@ -431,9 +482,13 @@
 }  // end vmm_mmap_alloc()
 
-//////////////////////////////////////////////
-vseg_t * vmm_create_vseg( process_t * process,
-                          intptr_t    base,
-	                      intptr_t    size,
-	                      uint32_t    type )
+////////////////////////////////////////////////
+vseg_t * vmm_create_vseg( process_t   * process,
+	                      vseg_type_t   type,
+                          intptr_t      base,
+	                      uint32_t      size,
+                          uint32_t      file_offset,
+                          uint32_t      file_size,
+                          xptr_t        mapper_xp,
+                          cxy_t         cxy )
 {
     vseg_t     * vseg;          // created vseg pointer
@@ -442,12 +497,13 @@
 	error_t      error;
 
-    // get pointer on VMM
-	vmm_t * vmm = &process->vmm;
-
-	vmm_dmsg("\n[DMSG] %s : enter for process %x / base = %x / size = %x / type = %s\n",
-		     __FUNCTION__ , process->pid , base , size , vseg_type_str(type) );
+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 );
+
+    // get pointer on VMM 
+	vmm_t * vmm    = &process->vmm;
 
     // compute base, size, vpn_base, vpn_size, depending on vseg type
-    // we use the VMM specific allocators for STACK and MMAP vsegs
+    // we use the VMM specific allocators for "stack", "file", "anon", & "remote" vsegs
     if( type == VSEG_TYPE_STACK )
     {
@@ -456,6 +512,6 @@
         if( error )
         {
-            printk("\n[ERROR] in %s : no vspace for stack vseg / process %x in cluster %x\n",
-                   __FUNCTION__ , process->pid , local_cxy );
+            printk("\n[ERROR] in %s : no space for stack vseg / process %x in cluster %x\n",
+            __FUNCTION__ , process->pid , local_cxy );
             return NULL;
         }
@@ -498,6 +554,5 @@
         printk("\n[ERROR] in %s for process %x : new vseg [vpn_base = %x / vpn_size = %x]\n"
                "  overlap existing vseg [vpn_base = %x / vpn_size = %x]\n",
-               __FUNCTION__ , process->pid, vpn_base, vpn_size,
-               vseg->vpn_base, vseg->vpn_size );
+        __FUNCTION__ , process->pid, vpn_base, vpn_size, vseg->vpn_base, vseg->vpn_size );
         return NULL;
     }
@@ -508,13 +563,19 @@
 	{
 	    printk("\n[ERROR] in %s for process %x : cannot allocate memory for vseg\n",
-             __FUNCTION__ , process->pid );
+        __FUNCTION__ , process->pid );
         return NULL;
 	}
 
     // initialize vseg descriptor
-	vseg_init( vseg , base, size , vpn_base , vpn_size , type , local_cxy );
-
-    // update "heap_vseg" in VMM
-	if( type == VSEG_TYPE_HEAP ) process->vmm.heap_vseg = vseg;
+	vseg_init( vseg,
+               type,
+               base,
+               size,
+               vpn_base,
+               vpn_size,
+               file_offset,
+               file_size,
+               mapper_xp,
+               cxy );
 
     // attach vseg to vmm
@@ -523,6 +584,7 @@
 	rwlock_wr_unlock( &vmm->vsegs_lock );
 
-	vmm_dmsg("\n[DMSG] %s : exit for process %x / vseg [%x, %x] registered\n",
-		     __FUNCTION__ , process->pid , vseg->min , vseg->max );
+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) );
 
 	return vseg;
@@ -579,5 +641,5 @@
         vseg_free( vseg );
     }
-}
+}  // end vmm_remove_vseg()
 
 //////////////////////////////////////////////
@@ -655,13 +717,13 @@
 }
 
-///////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////
 // This low-level static function is called by the vmm_get_vseg() and vmm_resize_vseg()
 // functions.  It scan the list of registered vsegs to find the unique vseg containing
 // a given virtual address.
-///////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////
 // @ vmm     : pointer on the process VMM.
 // @ vaddr   : virtual address.
 // @ return vseg pointer if success / return NULL if not found.
-///////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////
 static vseg_t * vseg_from_vaddr( vmm_t    * vmm,
                                  intptr_t   vaddr )
@@ -755,5 +817,13 @@
 
         // create new vseg
-        new = vmm_create_vseg( process , addr_min , (vseg->max - addr_max) , vseg->type ); 
+        new = vmm_create_vseg( process, 
+                               vseg->type,
+                               addr_min, 
+                               (vseg->max - addr_max),
+                               vseg->file_offset,
+                               vseg->file_size,
+                               vseg->mapper_xp,
+                               vseg->cxy ); 
+
         if( new == NULL ) error = EINVAL;
         else              error = 0;
@@ -814,4 +884,56 @@
 }  // end vmm_get_vseg()
 
+//////////////////////////////////////////////////////////////////////////////////////
+// This static function compute the target cluster to allocate a physical page
+// for a given <vpn> in a given <vseg>, allocates the page (with an RPC if required)
+// and returns an extended pointer on the allocated page descriptor.
+// The vseg cannot have the FILE type.
+//////////////////////////////////////////////////////////////////////////////////////
+static xptr_t vmm_page_allocate( vseg_t * vseg,
+                                 vpn_t    vpn )
+{
+    // compute target cluster
+    page_t     * page_ptr;
+    cxy_t        page_cxy;
+    kmem_req_t   req;
+
+    uint32_t     type  = vseg->type;
+    uint32_t     flags = vseg->flags;
+
+    assert( ( type != VSEG_TYPE_FILE ) , __FUNCTION__ , "illegal vseg type\n" );
+
+    if( flags & VSEG_DISTRIB )    // distributed => cxy depends on vpn LSB
+    {
+        uint32_t x_size  = LOCAL_CLUSTER->x_size;
+        uint32_t y_size  = LOCAL_CLUSTER->y_size;
+        uint32_t y_width = LOCAL_CLUSTER->y_width;
+        uint32_t index   = vpn & ((x_size * y_size) - 1);
+        uint32_t x       = index / y_size;
+        uint32_t y       = index % y_size;
+        page_cxy         = (x<<y_width) + y;
+    }
+    else                          // other cases => cxy specified in vseg
+    {
+        page_cxy         = vseg->cxy;
+    }
+
+    // allocate a physical page from target cluster
+    if( page_cxy == local_cxy )  // target cluster is the local cluster
+    {
+        req.type  = KMEM_PAGE;
+        req.size  = 0;
+        req.flags = AF_NONE;
+        page_ptr  = (page_t *)kmem_alloc( &req );
+    }
+    else                           // target cluster is not the local cluster
+    {
+        rpc_pmem_get_pages_client( page_cxy , 0 , &page_ptr );
+    }
+
+    if( page_ptr == NULL ) return XPTR_NULL;
+    else                   return XPTR( page_cxy , page_ptr );
+
+}  // end vmm_page_allocate()  
+
 ////////////////////////////////////////
 error_t vmm_get_one_ppn( vseg_t * vseg,
@@ -820,5 +942,5 @@
 {
     error_t    error;
-    cxy_t      page_cxy;          // physical page cluster
+    xptr_t     page_xp;           // extended pointer on physical page descriptor
     page_t   * page_ptr;          // local pointer on physical page descriptor
     uint32_t   index;             // missing page index in vseg mapper
@@ -828,6 +950,6 @@
     index     = vpn - vseg->vpn_base;
 
-    vmm_dmsg("\n[DMSG] %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 );
+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 );
 
     // FILE type : get the physical page from the file mapper
@@ -835,5 +957,5 @@
     {
         // get extended pointer on mapper
-        xptr_t     mapper_xp = vseg->mapper_xp;
+        xptr_t mapper_xp = vseg->mapper_xp;
 
         assert( (mapper_xp != XPTR_NULL), __FUNCTION__,
@@ -856,39 +978,15 @@
         if ( page_ptr == NULL ) return EINVAL;
 
-        page_cxy = mapper_cxy;
+        page_xp = XPTR( mapper_cxy , page_ptr );
     }
 
     // Other types : allocate a physical page from target cluster,
+    // as defined by vseg type and vpn value
     else
     {
-        uint32_t flags = vseg->flags;
-
-        // get target cluster for physical page
-        if( flags & VSEG_DISTRIB ) // depends on VPN LSB
-        {
-            uint32_t x_size = LOCAL_CLUSTER->x_size;
-            uint32_t y_size = LOCAL_CLUSTER->y_size;
-            page_cxy = vpn & ((x_size * y_size) - 1);
-        }
-        else                       // defined in vseg descriptor
-        {
-            page_cxy = vseg->cxy;
-        }
-
-        // allocate a physical page in target cluster
-        kmem_req_t   req;
-        if( page_cxy == local_cxy )  // target cluster is the local cluster
-        {
-            req.type  = KMEM_PAGE;
-            req.size  = 0;
-            req.flags = AF_NONE;
-            page_ptr  = (page_t *)kmem_alloc( &req );
-        }
-        else                           // target cluster is not the local cluster
-        {
-            rpc_pmem_get_pages_client( page_cxy , 0 , &page_ptr );
-        }
-
-        if( page_ptr == NULL ) return ENOMEM;
+        // allocate physical page 
+        page_xp = vmm_page_allocate( vseg , vpn );
+
+        if( page_xp == XPTR_NULL ) return ENOMEM;
 
         // initialise missing page from .elf file mapper for DATA and CODE types
@@ -912,9 +1010,9 @@
             uint32_t elf_offset = vseg->file_offset + offset;
 
-            vmm_dmsg("\n[DMSG] %s : core[%x,%d] for vpn = %x / elf_offset = %x\n",
-            __FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, vpn, elf_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 );
 
             // compute extended pointer on page base 
-            xptr_t base_xp  = ppm_page2base( XPTR( page_cxy , page_ptr ) );
+            xptr_t base_xp  = ppm_page2base( page_xp );
 
             // file_size (in .elf mapper) can be smaller than vseg_size (BSS)
@@ -923,8 +1021,8 @@
             if( file_size < offset )                 // missing page fully in  BSS 
             {
-                vmm_dmsg("\n[DMSG] %s : core[%x,%d] for vpn = %x / fully in BSS\n",
-                __FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, vpn );
-
-                if( page_cxy == local_cxy )
+vmm_dmsg("\n[DBG] %s : core[%x,%d] for vpn = %x / fully in BSS\n",
+__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, vpn );
+
+                if( GET_CXY( page_xp ) == local_cxy )
                 {
                     memset( GET_PTR( base_xp ) , 0 , CONFIG_PPM_PAGE_SIZE );
@@ -937,6 +1035,7 @@
             else if( file_size >= (offset + CONFIG_PPM_PAGE_SIZE) )  // fully in  mapper
             {
-                vmm_dmsg("\n[DMSG] %s : core[%x,%d] for vpn = %x / fully in mapper\n",
-                __FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, vpn );
+
+vmm_dmsg("\n[DBG] %s : core[%x,%d] for vpn = %x / fully in mapper\n",
+__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, vpn );
 
                 if( mapper_cxy == local_cxy ) 
@@ -965,8 +1064,9 @@
                   // - (page_size + offset - file_size) bytes from BSS
             {
-                vmm_dmsg("\n[DMSG] %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,
-                file_size - offset , offset + CONFIG_PPM_PAGE_SIZE - file_size  );
+
+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,
+file_size - offset , offset + CONFIG_PPM_PAGE_SIZE - file_size  );
 
                 // initialize mapper part
@@ -993,5 +1093,5 @@
 
                 // initialize BSS part
-                if( page_cxy == local_cxy )
+                if( GET_CXY( page_xp ) == local_cxy )
                 {
                     memset( GET_PTR( base_xp ) + file_size - offset , 0 , 
@@ -1008,8 +1108,8 @@
 
     // return ppn
-    *ppn = ppm_page2ppn( XPTR( page_cxy , page_ptr ) );
-
-    vmm_dmsg("\n[DMSG] %s : core[%x,%d] exit for vpn = %x / ppn = %x\n",
-    __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , *ppn );
+    *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 );
 
     return 0;
@@ -1020,10 +1120,14 @@
 error_t vmm_get_pte( process_t * process,
                      vpn_t       vpn,
-                     uint32_t  * ret_attr,
-                     ppn_t     * ret_ppn )
-{
-    vseg_t  * vseg;   // pointer on vseg containing VPN
-    ppn_t     ppn;    // physical page number
-    uint32_t  attr;   // attributes from GPT entry
+                     bool_t      cow,
+                     uint32_t  * attr,
+                     ppn_t     * ppn )
+{
+    vseg_t  * vseg;       // pointer on vseg containing VPN
+    ppn_t     old_ppn;    // current PTE_PPN
+    uint32_t  old_attr;   // current PTE_ATTR
+    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;
 
@@ -1032,68 +1136,119 @@
     "not called in the reference cluster\n" );
 
-    vmm_dmsg("\n[DMSG] %s : core[%x,%d] enter for vpn = %x in process %x\n",
-    __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , process->pid );
+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);
 
     // get VMM pointer
     vmm_t * vmm = &process->vmm;
 
-    // access GPT to get PTE attributes and PPN
-    hal_gpt_get_pte( &vmm->gpt , vpn , &attr , &ppn );
-
-    // if PTE is unmapped
-    // 1) get VSEG containing the missing VPN
-    // 2) get & initialize physical page (depending on vseg type),
-    // 3) register the PTE in reference GPT 
-    if( (attr & GPT_MAPPED) == 0 )
-    {
-        vmm_dmsg("\n[DMSG] %s : core[%x,%d] page %x unmapped => try to map it\n",
-        __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn );
-
-        // 1. get vseg pointer
-        error = vmm_get_vseg( process , vpn<<CONFIG_PPM_PAGE_SHIFT , &vseg );
+    // get vseg pointer from ref VSL
+    error = vmm_get_vseg( process , vpn<<CONFIG_PPM_PAGE_SHIFT , &vseg );
+
+    if( error )
+    {
+        printk("\n[ERROR] in %s : out of segment / process = %x / vpn = %x\n",
+        __FUNCTION__ , process->pid , vpn );
+        return error;
+    }
+
+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 );
+
+    // access GPT to get current PTE attributes and PPN
+    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
+
+    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",
+__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 ) 
+        {
+            printk("\n[ERROR] in %s : no memory / process = %x / vpn = %x\n",
+            __FUNCTION__ , process->pid , vpn );
+            return ENOMEM;
+        }
+
+        // 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 )
         {
-            printk("\n[ERROR] in %s : out of segment / process = %x / vpn = %x\n",
-                   __FUNCTION__ , process->pid , vpn );
+            printk("\n[ERROR] in %s : cannot update GPT / process = %x / vpn = %x\n",
+            __FUNCTION__ , process->pid , vpn );
             return error;
         }
-
-        vmm_dmsg("\n[DMSG] %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 );
-
-        // 2. get physical page number, depending on vseg type
-        error = vmm_get_one_ppn( vseg , vpn , &ppn );
-
-        if( error )
+    }
+    else                    //////////////////// page_fault request ///////////
+    {  
+        if( (old_attr & GPT_MAPPED) == 0 )    // PTE unmapped in ref GPT
         {
-            printk("\n[ERROR] in %s : cannot allocate memory / process = %x / vpn = %x\n",
-                   __FUNCTION__ , process->pid , vpn );
-            return error;
+
+vmm_dmsg("\n[DBG] %s : core[%x,%d] page %x unmapped => try to map it\n",
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn );
+
+            // allocate one physical page, 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;
+            }
+
+            // define attributes from vseg flags 
+            new_attr = GPT_MAPPED | GPT_SMALL;
+            if( vseg->flags & VSEG_USER  ) new_attr |= GPT_USER;
+            if( vseg->flags & VSEG_WRITE ) new_attr |= GPT_WRITABLE;
+            if( vseg->flags & VSEG_EXEC  ) new_attr |= GPT_EXECUTABLE;
+            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 );
+
+            if( error )
+            {
+                printk("\n[ERROR] in %s : cannot update GPT / process = %x / vpn = %x\n",
+                __FUNCTION__ , process->pid , vpn );
+                return error;
+            }
         }
-
-        // 3. define attributes from vseg flags and register in GPT
-        attr = GPT_MAPPED | GPT_SMALL;
-        if( vseg->flags & VSEG_USER  ) attr |= GPT_USER;
-        if( vseg->flags & VSEG_WRITE ) attr |= GPT_WRITABLE;
-        if( vseg->flags & VSEG_EXEC  ) attr |= GPT_EXECUTABLE;
-        if( vseg->flags & VSEG_CACHE ) attr |= GPT_CACHABLE;
-
-        error = hal_gpt_set_pte( &vmm->gpt , vpn , ppn , attr );
-
-        if( error )
+        else
         {
-            printk("\n[ERROR] in %s : cannot register PTE / process = %x / vpn = %x\n",
-                   __FUNCTION__ , process->pid , vpn );
-            return error;
+            new_attr = old_attr;
+            new_ppn  = old_ppn;
         }
-    }  // end new PTE
-
-    vmm_dmsg("\n[DMSG] %s : core[%x,%d] exit for vpn = %x / ppn = %x\n",
-    __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , ppn );
-
-    *ret_ppn  = ppn;
-    *ret_attr = attr;
+    }
+
+vmm_dmsg("\n[DBG] %s : core[%x,%d] exit for vpn = %x / ppn = %x / attr = %x\n",
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , new_ppn , new_attr );
+
+    *ppn  = new_ppn;
+    *attr = new_attr;
     return 0;
 
@@ -1106,5 +1261,5 @@
     uint32_t         attr;          // missing page attributes
     ppn_t            ppn;           // missing page PPN
-    error_t          error;         // return value
+    error_t          error;
 
     // get reference process cluster and local pointer
@@ -1113,11 +1268,27 @@
 
     // get missing PTE attributes and PPN from reference cluster
-    if( local_cxy != ref_cxy )   // local cluster is not the reference cluster
-    {
-        rpc_vmm_get_pte_client( ref_cxy , ref_ptr , vpn , &attr , &ppn , &error );
-    }
-    else                              // local cluster is the reference cluster
-    {
-        error = vmm_get_pte( process , vpn , &attr , &ppn );
+    if( local_cxy != ref_cxy )  
+    {
+        rpc_vmm_get_pte_client( ref_cxy,
+                                ref_ptr,
+                                vpn,
+                                false,    // page_fault
+                                &attr,
+                                &ppn,
+                                &error );
+
+        // get local VMM pointer
+        vmm_t * vmm = &process->vmm;
+
+        // update local GPT
+        error |= hal_gpt_set_pte( &vmm->gpt , vpn , ppn , attr );
+    }
+    else   // local cluster is the reference cluster
+    {
+        error = vmm_get_pte( process,
+                             vpn,
+                             false,      // page-fault
+                             &attr,
+                             &ppn );
     }
 
@@ -1126,4 +1297,45 @@
 }  // end vmm_handle_page_fault()
 
+///////////////////////////////////////////////
+error_t vmm_copy_on_write( process_t * process,
+                           vpn_t       vpn )
+{
+    uint32_t         attr;          // missing page attributes
+    ppn_t            ppn;           // missing 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 );
+
+    // get new PTE attributes and PPN from reference cluster
+    if( local_cxy != ref_cxy )
+    {
+        rpc_vmm_get_pte_client( ref_cxy,
+                                ref_ptr,
+                                vpn,
+                                true,     // copy-on-write
+                                &attr,
+                                &ppn,
+                                &error );
+
+        // get local VMM pointer
+        vmm_t * vmm = &process->vmm;
+
+        // update local GPT
+        error |= hal_gpt_set_pte( &vmm->gpt , vpn , ppn , attr );
+    }
+    else   // local cluster is the reference cluster
+    {
+        error = vmm_get_pte( process,
+                             vpn,
+                             true,      // copy-on-write
+                             &attr,
+                             &ppn );
+    }
+
+    return error;
+
+}  // end vmm_copy_on_write()
 
 ///////////////////////////////////////////
@@ -1152,5 +1364,5 @@
     if( local_cxy == GET_CXY( process->ref_xp) ) // calling process is reference process
     {
-        error = vmm_get_pte( process, vpn , &attr , &ppn );
+        error = vmm_get_pte( process, vpn , false , &attr , &ppn );
     }
     else                                         // calling process is not reference process
@@ -1158,5 +1370,5 @@
         cxy_t       ref_cxy = GET_CXY( process->ref_xp );
         process_t * ref_ptr = (process_t *)GET_PTR( process->ref_xp );
-        rpc_vmm_get_pte_client( ref_cxy , ref_ptr , vpn , &attr , &ppn , &error );
+        rpc_vmm_get_pte_client( ref_cxy , ref_ptr , vpn , false , &attr , &ppn , &error );
     }
 
