Index: trunk/hal/tsar_mips32/core/hal_gpt.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_gpt.c	(revision 626)
+++ trunk/hal/tsar_mips32/core/hal_gpt.c	(revision 629)
@@ -38,18 +38,18 @@
 ////////////////////////////////////////////////////////////////////////////////////////
 
-#define TSAR_MMU_MAPPED         0x80000000 
-#define TSAR_MMU_SMALL          0x40000000 
-#define TSAR_MMU_LOCAL          0x20000000 
-#define TSAR_MMU_REMOTE         0x10000000 
-#define TSAR_MMU_CACHABLE       0x08000000 
-#define TSAR_MMU_WRITABLE       0x04000000 
-#define TSAR_MMU_EXECUTABLE     0x02000000 
-#define TSAR_MMU_USER           0x01000000 
-#define TSAR_MMU_GLOBAL         0x00800000 
-#define TSAR_MMU_DIRTY          0x00400000 
-
-#define TSAR_MMU_COW            0x00000001       // only for small pages
-#define TSAR_MMU_SWAP           0x00000004       // only for small pages
-#define TSAR_MMU_LOCKED         0x00000008       // only for small pages
+#define TSAR_PTE_MAPPED         0x80000000 
+#define TSAR_PTE_SMALL          0x40000000 
+#define TSAR_PTE_LOCAL          0x20000000 
+#define TSAR_PTE_REMOTE         0x10000000 
+#define TSAR_PTE_CACHABLE       0x08000000 
+#define TSAR_PTE_WRITABLE       0x04000000 
+#define TSAR_PTE_EXECUTABLE     0x02000000 
+#define TSAR_PTE_USER           0x01000000 
+#define TSAR_PTE_GLOBAL         0x00800000 
+#define TSAR_PTE_DIRTY          0x00400000 
+
+#define TSAR_PTE_COW            0x00000001       // only for small pages
+#define TSAR_PTE_SWAP           0x00000004       // only for small pages
+#define TSAR_PTE_LOCKED         0x00000008       // only for small pages
 
 ////////////////////////////////////////////////////////////////////////////////////////
@@ -85,16 +85,16 @@
     uint32_t tsar_attr = 0;
 
-    if( gpt_attr & GPT_MAPPED     ) tsar_attr |= TSAR_MMU_MAPPED;
-    if( gpt_attr & GPT_SMALL      ) tsar_attr |= TSAR_MMU_SMALL;
-    if( gpt_attr & GPT_WRITABLE   ) tsar_attr |= TSAR_MMU_WRITABLE;
-    if( gpt_attr & GPT_EXECUTABLE ) tsar_attr |= TSAR_MMU_EXECUTABLE;
-    if( gpt_attr & GPT_CACHABLE   ) tsar_attr |= TSAR_MMU_CACHABLE; 
-    if( gpt_attr & GPT_USER       ) tsar_attr |= TSAR_MMU_USER;
-    if( gpt_attr & GPT_DIRTY      ) tsar_attr |= TSAR_MMU_DIRTY;
-    if( gpt_attr & GPT_ACCESSED   ) tsar_attr |= TSAR_MMU_LOCAL;
-    if( gpt_attr & GPT_GLOBAL     ) tsar_attr |= TSAR_MMU_GLOBAL;
-    if( gpt_attr & GPT_COW        ) tsar_attr |= TSAR_MMU_COW;
-    if( gpt_attr & GPT_SWAP       ) tsar_attr |= TSAR_MMU_SWAP;
-    if( gpt_attr & GPT_LOCKED     ) tsar_attr |= TSAR_MMU_LOCKED;
+    if( gpt_attr & GPT_MAPPED     ) tsar_attr |= TSAR_PTE_MAPPED;
+    if( gpt_attr & GPT_SMALL      ) tsar_attr |= TSAR_PTE_SMALL;
+    if( gpt_attr & GPT_WRITABLE   ) tsar_attr |= TSAR_PTE_WRITABLE;
+    if( gpt_attr & GPT_EXECUTABLE ) tsar_attr |= TSAR_PTE_EXECUTABLE;
+    if( gpt_attr & GPT_CACHABLE   ) tsar_attr |= TSAR_PTE_CACHABLE; 
+    if( gpt_attr & GPT_USER       ) tsar_attr |= TSAR_PTE_USER;
+    if( gpt_attr & GPT_DIRTY      ) tsar_attr |= TSAR_PTE_DIRTY;
+    if( gpt_attr & GPT_ACCESSED   ) tsar_attr |= TSAR_PTE_LOCAL;
+    if( gpt_attr & GPT_GLOBAL     ) tsar_attr |= TSAR_PTE_GLOBAL;
+    if( gpt_attr & GPT_COW        ) tsar_attr |= TSAR_PTE_COW;
+    if( gpt_attr & GPT_SWAP       ) tsar_attr |= TSAR_PTE_SWAP;
+    if( gpt_attr & GPT_LOCKED     ) tsar_attr |= TSAR_PTE_LOCKED;
 
     return tsar_attr;
@@ -108,18 +108,18 @@
     uint32_t gpt_attr = 0;
 
-    if( tsar_attr & TSAR_MMU_MAPPED     ) gpt_attr |= GPT_MAPPED;
-    if( tsar_attr & TSAR_MMU_MAPPED     ) gpt_attr |= GPT_READABLE;
-    if( tsar_attr & TSAR_MMU_SMALL      ) gpt_attr |= GPT_SMALL;
-    if( tsar_attr & TSAR_MMU_WRITABLE   ) gpt_attr |= GPT_WRITABLE;
-    if( tsar_attr & TSAR_MMU_EXECUTABLE ) gpt_attr |= GPT_EXECUTABLE;
-    if( tsar_attr & TSAR_MMU_CACHABLE   ) gpt_attr |= GPT_CACHABLE; 
-    if( tsar_attr & TSAR_MMU_USER       ) gpt_attr |= GPT_USER;
-    if( tsar_attr & TSAR_MMU_DIRTY      ) gpt_attr |= GPT_DIRTY;
-    if( tsar_attr & TSAR_MMU_LOCAL      ) gpt_attr |= GPT_ACCESSED;
-    if( tsar_attr & TSAR_MMU_REMOTE     ) gpt_attr |= GPT_ACCESSED;
-    if( tsar_attr & TSAR_MMU_GLOBAL     ) gpt_attr |= GPT_GLOBAL;
-    if( tsar_attr & TSAR_MMU_COW        ) gpt_attr |= GPT_COW;
-    if( tsar_attr & TSAR_MMU_SWAP       ) gpt_attr |= GPT_SWAP;
-    if( tsar_attr & TSAR_MMU_LOCKED     ) gpt_attr |= GPT_LOCKED;
+    if( tsar_attr & TSAR_PTE_MAPPED     ) gpt_attr |= GPT_MAPPED;
+    if( tsar_attr & TSAR_PTE_MAPPED     ) gpt_attr |= GPT_READABLE;
+    if( tsar_attr & TSAR_PTE_SMALL      ) gpt_attr |= GPT_SMALL;
+    if( tsar_attr & TSAR_PTE_WRITABLE   ) gpt_attr |= GPT_WRITABLE;
+    if( tsar_attr & TSAR_PTE_EXECUTABLE ) gpt_attr |= GPT_EXECUTABLE;
+    if( tsar_attr & TSAR_PTE_CACHABLE   ) gpt_attr |= GPT_CACHABLE; 
+    if( tsar_attr & TSAR_PTE_USER       ) gpt_attr |= GPT_USER;
+    if( tsar_attr & TSAR_PTE_DIRTY      ) gpt_attr |= GPT_DIRTY;
+    if( tsar_attr & TSAR_PTE_LOCAL      ) gpt_attr |= GPT_ACCESSED;
+    if( tsar_attr & TSAR_PTE_REMOTE     ) gpt_attr |= GPT_ACCESSED;
+    if( tsar_attr & TSAR_PTE_GLOBAL     ) gpt_attr |= GPT_GLOBAL;
+    if( tsar_attr & TSAR_PTE_COW        ) gpt_attr |= GPT_COW;
+    if( tsar_attr & TSAR_PTE_SWAP       ) gpt_attr |= GPT_SWAP;
+    if( tsar_attr & TSAR_PTE_LOCKED     ) gpt_attr |= GPT_LOCKED;
 
     return gpt_attr;
@@ -184,7 +184,5 @@
     uint32_t   * pt2;
     uint32_t     attr;
-    vpn_t        vpn;      
 	kmem_req_t   req;
-    bool_t       is_ref;
 
 #if DEBUG_HAL_GPT_DESTROY
@@ -196,10 +194,4 @@
 #endif
 
-    // get pointer on calling process
-    process_t  * process = CURRENT_THREAD->process;
-
-    // compute is_ref 
-    is_ref = ( GET_CXY( process->ref_xp ) == local_cxy );
-
     // get pointer on PT1
     pt1 = (uint32_t *)gpt->ptr;
