Index: trunk/hal/tsar_mips32/core/hal_context.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_context.c	(revision 634)
+++ trunk/hal/tsar_mips32/core/hal_context.c	(revision 635)
@@ -2,5 +2,5 @@
  * hal_context.c - implementation of Thread Context API for TSAR-MIPS32
  * 
- * Author  Alain Greiner    (2016)
+ * Author  Alain Greiner    (2016,2017,2018,2019)
  *
  * Copyright (c)  UPMC Sorbonne Universites
@@ -30,4 +30,5 @@
 #include <printk.h>
 #include <vmm.h>
+#include <bits.h>
 #include <core.h>
 #include <cluster.h>
@@ -36,5 +37,5 @@
 
 /////////////////////////////////////////////////////////////////////////////////////////
-//       Define various SR initialisation values for TSAR-MIPS32 
+//       Define various SR initialisation values for the TSAR-MIPS32 architecture.
 /////////////////////////////////////////////////////////////////////////////////////////
 
@@ -44,5 +45,5 @@
 
 /////////////////////////////////////////////////////////////////////////////////////////
-// This structure defines the CPU context for TSAR MIPS32.
+// This structure defines the CPU context for the TSAR-MIPS32 architecture.
 // The following registers are saved/restored at each context switch:
 // - GPR : all, but (zero, k0, k1), plus (hi, lo)
@@ -51,5 +52,5 @@
 //
 // WARNING : check the two CONFIG_CPU_CTX_SIZE & CONFIG_FPU_CTX_SIZE configuration 
-//           parameterss when modifying this structure.
+//           parameters when modifying this structure.
 /////////////////////////////////////////////////////////////////////////////////////////
 
@@ -101,5 +102,5 @@
 
 /////////////////////////////////////////////////////////////////////////////////////////
-// This structure defines the fpu_context for TSAR MIPS32.
+// This structure defines the fpu_context for the TSAR MIPS32 architecture.
 /////////////////////////////////////////////////////////////////////////////////////////
 
@@ -124,8 +125,10 @@
     // allocate memory for cpu_context
     kmem_req_t  req;
-    req.type   = KMEM_CPU_CTX;
+    req.type   = KMEM_KCM;
+    req.order  = bits_log2( sizeof(hal_cpu_context_t) );
     req.flags  = AF_KERNEL | AF_ZERO;
 
-    hal_cpu_context_t * context = (hal_cpu_context_t *)kmem_alloc( &req );
+    hal_cpu_context_t * context = kmem_alloc( &req );
+
     if( context == NULL ) return -1;
 
