Index: trunk/hal/tsar_mips32/core/hal_gpt.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_gpt.c	(revision 406)
+++ trunk/hal/tsar_mips32/core/hal_gpt.c	(revision 407)
@@ -135,6 +135,6 @@
     uint32_t   attr;
 
-    gpt_dmsg("\n[DMSG] %s : core[%x,%d] enter\n", 
-    __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid );
+gpt_dmsg("\n[DBG] %s : core[%x,%d] enter\n", 
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid );
 
     // check page size
@@ -157,8 +157,6 @@
     // initialize generic page table descriptor
     page_xp   = XPTR( local_cxy , page );
-
 	gpt->ptr  = GET_PTR( ppm_page2base( page_xp ) );
 	gpt->ppn  = ppm_page2ppn( page_xp );
-	gpt->page = GET_PTR( page_xp );
 
     // identity map the kentry_vseg (must exist for all processes)
@@ -167,5 +165,6 @@
          vpn < (CONFIG_VMM_KENTRY_BASE + CONFIG_VMM_KENTRY_SIZE); vpn++ )
     {
-        gpt_dmsg("\n[DMSG] %s : identity map vpn %d\n", __FUNCTION__ , vpn );
+
+gpt_dmsg("\n[DBG] %s : identity map vpn %d\n", __FUNCTION__ , vpn );
 
         error = hal_gpt_set_pte( gpt,
@@ -181,6 +180,6 @@
     }
 
-    gpt_dmsg("\n[DMSG] %s : core[%x,%d] exit\n",
-    __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid );
+gpt_dmsg("\n[DBG] %s : core[%x,%d] exit\n",
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid );
 
 	return 0;
@@ -271,8 +270,8 @@
 } // end hal_gpt_destroy()
 
-////////////////////////////////
-void hal_gpt_print( gpt_t * gpt,
-                    pid_t   pid )
-{
+///////////////////////////////////////////
+void hal_gpt_display( process_t * process )
+{
+    gpt_t    * gpt;
 	uint32_t   ix1;
 	uint32_t   ix2;
@@ -285,9 +284,14 @@
     vpn_t      vpn;
 
-
+    assert( (process != NULL) , __FUNCTION__ , "NULL process pointer\n");
+
+    // get pointer on gpt
+    gpt = &(process->vmm.gpt);
+
+    // get pointer on PT1 
     pt1 = (uint32_t *)gpt->ptr;
 
     printk("\n***** Generic Page Table for process %x : &gpt = %x / &pt1 = %x\n\n",
-    pid , gpt , pt1 );
+    process->pid , gpt , pt1 );
 
     // scan the PT1
@@ -324,5 +328,5 @@
         }
 	}
-} // end hal_gpt_print()
+} // end hal_gpt_display()
 
 
@@ -351,5 +355,5 @@
     uint32_t            tsar_attr;           // PTE attributes for TSAR MMU
 