@@ -209,23 +201,13 @@
 	{
         pte1 = pt1[ix1];
-		if( (pte1 & TSAR_MMU_MAPPED) != 0 )  // PTE1 valid
+
+		if( (pte1 & TSAR_PTE_MAPPED) != 0 )  // PTE1 mapped
         {
-            if( (pte1 & TSAR_MMU_SMALL) == 0 )   // BIG page
+            if( (pte1 & TSAR_PTE_SMALL) == 0 )   // BIG page
             {
-                if( (pte1 & TSAR_MMU_USER) != 0 ) 
-                {
-                    // warning message
-                    printk("\n[WARNING] in %s : found an USER BIG page / ix1 = %d\n", 
-                    __FUNCTION__ , ix1 );
-
-                    // release the big physical page if reference cluster
-                    if( is_ref )
-                    {
-                        vpn = (vpn_t)(ix1 << TSAR_MMU_IX2_WIDTH);
-                        hal_gpt_reset_pte( gpt , vpn );
-                    }
-                }
+                printk("\n[WARNING] in %s : mapped big page / ix1 %x\n", 
+                __FUNCTION__ , ix1 );
             }
-            else                              // SMALL page
+            else                             // PT2 exist
             {
                 // get local pointer on PT2
@@ -234,20 +216,17 @@
                 pt2     = GET_PTR( base_xp );
 
-                // scan the PT2 to release all entries VALID and USER if reference cluster
-	            if( is_ref )
+                // scan the PT2 
+                for( ix2 = 0 ; ix2 < 512 ; ix2++ )
                 {
-                    for( ix2 = 0 ; ix2 < 512 ; ix2++ )
+                    attr = TSAR_MMU_ATTR_FROM_PTE2( pt2[2 * ix2] );
+
+                    if( (attr & TSAR_PTE_MAPPED) != 0 )  // PTE2 mapped
                     {
-                        attr = TSAR_MMU_ATTR_FROM_PTE2( pt2[2 * ix2] );
-		                if( ((attr & TSAR_MMU_MAPPED) != 0 ) && ((attr & TSAR_MMU_USER) != 0) )  
-                        {
-                            // release the physical page
-                            vpn = (vpn_t)((ix1 << TSAR_MMU_IX2_WIDTH) | ix2);
-                            hal_gpt_reset_pte( gpt , vpn );
-                        }
+                        printk("\n[WARNING] in %s : mapped small page / ix1 %x / ix2 %x\n", 
+                        __FUNCTION__ , ix1, ix2 );
                     }
                 }
 
-                // release the PT2
+                // release the page allocated for the PT2
                 req.type = KMEM_PAGE;
                 req.ptr  = GET_PTR( ppm_base2page( XPTR(local_cxy , pt2 ) ) );
@@ -271,6 +250,10 @@
 } // end hal_gpt_destroy()
 
-///////////////////////////////////////////
-void hal_gpt_display( process_t * process )
+/*
+
+/////////////////////////////////////////////////////////////////////////////////////
+// This static function can be used for debug.
+/////////////////////////////////////////////////////////////////////////////////////
+static void hal_gpt_display( process_t * process )
 {
     gpt_t    * gpt;
@@ -301,7 +284,7 @@
 	{
         pte1 = pt1[ix1];
-		if( (pte1 & TSAR_MMU_MAPPED) != 0 )
+		if( (pte1 & TSAR_PTE_MAPPED) != 0 )
         {
-            if( (pte1 & TSAR_MMU_SMALL) == 0 )  // BIG page
+            if( (pte1 & TSAR_PTE_SMALL) == 0 )  // BIG page
             {
                 vpn = ix1 << 9;
@@ -320,5 +303,5 @@
                     pte2_ppn  = TSAR_MMU_PPN_FROM_PTE2( pt2[2 * ix2 + 1] );
 
-		            if( (pte2_attr & TSAR_MMU_MAPPED) != 0 )
+		            if( (pte2_attr & TSAR_PTE_MAPPED) != 0 )
                     {
                         vpn = (ix1 << 9) | ix2;
@@ -332,88 +315,46 @@
 } // end hal_gpt_display()
 
-
-//////////////////////////////////////////
-error_t hal_gpt_set_pte( xptr_t    gpt_xp,
-                         vpn_t     vpn,
-                         uint32_t  attr,     // GPT attributes
-                         ppn_t     ppn )
-{
-    cxy_t               gpt_cxy;             // target GPT cluster
-    gpt_t             * gpt_ptr;             // target GPT local pointer
-    uint32_t          * pt1_ptr;             // local pointer on PT1
-	xptr_t              pte1_xp;             // extended pointer on PT1 entry
-	uint32_t            pte1;                // PT1 entry value if PTE1
-
-	ppn_t               pt2_ppn;             // PPN of PT2
-	uint32_t          * pt2_ptr;             // PT2 base address
-
-	uint32_t            small;               // requested PTE is for a small page
-
-	page_t            * page;                // pointer on new physical page descriptor
-    xptr_t              page_xp;             // extended pointer on new page descriptor
-
-    uint32_t            ix1;                 // index in PT1
-    uint32_t            ix2;                 // index in PT2
-
-    uint32_t            tsar_attr;           // PTE attributes for TSAR MMU
-
-    thread_t * this = CURRENT_THREAD;
-
-    // get cluster and local pointer on GPT
-    gpt_cxy = GET_CXY( gpt_xp );
-    gpt_ptr = GET_PTR( gpt_xp );
-
-#if DEBUG_HAL_GPT_SET_PTE
-uint32_t cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_HAL_GPT_SET_PTE < cycle )
-printk("\n[%s] : thread[%x,%x] enter / vpn %x / attr %x / ppn %x / cluster %x / cycle %d\n", 
-__FUNCTION__, this->process->pid, this->trdid, vpn, attr, ppn, gpt_cxy, cycle );
-#endif
-
-    // compute indexes in PT1 and PT2
-    ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
-    ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
-
-    pt1_ptr = hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
-	small   = attr & GPT_SMALL;
-
-    // compute tsar attributes from generic attributes
-    tsar_attr = gpt2tsar( attr );
-
-    // build extended pointer on PTE1 = PT1[ix1]
-	pte1_xp = XPTR( gpt_cxy , &pt1_ptr[ix1] );
+*/
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// This static function check that a PTE1 entry, in the PT1 of a possibly remote GPT,
+// identified by the <pte1_xp> argument is mapped. If this entry is not mapped, 
+// it allocates a - local or remote - PT2, updates the PTE1 value in PT1, and
+// returns the PTE1 value in the <pte1> buffer.
+// It uses the TSR_MMU_LOCKED attribute in PTE1 to handle possible concurrent
+// mappings of the missing PTE1:
+// - If the PTE1 is unmapped and unlocked => it tries to atomically lock this PTE1,
+//   and map it if lock is successful.
+// - If the PTE1 is unmapped but locked => it poll the PTE1 value, unti the mapping
+//   is done by the other thread.
+// - If the PTE1 is already mapped => it does nothing
+// It returns an error if it cannot allocate memory fot a new PT2.
+/////////////////////////////////////////////////////////////////////////////////////////
+static error_t hal_gpt_allocate_pt2( xptr_t     pte1_xp,
+                                   uint32_t * pte1_value ) 
+{
+    cxy_t      gpt_cxy;     // target GPT cluster = GET_CXY( pte1_xp );
+    uint32_t   pte1;        // PTE1 value
+    ppn_t      pt2_ppn;     // PPN of page containing the new PT2
+    bool_t     atomic;
+    page_t   * page;
+    xptr_t     page_xp;
+
+    // get GPT cluster identifier
+    gpt_cxy = GET_CXY( pte1_xp );
 
     // get current pte1 value
     pte1 = hal_remote_l32( pte1_xp );
 
-	if( small == 0 )     // map a big page in PT1 
-    {
-
-// check PT1 entry not mapped
-assert( (pte1 == 0) , "try to set a big page in a mapped PT1 entry\n" );
-
-// check VPN aligned
-assert( (ix2 == 0) , "illegal vpn for a big page\n" );
-
-// check PPN aligned
-assert( ((ppn & 0x1FF) == 0) , "illegal ppn for a big page\n" );
-
-        // set the PTE1 value in PT1
-        pte1 = (tsar_attr  & TSAR_MMU_PTE1_ATTR_MASK) | ((ppn >> 9) & TSAR_MMU_PTE1_PPN_MASK);
-        hal_remote_s32( pte1_xp , pte1 );
-		hal_fence();
-
-#if DEBUG_HAL_GPT_SET_PTE
-if( DEBUG_HAL_GPT_SET_PTE < cycle )
-printk("\n[%s] : thread[%x,%x] map PTE1 / cxy %x / ix1 %x / pt1 %x / pte1 %x\n", 
-__FUNCTION__, this->process->pid, this->trdid, gpt_cxy, ix1, pt1_ptr, pte1 );
-#endif
-
-		return 0;
-	}
-    else                 // map a small page in PT1 & PT2
-    {
-        if( (pte1 & TSAR_MMU_MAPPED) == 0 )    // PT1 entry unmapped => map it
-        {
+    if( ((pte1 & TSAR_PTE_MAPPED) == 0) &&   // PTE1 unmapped and unlocked
+        ((pte1 & TSAR_PTE_LOCKED) == 0) )    // try to allocate a new PT2
+	{
+        // atomically lock the PTE1 to prevent concurrent PTE1 mappings
+        atomic = hal_remote_atomic_cas( pte1_xp,
+                                        pte1,
+                                        pte1 | TSAR_PTE_LOCKED );
+
+        if( atomic )  // PTE1 successfully locked
+		{
             // allocate one physical page for PT2
             if( gpt_cxy == local_cxy )
@@ -430,10 +371,5 @@
             }
 
-            if( page == NULL )
-            {
-                printk("\n[PANIC] in %s : no memory for GPT PT2 / process %x / cluster %x\n",
-                __FUNCTION__, this->process->pid, gpt_cxy );
-                return ENOMEM;
-            }
+            if( page == NULL ) return -1;
 
             // get the PT2 PPN
@@ -441,38 +377,302 @@
             pt2_ppn = ppm_page2ppn( page_xp );
 
-            // build PTD1 value
-            pte1 = TSAR_MMU_MAPPED | TSAR_MMU_SMALL | pt2_ppn;
+            // build  PTE1 value
+            pte1 = TSAR_PTE_MAPPED | TSAR_PTE_SMALL | pt2_ppn;
 
             // set the PTD1 value in PT1
             hal_remote_s32( pte1_xp , pte1 );
+            hal_fence();
+
+#if DEBUG_HAL_GPT_ALLOCATE_PT2
+thread_t * this  = CURRENT_THREAD;
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_HAL_GPT_ALLOCATE_PT2 < cycle )
+printk("\n[%s] : thread[%x,%x] map PTE1 / cxy %x / ix1 %d / pt1 %x / ptd1 %x\n", 
+__FUNCTION__, this->process->pid, this->trdid, gpt_cxy, ix1, pt1_ptr, pte1 );
+#endif
+        }
+        else
+        {
+            // poll PTE1 until mapped by another thread
+            while( (pte1 & TSAR_PTE_MAPPED) == 0 )  pte1 = hal_remote_l32( pte1_xp );
+        } 
+    }
+    else if( ((pte1 & TSAR_PTE_MAPPED) == 0) &&
+             ((pte1 & TSAR_PTE_LOCKED) != 0) )  
+    {
+        // poll PTE1 until mapped by another thread
+        while( (pte1 & TSAR_PTE_MAPPED) == 0 )  pte1 = hal_remote_l32( pte1_xp );
+	}
+    else                                   // PTE1 mapped => just use it
+    {
+
+#if DEBUG_HAL_GPT_ALLOCATE_PT2
+thread_t * this  = CURRENT_THREAD;
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_HAL_GPT_ALLOCATE_PT2 < cycle )
+printk("\n[%s] : thread[%x,%x] PTE1 mapped / cxy %x / ix1 %d / pt1 %x / ptd1 %x\n", 
+__FUNCTION__, this->process->pid, this->trdid, gpt_cxy, ix1, pt1_ptr, pte1 );
+#endif
+
+    }
+
+    *pte1_value = pte1;
+    return 0;
+
+}  // end hal_gpt_allocate_pt2
+
+
+
+
+////////////////////////////////////////////
+error_t hal_gpt_lock_pte( xptr_t     gpt_xp,
+                          vpn_t      vpn,
+                          uint32_t * attr,
+                          ppn_t    * ppn )
+{
+    error_t             error;
+    uint32_t          * pt1_ptr;         // local pointer on PT1 base 
+    xptr_t              pte1_xp;         // extended pointer on PT1[x1] entry
+	uint32_t            pte1;            // value of PT1[x1] entry
+
+	ppn_t               pt2_ppn;         // PPN of page containing PT2
+    uint32_t          * pt2_ptr;         // local pointer on PT2 base
+	xptr_t              pte2_attr_xp;    // extended pointer on PT2[ix2].attr
+    uint32_t            pte2_attr;       // PT2[ix2].attr current value   
+	xptr_t              pte2_ppn_xp;     // extended pointer on PT2[ix2].ppn
+    uint32_t            pte2_ppn;        // PT2[ix2].ppn current value   
+	bool_t              atomic;
+
+    // get cluster and local pointer on GPT
+    cxy_t   gpt_cxy = GET_CXY( gpt_xp );
+    gpt_t * gpt_ptr = GET_PTR( gpt_xp );
+
+    // get indexes in PTI & PT2
+    uint32_t  ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );    // index in PT1
+    uint32_t  ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );    // index in PT2
+
+    // get local pointer on PT1
+    pt1_ptr = hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
+
+    // build extended pointer on PTE1 == PT1[ix1]
+	pte1_xp = XPTR( gpt_cxy , &pt1_ptr[ix1] );
+
+    // get PTE1 value from PT1 
+    // allocate a new PT2 for this PTE1 if required
+    error = hal_gpt_allocate_pt2( pte1_xp , &pte1 );
+
+    if( error )
+    {
+        printk("\n[ERROR] in %s : cannot allocate memory for PT2\n", __FUNCTION__ );
+        return -1;
+    }
+
+    if( (pte1 & TSAR_PTE_SMALL) == 0 )
+    {
+        printk("\n[ERROR] in %s : cannot lock a small page\n", __FUNCTION__ );
+        return -1;
+    }
+
+    // get pointer on PT2 base from PTE1 
+	pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
+	pt2_ptr = GET_PTR( ppm_ppn2base( pt2_ppn ) );
+
+    // build extended pointers on PT2[ix2].attr and PT2[ix2].ppn 
+    pte2_attr_xp = XPTR( gpt_cxy , &pt2_ptr[2 * ix2] );
+    pte2_ppn_xp  = XPTR( gpt_cxy , &pt2_ptr[2 * ix2 + 1] );
+ 
+    // wait until PTE2 unlocked, get PTE2.attr and set lock
+    do
+    {
+        // busy waiting until TSAR_MMU_LOCK == 0
+        do
+		{
+			pte2_attr = hal_remote_l32( pte2_attr_xp );
+		}
+        while( (pte2_attr & TSAR_PTE_LOCKED) != 0 );
+
+        // try to atomically set the TSAR_MMU_LOCK attribute    
+		atomic = hal_remote_atomic_cas( pte2_attr_xp,
+                                        pte2_attr,
+                                        (pte2_attr | TSAR_PTE_LOCKED) );
+	}
+    while( atomic == 0 );
+
+    // get PTE2.ppn
+    pte2_ppn = hal_remote_l32( pte2_ppn_xp );
+
+#if DEBUG_HAL_GPT_LOCK_PTE
+thread_t * this  = CURRENT_THREAD;
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_HAL_GPT_LOCK_PTE < cycle )
+printk("\n[%s] : thread[%x,%x] locks vpn %x / attr %x / ppn %x / cluster %x / cycle %d\n", 
+__FUNCTION__, this->process->pid, this->trdid, vpn, attr, ppn, gpt_cxy, cycle );
+#endif
+    
+    // return PPN and GPT attributes
+    *ppn  = hal_remote_l32( pte2_ppn_xp ) & ((1<<TSAR_MMU_PPN_WIDTH)-1);
+    *attr = tsar2gpt( pte2_attr );
+	return 0;
+
+}  // end hal_gpt_lock_pte()
+
+////////////////////////////////////////
+void hal_gpt_unlock_pte( xptr_t  gpt_xp,
+                         vpn_t   vpn )
+{
+    uint32_t * pt1_ptr;         // local pointer on PT1 base
+    xptr_t     pte1_xp;         // extended pointer on PT1[ix1]
+	uint32_t   pte1;            // value of PT1[ix1] entry
+
+	ppn_t      pt2_ppn;         // PPN of page containing PT2
+    uint32_t * pt2_ptr;         // PT2 base address
+	uint32_t   pte2_attr_xp;    // extended pointer on PT2[ix2].attr
+
+	uint32_t   attr;            // PTE2 attribute
+
+    // get cluster and local pointer on GPT
+    cxy_t   gpt_cxy = GET_CXY( gpt_xp );
+    gpt_t * gpt_ptr = GET_PTR( gpt_xp );
+
+    // compute indexes in P1 and PT2
+    uint32_t  ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );    // index in PT1
+    uint32_t  ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );    // index in PT2
+
+    // get local pointer on PT1
+    pt1_ptr = hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
+
+    // build extended pointer on PTE1 == PT1[ix1]
+	pte1_xp = XPTR( gpt_cxy , &pt1_ptr[ix1] );
+
+    // get current pte1 value
+    pte1 = hal_remote_l32( pte1_xp );
+
+// check PTE1 attributes
+assert( (((pte1 & TSAR_PTE_MAPPED) != 0) && ((pte1 & TSAR_PTE_SMALL) != 0)),
+"try to unlock a big or unmapped PTE1\n");
+
+    // get pointer on PT2 base from PTE1 
+	pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
+	pt2_ptr = GET_PTR( ppm_ppn2base( pt2_ppn ) );
+
+    // build extended pointers on PT2[ix2].attr  
+    pte2_attr_xp = XPTR( gpt_cxy , &pt2_ptr[2 * ix2] );
+
+    // get PT2[ix2].attr
+    attr = hal_remote_l32( pte2_attr_xp );
+
+    // reset TSAR_MMU_LOCK attribute
+    hal_remote_s32( pte2_attr_xp , attr & ~TSAR_PTE_LOCKED );
+
+#if DEBUG_HAL_GPT_LOCK_PTE
+thread_t * this  = CURRENT_THREAD;
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_HAL_GPT_LOCK_PTE < cycle )
+printk("\n[%s] : thread[%x,%x] unlocks vpn %x / attr %x / ppn %x / cluster %x / cycle %d\n", 
+__FUNCTION__, this->process->pid, this->trdid, vpn, attr, ppn, gpt_cxy, cycle );
+#endif
+  
+}  // end hal_gpt_unlock_pte()
+
+///////////////////////////////////////
+void hal_gpt_set_pte( xptr_t    gpt_xp,
+                      vpn_t     vpn,
+                      uint32_t  attr,  
+                      ppn_t     ppn )
+{
+    cxy_t               gpt_cxy;             // target GPT cluster
+    gpt_t             * gpt_ptr;             // target GPT local pointer
+
+    uint32_t          * pt1_ptr;             // local pointer on PT1 base
+	xptr_t              pte1_xp;             // extended pointer on PT1 entry
+	uint32_t            pte1;                // PT1 entry value if PTE1
+
+	ppn_t               pt2_ppn;             // PPN of PT2
+	uint32_t          * pt2_ptr;             // local pointer on PT2 base
+    xptr_t              pte2_attr_xp;        // extended pointer on PT2[ix2].attr
+    xptr_t              pte2_ppn_xp;         // extended pointer on PT2[ix2].ppn
+    uint32_t            pte2_attr;           // current value of PT2[ix2].attr
+
+    uint32_t            ix1;                 // index in PT1
+    uint32_t            ix2;                 // index in PT2
+
+    uint32_t            tsar_attr;           // PTE attributes for TSAR MMU
+	uint32_t            small;               // requested PTE is for a small page
+
+    // get cluster and local pointer on GPT
+    gpt_cxy = GET_CXY( gpt_xp );
+    gpt_ptr = GET_PTR( gpt_xp );
+
+    // compute indexes in PT1 and PT2
+    ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
+    ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
+
+    pt1_ptr = hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
+	small   = attr & GPT_SMALL;
+
+    // compute tsar attributes from generic attributes
+    tsar_attr = gpt2tsar( attr );
+
+    // build extended pointer on PTE1 = PT1[ix1]
+	pte1_xp = XPTR( gpt_cxy , &pt1_ptr[ix1] );
+
+    // get current pte1 value
+    pte1 = hal_remote_l32( pte1_xp );
+
+	if( small == 0 )  ///////////////// map a big page in PT1 
+    {
+
+// check PT1 entry not mapped
+assert( (pte1 == 0) , "try to set a big page in an already mapped PTE1\n" );
+
+// check VPN aligned
+assert( (ix2 == 0) , "illegal vpn for a big page\n" );
+
+// check PPN aligned
+assert( ((ppn & 0x1FF) == 0) , "illegal ppn for a big page\n" );
+
+        // set the PTE1 value in PT1
+        pte1 = (tsar_attr  & TSAR_MMU_PTE1_ATTR_MASK) | ((ppn >> 9) & TSAR_MMU_PTE1_PPN_MASK);
+        hal_remote_s32( pte1_xp , pte1 );
+		hal_fence();
 
 #if DEBUG_HAL_GPT_SET_PTE
+thread_t * this  = CURRENT_THREAD;
+uint32_t   cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_HAL_GPT_SET_PTE < cycle )
-printk("\n[%s] : thread[%x,%x] map PTD1 / cxy %x / ix1 %d / pt1 %x / ptd1 %x\n", 
+printk("\n[%s] : thread[%x,%x] map PTE1 / cxy %x / ix1 %x / pt1 %x / pte1 %x\n", 
 __FUNCTION__, this->process->pid, this->trdid, gpt_cxy, ix1, pt1_ptr, pte1 );
 #endif
-        }
-        else                                   // pt1 entry mapped => use it
-        {
-
-#if DEBUG_HAL_GPT_SET_PTE
-if( DEBUG_HAL_GPT_SET_PTE < cycle )
-printk("\n[%s] : thread[%x,%x] get PTD1 / cxy %x / ix1 %d / pt1 %x / ptd1 %x\n", 
-__FUNCTION__, this->process->pid, this->trdid, gpt_cxy, ix1, pt1_ptr, pte1 );
-#endif
-
-        }
-
-        // get PT2 base from pte1 
+
+	}
+    else      ///////////////// map a small page in PT2
+    {
+
+// PTE1 must be mapped because PTE2 must be locked
+assert( (pte1 & TSAR_PTE_MAPPED), "PTE1 must be mapped\n" );
+
+        // get PT2 base from PTE1 
 	    pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
 	    pt2_ptr = GET_PTR( ppm_ppn2base( pt2_ppn ) );
 
+        // build extended pointers on PT2[ix2].attr and PT2[ix2].ppn
+        pte2_attr_xp = XPTR( gpt_cxy , &pt2_ptr[2 * ix2] );
+        pte2_ppn_xp  = XPTR( gpt_cxy , &pt2_ptr[2 * ix2 + 1] );
+
+        // get current value of PTE2.attr
+        pte2_attr = hal_remote_l32( pte2_attr_xp );
+
+// PTE2 must be locked
+assert( (pte2_attr & TSAR_PTE_LOCKED), "PTE2 must be locked\n" );
+ 
         // set PTE2 in PT2 (in this order)
-	    hal_remote_s32( XPTR( gpt_cxy , &pt2_ptr[2 * ix2 + 1] ) , ppn );
+	    hal_remote_s32( pte2_ppn_xp  , ppn );
 	    hal_fence();
-	    hal_remote_s32( XPTR( gpt_cxy , &pt2_ptr[2 * ix2] ) , tsar_attr );
+	    hal_remote_s32( pte2_attr_xp , tsar_attr );
 	    hal_fence();
 
 #if DEBUG_HAL_GPT_SET_PTE
+thread_t * this  = CURRENT_THREAD;
+uint32_t   cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_HAL_GPT_SET_PTE < cycle )
 printk("\n[%s] : thread[%x,%x] map PTE2 / cxy %x / ix2 %x / pt2 %x / attr %x / ppn %x\n", 
@@ -480,7 +680,91 @@
 #endif
 
-  	    return 0;
     }
 } // end of hal_gpt_set_pte()