@@ -175,34 +178,52 @@
 void hal_cpu_context_fork( xptr_t child_xp )
 {
-    // get pointer on calling thread
-    thread_t * this = CURRENT_THREAD;
-
+    cxy_t               parent_cxy;        // parent thread cluster
+    thread_t          * parent_ptr;        // local pointer on parent thread
+    hal_cpu_context_t * parent_context;    // local pointer on parent cpu_context
+    uint32_t          * parent_uzone;      // local_pointer on parent uzone (in kernel stack)
+    char              * parent_ksp;        // kernel stack pointer on parent kernel stack
+    uint32_t            parent_us_base;    // parent user stack base value
+
+    cxy_t               child_cxy;         // parent thread cluster
+    thread_t          * child_ptr;         // local pointer on child thread
+    hal_cpu_context_t * child_context;     // local pointer on child cpu_context
+    uint32_t          * child_uzone;       // local_pointer on child uzone (in kernel stack)
+    char              * child_ksp;         // kernel stack pointer on child kernel stack
+    uint32_t            child_us_base;     // child user stack base value
+
+    process_t         * child_process;     // local pointer on child processs
+    uint32_t            child_pt_ppn;      // PPN of child process PT1 
+    vseg_t            * child_us_vseg;     // local pointer on child user stack vseg
+    
     // allocate a local CPU context in parent kernel stack
-    hal_cpu_context_t  context;
-
-    // get local parent thread cluster and local pointer
-    cxy_t      parent_cxy = local_cxy;
-    thread_t * parent_ptr = CURRENT_THREAD;
-
-    // get remote child thread cluster and local pointer
-    cxy_t      child_cxy = GET_CXY( child_xp );
-    thread_t * child_ptr = GET_PTR( child_xp );
-
-    // get local pointer on remote child cpu context
-    char * child_context_ptr = hal_remote_lpt( XPTR(child_cxy , &child_ptr->cpu_context) );
+    hal_cpu_context_t context;
+
+    // get (local) parent thread cluster and local pointer
+    parent_cxy = local_cxy;
+    parent_ptr = CURRENT_THREAD;
+
+    // get (remote) child thread cluster and local pointer
+    child_cxy = GET_CXY( child_xp );
+    child_ptr = GET_PTR( child_xp );
+
+    // get local pointer on (local) parent CPU context
+    parent_context = parent_ptr->cpu_context;
+
+    // get local pointer on (remote) child CPU context
+    child_context = hal_remote_lpt( XPTR(child_cxy , &child_ptr->cpu_context) );
 
     // get local pointer on remote child process
-    process_t * process = hal_remote_lpt( XPTR(child_cxy , &child_ptr->process) );
+    child_process = hal_remote_lpt( XPTR(child_cxy , &child_ptr->process) );
 
     // get ppn of remote child process page table
-    uint32_t pt_ppn = hal_remote_l32( XPTR(child_cxy , &process->vmm.gpt.ppn) );
-
-    // get local pointer on parent uzone from parent thread descriptor
-    uint32_t * parent_uzone = parent_ptr->uzone_current;
-
-    // compute  local pointer on child uzone 
-    uint32_t * child_uzone  = (uint32_t *)( (intptr_t)parent_uzone +
-                                            (intptr_t)child_ptr    -
-                                            (intptr_t)parent_ptr  );
+    child_pt_ppn = hal_remote_l32( XPTR(child_cxy , &child_process->vmm.gpt.ppn) );
+
+    // get local pointer on local parent uzone (in parent kernel stack)
+    parent_uzone = parent_ptr->uzone_current;
+
+    // compute local pointer on remote child uzone (in child kernel stack)
+    child_uzone  = (uint32_t *)( (intptr_t)parent_uzone +
+                                 (intptr_t)child_ptr    -
+                                 (intptr_t)parent_ptr  );
 
     // update the uzone pointer in child thread descriptor
@@ -213,16 +234,39 @@
 if( DEBUG_HAL_CONTEXT < cycle )
 printk("\n[%s] thread[%x,%x] parent_uzone %x / child_uzone %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, parent_uzone, child_uzone, cycle );
-#endif
-
-    // copy parent kernel stack to child thread descriptor
+__FUNCTION__, parent_ptr->process->pid, parent_ptr->trdid, parent_uzone, child_uzone, cycle );
+#endif
+
+    // get user stack base for parent thread
+    parent_us_base = parent_ptr->user_stack_vseg->min;
+
+    // get user stack base for child thread
+    child_us_vseg  = hal_remote_lpt( XPTR( child_cxy , &child_ptr->user_stack_vseg ) );
+    child_us_base  = hal_remote_l32( XPTR( child_cxy , &child_us_vseg->min ) );
+
+#if DEBUG_HAL_CONTEXT
+if( DEBUG_HAL_CONTEXT < cycle )
+printk("\n[%s] thread[%x,%x] parent_ustack_base %x / child_ustack_base %x\n",
+__FUNCTION__, parent_ptr->process->pid, parent_ptr->trdid, parent_us_base, child_us_base );
+#endif
+
+    // get current value of kernel stack pointer in parent kernel stack
+    parent_ksp = (char *)hal_get_sp();
+
+    // compute value of kernel stack pointer in child kernel stack 
+    child_ksp  = (char *)((intptr_t)parent_ksp +
+                          (intptr_t)child_ptr  - 
+                          (intptr_t)parent_ptr );
+
+#if DEBUG_HAL_CONTEXT
+if( DEBUG_HAL_CONTEXT < cycle )
+printk("\n[%s] thread[%x,%x] parent_ksp %x / child_ksp %x\n",
+__FUNCTION__, parent_ptr->process->pid, parent_ptr->trdid, parent_ksp, child_ksp );
+#endif
+
+    // compute number of bytes to be copied, depending on current value of parent_ksp
+    uint32_t size = (uint32_t)parent_ptr + CONFIG_THREAD_DESC_SIZE - (uint32_t)parent_ksp;    
+
+    // copy parent kernel stack content to child thread descriptor
     // (this includes the uzone, that is allocated in the kernel stack)
-    char * parent_ksp = (char *)hal_get_sp();
-    char * child_ksp  = (char *)((intptr_t)parent_ksp +
-                                 (intptr_t)child_ptr  - 
-                                 (intptr_t)parent_ptr );
-
-    uint32_t size = (uint32_t)parent_ptr + CONFIG_THREAD_DESC_SIZE - (uint32_t)parent_ksp;
-
     hal_remote_memcpy( XPTR( child_cxy , child_ksp ),
                        XPTR( local_cxy , parent_ksp ),
@@ -230,62 +274,67 @@
 
 #if DEBUG_HAL_CONTEXT
-cycle = (uint32_t)hal_get_cycles();
-printk("\n[%s] thread[%x,%x] copied kstack from parent %x to child %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, parent_ptr, child_ptr, cycle );
-#endif
-
-    // patch the user stack pointer slot in the child uzone[UZ_SP]
-    // because parent and child use the same offset to access the user stack,
-    // but parent and child do not have the same user stack base address.
-    uint32_t parent_us_base = parent_ptr->user_stack_vseg->min;
-    vseg_t * child_us_vseg  = hal_remote_lpt( XPTR( child_cxy , &child_ptr->user_stack_vseg ) );
-    uint32_t child_us_base  = hal_remote_l32( XPTR( child_cxy , &child_us_vseg->min ) );
-    uint32_t parent_usp     = parent_uzone[UZ_SP];
-    uint32_t child_usp      = parent_usp + child_us_base - parent_us_base;
-
-    hal_remote_s32( XPTR( child_cxy , &child_uzone[UZ_SP] ) , child_usp );
-
-#if DEBUG_HAL_CONTEXT
-cycle = (uint32_t)hal_get_cycles();
-printk("\n[%s] thread[%x,%x] parent_usp %x / child_usp %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, parent_usp, child_usp, cycle );
-#endif
-
-    // save current values of CPU registers to local CPU context
+if( DEBUG_HAL_CONTEXT < cycle )
+printk("\n[%s] thread[%x,%x] copied kstack from parent (%x) to child (%x)\n",
+__FUNCTION__, parent_ptr->process->pid, parent_ptr->trdid, parent_ptr, child_ptr );
+#endif
+
+    // save current values of CPU registers to local copy of CPU context
     hal_do_cpu_save( &context );
 
-    // From this point, both parent and child can execute the following code,
+    // update  three slots in this local CPU context
+    context.sp_29   = (uint32_t)child_ksp;
+    context.c0_th   = (uint32_t)child_ptr;
+    context.c2_ptpr = (uint32_t)child_pt_ppn >> 1;
+
+    // From this point, both parent and child execute the following code,
     // but child thread will only execute it after being unblocked by parent thread.
     // They can be distinguished by the (CURRENT_THREAD,local_cxy) values,
     // and we must re-initialise the calling thread pointer from c0_th register
 
-    this = CURRENT_THREAD;
+    thread_t * this = CURRENT_THREAD;
 
     if( (this == parent_ptr) && (local_cxy == parent_cxy) )   // parent thread
     {
-        // patch 4 slots in the local CPU context: the sp_29 / c0_th / C0_sr / c2_ptpr
-        // slots are not identical in parent and child
-        context.sp_29   = context.sp_29 + (intptr_t)child_ptr - (intptr_t)parent_ptr;
-        context.c0_th   = (uint32_t)child_ptr;
-        context.c0_sr   = SR_SYS_MODE;
-        context.c2_ptpr = pt_ppn >> 1;
-
-        // copy this patched context to remote child context
-        hal_remote_memcpy( XPTR( child_cxy , child_context_ptr ),
+        // parent thread must update four slots in child uzone 
+        // - UZ_TH   : parent and child have different threads descriptors
+        // - UZ_SP   : parent and child have different user stack base addresses.
+        // - UZ_PTPR : parent and child use different Generic Page Tables
+
+        // parent thread computes values for child thread
+        uint32_t child_sp    = parent_uzone[UZ_SP]  + child_us_base - parent_us_base;
+        uint32_t child_th    = (uint32_t)child_ptr;
+        uint32_t child_ptpr  = (uint32_t)child_pt_ppn >> 1;
+
+#if DEBUG_HAL_CONTEXT
+if( DEBUG_HAL_CONTEXT < cycle )
+printk("\n[%s] thread[%x,%x] : parent_uz_sp %x / child_uz_sp %x\n",
+__FUNCTION__, parent_ptr->process->pid, parent_ptr->trdid,
+parent_uzone[UZ_SP], child_sp );
+#endif
+
+        // parent thread updates the child uzone
+        hal_remote_s32( XPTR( child_cxy , &child_uzone[UZ_SP]   ) , child_sp );
+        hal_remote_s32( XPTR( child_cxy , &child_uzone[UZ_TH]   ) , child_th );
+        hal_remote_s32( XPTR( child_cxy , &child_uzone[UZ_PTPR] ) , child_ptpr );
+
+        // parent thread copies the local context to remote child context
+        hal_remote_memcpy( XPTR( child_cxy , child_context ),
                            XPTR( local_cxy  , &context ) , 
                            sizeof( hal_cpu_context_t ) );
 #if DEBUG_HAL_CONTEXT
+if( DEBUG_HAL_CONTEXT < cycle )
+printk("\n[%s] thread[%x,%x] copied parent CPU context to child CPU context\n",
+__FUNCTION__, parent_ptr->process->pid, parent_ptr->trdid );
+#endif
+
+        // parent thread unblocks child thread
+        thread_unblock( XPTR( child_cxy , child_ptr ) , THREAD_BLOCKED_GLOBAL );
+
+#if DEBUG_HAL_CONTEXT
 cycle = (uint32_t)hal_get_cycles();
-printk("\n[%s] thread[%x,%x] copied CPU context to child / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, cycle );
-#endif
-
-        // parent thread unblock child thread
-        thread_unblock( XPTR( child_cxy , child_ptr ) , THREAD_BLOCKED_GLOBAL );
-
-#if DEBUG_HAL_CONTEXT
-cycle = (uint32_t)hal_get_cycles();
-printk("\n[%s] thread[%x,%x] unblocked child thread / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, cycle );
+trdid_t child_trdid = hal_remote_l32( XPTR( child_cxy , &child_ptr->trdid ) );
+pid_t   child_pid   = hal_remote_l32( XPTR( child_cxy , &child_process->pid ) );
+printk("\n[%s] thread[%x,%x] unblocked child thread[%x,%x] / cycle %d\n",
+__FUNCTION__, parent_ptr->process->pid, parent_ptr->trdid, child_pid, child_trdid, cycle );
 #endif
 
@@ -347,5 +396,5 @@
     if( ctx != NULL )
     {    
-        req.type = KMEM_CPU_CTX;
+        req.type = KMEM_KCM;
         req.ptr  = ctx;
         kmem_free( &req );
@@ -366,8 +415,10 @@
     // allocate memory for fpu_context
     kmem_req_t  req;
-    req.type   = KMEM_FPU_CTX;
+    req.type   = KMEM_KCM;
     req.flags  = AF_KERNEL | AF_ZERO;
-
-    hal_fpu_context_t * context = (hal_fpu_context_t *)kmem_alloc( &req );
+    req.order  = bits_log2( sizeof(hal_fpu_context_t) );
+
+    hal_fpu_context_t * context = kmem_alloc( &req );
+
     if( context == NULL ) return -1;
 
@@ -414,5 +465,5 @@
     if( context != NULL )
     {    
-        req.type = KMEM_FPU_CTX;
+        req.type = KMEM_KCM;
         req.ptr  = context;
         kmem_free( &req );
Index: trunk/hal/tsar_mips32/core/hal_exception.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_exception.c	(revision 634)
+++ trunk/hal/tsar_mips32/core/hal_exception.c	(revision 635)
@@ -189,13 +189,4 @@
     uint32_t         excp_code;
 
-    // check thread type
-   if( CURRENT_THREAD->type != THREAD_USER )
-    {
-        printk("\n[PANIC] in %s : illegal thread type %s\n",
-        __FUNCTION__, thread_type_str(CURRENT_THREAD->type) );
-
-        return EXCP_KERNEL_PANIC;
-    }
-
     // get faulty thread process  
     process = this->process;
@@ -447,7 +438,8 @@
             else                                                // undefined coprocessor
             {
-                printk("\n[USER_ERROR] in %s for thread[%x,%x]\n"
+                printk("\n[USER_ERROR] in %s for thread[%x,%x] / cycle %d\n"
                 "   undefined coprocessor / epc %x\n",
-                __FUNCTION__, this->process->pid, this->trdid, excPC );
+                __FUNCTION__, this->process->pid, this->trdid, 
+                (uint32_t)hal_get_cycles() , excPC );
 
 		        error = EXCP_USER_ERROR;
@@ -457,7 +449,8 @@
         case XCODE_OVR:    // Arithmetic Overflow : user fatal error
         {
-            printk("\n[USER_ERROR] in %s for thread[%x,%x]\n"
+            printk("\n[USER_ERROR] in %s for thread[%x,%x] / cycle %d\n"
             "   arithmetic overflow / epc %x\n",
-            __FUNCTION__, this->process->pid, this->trdid, excPC );
+            __FUNCTION__, this->process->pid, this->trdid, 
+            (uint32_t)hal_get_cycles() , excPC );
 
 		    error = EXCP_USER_ERROR;
@@ -466,7 +459,8 @@
         case XCODE_RI:     // Reserved Instruction : user fatal error
         {
-            printk("\n[USER_ERROR] in %s for thread[%x,%x]\n"
+            printk("\n[USER_ERROR] in %s for thread[%x,%x] / cycle %d\n"
             "   reserved instruction / epc %x\n",
-            __FUNCTION__, this->process->pid, this->trdid, excPC );
+            __FUNCTION__, this->process->pid, this->trdid, 
+            (uint32_t)hal_get_cycles() , excPC );
 
 		    error = EXCP_USER_ERROR;
@@ -475,7 +469,8 @@
         case XCODE_ADEL:   // user fatal error
         {
-            printk("\n[USER_ERROR] in %s for thread[%x,%x]\n"
+            printk("\n[USER_ERROR] in %s for thread[%x,%x] / cycle %d\n"
             "   illegal data load address / epc %x / bad_address %x\n",
-            __FUNCTION__, this->process->pid, this->trdid, excPC, hal_get_bad_vaddr() );
+            __FUNCTION__, this->process->pid, this->trdid,
+            (uint32_t)hal_get_cycles(), excPC, hal_get_bad_vaddr() );
 
 		    error = EXCP_USER_ERROR;
@@ -484,7 +479,8 @@
         case XCODE_ADES:   //   user fatal error
         {
-            printk("\n[USER_ERROR] in %s for thread[%x,%x]\n"
+            printk("\n[USER_ERROR] in %s for thread[%x,%x] / cycle %d\n"
             "   illegal data store address / epc %x / bad_address %x\n",
-            __FUNCTION__, this->process->pid, this->trdid, excPC, hal_get_bad_vaddr() );
+            __FUNCTION__, this->process->pid, this->trdid, 
+            (uint32_t)hal_get_cycles(), excPC, hal_get_bad_vaddr() );
 
 		    error = EXCP_USER_ERROR;
Index: trunk/hal/tsar_mips32/core/hal_gpt.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_gpt.c	(revision 634)
+++ trunk/hal/tsar_mips32/core/hal_gpt.c	(revision 635)
@@ -2,5 +2,5 @@
  * hal_gpt.c - implementation of the Generic Page Table API for TSAR-MIPS32
  *
- * Author   Alain Greiner (2016,2017,2018)
+ * Author   Alain Greiner (2016,2017,2018,2019)
  *
  * Copyright (c) UPMC Sorbonne Universites
@@ -70,6 +70,6 @@
 #define TSAR_MMU_IX2_FROM_VPN( vpn )       (vpn & 0x1FF)
 
-#define TSAR_MMU_PTBA_FROM_PTE1( pte1 )    (pte1 & 0x0FFFFFFF)
-#define TSAR_MMU_PPN_FROM_PTE1( pte1 )     ((pte1 & 0x0007FFFF)<<9) 
+#define TSAR_MMU_PPN2_FROM_PTE1( pte1 )    (pte1 & 0x0FFFFFFF)
+#define TSAR_MMU_PPN1_FROM_PTE1( pte1 )    ((pte1 & 0x0007FFFF)<<9) 
 #define TSAR_MMU_ATTR_FROM_PTE1( pte1 )    (pte1 & 0xFFC00000)
 
@@ -138,6 +138,5 @@
 error_t hal_gpt_create( gpt_t * gpt )
 {
-	page_t   * page;
-    xptr_t     page_xp;
+    void * base;
 
     thread_t * this = CURRENT_THREAD;
@@ -146,19 +145,19 @@
 uint32_t cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_HAL_GPT_CREATE < cycle )
-printk("\n[%s] : thread[%x,%x] enter / cycle %d\n", 
+printk("\n[%s] thread[%x,%x] enter / cycle %d\n", 
 __FUNCTION__, this->process->pid, this->trdid, cycle );
 #endif
 
 // check page size
-assert( (CONFIG_PPM_PAGE_SIZE == 4096) , "for TSAR, the page size must be 4 Kbytes\n" );
+assert( (CONFIG_PPM_PAGE_SIZE == 4096) , "the TSAR page size must be 4 Kbytes\n" );
 
     // allocates 2 physical pages for PT1
 	kmem_req_t req;
-	req.type  = KMEM_PAGE;
-	req.size  = 1;                     // 2 small pages 
+	req.type  = KMEM_PPM;
+	req.order = 1;                     // 2 small pages 
 	req.flags = AF_KERNEL | AF_ZERO;
-	page = (page_t *)kmem_alloc( &req );
-
-	if( page == NULL ) 
+	base = kmem_alloc( &req );
+
+	if( base == NULL ) 
     {
         printk("\n[PANIC] in %s : no memory for PT1 / process %x / cluster %x\n",
@@ -167,14 +166,12 @@
     }
 
-    // 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->ptr = base;
+	gpt->ppn = ppm_base2ppn( XPTR( local_cxy , base ) );
 
 #if DEBUG_HAL_GPT_CREATE
 cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_HAL_GPT_CREATE < cycle )
-printk("\n[%s] : thread[%x,%x] exit / cycle %d\n", 
-__FUNCTION__, this->process->pid, this->trdid, cycle );
+printk("\n[%s] thread[%x,%x] exit / pt1_base %x / pt1_ppn %x / cycle %d\n", 
+__FUNCTION__, this->process->pid, this->trdid, gpt->ptr, gpt->ppn, cycle );
 #endif
 
@@ -199,5 +196,5 @@
 thread_t * this  = CURRENT_THREAD;
 if( DEBUG_HAL_GPT_DESTROY < cycle )
-printk("\n[%s] : thread[%x,%x] enter / cycle %d\n", 
+printk("\n[%s] thread[%x,%x] enter / cycle %d\n", 
 __FUNCTION__, this->process->pid, this->trdid, cycle );
 #endif
@@ -221,7 +218,6 @@
             {
                 // get local pointer on PT2
-                pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
-                xptr_t base_xp = ppm_ppn2base( pt2_ppn );
-                pt2     = GET_PTR( base_xp );
+                pt2_ppn = TSAR_MMU_PPN2_FROM_PTE1( pte1 );
+                pt2     = GET_PTR( ppm_ppn2base( pt2_ppn ) );
 
                 // scan the PT2 
@@ -238,6 +234,6 @@
 
                 // release the page allocated for the PT2
-                req.type = KMEM_PAGE;
-                req.ptr  = GET_PTR( ppm_base2page( XPTR(local_cxy , pt2 ) ) );
+                req.type = KMEM_PPM;
+                req.ptr  = pt2;
                 kmem_free( &req );
             }
@@ -246,6 +242,6 @@
 
     // release the PT1
-    req.type = KMEM_PAGE;
-    req.ptr  = GET_PTR( ppm_base2page( XPTR(local_cxy , pt1 ) ) );
+    req.type = KMEM_PPM;
+    req.ptr  = pt1;
     kmem_free( &req );
 
@@ -253,76 +249,9 @@
 cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_HAL_GPT_DESTROY < cycle )
-printk("\n[%s] : thread[%x,%x] exit / cycle %d\n", 
+printk("\n[%s] thread[%x,%x] exit / cycle %d\n", 
 __FUNCTION__, this->process->pid, this->trdid, cycle );
 #endif
 
 } // end hal_gpt_destroy()
-
-/*
-
-/////////////////////////////////////////////////////////////////////////////////////
-// This static function can be used for debug.
-/////////////////////////////////////////////////////////////////////////////////////
-static void hal_gpt_display( process_t * process )
-{
-    gpt_t    * gpt;
-	uint32_t   ix1;
-	uint32_t   ix2;
-	uint32_t * pt1;
-    uint32_t   pte1;
-    ppn_t      pt2_ppn;
-    uint32_t * pt2;
-    uint32_t   pte2_attr;
-    ppn_t      pte2_ppn;
-    vpn_t      vpn;
-
-// check argument
-assert( (process != NULL) , "NULL process pointer\n");
-
-    // get pointer on gpt
-    gpt = &(process->vmm.gpt);
-
-    // get pointer on PT1 
-    pt1 = (uint32_t *)gpt->ptr;
-
-    printk("\n***** Tsar Page Table for process %x : &gpt = %x / &pt1 = %x\n\n",
-    process->pid , gpt , pt1 );
-
-    // scan the PT1
-	for( ix1 = 0 ; ix1 < 2048 ; ix1++ )
-	{
-        pte1 = pt1[ix1];
-		if( (pte1 & TSAR_PTE_MAPPED) != 0 )
-        {
-            if( (pte1 & TSAR_PTE_SMALL) == 0 )  // BIG page
-            {
-                vpn = ix1 << 9;
-                printk(" - BIG   : vpn = %x / pt1[%d] = %X\n", vpn , ix1 , pte1 );
-            }
-            else                           // SMALL pages
-            {
-                pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
-                xptr_t base_xp = ppm_ppn2base ( pt2_ppn );
-                pt2     = GET_PTR( base_xp );
-
-                // scan the PT2
-	            for( ix2 = 0 ; ix2 < 512 ; ix2++ )
-                {
-                    pte2_attr = TSAR_MMU_ATTR_FROM_PTE2( pt2[2 * ix2] );
-                    pte2_ppn  = TSAR_MMU_PPN_FROM_PTE2( pt2[2 * ix2 + 1] );
-
-		            if( (pte2_attr & TSAR_PTE_MAPPED) != 0 )
-                    {
-                        vpn = (ix1 << 9) | ix2;
-                        printk(" - SMALL : vpn %X / ppn %X / attr %X\n",
-                        vpn , pte2_ppn , tsar2gpt(pte2_attr) );
-                    }
-                }
-            }
-        }
-	}
-} // end hal_gpt_display()
-
-*/
 
 ////////////////////////////////////////////
@@ -332,12 +261,12 @@
                           ppn_t    * ppn )
 {
-    uint32_t          * pt1_ptr;         // local pointer on PT1 base 
-    xptr_t              ptd1_xp;         // extended pointer on PT1[x1] entry
-	uint32_t            ptd1;            // value of PT1[x1] entry
-
-    xptr_t              page_xp;
-
+    uint32_t          * pt1;             // local pointer on PT1 base 
+    xptr_t              pte1_xp;         // extended pointer on PT1[x1] entry
+	uint32_t            pte1;            // value of PT1[x1] entry
+
+    kmem_req_t          req;             // kmem request fro PT2 allocation
+
+    uint32_t          * pt2;             // local pointer on PT2 base
 	ppn_t               pt2_ppn;         // PPN of page containing PT2
-    uint32_t          * pt2_ptr;         // local pointer on PT2 base
 	xptr_t              pte2_xp;         // extended pointer on PT2[ix2].attr
     uint32_t            pte2_attr;       // PT2[ix2].attr current value   
@@ -357,68 +286,72 @@
 uint32_t   cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_HAL_GPT_LOCK_PTE < cycle )
-printk("\n[%s] : thread[%x,%x] enters / vpn %x in cluster %x / cycle %d\n", 
+printk("\n[%s] thread[%x,%x] enters / vpn %x in cluster %x / cycle %d\n", 
 __FUNCTION__, this->process->pid, this->trdid, vpn, gpt_cxy, cycle );
 #endif
 
     // get indexes in PTI & PT2 from vpn
-    uint32_t  ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );    // index in PT1
-    uint32_t  ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );    // index in PT2
+    uint32_t  ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
+    uint32_t  ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
 
     // get local pointer on PT1
-    pt1_ptr = hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
-
-    // build extended pointer on PTD1 == PT1[ix1]
-	ptd1_xp = XPTR( gpt_cxy , &pt1_ptr[ix1] );
+    pt1 = hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
+
+    // build extended pointer on PTE1 == PT1[ix1]
+	pte1_xp = XPTR( gpt_cxy , &pt1[ix1] );
 
     // get current PT1 entry value
-    ptd1 = hal_remote_l32( ptd1_xp );
-
-    // If PTD1 is unmapped and unlocked, try to atomically lock this PT1 entry.
-    // This PTD1 lock prevent multiple concurrent PT2 allocations
-    // - only the thread that successfully locked the PTD1 allocates a new PT2
-    //   and updates the PTD1
-    // - all other threads simply wait until the missing PTD1 is mapped.
-
-    if( ptd1 == 0 )  
+    pte1 = hal_remote_l32( pte1_xp );
+
+    // If PTE1 is unmapped and unlocked, try to atomically lock this PT1 entry.
+    // This PTE1 locking prevent multiple concurrent PT2 allocations
+    // - only the thread that successfully locked the PTE1 allocates a new PT2
+    //   and updates the PTE1
+    // - all other threads simply wait until the missing PTE1 is mapped.
+
+    if( pte1 == 0 )  
 	{
-        // try to atomically lock the PTD1 to prevent concurrent PT2 allocations
-        atomic = hal_remote_atomic_cas( ptd1_xp,
-                                        ptd1,
-                                        ptd1 | TSAR_PTE_LOCKED );
+        // try to atomically lock the PTE1 to prevent concurrent PT2 allocations
+        atomic = hal_remote_atomic_cas( pte1_xp,
+                                        pte1,
+                                        pte1 | TSAR_PTE_LOCKED );
         if( atomic )  
 		{
             // allocate one 4 Kbytes physical page for PT2
-            page_xp = ppm_remote_alloc_pages( gpt_cxy , 0 );
-
-            if( page_xp == XPTR_NULL )
+            req.type  = KMEM_PPM;
+            req.order = 0;  
+            req.flags = AF_ZERO | AF_KERNEL;
+            pt2       = kmem_remote_alloc( gpt_cxy , &req );
+
+            if( pt2 == NULL )
             {
-                printk("\n[ERROR] in %s : cannot allocate memory for PT2\n", __FUNCTION__ );
+                printk("\n[ERROR] in %s : cannot allocate memory for PT2 in cluster %d\n",
+                __FUNCTION__, gpt_cxy );
                 return -1;
             }
 
             // get the PT2 PPN
-            pt2_ppn = ppm_page2ppn( page_xp );
-
-            // build  PTD1
-            ptd1 = TSAR_PTE_MAPPED | TSAR_PTE_SMALL | pt2_ppn;
-
-            // set the PTD1 value in PT1
-            // this unlocks the PTD1
-            hal_remote_s32( ptd1_xp , ptd1 );
+            pt2_ppn = ppm_base2ppn( XPTR( gpt_cxy , pt2 ) );
+
+            // build  PTE1
+            pte1 = TSAR_PTE_MAPPED | TSAR_PTE_SMALL | pt2_ppn;
+
+            // set the PTE1 value in PT1
+            // this unlocks the PTE1
+            hal_remote_s32( pte1_xp , pte1 );
             hal_fence();
 
 #if (DEBUG_HAL_GPT_LOCK_PTE & 1)
 if( DEBUG_HAL_GPT_LOCK_PTE < cycle )
-printk("\n[%s] : thread[%x,%x] allocates a new PT2 for vpn %x in cluster %x\n", 
+printk("\n[%s] thread[%x,%x] allocates a new PT2 for vpn %x in cluster %x\n", 
 __FUNCTION__, this->process->pid, this->trdid, vpn, gpt_cxy );
 #endif
 
         }  // end if atomic
-    }  // end if (ptd1 == 0)
-
-    // wait until PTD1 is mapped by another thread
-    while( (ptd1 & TSAR_PTE_MAPPED) == 0 )
+    }  // end if (pte1 == 0)
+
+    // wait until PTE1 is mapped by another thread
+    while( (pte1 & TSAR_PTE_MAPPED) == 0 )
     {
-        ptd1 = hal_remote_l32( ptd1_xp );
+        pte1 = hal_remote_l32( pte1_xp );
 
 #if GPT_LOCK_WATCHDOG
@@ -426,5 +359,5 @@
 {
     thread_t * thread = CURRENT_THREAD;
-    printk("\n[PANIC] in %s : thread[%x,%x] waiting PTD1 / vpn %x / cxy %x / %d iterations\n",
+    printk("\n[PANIC] in %s : thread[%x,%x] waiting PTE1 / vpn %x / cxy %x / %d iterations\n",
     __FUNCTION__, thread->process->pid, thread->trdid, vpn, gpt_cxy, count );
     hal_core_sleep();
@@ -435,19 +368,19 @@
     }
 
-// check ptd1 because only small page can be locked
-assert( (ptd1 & TSAR_PTE_SMALL), "cannot lock a big page\n");
+// check pte1 because only small page can be locked
+assert( (pte1 & TSAR_PTE_SMALL), "cannot lock a big page\n");
 
 #if (DEBUG_HAL_GPT_LOCK_PTE & 1)
 if( DEBUG_HAL_GPT_LOCK_PTE < cycle )
-printk("\n[%s] : thread[%x,%x] get ptd1 %x for vpn %x in cluster %x\n", 
-__FUNCTION__, this->process->pid, this->trdid, ptd1, vpn, gpt_cxy );
-#endif
-
-    // get pointer on PT2 base from PTD1 
-    pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( ptd1 );
-    pt2_ptr = GET_PTR( ppm_ppn2base( pt2_ppn ) );
+printk("\n[%s] thread[%x,%x] get pte1 %x for vpn %x in cluster %x\n", 
+__FUNCTION__, this->process->pid, this->trdid, pte1, vpn, gpt_cxy );
+#endif
+
+    // get pointer on PT2 base 
+    pt2_ppn = TSAR_MMU_PPN2_FROM_PTE1( pte1 );
+    pt2     = GET_PTR( ppm_ppn2base( pt2_ppn ) );
 
     // build extended pointers on PT2[ix2].attr  
-    pte2_xp = XPTR( gpt_cxy , &pt2_ptr[2 * ix2] );
+    pte2_xp = XPTR( gpt_cxy , &pt2[2 * ix2] );
 
     // wait until PTE2 atomically set using a remote CAS
@@ -491,5 +424,5 @@
 cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_HAL_GPT_LOCK_PTE < cycle )
-printk("\n[%s] : thread[%x,%x] exit / vpn %x in cluster %x / attr %x / ppn %x / cycle %d\n", 
+printk("\n[%s] thread[%x,%x] exit / vpn %x in cluster %x / attr %x / ppn %x / cycle %d\n", 
 __FUNCTION__, this->process->pid, this->trdid, vpn, gpt_cxy, pte2_attr, pte2_ppn, cycle );
 #endif
@@ -506,10 +439,10 @@
                          vpn_t   vpn )
 {
-    uint32_t * pt1_ptr;         // local pointer on PT1 base
-    xptr_t     ptd1_xp;         // extended pointer on PT1[ix1]
-	uint32_t   ptd1;            // value of PT1[ix1] entry
-
+    uint32_t * pt1;             // local pointer on PT1 base
+    xptr_t     pte1_xp;         // extended pointer on PT1[ix1]
+	uint32_t   pte1;            // value of PT1[ix1] entry
+
+    uint32_t * pt2;             // PT2 base address
 	ppn_t      pt2_ppn;         // PPN of page containing PT2
-    uint32_t * pt2_ptr;         // PT2 base address
 	xptr_t     pte2_xp;         // extended pointer on PT2[ix2].attr 
 	uint32_t   pte2_attr;       // PTE2 attribute
@@ -523,31 +456,31 @@
 uint32_t   cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_HAL_GPT_LOCK_PTE < cycle )
-printk("\n[%s] : thread[%x,%x] enters for vpn %x in cluster %x / cycle %d\n", 
+printk("\n[%s] thread[%x,%x] enters for vpn %x in cluster %x / cycle %d\n", 
 __FUNCTION__, this->process->pid, this->trdid, vpn, gpt_cxy, cycle );
 #endif
 
     // 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
+    uint32_t  ix1 = TSAR_MMU_IX1_FROM_VPN( vpn ); 
+    uint32_t  ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
 
     // get local pointer on PT1
-    pt1_ptr = hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
-
-    // build extended pointer on PTD1 == PT1[ix1]
-	ptd1_xp = XPTR( gpt_cxy , &pt1_ptr[ix1] );
-
-    // get current ptd1 value
-    ptd1 = hal_remote_l32( ptd1_xp );
-
-// check PTD1 attributes
-assert( ((ptd1 & TSAR_PTE_MAPPED) != 0), "unmapped PTE1\n");
-assert( ((ptd1 & TSAR_PTE_SMALL ) != 0), "big page PTE1\n");
-
-    // get pointer on PT2 base from PTD1 
-	pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( ptd1 );
-	pt2_ptr = GET_PTR( ppm_ppn2base( pt2_ppn ) );
+    pt1 = hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
+
+    // build extended pointer on PTE1 == PT1[ix1]
+	pte1_xp = XPTR( gpt_cxy , &pt1[ix1] );
+
+    // get current pte1 value
+    pte1 = hal_remote_l32( pte1_xp );
+
+// check PTE1 attributes
+assert( ((pte1 & TSAR_PTE_MAPPED) != 0), "unmapped PTE1\n");
+assert( ((pte1 & TSAR_PTE_SMALL ) != 0), "big page PTE1\n");
+
+    // get pointer on PT2 base  
+	pt2_ppn = TSAR_MMU_PPN2_FROM_PTE1( pte1 );
+	pt2     = GET_PTR( ppm_ppn2base( pt2_ppn ) );
 
     // build extended pointers on PT2[ix2].attr  
-    pte2_xp = XPTR( gpt_cxy , &pt2_ptr[2 * ix2] );
+    pte2_xp = XPTR( gpt_cxy , &pt2[2 * ix2] );
 
     // get PT2[ix2].attr
@@ -564,5 +497,5 @@
 cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_HAL_GPT_LOCK_PTE < cycle )
-printk("\n[%s] : thread[%x,%x] unlocks vpn %x in cluster %x / cycle %d\n", 
+printk("\n[%s] thread[%x,%x] unlocks vpn %x in cluster %x / cycle %d\n", 
 __FUNCTION__, this->process->pid, this->trdid, vpn, gpt_cxy, cycle );
 #endif
@@ -580,10 +513,10 @@
     gpt_t             * gpt_ptr;             // target GPT local pointer
 
-    uint32_t          * pt1_ptr;             // local pointer on PT1 base
+    uint32_t          * pt1;                 // local pointer on PT1 base
 	xptr_t              pte1_xp;             // extended pointer on PT1 entry
 	uint32_t            pte1;                // PT1 entry value if PTE1
 
+	uint32_t          * pt2;                 // local pointer on PT2 base
 	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
@@ -604,6 +537,16 @@
     ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
 
-    pt1_ptr = hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
-	small   = attr & GPT_SMALL;
+#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] enter gpt (%x,%x) / vpn %x / attr %x / ppn %x\n", 
+__FUNCTION__, this->process->pid, this->trdid, gpt_cxy, &gpt_ptr->ptr, vpn, attr, ppn );
+#endif
+
+	small = attr & GPT_SMALL;
+
+    // get local pointer on PT1
+    pt1 = hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
 
     // compute tsar attributes from generic attributes
@@ -611,5 +554,5 @@
 
     // build extended pointer on PTE1 = PT1[ix1]
-	pte1_xp = XPTR( gpt_cxy , &pt1_ptr[ix1] );
+	pte1_xp = XPTR( gpt_cxy , &pt1[ix1] );
 
     // get current pte1 value
@@ -634,9 +577,7 @@
 
 #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 PTE1 / cxy %x / ix1 %x / pt1 %x / pte1 %x\n", 
-__FUNCTION__, this->process->pid, this->trdid, gpt_cxy, ix1, pt1_ptr, pte1 );
+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, pte1 );
 #endif
 
@@ -648,11 +589,11 @@
 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 ) );
+        // get PT2 base 
+	    pt2_ppn = TSAR_MMU_PPN2_FROM_PTE1( pte1 );
+	    pt2     = 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] );
+        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
@@ -672,6 +613,6 @@
 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", 
-__FUNCTION__, this->process->pid, this->trdid, gpt_cxy, ix2, pt2_ptr, tsar_attr, ppn );
+printk("\n[%s] thread[%x,%x] map PTE2 / cxy %x / ix2 %x / pt2 %x / attr %x / ppn %x\n", 
+__FUNCTION__, this->process->pid, this->trdid, gpt_cxy, ix2, pt2, tsar_attr, ppn );
 #endif
 
@@ -689,10 +630,10 @@
     uint32_t   ix2;            // index in PT2
 
-    uint32_t * pt1_ptr;        // PT1 base address
+    uint32_t * pt1;            // PT1 base address
     xptr_t     pte1_xp;        // extended pointer on PT1[ix1]
     uint32_t   pte1;           // PT1 entry value
 
+    uint32_t * pt2;            // PT2 base address
     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
@@ -707,8 +648,8 @@
 
     // get local pointer on PT1 base
-    pt1_ptr = hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
+    pt1 = hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
 
     // build extended pointer on PTE1 = PT1[ix1]
-	pte1_xp = XPTR( gpt_cxy , &pt1_ptr[ix1] );
+	pte1_xp = XPTR( gpt_cxy , &pt1[ix1] );
 
     // get current PTE1 value
@@ -729,5 +670,5 @@
 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", 
+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
@@ -737,11 +678,11 @@
     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 ) );
+        // get PT2 base
+        pt2_ppn = TSAR_MMU_PPN2_FROM_PTE1( pte1 );
+        pt2     = 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] );
+        pte2_attr_xp = XPTR( gpt_cxy , &pt2[2 * ix2] );
+        pte2_ppn_xp  = XPTR( gpt_cxy , &pt2[2 * ix2 + 1] );
 
         // unmap the PTE2
@@ -755,5 +696,5 @@
 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", 
+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
@@ -804,12 +745,12 @@
 	if( (pte1 & TSAR_PTE_SMALL) == 0 )     // it's a PTE1
 	{
-        // get PPN & ATTR from PT1
+        // get PPN & ATTR
 		*attr = tsar2gpt( TSAR_MMU_ATTR_FROM_PTE1( pte1 ) );
-        *ppn  = TSAR_MMU_PPN_FROM_PTE1( pte1 ) | (vpn & ((1<<TSAR_MMU_IX2_WIDTH)-1));
+        *ppn  = TSAR_MMU_PPN1_FROM_PTE1( pte1 ) | (vpn & ((1<<TSAR_MMU_IX2_WIDTH)-1));
 	}
     else                                  // it's a PTE2
     {
         // compute PT2 base address
-        pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
+        pt2_ppn = TSAR_MMU_PPN2_FROM_PTE1( pte1 );
         pt2     = GET_PTR( ppm_ppn2base( pt2_ppn ) );
 
@@ -849,4 +790,5 @@
 	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
@@ -874,11 +816,7 @@
 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", 
+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
@@ -907,14 +845,14 @@
         dst_pte1 = dst_pt1[dst_ix1];
 
-        // map dst_pte1 if required
+        // map dst_pte1 when this entry is not mapped
         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.type  = KMEM_PPM;
+	        req.order = 0;                     // 1 small page 
 	        req.flags = AF_KERNEL | AF_ZERO;
-	        page = (page_t *)kmem_alloc( &req );
-
-            if( page == NULL )
+	        dst_pt2   = kmem_alloc( &req );
+
+            if( dst_pt2 == NULL )
             {
 		        printk("\n[ERROR] in %s : cannot allocate PT2\n", __FUNCTION__ );
@@ -926,7 +864,7 @@
 
             // get PPN for this new PT2 
-            dst_pt2_ppn = (ppn_t)ppm_page2ppn( page_xp );
-
-            // build the new dst_pte1
+            dst_pt2_ppn = ppm_base2ppn( XPTR( local_cxy , dst_pt2 ) );
+
+            // build new dst_pte1
             dst_pte1 = TSAR_PTE_MAPPED | TSAR_PTE_SMALL | dst_pt2_ppn;
 
@@ -936,9 +874,9 @@
 
         // get pointer on src_pt2
-        src_pt2_ppn = (ppn_t)TSAR_MMU_PTBA_FROM_PTE1( src_pte1 );
+        src_pt2_ppn = TSAR_MMU_PPN2_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_ppn = TSAR_MMU_PPN2_FROM_PTE1( dst_pte1 );
         dst_pt2     = GET_PTR( ppm_ppn2base( dst_pt2_ppn ) );
 
@@ -970,5 +908,5 @@
 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", 
+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
@@ -987,5 +925,5 @@
 cycle = (uint32_t)hal_get_cycles;
 if( DEBUG_HAL_GPT_COPY < cycle )
-printk("\n[%s] : thread[%x,%x] exit / nothing done / cycle %d\n", 
+printk("\n[%s] thread[%x,%x] exit / nothing done / cycle %d\n", 
 __FUNCTION__, this->process->pid, this->trdid, cycle );
 #endif
@@ -1005,8 +943,15 @@
     gpt_t    * gpt_ptr;
 
-    vpn_t      vpn;
-
-    uint32_t   ix1;
-    uint32_t   ix2;
+    uint32_t   ix1;       // current
+    uint32_t   ix2;       // current
+
+    vpn_t      vpn_min;
+    vpn_t      vpn_max;   // included
+
+    uint32_t   ix1_min;
+    uint32_t   ix1_max;   // included
+
+    uint32_t   ix2_min;
+    uint32_t   ix2_max;   // included
 
     uint32_t * pt1;
@@ -1021,37 +966,91 @@
     gpt_ptr = GET_PTR( gpt_xp );
 
-    // get local PT1 pointer
+#if DEBUG_HAL_GPT_SET_COW
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+thread_t * this  = CURRENT_THREAD;
+if(DEBUG_HAL_GPT_SET_COW < cycle )
+printk("\n[%s] thread[%x,%x] enter / gpt[%x,%x] / vpn_base %x / vpn_size %x / cycle %d\n", 
+__FUNCTION__, this->process->pid, this->trdid, gpt_cxy, gpt_ptr, vpn_base, vpn_size, cycle );
+#endif
+
+    // get 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++ )
+#if (DEBUG_HAL_GPT_SET_COW & 1)
+if(DEBUG_HAL_GPT_SET_COW < cycle )
+printk("\n[%s] thread[%x,%x] get pt1 = %x\n", 
+__FUNCTION__, this->process->pid, this->trdid, pt1 );
+#endif
+
+    vpn_min = vpn_base;
+    vpn_max = vpn_base + vpn_size - 1;
+
+    ix1_min = TSAR_MMU_IX1_FROM_VPN( vpn_base );
+    ix1_max = TSAR_MMU_IX1_FROM_VPN( vpn_max );
+
+    for( ix1 = ix1_min ; ix1 <= ix1_max ; ix1++ )
     {
-        ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
-        ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
-
+
+#if (DEBUG_HAL_GPT_SET_COW & 1)
+if(DEBUG_HAL_GPT_SET_COW < cycle )
+printk("\n[%s] thread[%x,%x] : &pt1[%x] = %x\n", 
+__FUNCTION__, this->process->pid, this->trdid, ix1,  &pt1[ix1] );
+#endif
         // get PTE1 value
         pte1 = hal_remote_l32( XPTR( gpt_cxy , &pt1[ix1] ) );
+
+#if (DEBUG_HAL_GPT_SET_COW & 1)
+if(DEBUG_HAL_GPT_SET_COW < cycle )
+printk("\n[%s] thread[%x,%x] : pt1[%x] = %x\n", 
+__FUNCTION__, this->process->pid, this->trdid, ix1, pte1 );
+#endif
 
         // 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 );
+            // get PT2 pointer
+            pt2_ppn = TSAR_MMU_PPN2_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 ) 
+#if (DEBUG_HAL_GPT_SET_COW & 1)
+if(DEBUG_HAL_GPT_SET_COW < cycle )
+printk("\n[%s] thread[%x,%x] : get pt2 = %x\n", 
+__FUNCTION__, this->process->pid, this->trdid, pt2 );
+#endif
+            ix2_min = (ix1 == ix1_min) ? TSAR_MMU_IX2_FROM_VPN(vpn_min) : 0;
+            ix2_max = (ix1 == ix1_max) ? TSAR_MMU_IX2_FROM_VPN(vpn_max) : 511;
+ 
+            for( ix2 = ix2_min ; ix2 <= ix2_max ; ix2++ )
             {
-                attr = (attr | TSAR_PTE_COW) & (~TSAR_PTE_WRITABLE);
-                hal_remote_s32( XPTR( gpt_cxy , &pt2[2*ix2] ) , attr );
-            } 
-        } 
-    }   // end loop on pages
+
+#if (DEBUG_HAL_GPT_SET_COW & 1)
+if(DEBUG_HAL_GPT_SET_COW < cycle )
+printk("\n[%s] thread[%x,%x] : &pte2[%x] = %x\n", 
+__FUNCTION__, this->process->pid, this->trdid, 2*ix2, &pt2[2*ix2] );
+#endif
+                // get current PTE2 attributes
+                attr = hal_remote_l32( XPTR( gpt_cxy , &pt2[2*ix2] ) );
+
+#if (DEBUG_HAL_GPT_SET_COW & 1)
+if(DEBUG_HAL_GPT_SET_COW < cycle )
+printk("\n[%s] thread[%x,%x] : pte2[%x] (attr) = %x\n", 
+__FUNCTION__, this->process->pid, this->trdid, 2*ix2, attr );
+#endif
+                // 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 ix2
+        }
+    }  // end loop on ix1
+
+#if DEBUG_HAL_GPT_SET_COW
+cycle = (uint32_t)hal_get_cycles();
+if(DEBUG_HAL_GPT_SET_COW < cycle )
+printk("\n[%s] thread[%x,%x] exit / cycle %d\n", 
+__FUNCTION__, this->process->pid, this->trdid, cycle );
+#endif
 
 }  // end hal_gpt_set_cow()
@@ -1068,11 +1067,9 @@
 	ppn_t               pt2_ppn;             // PPN of PT2
 	uint32_t          * pt2;                 // PT2 base address
-    xptr_t              pte2_xp;             // exended pointer on PTE2
+    xptr_t              pte2_attr_xp;        // exended pointer on pte2.attr
+    xptr_t              pte2_ppn_xp;         // exended pointer on pte2.ppn
 
     uint32_t            ix1;                 // index in PT1
     uint32_t            ix2;                 // index in PT2
-
-
-    uint32_t            tsar_attr;           // PTE attributes for TSAR MMU
 
 // check MAPPED, SMALL, and not LOCKED in attr argument
@@ -1092,29 +1089,28 @@
     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] ) );
 
 // check MAPPED and SMALL in target PTE1