-    gpt_dmsg("\n[DMSG] %s : core[%x,%d] enter for vpn = %x / ppn = %x / gpt_attr = %x\n", 
+    gpt_dmsg("\n[DBG] %s : core[%x,%d] enter for vpn = %x / ppn = %x / gpt_attr = %x\n", 
     __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , ppn , attr );
  
@@ -364,5 +368,5 @@
     tsar_attr = gpt2tsar( attr );
 
-    gpt_dmsg("\n[DMSG] %s : core[%x,%d] / vpn = %x / &pt1 = %x / tsar_attr = %x\n", 
+    gpt_dmsg("\n[DBG] %s : core[%x,%d] / vpn = %x / &pt1 = %x / tsar_attr = %x\n", 
     __FUNCTION__, local_cxy , CURRENT_THREAD->core->lid , vpn , pt1 , tsar_attr );
 
@@ -396,5 +400,5 @@
         pte1 = *pte1_ptr;
         
-        gpt_dmsg("\n[DMSG] %s : core[%x,%d] / vpn = %x / current_pte1 = %x\n", 
+        gpt_dmsg("\n[DBG] %s : core[%x,%d] / vpn = %x / current_pte1 = %x\n", 
         __FUNCTION__, local_cxy , CURRENT_THREAD->core->lid , vpn , pte1 );
         
@@ -438,5 +442,5 @@
 	    pt2     = (uint32_t *)GET_PTR( ppm_ppn2base( pt2_ppn ) );
 
-        gpt_dmsg("\n[DMSG] %s : core[%x,%d] / vpn = %x / pte1 = %x / &pt2 = %x\n", 
+        gpt_dmsg("\n[DBG] %s : core[%x,%d] / vpn = %x / pte1 = %x / &pt2 = %x\n", 
         __FUNCTION__, local_cxy , CURRENT_THREAD->core->lid , vpn , pte1 , pt2 );
         
@@ -450,5 +454,5 @@
 	hal_fence();
 
-    gpt_dmsg("\n[DMSG] %s : core[%x,%d] exit / vpn = %x / pte2_attr = %x / pte2_ppn = %x\n", 
+    gpt_dmsg("\n[DBG] %s : core[%x,%d] exit / vpn = %x / pte2_attr = %x / pte2_ppn = %x\n", 
     __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , 
     pt2[2 * ix2] , pt2[2 * ix2 + 1] );
@@ -727,6 +731,10 @@
 error_t hal_gpt_copy( gpt_t  * dst_gpt,
                       gpt_t  * src_gpt,
+                      vpn_t    vpn_base,
+                      vpn_t    vpn_size,
                       bool_t   cow )
 {
+    vpn_t        vpn;       // current vpn
+
     uint32_t     ix1;       // index in PT1
     uint32_t     ix2;       // index in PT2
@@ -737,8 +745,11 @@
     uint32_t   * src_pt2;   // local pointer on PT2 for SRC_GPT
 
-    uint32_t     pte1;
+	kmem_req_t   req;       // for dynamic PT2 allocation
+
+    uint32_t     src_pte1;
+    uint32_t     dst_pte1;
+
     uint32_t     pte2_attr;
     uint32_t     pte2_ppn;
-    uint32_t     pte2_writable;
 
     page_t     * page;
@@ -748,8 +759,158 @@
     ppn_t        dst_pt2_ppn;
 
-    // get pointers on PT1 for src_gpt & dst_gpt
+gpt_dmsg("\n[DBG] %s : core[%x,%d] enter\n", 
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid );
+
+    // check page size
+    assert( (CONFIG_PPM_PAGE_SIZE == 4096) , __FUNCTION__ ,
+    "for TSAR, the page must be 4 Kbytes\n" );
+
+    // check SRC_PT1 and DST_PT1 existence
+    assert( (src_gpt->ptr != NULL) , __FUNCTION__ , "SRC_PT1 does not exist\n");
+    assert( (dst_gpt->ptr != NULL) , __FUNCTION__ , "DST_PT1 does not exist\n");
+
+    // get pointers on SRC_PT1 and DST_PT1
     src_pt1 = (uint32_t *)src_gpt->ptr;
     dst_pt1 = (uint32_t *)dst_gpt->ptr;
 
+    // scan pages in vseg
+    for( vpn = vpn_base ; vpn < (vpn_base + vpn_size) ; vpn++ )
+    {
+        ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
+        ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
+
+        // get SRC_PT1 entry
+        src_pte1 = src_pt1[ix1];
+
+        // do nothing if SRC_PTE1 unmapped
+		if( (src_pte1 & TSAR_MMU_MAPPED) != 0 )   // SRC_PTE1 is mapped 
+        {
+            assert( (src_pte1 & TSAR_MMU_SMALL) , __FUNCTION__ ,
+            "no BIG page for user process in TSAR architecture\n" );
+
+            // get DST_PT1 entry
+            dst_pte1 = dst_pt1[ix1];
+
+            // map dst_pte1 if required
+            if( (dst_pte1 & TSAR_MMU_MAPPED) == 0 ) 
+            { 
+                // allocate one physical page for a new DST_PT2
+	            req.type  = KMEM_PAGE;
+	            req.size  = 0;                     // 1 small page 
+	            req.flags = AF_KERNEL | AF_ZERO;
+	            page = (page_t *)kmem_alloc( &req );
+
+                if( page == NULL )
+                {
+			        printk("\n[ERROR] in %s : cannot allocate PT2\n", __FUNCTION__ );
+                    return ENOMEM;
+                }
+
+                // build extended pointer on page descriptor
+                page_xp = XPTR( local_cxy , page );
+
+                // get PPN for this new DST_PT2 
+                dst_pt2_ppn    = (ppn_t)ppm_page2ppn( page_xp );
+
+                // build the new dst_pte1
+                dst_pte1 = TSAR_MMU_MAPPED | TSAR_MMU_SMALL | dst_pt2_ppn;
+
+                // register it in DST_GPT
+                dst_pt1[ix1] = dst_pte1;
+            }
+
+            // get PPN and pointer on SRC_PT2
+            src_pt2_ppn = (ppn_t)TSAR_MMU_PTBA_FROM_PTE1( src_pte1 );
+            src_pt2     = (uint32_t *)GET_PTR( ppm_ppn2base( src_pt2_ppn ) );
+
+            // get PPN and pointer on DST_PT2
+            dst_pt2_ppn = (ppn_t)TSAR_MMU_PTBA_FROM_PTE1( dst_pte1 );
+            dst_pt2     = (uint32_t *)GET_PTR( ppm_ppn2base( dst_pt2_ppn ) );
+
+            // get attr and ppn from SRC_PT2
+            pte2_attr = TSAR_MMU_ATTR_FROM_PTE2( src_pt2[2 * ix2] );
+            pte2_ppn  = TSAR_MMU_PPN_FROM_PTE2(  src_pt2[2 * ix2 + 1] );
+
+            // no copy if SRC_PTE2 unmapped
+            if( (pte2_attr & TSAR_MMU_MAPPED) != 0 )  // valid PTE2 in SRC_GPT
+            {
+                // set a new PTE2 in DST_PT2
+                dst_pt2[2*ix2]     = pte2_attr;
+                dst_pt2[2*ix2 + 1] = pte2_ppn;
+                        
+                // FIXME increment page descriptor refcount for the referenced page
+
+                // handle Copy-On-Write 
+                if( cow && (pte2_attr & TSAR_MMU_WRITABLE) )
+                {
+                    // reset WRITABLE flag in DST_GPT
+                    hal_atomic_and( &dst_pt2[2*ix2] , ~TSAR_MMU_WRITABLE );
+
+                    // set COW flag in DST_GPT
+                    hal_atomic_or( &dst_pt2[2*ix2] , TSAR_MMU_COW );
+                }
+            }
+        }   // end if PTE1 mapped
+    }   // end loop on vpn
+
+    hal_fence();
+
+gpt_dmsg("\n[DBG] %s : core[%x,%d] exit\n", 
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid );
+
+    return 0;
+
+}  // end hal_gpt_copy()
+
+///////////////////////////////////////
+bool_t hal_gpt_pte_is_cow( gpt_t * gpt,
+                           vpn_t   vpn )
+{
+    uint32_t * pt1;
+    uint32_t   pte1;
+
+    uint32_t * pt2;
+    ppn_t      pt2_ppn;
+
+    uint32_t   ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
+    uint32_t   ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
+
+    // get PTE1 value
+	pt1  = gpt->ptr;
+    pte1 = pt1[ix1];
+
+	if( (pte1 & TSAR_MMU_MAPPED) == 0 )    // PT1 entry not mapped
+	{
+		return false;
+	}
+
+	if( (pte1 & TSAR_MMU_SMALL) == 0 )     // it's a PTE1
+	{
+		return false;
+	}
+    else                                   // it's a PTD1
+    {
+        // compute PT2 base address
+        pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
+        pt2     = (uint32_t*)GET_PTR( ppm_ppn2base( pt2_ppn ) );
+
+        if( pt2[2*ix2] & TSAR_MMU_COW ) return true;
+        else                            return false;
+    }
+}   // end hal_gpt_pte_is_cow()
+
+
+
+
+
+
+
+
+
+
+
+
+/* deprecated : old hal_gpt_copy [AG]
+ 
     // scan the SRC_PT1
 	for( ix1 = 0 ; ix1 < 2048 ; ix1++ )
@@ -834,2 +995,3 @@
 }  // end hal_gpt_copy()
 
+*/