+
+///////////////////////////////////////
+void hal_gpt_reset_pte( xptr_t  gpt_xp,
+                        vpn_t   vpn )
+{
+    cxy_t      gpt_cxy;        // target GPT cluster
+    gpt_t    * gpt_ptr;        // target GPT local pointer
+
+    uint32_t   ix1;            // index in PT1 
+    uint32_t   ix2;            // index in PT2
+
+    uint32_t * pt1_ptr;        // PT1 base address
+    xptr_t     pte1_xp;        // extended pointer on PT1[ix1]
+    uint32_t   pte1;           // PT1 entry value
+
+    ppn_t      pt2_ppn;        // PPN of PT2 
+    uint32_t * pt2_ptr;        // PT2 base address
+    xptr_t     pte2_attr_xp;   // extended pointer on PT2[ix2].attr
+    xptr_t     pte2_ppn_xp;    // extended pointer on PT2[ix2].ppn
+    uint32_t   pte2_attr;      // current value of PT2[ix2].attr
+
+    // get cluster and local pointer on GPT
+    gpt_cxy = GET_CXY( gpt_xp );
+    gpt_ptr = GET_PTR( gpt_xp );
+
+    // get ix1 & ix2 indexes
+    ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
+    ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
+
+    // get local pointer on PT1 base
+    pt1_ptr = hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
+
+    // build extended pointer on PTE1 = PT1[ix1]
+	pte1_xp = XPTR( gpt_cxy , &pt1_ptr[ix1] );
+
+    // get current PTE1 value
+    pte1 = hal_remote_l32( pte1_xp );
+
+	if( (pte1 & TSAR_PTE_MAPPED) == 0 )     // PTE1 unmapped => do nothing
+	{
+		return;
+	}
+
+	if( (pte1 & TSAR_PTE_SMALL) == 0 )      // it's a PTE1 => unmap it from PT1
+	{
+        hal_remote_s32( pte1_xp , 0 );
+	    hal_fence();
+
+#if DEBUG_HAL_GPT_RESET_PTE
+thread_t * this  = CURRENT_THREAD;
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_HAL_GPT_RESET_PTE < cycle )
+printk("\n[%s] : thread[%x,%x] unmap PTE1 / cxy %x / vpn %x / ix1 %x\n", 
+__FUNCTION__, this->process->pid, this->trdid, gpt_cxy, vpn, ix1 );
+#endif
+
+        return;
+	}
+    else                                    // it's a PTE2 => unmap it from PT2
+    {
+        // compute PT2 base address
+        pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
+        pt2_ptr = GET_PTR( ppm_ppn2base( pt2_ppn ) );
+        
+        // build extended pointer on PT2[ix2].attr and PT2[ix2].ppn
+        pte2_attr_xp = XPTR( gpt_cxy , &pt2_ptr[2 * ix2] );
+        pte2_ppn_xp  = XPTR( gpt_cxy , &pt2_ptr[2 * ix2 + 1] );
+
+        // unmap the PTE2
+        hal_remote_s32( pte2_attr_xp , 0 );
+	    hal_fence();        
+        hal_remote_s32( pte2_ppn_xp  , 0 );
+	    hal_fence();        
+
+#if DEBUG_HAL_GPT_RESET_PTE
+thread_t * this  = CURRENT_THREAD;
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_HAL_GPT_RESET_PTE < cycle )
+printk("\n[%s] : thread[%x,%x] unmap PTE2 / cxy %x / vpn %x / ix2 %x\n", 
+__FUNCTION__, this->process->pid, this->trdid, gpt_cxy, vpn, ix2 );
+#endif
+
+        return;
+    }
+}  // end hal_gpt_reset_pte()
 
 ////////////////////////////////////////