-assert( ((pte1 & GPT_MAPPED) != 0), "attribute MAPPED must be set in target PTE1\n" );
-assert( ((pte1 & GPT_SMALL ) != 0), "attribute SMALL  must be set in target PTE1\n" );
-
-    // get PT2 base from PTE1 
-    pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
+assert( ((pte1 & TSAR_PTE_MAPPED) != 0), "attribute MAPPED must be set in target PTE1\n" );
+assert( ((pte1 & TSAR_PTE_SMALL ) != 0), "attribute SMALL  must be set in target PTE1\n" );
+
+    // get PT2 base 
+    pt2_ppn = TSAR_MMU_PPN2_FROM_PTE1( pte1 );
     pt2     = GET_PTR( ppm_ppn2base( pt2_ppn ) );
 
-    // get extended pointer on PTE2
-    pte2_xp = XPTR( gpt_cxy , &pt2[2*ix2] );
+    // build extended pointers 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] );
+
     
 // check MAPPED in target PTE2
-assert( ((hal_remote_l32(pte2_xp) & GPT_MAPPED) != 0),
+assert( ((hal_remote_l32(pte2_attr_xp) & TSAR_PTE_MAPPED) != 0),
 "attribute MAPPED must be set in target PTE2\n" );
 
     // set PTE2 in this order
-	hal_remote_s32( pte2_xp     , ppn );
+	hal_remote_s32( pte2_ppn_xp , ppn );
 	hal_fence();
-	hal_remote_s32( pte2_xp + 4 , tsar_attr );
+	hal_remote_s32( pte2_attr_xp , gpt2tsar( attr ) );
 	hal_fence();
 
Index: trunk/hal/tsar_mips32/core/hal_vmm.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_vmm.c	(revision 634)
+++ trunk/hal/tsar_mips32/core/hal_vmm.c	(revision 635)
@@ -44,10 +44,12 @@
 extern process_t            process_zero;
 extern chdev_directory_t    chdev_dir;
+extern char               * lock_type_str[];
 
 //////////////////////////////////////////////////////////////////////////////////////////
 // This function is called by the process_zero_init() function during kernel_init.
 // It initializes the VMM of the kernel proces_zero (containing all kernel threads)
-// in the local cluster: For TSAR, it registers one "kcode" vseg in kernel VSL, 
-// and registers one big page in slot[0] of kernel GPT.
+// in the local cluster.
+// For TSAR, it registers one "kcode" vseg in kernel VSL, and registers one big page 
+// in slot[0] of kernel GPT.
 //////////////////////////////////////////////////////////////////////////////////////////
 error_t  hal_vmm_kernel_init( boot_info_t * info )
@@ -58,6 +60,9 @@
     gpt_t * gpt = &process_zero.vmm.gpt;
 
-    // get cluster identifier
-    cxy_t cxy = local_cxy;
+#if DEBUG_HAL_VMM
+thread_t * this = CURRENT_THREAD;
+printk("\n[%s] thread[%x,%x] enter in cluster %x\n", 
+__FUNCTION__, this->process->pid, this->trdid, local_cxy );
+#endif
 
     // allocate memory for kernel GPT
@@ -67,11 +72,10 @@
     {
         printk("\n[PANIC] in %s : cannot allocate kernel GPT in cluster %x\n",
-        __FUNCTION__ , cxy );
+        __FUNCTION__ , local_cxy );
         hal_core_sleep();
     }
 
 #if DEBUG_HAL_VMM
-thread_t * this = CURRENT_THREAD;
-printk("\n[%s] thread[%x,%x] enter in cluster %x / gpt %x\n", 
+printk("\n[%s] thread[%x,%x] created GPT PT1 in cluster %x / gpt %x\n", 
 __FUNCTION__, this->process->pid, this->trdid, local_cxy, gpt );
 #endif
@@ -79,12 +83,12 @@
     // compute attr and ppn for one PTE1
     uint32_t attr = GPT_MAPPED | GPT_READABLE | GPT_CACHABLE | GPT_EXECUTABLE | GPT_GLOBAL;
-    uint32_t ppn  = cxy << 20;    
+    uint32_t ppn  = local_cxy << 20;    
 
     // set PT1[0]
-    hal_gpt_set_pte( XPTR( cxy , gpt ) , 0 , attr , ppn );
-
-#if DEBUG_HAL_VMM
-printk("\n[%s] thread[%x,%x] created PT1[0] : ppn %x / attr %x\n", 
-__FUNCTION__, this->process->pid, this->trdid, ppn, attr );
+    hal_gpt_set_pte( XPTR( local_cxy , gpt ) , 0 , attr , ppn );
+
+#if DEBUG_HAL_VMM
+printk("\n[%s] thread[%x,%x] mapped PT1[0] in cluster %d : ppn %x / attr %x\n", 
+__FUNCTION__, this->process->pid, this->trdid, local_cxy, ppn, attr );
 #endif
 
@@ -94,17 +98,17 @@
                                      info->kcode_base,
                                      info->kcode_size,
-                                     0, 0,                  // file ofset and file size (unused)
-                                     XPTR_NULL,             // no mapper
+                                     0, 0,               // file ofset and file size (unused)
+                                     XPTR_NULL,          // no mapper
                                      local_cxy );
     if( vseg == NULL )
     {
         printk("\n[PANIC] in %s : cannot register vseg to VSL in cluster %x\n",
-        __FUNCTION__ , cxy );
+        __FUNCTION__ , local_cxy );
         hal_core_sleep();
     }
 
 #if DEBUG_HAL_VMM