@@ -490,9 +774,13 @@
                       ppn_t    * ppn )
 {
-    uint32_t * pt1;
-    uint32_t   pte1;
-
-    uint32_t * pt2;
-    ppn_t      pt2_ppn;
+    uint32_t * pt1;            // local pointer on PT1 base
+    uint32_t   pte1;           // PTE1 value
+
+    uint32_t * pt2;            // local pointer on PT2 base
+    ppn_t      pt2_ppn;        // PPN of page containing the PT2
+    xptr_t     pte2_attr_xp;   // extended pointer on PT2[ix2].attr
+    xptr_t     pte2_ppn_xp;    // extended pointer on PT2[ix2].ppn
+    uint32_t   pte2_attr;      // current value of PT2[ix2].attr
+    ppn_t      pte2_ppn;       // current value of PT2[ix2].ppn 
 
     // get cluster and local pointer on GPT
@@ -505,5 +793,5 @@
 
     // get PT1 base
-    pt1 = (uint32_t *)hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
+    pt1 = hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
     
     // get pte1
@@ -511,5 +799,5 @@
 
     // check PTE1 mapped
-	if( (pte1 & TSAR_MMU_MAPPED) == 0 )   // PT1 entry not present
+	if( (pte1 & TSAR_PTE_MAPPED) == 0 )   // PTE1 unmapped
 	{
 		*attr = 0;
@@ -519,5 +807,5 @@
 
     // access GPT
-	if( (pte1 & TSAR_MMU_SMALL) == 0 )     // it's a PTE1
+	if( (pte1 & TSAR_PTE_SMALL) == 0 )     // it's a PTE1
 	{
         // get PPN & ATTR from PT1
@@ -525,5 +813,5 @@
         *ppn  = TSAR_MMU_PPN_FROM_PTE1( pte1 ) | (vpn & ((1<<TSAR_MMU_IX2_WIDTH)-1));
 	}
-    else                                  // it's a PTD1
+    else                                  // it's a PTE2
     {
         // compute PT2 base address
@@ -531,54 +819,301 @@
         pt2     = GET_PTR( ppm_ppn2base( pt2_ppn ) );
 
-        // get PPN & ATTR from PT2
-        *ppn  = hal_remote_l32( XPTR( gpt_cxy , &pt2[2*ix2+1] ) ) & ((1<<TSAR_MMU_PPN_WIDTH)-1);
-        *attr = tsar2gpt( hal_remote_l32( XPTR( gpt_cxy , &pt2[2*ix2] ) ) );
+        // build extended pointer on PT2[ix2].attr and PT2[ix2].ppn
+        pte2_attr_xp = XPTR( gpt_cxy , &pt2[2 * ix2] );
+        pte2_ppn_xp  = XPTR( gpt_cxy , &pt2[2 * ix2 + 1] );
+
+        // get current value of PTE2.attr & PTE2.ppn
+        pte2_attr = hal_remote_l32( pte2_attr_xp );
+        pte2_ppn  = hal_remote_l32( pte2_ppn_xp );
+
+        // return PPN & GPT attributes 
+        *ppn  = pte2_ppn & ((1<<TSAR_MMU_PPN_WIDTH)-1);
+        *attr = tsar2gpt( pte2_attr );
     }
 } // end hal_gpt_get_pte()
 
-////////////////////////////////////
-void hal_gpt_reset_pte( gpt_t * gpt,
-                        vpn_t   vpn )
-{
-    uint32_t * pt1;         // PT1 base address
-    uint32_t   pte1;        // PT1 entry value
-
-    ppn_t      pt2_ppn;     // PPN of PT2 
-    uint32_t * pt2;         // PT2 base address
-
-    // get ix1 & ix2 indexes
-    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 present
-	{
-		return;
-	}
-
-	if( (pte1 & TSAR_MMU_SMALL) == 0 )      // it's a PTE1
-	{
-        // unmap the big page
-        pt1[ix1] = 0;
-	    hal_fence();
-
-        return;
-	}
-    else                                   // it's a PTD1
-    {
-        // compute PT2 base address
-        pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
-        pt2     = GET_PTR( ppm_ppn2base( pt2_ppn ) );
+
+///////////////////////////////////////////
+error_t hal_gpt_pte_copy( gpt_t  * dst_gpt,
+                          vpn_t    dst_vpn,
+                          xptr_t   src_gpt_xp,
+                          vpn_t    src_vpn,
+                          bool_t   cow,
+                          ppn_t  * ppn,
+                          bool_t * mapped )
+{
+    uint32_t     src_ix1;   // index in SRC PT1
+    uint32_t     src_ix2;   // index in SRC PT2
+
+    uint32_t     dst_ix1;   // index in DST PT1
+    uint32_t     dst_ix2;   // index in DST PT2
+
+    cxy_t        src_cxy;   // SRC GPT cluster
+    gpt_t      * src_gpt;   // SRC GPT local pointer
+
+	uint32_t   * src_pt1;   // local pointer on SRC PT1 
+	uint32_t   * dst_pt1;   // local pointer on DST PT1
+    uint32_t   * src_pt2;   // local pointer on SRC PT2
+    uint32_t   * dst_pt2;   // local pointer on DST PT2
+
+	kmem_req_t   req;       // for PT2 allocation
+
+    uint32_t     src_pte1;
+    uint32_t     dst_pte1;
+
+    uint32_t     src_pte2_attr;
+    uint32_t     src_pte2_ppn;
+
+    page_t     * page;
+    xptr_t       page_xp;
+
+    ppn_t        src_pt2_ppn;
+    ppn_t        dst_pt2_ppn;
+
+    // get remote src_gpt cluster and local pointer
+    src_cxy = GET_CXY( src_gpt_xp );
+    src_gpt = GET_PTR( src_gpt_xp );
+
+#if DEBUG_HAL_GPT_COPY
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+thread_t * this  = CURRENT_THREAD;
+if( DEBUG_HAL_GPT_COPY < cycle )
+printk("\n[%s] : thread[%x,%x] enter / src_cxy %x / dst_cxy %x / cycle %d\n", 
+__FUNCTION__, this->process->pid, this->trdid, src_cxy, local_cxy, cycle );
+#endif
+
+    // get remote src_gpt cluster and local pointer
+    src_cxy = GET_CXY( src_gpt_xp );
+    src_gpt = GET_PTR( src_gpt_xp );
+
+    // get remote src_pt1 and local dst_pt1
+    src_pt1 = (uint32_t *)hal_remote_lpt( XPTR( src_cxy , &src_gpt->ptr ) );
+    dst_pt1 = (uint32_t *)dst_gpt->ptr;
+
+    // check src_pt1 and dst_pt1 existence
+    assert( (src_pt1 != NULL) , "src_pt1 does not exist\n");
+    assert( (dst_pt1 != NULL) , "dst_pt1 does not exist\n");
+
+    // compute SRC indexes
+    src_ix1 = TSAR_MMU_IX1_FROM_VPN( src_vpn );
+    src_ix2 = TSAR_MMU_IX2_FROM_VPN( src_vpn );
+
+    // compute DST indexes
+    dst_ix1 = TSAR_MMU_IX1_FROM_VPN( dst_vpn );
+    dst_ix2 = TSAR_MMU_IX2_FROM_VPN( dst_vpn );
+
+    // get src_pte1 
+    src_pte1 = hal_remote_l32( XPTR( src_cxy , &src_pt1[src_ix1] ) );
+
+    // do nothing if src_pte1 not MAPPED or not SMALL
+	if( (src_pte1 & TSAR_PTE_MAPPED) && (src_pte1 & TSAR_PTE_SMALL) )    
+    {
+        // get dst_pt1 entry
+        dst_pte1 = dst_pt1[dst_ix1];
+
+        // map dst_pte1 if required
+        if( (dst_pte1 & TSAR_PTE_MAPPED) == 0 ) 
+        { 
+            // allocate one physical page for a new 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 -1;
+            }
+
+            // build extended pointer on page descriptor
+            page_xp = XPTR( local_cxy , page );
+
+            // get PPN for this new PT2 
+            dst_pt2_ppn = (ppn_t)ppm_page2ppn( page_xp );
+
+            // build the new dst_pte1
+            dst_pte1 = TSAR_PTE_MAPPED | TSAR_PTE_SMALL | dst_pt2_ppn;
+
+            // register it in DST_GPT
+            dst_pt1[dst_ix1] = dst_pte1;
+        }
+
+        // get pointer on src_pt2
+        src_pt2_ppn = (ppn_t)TSAR_MMU_PTBA_FROM_PTE1( src_pte1 );
+        src_pt2     = GET_PTR( ppm_ppn2base( src_pt2_ppn ) );
+
+        // get pointer on dst_pt2
+        dst_pt2_ppn = (ppn_t)TSAR_MMU_PTBA_FROM_PTE1( dst_pte1 );
+        dst_pt2     = GET_PTR( ppm_ppn2base( dst_pt2_ppn ) );
+
+        // get attr and ppn from SRC_PT2
+        src_pte2_attr = hal_remote_l32( XPTR( src_cxy , &src_pt2[2 * src_ix2]     ) );
+        src_pte2_ppn  = hal_remote_l32( XPTR( src_cxy , &src_pt2[2 * src_ix2 + 1] ) );
+
+        // do nothing if src_pte2 not MAPPED
+        if( (src_pte2_attr & TSAR_PTE_MAPPED) != 0 )  
+        {
+            // set PPN in DST PTE2
+            dst_pt2[2 * dst_ix2 + 1] = src_pte2_ppn;
+                        
+            // set attributes in DST PTE2         
+            if( cow && (src_pte2_attr & TSAR_PTE_WRITABLE) ) 
+            {
+                dst_pt2[2 * dst_ix2] = (src_pte2_attr | TSAR_PTE_COW) & (~TSAR_PTE_WRITABLE);
+            } 
+            else
+            {
+                dst_pt2[2 * dst_ix2] = src_pte2_attr;
+            }
+
+            // return "successfully copied"
+            *mapped = true;
+            *ppn    = src_pte2_ppn;
         
-        // unmap the small page
-	    pt2[2*ix2]   = 0;          
-	    hal_fence();        
-
-        return;
-    }
-}  // end hal_gpt_reset_pte()
+#if DEBUG_HAL_GPT_COPY
+cycle = (uint32_t)hal_get_cycles;
+if( DEBUG_HAL_GPT_COPY < cycle )
+printk("\n[%s] : thread[%x,%x] exit / copy done for src_vpn %x / dst_vpn %x / cycle %d\n", 
+__FUNCTION__, this->process->pid, this->trdid, src_vpn, dst_vpn, cycle );
+#endif
+
+            hal_fence();
+
+            return 0;
+        }   // end if PTE2 mapped
+    }   // end if PTE1 mapped
+
+    // return "nothing done"
+    *mapped = false;
+    *ppn    = 0;
+   
+#if DEBUG_HAL_GPT_COPY
+cycle = (uint32_t)hal_get_cycles;
+if( DEBUG_HAL_GPT_COPY < cycle )
+printk("\n[%s] : thread[%x,%x] exit / nothing done / cycle %d\n", 
+__FUNCTION__, this->process->pid, this->trdid, cycle );
+#endif
+
+    hal_fence();
+
+    return 0;
+
+}  // end hal_gpt_pte_copy()
+
+/////////////////////////////////////////
+void hal_gpt_set_cow( xptr_t  gpt_xp,
+                      vpn_t   vpn_base,
+                      vpn_t   vpn_size )
+{
+    cxy_t      gpt_cxy;
+    gpt_t    * gpt_ptr;
+
+    vpn_t      vpn;
+
+    uint32_t   ix1;
+    uint32_t   ix2;
+
+    uint32_t * pt1;
+    uint32_t   pte1;
+
+    uint32_t * pt2;
+    ppn_t      pt2_ppn;
+    uint32_t   attr;
+
+    // get GPT cluster and local pointer
+    gpt_cxy = GET_CXY( gpt_xp );
+    gpt_ptr = GET_PTR( gpt_xp );
+
+    // get local PT1 pointer
+    pt1 = (uint32_t *)hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
+
+    // loop on pages
+    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 PTE1 value
+        pte1 = hal_remote_l32( XPTR( gpt_cxy , &pt1[ix1] ) );
+
+        // only MAPPED & SMALL PTEs are modified
+	    if( (pte1 & TSAR_PTE_MAPPED) && (pte1 & TSAR_PTE_SMALL) )
+        {
+            // compute PT2 base address
+            pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
+            pt2     = GET_PTR( ppm_ppn2base( pt2_ppn ) );
+
+            assert( (GET_CXY( ppm_ppn2base( pt2_ppn ) ) == gpt_cxy ),
+            "PT2 and PT1 must be in the same cluster\n");
+  
+            // get current PTE2 attributes
+            attr = hal_remote_l32( XPTR( gpt_cxy , &pt2[2*ix2] ) );
+
+            // only MAPPED PTEs are modified        
+            if( attr & TSAR_PTE_MAPPED ) 
+            {
+                attr = (attr | TSAR_PTE_COW) & (~TSAR_PTE_WRITABLE);
+                hal_remote_s32( XPTR( gpt_cxy , &pt2[2*ix2] ) , attr );
+            } 
+        } 
+    }   // end loop on pages
+
+}  // end hal_gpt_set_cow()
+
+//////////////////////////////////////////
+void hal_gpt_update_pte( xptr_t    gpt_xp,
+                         vpn_t     vpn,
+                         uint32_t  attr,     // generic GPT attributes
+                         ppn_t     ppn )
+{
+    uint32_t          * pt1;                 // PT1 base addres
+	uint32_t            pte1;                // PT1 entry value
+
+	ppn_t               pt2_ppn;             // PPN of PT2
+	uint32_t          * pt2;                 // PT2 base address
+
+    uint32_t            ix1;                 // index in PT1
+    uint32_t            ix2;                 // index in PT2
+
+    uint32_t            tsar_attr;           // PTE attributes for TSAR MMU
+
+    // check attr argument MAPPED and SMALL 
+    if( (attr & GPT_MAPPED) == 0 )  return;
+    if( (attr & GPT_SMALL ) == 0 )  return;
+
+    // get cluster and local pointer on remote GPT
+    cxy_t   gpt_cxy = GET_CXY( gpt_xp );
+    gpt_t * gpt_ptr = GET_PTR( gpt_xp );
+
+    // compute indexes in PT1 and PT2
+    ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
+    ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
+
+    // get PT1 base
+    pt1 = (uint32_t *)hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
+
+    // compute tsar_attr from generic attributes
+    tsar_attr = gpt2tsar( attr );
+
+    // get PTE1 value
+    pte1 = hal_remote_l32( XPTR( gpt_cxy , &pt1[ix1] ) );
+
+    if( (pte1 & TSAR_PTE_MAPPED) == 0 ) return;
+    if( (pte1 & TSAR_PTE_SMALL ) == 0 ) return;
+
+    // get PT2 base from PTE1 
+    pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
+    pt2     = GET_PTR( ppm_ppn2base( pt2_ppn ) );
+
+    // set PTE2 in this order
+	hal_remote_s32( XPTR( gpt_cxy, &pt2[2 * ix2 + 1] ) , ppn );
+	hal_fence();
+	hal_remote_s32( XPTR( gpt_cxy, &pt2[2 * ix2]     ) , tsar_attr );
+	hal_fence();
+
+} // end hal_gpt_update_pte()
+
+
 
 
@@ -616,10 +1151,10 @@
         pte1 = pt1[ix1]
 