-printk("\n[%s] thread[%x,%x] registered kcode vseg[%x,%x]\n",
-__FUNCTION__, this->process->pid, this->trdid, info->kcode_base, info->kcode_size );
+printk("\n[%s] thread[%x,%x] registered kcode vseg[%x,%x] in cluster %x\n",
+__FUNCTION__, this->process->pid, this->trdid, info->kcode_base, info->kcode_size, local_cxy );
 hal_vmm_display( &process_zero , true );
 #endif
@@ -194,9 +198,13 @@
 
 //////////////////////////////////////////
-void hal_vmm_display( process_t * process,
-                      bool_t      mapping )
+void hal_vmm_display( xptr_t   process_xp,
+                      bool_t   mapping )
 {
-    // get pointer on process VMM
-    vmm_t * vmm = &process->vmm;
+    // get target process cluster and local pointer
+    process_t * process_ptr = GET_PTR( process_xp );
+    cxy_t       process_cxy = GET_CXY( process_xp );
+
+    // get local pointer on target process VMM
+    vmm_t * vmm = &process_ptr->vmm;
 
     // get pointers on TXT0 chdev
@@ -205,19 +213,23 @@
     chdev_t * txt0_ptr = GET_PTR( txt0_xp );
 
-    // build extended pointer on TXT0 lock and VSL lock
+    // build extended pointer on TXT0 lock
     xptr_t  txt_lock_xp = XPTR( txt0_cxy  , &txt0_ptr->wait_lock );
-    xptr_t  vsl_lock_xp = XPTR( local_cxy , &vmm->vsl_lock );
-
-    // get root of vsegs list
-    xptr_t root_xp = XPTR( local_cxy , &vmm->vsegs_root );
-
-    // get the locks protecting TXT0, VSL, and GPT
+
+    // build extended pointers on VSL lock and VSL root
+    xptr_t vsl_root_xp = XPTR( process_cxy , &vmm->vsegs_root );
+    xptr_t vsl_lock_xp = XPTR( process_cxy , &vmm->vsl_lock );
+
+    // get the locks protecting TXT0 and VSL
     remote_rwlock_rd_acquire( vsl_lock_xp );
     remote_busylock_acquire( txt_lock_xp );
 
-    nolock_printk("\n***** VSL and GPT for process %x in cluster %x / PT1 = %x\n",
-    process->pid , local_cxy , vmm->gpt.ptr );
-
-    if( xlist_is_empty( root_xp ) )
+    // get PID and PT1 values
+    pid_t      pid = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
+    uint32_t * pt1 = hal_remote_lpt( XPTR( process_cxy , &vmm->gpt.ptr ) );
+
+    nolock_printk("\n***** VSL and GPT / process %x / cluster %x / PT1 %x / cycle %d\n",
+    pid , process_cxy , pt1 , (uint32_t)hal_get_cycles() );
+
+    if( xlist_is_empty( vsl_root_xp ) )
     {
         nolock_printk("   ... no vsegs registered\n");
@@ -227,18 +239,31 @@
         xptr_t         iter_xp;
         xptr_t         vseg_xp;
-        vseg_t       * vseg;
-
-        XLIST_FOREACH( root_xp , iter_xp )
+        vseg_t       * vseg_ptr;
+        cxy_t          vseg_cxy;
+        intptr_t       min;
+        intptr_t       max;
+        uint32_t       type;
+        intptr_t       vpn_base;
+        intptr_t       vpn_size;
+
+        XLIST_FOREACH( vsl_root_xp , iter_xp )
         {
-            vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
-            vseg    = GET_PTR( vseg_xp );
+            vseg_xp  = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
+            vseg_ptr = GET_PTR( vseg_xp );
+            vseg_cxy = GET_CXY( vseg_xp );
+
+            type     =           hal_remote_l32( XPTR( vseg_cxy , &vseg_ptr->type ) );
+            min      = (intptr_t)hal_remote_lpt( XPTR( vseg_cxy , &vseg_ptr->min ) );
+            max      = (intptr_t)hal_remote_lpt( XPTR( vseg_cxy , &vseg_ptr->max ) );
+            vpn_size = (intptr_t)hal_remote_lpt( XPTR( vseg_cxy , &vseg_ptr->vpn_size ) );
+            vpn_base = (intptr_t)hal_remote_lpt( XPTR( vseg_cxy , &vseg_ptr->vpn_base ) );
 
             nolock_printk(" - %s : base = %X / size = %X / npages = %d\n",
-            vseg_type_str(vseg->type), vseg->min, vseg->max - vseg->min, vseg->vpn_size );
+            vseg_type_str(type), min, max - min, vpn_size );
 
             if( mapping )  
             {
-                vpn_t    vpn     = vseg->vpn_base;
-                vpn_t    vpn_max = vpn + vseg->vpn_size;
+                vpn_t    vpn     = vpn_base;
+                vpn_t    vpn_max = vpn_base + vpn_size;
                 ppn_t    ppn;
                 uint32_t attr;
@@ -246,5 +271,5 @@
                 while( vpn < vpn_max )   // scan the PTEs
                 {
-                    hal_gpt_get_pte( XPTR( local_cxy , &vmm->gpt ) , vpn , &attr , &ppn );
+                    hal_gpt_get_pte( XPTR( process_cxy , &vmm->gpt ) , vpn , &attr , &ppn );
 
                     if( attr & GPT_MAPPED )