-	    if( (pte1 & TSAR_MMU_MAPPED) == 0 )     // PT1[ix1] unmapped 
+	    if( (pte1 & TSAR_PTE_MAPPED) == 0 )     // PT1[ix1] unmapped 
         {
             // update vpn (next big page)
             (vpn = ix1 + 1) << 9;
         }
-	    if( (pte1 & TSAR_MMU_SMALL) == 0 )      // it's a PTE1 (big page)
+	    if( (pte1 & TSAR_PTE_SMALL) == 0 )      // it's a PTE1 (big page)
 	    {
             // unmap the big page
@@ -650,524 +1185,3 @@
 */
 
-//////////////////////////////////////
-error_t hal_gpt_lock_pte( gpt_t * gpt,
-                          vpn_t   vpn )
-{
-    uint32_t          * pt1;             // PT1 base address
-	volatile uint32_t * pte1_ptr;        // address of PT1 entry
-	uint32_t            pte1;            // value of PT1 entry
-
-    uint32_t          * pt2;             // PT2 base address
-	ppn_t               pt2_ppn;         // PPN of PT2 page if missing PT2
-	volatile uint32_t * pte2_ptr;        // address of PT2 entry
-
-	uint32_t            attr;
-	bool_t              atomic;
-    page_t            * page;
-    xptr_t              page_xp;
-
-    uint32_t  ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );    // index in PT1
-    uint32_t  ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );    // index in PT2
-
-    // get the PTE1 value
-    pt1       = gpt->ptr; 
-	pte1_ptr  = &pt1[ix1];
-	pte1      = *pte1_ptr;
-
-    // If present, the page must be small
-	if( ((pte1 & TSAR_MMU_MAPPED) != 0) && ((pte1 & TSAR_MMU_SMALL) == 0) )
-    {
-        printk("\n[ERROR] in %s : try to lock a big page / PT1[%d] = %x\n",
-               __FUNCTION__ , ix1 , pte1 );
-		return EINVAL;
-    }
-
-	if( (pte1 & TSAR_MMU_MAPPED) == 0 )  // missing PT1 entry   
-	{
-        // allocate one physical page for PT2
-	    kmem_req_t req;
-	    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 : try to set a small page but cannot allocate PT2\n",
-                      __FUNCTION__ );
-            return ENOMEM;
-        }
-
-        page_xp = XPTR( local_cxy , page );
-        pt2_ppn = ppm_page2ppn( page_xp );
-        pt2     = GET_PTR( ppm_page2base( page_xp ) );
-
-        // try to set the PT1 entry
-		do 
-		{
-			atomic = hal_atomic_cas( (void*)pte1_ptr , 0 , 
-                                     TSAR_MMU_MAPPED | TSAR_MMU_SMALL | pt2_ppn );
-		} 
-        while( (atomic == false) && (*pte1_ptr == 0) );
-
-		if( atomic == false )  // missing PT2 has been allocate by another core
-		{
-            // release the allocated page
-			ppm_free_pages( page );
-
-            // read again the PTE1	
-			pte1 = *pte1_ptr;
-
-            // get the PT2 base address
-			pt2_ppn = TSAR_MMU_PPN_FROM_PTE1( pte1 );
- 			pt2     = GET_PTR( ppm_ppn2base( pt2_ppn ) );
-		}
-	}
-    else
-    {
-        // This valid entry must be a PTD1
-        if( (pte1 & TSAR_MMU_SMALL) == 0 )
-        {
-			printk("\n[ERROR] in %s : set a small page in a big PT1 entry / PT1[%d] = %x\n",
-                    __FUNCTION__ , ix1 , pte1 );
-            return EINVAL;
-        }
-
-        // compute PPN of PT2 base
-		pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
-
-        // compute pointer on PT2 base
-	    pt2 = GET_PTR( ppm_ppn2base( pt2_ppn ) );
-    }
-    
-    // from here we have the PT2 pointer
-    
-    // compute pointer on PTE2
-    pte2_ptr = &pt2[2 * ix2];
-
-    // try to atomically lock the PTE2 until success
-	do
-    {
-        // busy waiting until TSAR_MMU_LOCK == 0
-        do
-		{
-			attr = *pte2_ptr;
-			hal_rdbar();
-		}
-        while( (attr & TSAR_MMU_LOCKED) != 0 );
-
-		atomic = hal_atomic_cas( (void*)pte2_ptr, attr , (attr | TSAR_MMU_LOCKED) );
-	}
-    while( atomic == 0 );
-
-	return 0;
-
-}  // end hal_gpt_lock_pte()
-
-////////////////////////////////////////
-error_t hal_gpt_unlock_pte( gpt_t * gpt,
-                            vpn_t   vpn )
-{
-    uint32_t * pt1;             // PT1 base address
-	uint32_t   pte1;            // value of PT1 entry
-
-    uint32_t * pt2;             // PT2 base address
-	ppn_t      pt2_ppn;         // PPN of PT2 page if missing PT2
-	uint32_t * pte2_ptr;        // address of PT2 entry
-
-	uint32_t   attr;            // PTE2 attribute
-
-    // compute indexes in P1 and PT2
-    uint32_t  ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );    // index in PT1
-    uint32_t  ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );    // index in PT2
-
-    // get pointer on PT1 base
-    pt1  = (uint32_t*)gpt->ptr;
-
-    // get PTE1
-    pte1 = pt1[ix1];
-
-    // check PTE1 present and small page
-    if( ((pte1 & TSAR_MMU_MAPPED) == 0) || ((pte1 & TSAR_MMU_SMALL) == 0) )
-    {
-        printk("\n[ERROR] in %s : try to unlock a big or undefined page / PT1[%d] = %x\n",
-                 __FUNCTION__ , ix1 , pte1 );
-        return EINVAL;
-    }
-
-    // get pointer on PT2 base
-    pt2_ppn = TSAR_MMU_PPN_FROM_PTE1( pte1 );
-    pt2     = GET_PTR( ppm_ppn2base( pt2_ppn ) );
- 
-    // get pointer on PTE2
-	pte2_ptr = &pt2[2 * ix2];
-
-    // get PTE2_ATTR
-	attr = *pte2_ptr;
-
-    // check PTE2 present and locked
-    if( ((attr & TSAR_MMU_MAPPED) == 0) || ((attr & TSAR_MMU_LOCKED) == 0) )
-    {
-        printk("\n[ERROR] in %s : unlock an unlocked/unmapped page / PT1[%d] = %x\n",
-                 __FUNCTION__ , ix1 , pte1 );
-        return EINVAL;
-    }
-
-    // reset GPT_LOCK
-	*pte2_ptr = attr & ~TSAR_MMU_LOCKED;
-
-	return 0;
-
-}  // end hal_gpt_unlock_pte()
-
-///////////////////////////////////////////
-error_t hal_gpt_pte_copy( gpt_t  * dst_gpt,
-                          vpn_t    dst_vpn,
-                          xptr_t   src_gpt_xp,
-                          vpn_t    src_vpn,
-                          bool_t   cow,
-                          ppn_t  * ppn,
-                          bool_t * mapped )
-{
-    uint32_t     src_ix1;   // index in SRC PT1
-    uint32_t     src_ix2;   // index in SRC PT2
-
-    uint32_t     dst_ix1;   // index in DST PT1
-    uint32_t     dst_ix2;   // index in DST PT2
-
-    cxy_t        src_cxy;   // SRC GPT cluster
-    gpt_t      * src_gpt;   // SRC GPT local pointer
-
-	uint32_t   * src_pt1;   // local pointer on SRC PT1 
-	uint32_t   * dst_pt1;   // local pointer on DST PT1
-    uint32_t   * src_pt2;   // local pointer on SRC PT2
-    uint32_t   * dst_pt2;   // local pointer on DST PT2
-
-	kmem_req_t   req;       // for PT2 allocation
-
-    uint32_t     src_pte1;
-    uint32_t     dst_pte1;
-
-    uint32_t     src_pte2_attr;
-    uint32_t     src_pte2_ppn;
-
-    page_t     * page;
-    xptr_t       page_xp;
-
-    ppn_t        src_pt2_ppn;
-    ppn_t        dst_pt2_ppn;
-
-    // get remote src_gpt cluster and local pointer
-    src_cxy = GET_CXY( src_gpt_xp );
-    src_gpt = GET_PTR( src_gpt_xp );
-
-#if DEBUG_HAL_GPT_COPY
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-thread_t * this  = CURRENT_THREAD;
-if( DEBUG_HAL_GPT_COPY < cycle )
-printk("\n[%s] : thread[%x,%x] enter / src_cxy %x / dst_cxy %x / cycle %d\n", 
-__FUNCTION__, this->process->pid, this->trdid, src_cxy, local_cxy, cycle );
-#endif
-
-    // get remote src_gpt cluster and local pointer
-    src_cxy = GET_CXY( src_gpt_xp );
-    src_gpt = GET_PTR( src_gpt_xp );
-
-    // get remote src_pt1 and local dst_pt1
-    src_pt1 = (uint32_t *)hal_remote_lpt( XPTR( src_cxy , &src_gpt->ptr ) );
-    dst_pt1 = (uint32_t *)dst_gpt->ptr;
-
-    // check src_pt1 and dst_pt1 existence
-    assert( (src_pt1 != NULL) , "src_pt1 does not exist\n");
-    assert( (dst_pt1 != NULL) , "dst_pt1 does not exist\n");
-
-    // compute SRC indexes
-    src_ix1 = TSAR_MMU_IX1_FROM_VPN( src_vpn );
-    src_ix2 = TSAR_MMU_IX2_FROM_VPN( src_vpn );
-
-    // compute DST indexes
-    dst_ix1 = TSAR_MMU_IX1_FROM_VPN( dst_vpn );
-    dst_ix2 = TSAR_MMU_IX2_FROM_VPN( dst_vpn );
-
-    // get src_pte1 
-    src_pte1 = hal_remote_l32( XPTR( src_cxy , &src_pt1[src_ix1] ) );
-
-    // do nothing if src_pte1 not MAPPED or not SMALL
-	if( (src_pte1 & TSAR_MMU_MAPPED) && (src_pte1 & TSAR_MMU_SMALL) )    
-    {
-        // get dst_pt1 entry
-        dst_pte1 = dst_pt1[dst_ix1];
-
-        // map dst_pte1 if required
-        if( (dst_pte1 & TSAR_MMU_MAPPED) == 0 ) 
-        { 
-            // allocate one physical page for a new 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 -1;
-            }
-
-            // build extended pointer on page descriptor
-            page_xp = XPTR( local_cxy , page );
-
-            // get PPN for this new 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[dst_ix1] = dst_pte1;
-        }
-
-        // get pointer on src_pt2
-        src_pt2_ppn = (ppn_t)TSAR_MMU_PTBA_FROM_PTE1( src_pte1 );
-        src_pt2     = GET_PTR( ppm_ppn2base( src_pt2_ppn ) );
-
-        // get pointer on dst_pt2
-        dst_pt2_ppn = (ppn_t)TSAR_MMU_PTBA_FROM_PTE1( dst_pte1 );
-        dst_pt2     = GET_PTR( ppm_ppn2base( dst_pt2_ppn ) );
-
-        // get attr and ppn from SRC_PT2
-        src_pte2_attr = hal_remote_l32( XPTR( src_cxy , &src_pt2[2 * src_ix2]     ) );
-        src_pte2_ppn  = hal_remote_l32( XPTR( src_cxy , &src_pt2[2 * src_ix2 + 1] ) );
-
-        // do nothing if src_pte2 not MAPPED
-        if( (src_pte2_attr & TSAR_MMU_MAPPED) != 0 )  
-        {
-            // set PPN in DST PTE2
-            dst_pt2[2 * dst_ix2 + 1] = src_pte2_ppn;
-                        
-            // set attributes in DST PTE2         
-            if( cow && (src_pte2_attr & TSAR_MMU_WRITABLE) ) 
-            {
-                dst_pt2[2 * dst_ix2] = (src_pte2_attr | TSAR_MMU_COW) & (~TSAR_MMU_WRITABLE);
-            } 
-            else
-            {
-                dst_pt2[2 * dst_ix2] = src_pte2_attr;
-            }
-
-            // return "successfully copied"
-            *mapped = true;
-            *ppn    = src_pte2_ppn;
-        
-#if DEBUG_HAL_GPT_COPY
-cycle = (uint32_t)hal_get_cycles;
-if( DEBUG_HAL_GPT_COPY < cycle )
-printk("\n[%s] : thread[%x,%x] exit / copy done for src_vpn %x / dst_vpn %x / cycle %d\n", 
-__FUNCTION__, this->process->pid, this->trdid, src_vpn, dst_vpn, cycle );
-#endif
-
-            hal_fence();
-
-            return 0;
-        }   // end if PTE2 mapped
-    }   // end if PTE1 mapped
-
-    // return "nothing done"
-    *mapped = false;
-    *ppn    = 0;
-   
-#if DEBUG_HAL_GPT_COPY
-cycle = (uint32_t)hal_get_cycles;
-if( DEBUG_HAL_GPT_COPY < cycle )
-printk("\n[%s] : thread[%x,%x] exit / nothing done / cycle %d\n", 
-__FUNCTION__, this->process->pid, this->trdid, cycle );
-#endif
-
-    hal_fence();
-
-    return 0;
-
-}  // end hal_gpt_pte_copy()
-
-//////////////////////////////////////////
-bool_t hal_gpt_pte_is_mapped( gpt_t * gpt,
-                              vpn_t   vpn )
-{
-    uint32_t * pt1;
-    uint32_t   pte1;
-    uint32_t   pte2_attr;
-
-    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 ) return false;
-
-	if( (pte1 & TSAR_MMU_SMALL) == 0 ) return false; 
-
-    // compute PT2 base address
-    pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
-    pt2     = GET_PTR( ppm_ppn2base( pt2_ppn ) );
-
-    // get pte2_attr
-    pte2_attr = pt2[2*ix2];
-
-    if( (pte2_attr & TSAR_MMU_MAPPED) == 0 ) return false;
-    else                                     return true;
-
-}   // end hal_gpt_pte_is_mapped()
-
-///////////////////////////////////////
-bool_t hal_gpt_pte_is_cow( gpt_t * gpt,
-                           vpn_t   vpn )
-{
-    uint32_t * pt1;
-    uint32_t   pte1;
-    uint32_t   pte2_attr;
-
-    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 ) return false;
-
-	if( (pte1 & TSAR_MMU_SMALL) == 0 ) return false;
-
-    // compute PT2 base address
-    pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
-    pt2     = GET_PTR( ppm_ppn2base( pt2_ppn ) );
-
-    // get pte2_attr
-    pte2_attr = pt2[2*ix2];
-
-    if( (pte2_attr & TSAR_MMU_MAPPED) == 0 ) return false;
-
-    if( (pte2_attr & TSAR_MMU_COW)    == 0 ) return false;
-    else                                     return true;
-
-}   // end hal_gpt_pte_is_cow()
-
-/////////////////////////////////////////
-void hal_gpt_set_cow( xptr_t  gpt_xp,
-                      vpn_t   vpn_base,
-                      vpn_t   vpn_size )
-{
-    cxy_t      gpt_cxy;
-    gpt_t    * gpt_ptr;
-
-    vpn_t      vpn;
-
-    uint32_t   ix1;
-    uint32_t   ix2;
-
-    uint32_t * pt1;
-    uint32_t   pte1;
-
-    uint32_t * pt2;
-    ppn_t      pt2_ppn;
-    uint32_t   attr;
-
-    // get GPT cluster and local pointer
-    gpt_cxy = GET_CXY( gpt_xp );
-    gpt_ptr = GET_PTR( gpt_xp );
-
-    // get local PT1 pointer
-    pt1 = (uint32_t *)hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
-
-    // loop on pages
-    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 PTE1 value
-        pte1 = hal_remote_l32( XPTR( gpt_cxy , &pt1[ix1] ) );
-
-        // only MAPPED & SMALL PTEs are modified
-	    if( (pte1 & TSAR_MMU_MAPPED) && (pte1 & TSAR_MMU_SMALL) )
-        {
-            // compute PT2 base address
-            pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
-            pt2     = GET_PTR( ppm_ppn2base( pt2_ppn ) );
-
-            assert( (GET_CXY( ppm_ppn2base( pt2_ppn ) ) == gpt_cxy ),
-            "PT2 and PT1 must be in the same cluster\n");
-  
-            // get current PTE2 attributes
-            attr = hal_remote_l32( XPTR( gpt_cxy , &pt2[2*ix2] ) );
-
-            // only MAPPED PTEs are modified        
-            if( attr & TSAR_MMU_MAPPED ) 
-            {
-                attr = (attr | TSAR_MMU_COW) & (~TSAR_MMU_WRITABLE);
-                hal_remote_s32( XPTR( gpt_cxy , &pt2[2*ix2] ) , attr );
-            } 
-        } 
-    }   // end loop on pages
-
-}  // end hal_gpt_set_cow()
-
-//////////////////////////////////////////
-void hal_gpt_update_pte( xptr_t    gpt_xp,
-                         vpn_t     vpn,
-                         uint32_t  attr,     // generic GPT attributes
-                         ppn_t     ppn )
-{
-    uint32_t          * pt1;                 // PT1 base addres
-	uint32_t            pte1;                // PT1 entry value
-
-	ppn_t               pt2_ppn;             // PPN of PT2
-	uint32_t          * pt2;                 // PT2 base address
-
-    uint32_t            ix1;                 // index in PT1
-    uint32_t            ix2;                 // index in PT2
-
-    uint32_t            tsar_attr;           // PTE attributes for TSAR MMU
-
-    // check attr argument MAPPED and SMALL 
-    if( (attr & GPT_MAPPED) == 0 )  return;
-    if( (attr & GPT_SMALL ) == 0 )  return;
-
-    // get cluster and local pointer on remote GPT
-    cxy_t   gpt_cxy = GET_CXY( gpt_xp );
-    gpt_t * gpt_ptr = GET_PTR( gpt_xp );
-
-    // compute indexes in PT1 and PT2
-    ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
-    ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
-
-    // get PT1 base
-    pt1 = (uint32_t *)hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
-
-    // compute tsar_attr from generic attributes
-    tsar_attr = gpt2tsar( attr );
-
-    // get PTE1 value
-    pte1 = hal_remote_l32( XPTR( gpt_cxy , &pt1[ix1] ) );
-
-    if( (pte1 & TSAR_MMU_MAPPED) == 0 ) return;
-    if( (pte1 & TSAR_MMU_SMALL ) == 0 ) return;
-
-    // get PT2 base from PTE1 
-    pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
-    pt2     = GET_PTR( ppm_ppn2base( pt2_ppn ) );
-
-    // set PTE2 in this order
-	hal_remote_s32( XPTR( gpt_cxy, &pt2[2 * ix2 + 1] ) , ppn );
-	hal_fence();
-	hal_remote_s32( XPTR( gpt_cxy, &pt2[2 * ix2]     ) , tsar_attr );
-	hal_fence();
-
-} // end hal_gpt_update_pte()
-
+
Index: trunk/hal/tsar_mips32/core/hal_vmm.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_vmm.c	(revision 626)
+++ trunk/hal/tsar_mips32/core/hal_vmm.c	(revision 629)
@@ -81,13 +81,6 @@
     uint32_t ppn  = cxy << 20;    
 
-    // register PTE1  in slot[0] of kernel GPT
-    error = hal_gpt_set_pte( XPTR( cxy , gpt ) , 0 , attr , ppn );
-
-    if( error )
-    {
-        printk("\n[PANIC] in %s : cannot initialize kernel GPT in cluster %x\n",
-        __FUNCTION__ , cxy );
-        hal_core_sleep();
-    }
+    // set PT1[0]
+    hal_gpt_set_pte( XPTR( cxy , gpt ) , 0 , attr , ppn );
 
 #if DEBUG_HAL_VMM
@@ -159,12 +152,5 @@
 
     // update user GPT : set PTE1 in slot[0]
-    error = hal_gpt_set_pte( u_gpt_xp , 0 , attr , ppn );
-
-    if( error )
-    {
-        printk("\n[ERROR] in %s : cannot update user GPT in cluster %x\n",
-        __FUNCTION__ , cxy );
-        return -1;
-    }
+    hal_gpt_set_pte( u_gpt_xp , 0 , attr , ppn );
 
 #if DEBUG_HAL_VMM
@@ -220,8 +206,7 @@
     chdev_t * txt0_ptr = GET_PTR( txt0_xp );
 
-    // build extended pointers on TXT0 lock, GPT lock and VSL lock
+    // build extended pointer on TXT0 lock and VSL lock
     xptr_t  txt_lock_xp = XPTR( txt0_cxy  , &txt0_ptr->wait_lock );
     xptr_t  vsl_lock_xp = XPTR( local_cxy , &vmm->vsl_lock );
-    xptr_t  gpt_lock_xp = XPTR( local_cxy , &vmm->gpt_lock );
 
     // get root of vsegs list
@@ -230,5 +215,4 @@
     // get the locks protecting TXT0, VSL, and GPT
     remote_rwlock_rd_acquire( vsl_lock_xp );
-    remote_rwlock_rd_acquire( gpt_lock_xp );
     remote_busylock_acquire( txt_lock_xp );
 
@@ -291,5 +275,4 @@
     // release locks
     remote_busylock_release( txt_lock_xp );
-    remote_rwlock_rd_release( gpt_lock_xp );
     remote_rwlock_rd_release( vsl_lock_xp );
 
