Index: trunk/hal/tsar_mips32/core/hal_context.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_context.c	(revision 407)
+++ trunk/hal/tsar_mips32/core/hal_context.c	(revision 408)
@@ -36,10 +36,10 @@
 
 /////////////////////////////////////////////////////////////////////////////////////////
-//       Define various SR values for TSAR-MIPS32 
-/////////////////////////////////////////////////////////////////////////////////////////
-
-#define SR_USR_MODE       0x0000FC13
-#define SR_USR_MODE_FPU   0x2000FC13
-#define SR_SYS_MODE       0x0000FC00
+//       Define various SR initialisation values for TSAR-MIPS32 
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define SR_USR_MODE       0x0000FF13
+#define SR_USR_MODE_FPU   0x2000FF13
+#define SR_SYS_MODE       0x0000FF00
 
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -191,17 +191,101 @@
 }  // end hal_cpu_context_create()
 
+////////////////////////////////////////////
+void hal_cpu_context_fork( xptr_t child_xp )
+{
+    // allocate a local CPU context in kernel stack
+    // It is initialized from local parent context
+    // and from child specific values, and is copied in
+    // in the remote child context using a remote_memcpy()
+    hal_cpu_context_t  context;
+
+    // get local parent thread local pointer
+    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 = (thread_t *)GET_PTR( child_xp );
+
+    // get remote child cpu_context local pointer
+    char * child_context_ptr = hal_remote_lpt( XPTR(child_cxy , &child_ptr->cpu_context) );
+
+    // get local pointer on remote child process
+    process_t * process = (process_t *)hal_remote_lpt( XPTR(child_cxy , &child_ptr->process) );
+
+    // get ppn of remote child process page table
+    uint32_t    pt_ppn = hal_remote_lw( XPTR(child_cxy , &process->vmm.gpt.ppn) );
+
+    // save CPU registers in local CPU context
+    hal_do_cpu_save( &context );
+
+    // From this point, both parent and child threads execute the following code.
+    // They can be distinguished by the CURRENT_THREAD value, and child will only 
+    // execute it when it is unblocked by parent, after return to sys_fork().
+    // - parent thread copies user stack, and patch sp_29 / c0_th / C0_sr / c2_ptpr
+    // - child thread does nothing
+
+    thread_t * current = CURRENT_THREAD;
+
+    if( current == parent_ptr )    // current == parent thread
+    {
+        // get parent and child stack pointers
+        char * parent_sp = (char *)context.sp_29;
+        char * child_sp  = (char *)((intptr_t)parent_sp +
+                                    (intptr_t)child_ptr - 
+                                    (intptr_t)parent_ptr );
+ 
+        // patch kernel_stack pointer, current thread, and status slots
+        context.sp_29   = (uint32_t)child_sp;
+        context.c0_th   = (uint32_t)child_ptr;
+        context.c0_sr   = SR_SYS_MODE;
+        context.c2_ptpr = pt_ppn >> 1;
+
+        // copy local context to remote child context)
+        hal_remote_memcpy( XPTR( child_cxy , child_context_ptr ),
+                           XPTR( local_cxy  , &context ) , 
+                           sizeof( hal_cpu_context_t ) );
+
+        // copy kernel stack content from local parent thread to remote child thread
+        uint32_t size = (uint32_t)parent_ptr + CONFIG_THREAD_DESC_SIZE - (uint32_t)parent_sp;
+        hal_remote_memcpy( XPTR( child_cxy , child_sp ),
+                           XPTR( local_cxy , parent_sp ),
+                           size );
+    }
+    else                           // current == child thread
+    {
+        assert( (current == child_ptr) , __FUNCTION__ , "current = %x / child = %x\n");
+    }
+
+}  // end hal_cpu_context_fork()
+
 /////////////////////////////////////////////////
-void hal_cpu_context_display( thread_t * thread )
-{
-    hal_cpu_context_t * ctx = (hal_cpu_context_t *)thread->cpu_context;
-
+void hal_cpu_context_display( xptr_t  thread_xp )
+{
+    hal_cpu_context_t * ctx;
+
+    // get thread cluster and local pointer
+    cxy_t      cxy = GET_CXY( thread_xp );
+    thread_t * ptr = (thread_t *)GET_PTR( thread_xp );
+
+    // get context pointer
+    ctx = (hal_cpu_context_t *)hal_remote_lpt( XPTR( cxy , &ptr->cpu_context ) );
+
+    // get relevant context slots values
+    uint32_t sp_29   = hal_remote_lw( XPTR( cxy , &ctx->sp_29   ) );
+    uint32_t ra_31   = hal_remote_lw( XPTR( cxy , &ctx->ra_31   ) );
+    uint32_t c0_sr   = hal_remote_lw( XPTR( cxy , &ctx->c0_sr   ) );
+    uint32_t c0_epc  = hal_remote_lw( XPTR( cxy , &ctx->c0_epc  ) );
+    uint32_t c0_th   = hal_remote_lw( XPTR( cxy , &ctx->c0_th   ) );
+    uint32_t c2_ptpr = hal_remote_lw( XPTR( cxy , &ctx->c2_ptpr ) );
+    uint32_t c2_mode = hal_remote_lw( XPTR( cxy , &ctx->c2_mode ) );
+    
     printk("\n***** CPU context for thread %x in process %x / cycle %d\n" 
-           " gp_28   = %X    sp_29   = %X    ra_31   = %X\n" 
+           " sp_29   = %X    ra_31   = %X\n" 
            " c0_sr   = %X    c0_epc  = %X    c0_th = %X\n"
            " c2_ptpr = %X    c2_mode = %X\n",
-           thread->trdid, thread->process->pid, hal_time_stamp(),
-           ctx->gp_28   , ctx->sp_29   , ctx->ra_31,
-           ctx->c0_sr   , ctx->c0_epc  , ctx->c0_th,
-           ctx->c2_ptpr , ctx->c2_mode );
+           ptr->trdid, ptr->process->pid, hal_time_stamp(),
+           sp_29   , ra_31,
+           c0_sr   , c0_epc  , c0_th,
+           c2_ptpr , c2_mode );
 
 }  // end hal_cpu_context_display()
@@ -270,7 +354,12 @@
 
 //////////////////////////////////////////////
-void hal_fpu_context_save( thread_t * thread )
-{
-    uint32_t ctx = (uint32_t)thread->fpu_context;
+void hal_fpu_context_save( xptr_t  thread_xp )
+{
+    // allocate a local FPU context in kernel stack
+    hal_fpu_context_t  context;
+
+    // get remote child cluster and local pointer
+    cxy_t      thread_cxy = GET_CXY( thread_xp );
+    thread_t * thread_ptr = (thread_t *)GET_PTR( thread_xp );
 
     asm volatile(
@@ -309,7 +398,12 @@
     "swc1    $f31,  31*4(%0)  \n"   
     ".set reorder             \n"
-    : : "r"(ctx) );
-
-}  // end hal_cpu_context_save()
+    : : "r"(&context) );
+
+    // copy local context to remote child context)
+    hal_remote_memcpy( XPTR( thread_cxy , &thread_ptr->fpu_context ),
+                       XPTR( local_cxy  , &context ) , 
+                       sizeof( hal_fpu_context_t ) );
+
+}  // end hal_fpu_context_save()
 
 /////////////////////////////////////////////////
Index: trunk/hal/tsar_mips32/core/hal_exception.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_exception.c	(revision 407)
+++ trunk/hal/tsar_mips32/core/hal_exception.c	(revision 408)
@@ -99,4 +99,26 @@
 xcode_values_t;
 
+////////////////////////////////////////////////////
+static char * hal_mmu_exception_str( uint32_t code )
+{
+    if     ( code == MMU_WRITE_PT1_UNMAPPED        ) return "WRITE_PT1_UNMAPPED";
+    else if( code == MMU_WRITE_PT2_UNMAPPED        ) return "WRITE_PT2_UNMAPPED";
+    else if( code == MMU_WRITE_PRIVILEGE_VIOLATION ) return "WRITE_PRIVILEGE_VIOLATION";
+    else if( code == MMU_WRITE_ACCESS_VIOLATION    ) return "WRITE_ACCESS_VIOLATION";
+    else if( code == MMU_WRITE_UNDEFINED_XTN       ) return "WRITE_UNDEFINED_XTN";
+    else if( code == MMU_WRITE_PT1_ILLEGAL_ACCESS  ) return "WRITE_PT1_ILLEGAL_ACCESS";
+    else if( code == MMU_WRITE_PT2_ILLEGAL_ACCESS  ) return "WRITE_PT2_ILLEGAL_ACCESS";
+    else if( code == MMU_WRITE_DATA_ILLEGAL_ACCESS ) return "WRITE_DATA_ILLEGAL_ACCESS";
+    else if( code == MMU_READ_PT1_UNMAPPED         ) return "READ_PT1_UNMAPPED";
+    else if( code == MMU_READ_PT2_UNMAPPED         ) return "READ_PT2_UNMAPPED";
+    else if( code == MMU_READ_PRIVILEGE_VIOLATION  ) return "READ_PRIVILEGE_VIOLATION";
+    else if( code == MMU_READ_EXEC_VIOLATION       ) return "READ_EXEC_VIOLATION";
+    else if( code == MMU_READ_UNDEFINED_XTN        ) return "READ_UNDEFINED_XTN";
+    else if( code == MMU_READ_PT1_ILLEGAL_ACCESS   ) return "READ_PT1_ILLEGAL_ACCESS";
+    else if( code == MMU_READ_PT2_ILLEGAL_ACCESS   ) return "READ_PT2_ILLEGAL_ACCESS";
+    else if( code == MMU_READ_DATA_ILLEGAL_ACCESS  ) return "READ_DATA_ILLEGAL_ACCESS";
+    else                                             return "undefined";
+}
+
 //////////////////////////////////////////////////////////////////////////////////////////
 // This function is called when a FPU Coprocessor Unavailable exception has been 
@@ -120,5 +142,5 @@
         if( core->fpu_owner != this )
 	    {
-		    hal_fpu_context_save ( core->fpu_owner->fpu_context );
+		    hal_fpu_context_save( XPTR( local_cxy , core->fpu_owner ) );
         }
 	}
@@ -179,6 +201,13 @@
     }
 
- excp_dmsg("\n[DBG] %s : core[%x,%d] / is_ins %d / code %x / vaddr %x\n",
-__FUNCTION__ , local_cxy , this->core->lid , is_ins, excp_code, bad_vaddr );
+// @@@
+thread_t * parent = (thread_t *)0xa4000;
+uint32_t cond = (this == 0xe0000) && (hal_time_stamp() > 5380000);
+
+if( cond ) hal_gpt_display( this->process );
+if( cond ) hal_gpt_display( parent->process );
+if( cond ) printk("\n[DBG] %s : core[%x,%d] / is_ins %d / %s / vaddr %x\n",
+__FUNCTION__ , local_cxy , this->core->lid , is_ins,
+hal_mmu_exception_str(excp_code) , bad_vaddr );
 
    // analyse exception code
@@ -217,15 +246,15 @@
             return EXCP_USER_ERROR;
         }
-        case MMU_WRITE_ACCESS_VIOLATION:     // user error or Copy-on-Write
+        case MMU_WRITE_ACCESS_VIOLATION:     // user error, or Copy-on-Write
         {
             // access page table to get GPT_COW flag
             bool_t cow = hal_gpt_pte_is_cow( &(process->vmm.gpt),
-                                             bad_vaddr >> CONFIG_PPM_PAGE_SHIFT );  // vpn
+                                             bad_vaddr >> CONFIG_PPM_PAGE_SHIFT ); 
 
             if( cow )                        // Copy-on-Write 
             {
                 // try to allocate and copy the page
-                error = vmm_copy_on_write( process,
-                                           bad_vaddr >> CONFIG_PPM_PAGE_SHIFT );  // vpn
+                error = vmm_handle_cow( process,
+                                        bad_vaddr >> CONFIG_PPM_PAGE_SHIFT );  
                 if( error )
                 {
@@ -238,5 +267,5 @@
                 {
 
-excp_dmsg("\n[DBG] %s : core[%x,%d] / copy-on-write handled for vaddr = %x\n",
+if( cond ) printk("\n[DBG] %s : core[%x,%d] / copy-on-write handled for vaddr = %x\n",
 __FUNCTION__ , local_cxy , this->core->lid , bad_vaddr );
 
@@ -274,13 +303,14 @@
 //////////////////////////////////////////////////////////////////////////////////////////
 // @ this     : pointer on faulty thread descriptor.
-// @ regs_tbl : pointer on register array.
+// @ uzone : pointer on register array.
 // @ error    : EXCP_USER_ERROR or EXCP_KERNEL_PANIC
 //////////////////////////////////////////////////////////////////////////////////////////
 static void hal_exception_dump( thread_t * this,
-                                reg_t    * regs_tbl,
+                                reg_t    * uzone,
                                 error_t    error )
 {
-    uint32_t  save_sr;
-    core_t  * core = this->core;
+    uint32_t    save_sr;
+    core_t    * core    = this->core;
+    process_t * process = this->process;
 
     // get pointers on TXT0 chdev
@@ -297,38 +327,39 @@
     if( error == EXCP_USER_ERROR )
     {
-        nolock_printk("\n========= USER ERROR / core[%x,%d] / cycle %d ==============\n",
-        local_cxy , core->lid , (uint32_t)hal_get_cycles() );
+        nolock_printk("\n=== USER ERROR / trdid %x / pid %x / core[%x,%d] / cycle %d ===\n",
+        this->trdid, process->pid, local_cxy, core->lid , (uint32_t)hal_get_cycles() );
     }
     else
     {
-        nolock_printk("\n======= KERNEL PANIC / core[%x,%d] / cycle %d ==============\n",
-        local_cxy , core->lid , (uint32_t)hal_get_cycles() );
+        nolock_printk("\n=== KERNEL PANIC / trdid %x / pid %x / core[%x,%d] / cycle %d ===\n",
+        this->trdid, process->pid, local_cxy, core->lid , (uint32_t)hal_get_cycles() );
     }
 
-	nolock_printk("  thread type = %s / trdid = %x / pid %x / core[%x,%d]\n"
-           "  local locks = %d / remote locks = %d / blocked_vector = %X\n\n",
-           thread_type_str(this->type), this->trdid, this->process->pid, local_cxy,
-           this->core->lid, this->local_locks, this->remote_locks, this->blocked );
-
-	nolock_printk("cp0_cr %X   cp0_epc %X   cp0_sr %X   cp2_mode %X\n",
-		   regs_tbl[UZ_CR], regs_tbl[UZ_EPC], regs_tbl[UZ_SR], regs_tbl[UZ_MODE]);
-
-    nolock_printk("at_01 %X  v0_2  %X  v1_3  %X  a0_4   %X  a1_5   %X\n",
-   	       regs_tbl[UZ_AT],regs_tbl[UZ_V0],regs_tbl[UZ_V1],regs_tbl[UZ_A0],regs_tbl[UZ_A1]);
-
-    nolock_printk("a2_6  %X  a3_7  %X  t0_8  %X  t1_9   %X  t2_10  %X\n",
-		   regs_tbl[UZ_A2],regs_tbl[UZ_A3],regs_tbl[UZ_T0],regs_tbl[UZ_T1],regs_tbl[UZ_T2]);
+	nolock_printk("local locks = %d / remote locks = %d / blocked_vector = %X\n\n",
+    this->local_locks, this->remote_locks, this->blocked );
+
+    nolock_printk("c0_cr   %X  c0_epc  %X  c0_sr  %X  c0_th  %X\n",
+    uzone[UZ_CR], uzone[UZ_EPC], uzone[UZ_SR], uzone[UZ_TH] );
+
+    nolock_printk("c2_mode %X  c2_ptpr %X\n",
+    uzone[UZ_MODE], uzone[UZ_PTPR] );
+
+    nolock_printk("at_01   %X  v0_2    %X  v1_3   %X  a0_4   %X  a1_5   %X\n",
+   	uzone[UZ_AT], uzone[UZ_V0], uzone[UZ_V1], uzone[UZ_A0], uzone[UZ_A1] );
+
+    nolock_printk("a2_6    %X  a3_7    %X  t0_8   %X  t1_9   %X  t2_10  %X\n",
+	uzone[UZ_A2], uzone[UZ_A3], uzone[UZ_T0], uzone[UZ_T1], uzone[UZ_T2] );
   
-    nolock_printk("t3_11 %X  t4_12 %X  t5_13 %X  t6_14  %X  t7_15  %X\n",
-		   regs_tbl[UZ_T3],regs_tbl[UZ_T4],regs_tbl[UZ_T5],regs_tbl[UZ_T6],regs_tbl[UZ_T7]);
-
-    nolock_printk("s0_16 %X  s1_17 %X  s2_18 %X  s3_19  %X  s4_20  %X\n",
-		   regs_tbl[UZ_S0],regs_tbl[UZ_S1],regs_tbl[UZ_S2],regs_tbl[UZ_S3],regs_tbl[UZ_S4]);
+    nolock_printk("t3_11   %X  t4_12   %X  t5_13  %X  t6_14  %X  t7_15  %X\n",
+	uzone[UZ_T3], uzone[UZ_T4], uzone[UZ_T5], uzone[UZ_T6], uzone[UZ_T7] );
+
+    nolock_printk("s0_16   %X  s1_17   %X  s2_18  %X  s3_19  %X  s4_20  %X\n",
+	uzone[UZ_S0], uzone[UZ_S1], uzone[UZ_S2], uzone[UZ_S3], uzone[UZ_S4] );
   
-    nolock_printk("s5_21 %X  s6_22 %X  s7_23 %X  s8_24  %X  ra_25  %X\n",
-	       regs_tbl[UZ_S5],regs_tbl[UZ_S6],regs_tbl[UZ_S7],regs_tbl[UZ_T8],regs_tbl[UZ_T9]);
-
-    nolock_printk("gp_28 %X  sp_29 %X  S8_30 %X  ra_31  %X\n",
-		   regs_tbl[UZ_GP],regs_tbl[UZ_SP],regs_tbl[UZ_S8],regs_tbl[UZ_RA]);
+    nolock_printk("s5_21   %X  s6_22   %X  s7_23  %X  s8_24  %X  ra_25  %X\n",
+	uzone[UZ_S5], uzone[UZ_S6], uzone[UZ_S7], uzone[UZ_T8], uzone[UZ_T9] );
+
+    nolock_printk("gp_28   %X  sp_29   %X  S8_30  %X  ra_31  %X\n",
+	uzone[UZ_GP], uzone[UZ_SP], uzone[UZ_S8], uzone[UZ_RA] );
 
     // release the lock
@@ -337,20 +368,22 @@
 }  // end hal_exception_dump()
 
-
-///////////////////////////////////////////////////////////////////////////////
-// TODO replace the hal_core_sleep() by the generic panic() function.
-///////////////////////////////////////////////////////////////////////////////
-void hal_do_exception( thread_t * this, 
-                       reg_t    * regs_tbl )
-{
-	error_t             error;
-	uint32_t            excCode;                  // 4 bits XCODE from CP0_CR
+///////////////////////
+void hal_do_exception()
+{
+    uint32_t   * uzone;
+    thread_t   * this;
+	error_t      error;
+	uint32_t     excCode;                  // 4 bits XCODE from CP0_CR
+
+    // get pointer on faulty thread uzone
+    this  = CURRENT_THREAD;
+    uzone = (uint32_t *)CURRENT_THREAD->uzone;
 
     // get 4 bits XCODE from CP0_CR register
-	excCode        = (regs_tbl[UZ_CR] >> 2) & 0xF;
+	excCode        = (uzone[UZ_CR] >> 2) & 0xF;
 
 excp_dmsg("\n[DBG] %s : core[%x,%d] / thread %x in process %x / xcode %x / cycle %d\n",
 __FUNCTION__, local_cxy, this->core->lid, this->trdid, 
-this->process->pid, excCode, (uint32_t)hal_get_cycle() );
+this->process->pid, excCode, (uint32_t)hal_get_cycles() );
 
 	switch(excCode)
@@ -368,5 +401,5 @@
 	    case XCODE_CPU:    // can be non fatal
         {
-            if( ((regs_tbl[UZ_CR] >> 28) & 0x3) == 1 )  // unavailable FPU
+            if( ((uzone[UZ_CR] >> 28) & 0x3) == 1 )     // unavailable FPU
             {
                 error = hal_fpu_exception( this );
@@ -395,5 +428,5 @@
 	if( error == EXCP_USER_ERROR )          //  user error => kill user process
 	{
-        hal_exception_dump( this , regs_tbl , error );
+        hal_exception_dump( this , uzone , error );
 
         // FIXME : replace this loop by sys_kill()
@@ -403,10 +436,12 @@
     else if( error == EXCP_KERNEL_PANIC )   // kernel error => kernel panic
     {
-        hal_exception_dump( this , regs_tbl , error );
-        hal_core_sleep();
+        hal_exception_dump( this , uzone , error );
+        panic( "KERNEL_PANIC for thread %x in process %x on core [%x,%d]/n",
+        this->trdid , this->process->pid , local_cxy , this->core->lid );
     }
 
 excp_dmsg("\n[DBG] %s : core[%x,%d] exit / thread %x in process %x / cycle %d\n",
-__FUNCTION__, local_cxy, this->core->lid, this->trdid, this->process->pid, hal_time_stamp() );
+__FUNCTION__, local_cxy, this->core->lid, this->trdid, this->process->pid,
+(uint32_t)hal_get_cycles() );
 
 }  // end hal_do_exception()
Index: trunk/hal/tsar_mips32/core/hal_gpt.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_gpt.c	(revision 407)
+++ trunk/hal/tsar_mips32/core/hal_gpt.c	(revision 408)
@@ -170,6 +170,6 @@
         error = hal_gpt_set_pte( gpt,
                                  vpn,
-                                 (local_cxy<<20) | (vpn & 0xFFFFF),
-                                 attr );
+                                 attr,
+                                 (local_cxy<<20) | (vpn & 0xFFFFF) );
 
         if( error )
@@ -321,6 +321,6 @@
                     {
                         vpn = (ix1 << 9) | ix2;
-                        printk(" - SMALL : vpn = %x / PT2[%d] = %x / pt2[%d] = %x\n",
-                        vpn , 2*ix2 , pte2_attr , 2*ix2+1 , pte2_ppn );
+                        printk(" - SMALL : vpn %X / ppn %X / attr %X\n",
+                        vpn , pte2_ppn , tsar2gpt(pte2_attr) );
                     }
                 }
@@ -334,6 +334,6 @@
 error_t hal_gpt_set_pte( gpt_t   * gpt,
                          vpn_t     vpn,
-                         ppn_t     ppn,
-                         uint32_t  attr )    // generic GPT attributes
+                         uint32_t  attr,     // generic GPT attributes
+                         ppn_t     ppn )
 {
     uint32_t          * pt1;                 // PT1 base addres
@@ -355,6 +355,6 @@
     uint32_t            tsar_attr;           // PTE attributes for TSAR MMU
 
-    gpt_dmsg("\n[DBG] %s : core[%x,%d] enter for vpn = %x / ppn = %x / gpt_attr = %x\n", 
-    __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , ppn , attr );
+gpt_dmsg("\n[DBG] %s : core[%x,%d] enter for vpn = %x / ppn = %x / gpt_attr = %x\n", 
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , ppn , attr );
  
     // compute indexes in PT1 and PT2
@@ -368,6 +368,6 @@
     tsar_attr = gpt2tsar( attr );
 
-    gpt_dmsg("\n[DBG] %s : core[%x,%d] / vpn = %x / &pt1 = %x / tsar_attr = %x\n", 
-    __FUNCTION__, local_cxy , CURRENT_THREAD->core->lid , vpn , pt1 , tsar_attr );
+gpt_dmsg("\n[DBG] %s : core[%x,%d] / vpn = %x / &pt1 = %x / tsar_attr = %x\n", 
+__FUNCTION__, local_cxy , CURRENT_THREAD->core->lid , vpn , pt1 , tsar_attr );
 
     // get pointer on PT1[ix1]
@@ -400,6 +400,6 @@
         pte1 = *pte1_ptr;
         
-        gpt_dmsg("\n[DBG] %s : core[%x,%d] / vpn = %x / current_pte1 = %x\n", 
-        __FUNCTION__, local_cxy , CURRENT_THREAD->core->lid , vpn , pte1 );
+gpt_dmsg("\n[DBG] %s : core[%x,%d] / vpn = %x / current_pte1 = %x\n", 
+__FUNCTION__, local_cxy , CURRENT_THREAD->core->lid , vpn , pte1 );
         
         // allocate a PT2 if PT1 entry not valid
@@ -442,6 +442,6 @@
 	    pt2     = (uint32_t *)GET_PTR( ppm_ppn2base( pt2_ppn ) );
 
-        gpt_dmsg("\n[DBG] %s : core[%x,%d] / vpn = %x / pte1 = %x / &pt2 = %x\n", 
-        __FUNCTION__, local_cxy , CURRENT_THREAD->core->lid , vpn , pte1 , pt2 );
+gpt_dmsg("\n[DBG] %s : core[%x,%d] / vpn = %x / pte1 = %x / &pt2 = %x\n", 
+__FUNCTION__, local_cxy , CURRENT_THREAD->core->lid , vpn , pte1 , pt2 );
         
     }
@@ -454,7 +454,7 @@
 	hal_fence();
 
-    gpt_dmsg("\n[DBG] %s : core[%x,%d] exit / vpn = %x / pte2_attr = %x / pte2_ppn = %x\n", 
-    __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , 
-    pt2[2 * ix2] , pt2[2 * ix2 + 1] );
+gpt_dmsg("\n[DBG] %s : core[%x,%d] exit / vpn = %x / pte2_attr = %x / pte2_ppn = %x\n", 
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , 
+pt2[2 * ix2] , pt2[2 * ix2 + 1] );
  
 	return 0;
@@ -728,20 +728,22 @@
 }  // end hal_gpt_unlock_pte()
 
-///////////////////////////////////////
-error_t hal_gpt_copy( gpt_t  * dst_gpt,
-                      gpt_t  * src_gpt,
-                      vpn_t    vpn_base,
-                      vpn_t    vpn_size,
-                      bool_t   cow )
-{
-    vpn_t        vpn;       // current vpn
-
+///////////////////////////////////////////
+error_t hal_gpt_pte_copy( gpt_t  * dst_gpt,
+                          xptr_t   src_gpt_xp,
+                          vpn_t    vpn,
+                          bool_t   cow,
+                          ppn_t  * ppn,
+                          bool_t * mapped )
+{
     uint32_t     ix1;       // index in PT1
     uint32_t     ix2;       // index in PT2
 
-	uint32_t   * src_pt1;   // local pointer on PT1 for SRC_GPT 
-	uint32_t   * dst_pt1;   // local pointer on PT1 for DST_GPT
-    uint32_t   * dst_pt2;   // local pointer on PT2 for DST_GPT
-    uint32_t   * src_pt2;   // local pointer on PT2 for SRC_GPT
+    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 dynamic PT2 allocation
@@ -750,6 +752,6 @@
     uint32_t     dst_pte1;
 
-    uint32_t     pte2_attr;
-    uint32_t     pte2_ppn;
+    uint32_t     src_pte2_attr;
+    uint32_t     src_pte2_ppn;
 
     page_t     * page;
@@ -759,107 +761,146 @@
     ppn_t        dst_pt2_ppn;
 
-gpt_dmsg("\n[DBG] %s : core[%x,%d] enter\n", 
-__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid );
-
-    // check page size
-    assert( (CONFIG_PPM_PAGE_SIZE == 4096) , __FUNCTION__ ,
-    "for TSAR, the page must be 4 Kbytes\n" );
-
-    // check SRC_PT1 and DST_PT1 existence
-    assert( (src_gpt->ptr != NULL) , __FUNCTION__ , "SRC_PT1 does not exist\n");
-    assert( (dst_gpt->ptr != NULL) , __FUNCTION__ , "DST_PT1 does not exist\n");
-
-    // get pointers on SRC_PT1 and DST_PT1
-    src_pt1 = (uint32_t *)src_gpt->ptr;
+gpt_dmsg("\n[DBG] %s : core[%x,%d] enter for vpn %x\n", 
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn );
+
+    // get remote src_gpt cluster and local pointer
+    src_cxy = GET_CXY( src_gpt_xp );
+    src_gpt = (gpt_t *)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;
 
-    // scan pages in vseg
-    for( vpn = vpn_base ; vpn < (vpn_base + vpn_size) ; vpn++ )
-    {
-        ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
-        ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
-
-        // get SRC_PT1 entry
-        src_pte1 = src_pt1[ix1];
-
-        // do nothing if SRC_PTE1 unmapped
-		if( (src_pte1 & TSAR_MMU_MAPPED) != 0 )   // SRC_PTE1 is mapped 
+    // check src_pt1 and dst_pt1 existence
+    assert( (src_pt1 != NULL) , __FUNCTION__ , "src_pt1 does not exist\n");
+    assert( (dst_pt1 != NULL) , __FUNCTION__ , "dst_pt1 does not exist\n");
+
+    ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
+    ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
+
+    // get src_pte1 
+    src_pte1 = hal_remote_lw( XPTR( src_cxy , &src_pt1[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[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[ix1] = dst_pte1;
+        }
+
+        // get pointer on src_pt2
+        src_pt2_ppn = (ppn_t)TSAR_MMU_PTBA_FROM_PTE1( src_pte1 );
+        src_pt2     = (uint32_t *)GET_PTR( ppm_ppn2base( src_pt2_ppn ) );
+
+        // get pointer on dst_pt2
+        dst_pt2_ppn = (ppn_t)TSAR_MMU_PTBA_FROM_PTE1( dst_pte1 );
+        dst_pt2     = (uint32_t *)GET_PTR( ppm_ppn2base( dst_pt2_ppn ) );
+
+        // get attr and ppn from SRC_PT2
+        src_pte2_attr = hal_remote_lw( XPTR( src_cxy , &src_pt2[2 * ix2]     ) );
+        src_pte2_ppn  = hal_remote_lw( XPTR( src_cxy , &src_pt2[2 * ix2 + 1] ) );
+
+        // do nothing if src_pte2 not MAPPED
+        if( (src_pte2_attr & TSAR_MMU_MAPPED) != 0 )  
         {
-            assert( (src_pte1 & TSAR_MMU_SMALL) , __FUNCTION__ ,
-            "no BIG page for user process in TSAR architecture\n" );
-
-            // get DST_PT1 entry
-            dst_pte1 = dst_pt1[ix1];
-
-            // map dst_pte1 if required
-            if( (dst_pte1 & TSAR_MMU_MAPPED) == 0 ) 
-            { 
-                // allocate one physical page for a new DST_PT2
-	            req.type  = KMEM_PAGE;
-	            req.size  = 0;                     // 1 small page 
-	            req.flags = AF_KERNEL | AF_ZERO;
-	            page = (page_t *)kmem_alloc( &req );
-
-                if( page == NULL )
-                {
-			        printk("\n[ERROR] in %s : cannot allocate PT2\n", __FUNCTION__ );
-                    return ENOMEM;
-                }
-
-                // build extended pointer on page descriptor
-                page_xp = XPTR( local_cxy , page );
-
-                // get PPN for this new DST_PT2 
-                dst_pt2_ppn    = (ppn_t)ppm_page2ppn( page_xp );
-
-                // build the new dst_pte1
-                dst_pte1 = TSAR_MMU_MAPPED | TSAR_MMU_SMALL | dst_pt2_ppn;
-
-                // register it in DST_GPT
-                dst_pt1[ix1] = dst_pte1;
+            // set PPN in DST PTE2
+            dst_pt2[2*ix2+1] = src_pte2_ppn;
+                        
+            // set attributes in DST PTE2         
+            if( cow && (src_pte2_attr & TSAR_MMU_WRITABLE) ) 
+            {
+                dst_pt2[2*ix2] = (src_pte2_attr | TSAR_MMU_COW) & (~TSAR_MMU_WRITABLE);
+            } 
+            else
+            {
+                dst_pt2[2*ix2] = src_pte2_attr;
             }
 
-            // get PPN and pointer on SRC_PT2
-            src_pt2_ppn = (ppn_t)TSAR_MMU_PTBA_FROM_PTE1( src_pte1 );
-            src_pt2     = (uint32_t *)GET_PTR( ppm_ppn2base( src_pt2_ppn ) );
-
-            // get PPN and pointer on DST_PT2
-            dst_pt2_ppn = (ppn_t)TSAR_MMU_PTBA_FROM_PTE1( dst_pte1 );
-            dst_pt2     = (uint32_t *)GET_PTR( ppm_ppn2base( dst_pt2_ppn ) );
-
-            // get attr and ppn from SRC_PT2
-            pte2_attr = TSAR_MMU_ATTR_FROM_PTE2( src_pt2[2 * ix2] );
-            pte2_ppn  = TSAR_MMU_PPN_FROM_PTE2(  src_pt2[2 * ix2 + 1] );
-
-            // no copy if SRC_PTE2 unmapped
-            if( (pte2_attr & TSAR_MMU_MAPPED) != 0 )  // valid PTE2 in SRC_GPT
-            {
-                // set a new PTE2 in DST_PT2
-                dst_pt2[2*ix2]     = pte2_attr;
-                dst_pt2[2*ix2 + 1] = pte2_ppn;
-                        
-                // FIXME increment page descriptor refcount for the referenced page
-
-                // handle Copy-On-Write 
-                if( cow && (pte2_attr & TSAR_MMU_WRITABLE) )
-                {
-                    // reset WRITABLE flag in DST_GPT
-                    hal_atomic_and( &dst_pt2[2*ix2] , ~TSAR_MMU_WRITABLE );
-
-                    // set COW flag in DST_GPT
-                    hal_atomic_or( &dst_pt2[2*ix2] , TSAR_MMU_COW );
-                }
-            }
-        }   // end if PTE1 mapped
-    }   // end loop on vpn
+            // return "successfully copied"
+            *mapped = true;
+            *ppn    = src_pte2_ppn;
+        
+gpt_dmsg("\n[DBG] %s : core[%x,%d] exit for vpn %x / copy done\n", 
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn );
+
+            hal_fence();
+
+            return 0;
+        }   // end if PTE2 mapped
+    }   // end if PTE1 mapped
+
+    // return "nothing done"
+    *mapped = false;
+    *ppn    = 0;
+    
+gpt_dmsg("\n[DBG] %s : core[%x,%d] exit for vpn %x / nothing done\n", 
+__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn );
 
     hal_fence();
 
-gpt_dmsg("\n[DBG] %s : core[%x,%d] exit\n", 
-__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid );
-
     return 0;
 
-}  // end hal_gpt_copy()
+}  // 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     = (uint32_t*)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()
 
 ///////////////////////////////////////
@@ -869,4 +910,5 @@
     uint32_t * pt1;
     uint32_t   pte1;
+    uint32_t   pte2_attr;
 
     uint32_t * pt2;
@@ -880,118 +922,151 @@
     pte1 = pt1[ix1];
 
-	if( (pte1 & TSAR_MMU_MAPPED) == 0 )    // PT1 entry not mapped
-	{
-		return false;
-	}
-
-	if( (pte1 & TSAR_MMU_SMALL) == 0 )     // it's a PTE1
-	{
-		return false;
-	}
-    else                                   // it's a PTD1
-    {
-        // compute PT2 base address
-        pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
-        pt2     = (uint32_t*)GET_PTR( ppm_ppn2base( pt2_ppn ) );
-
-        if( pt2[2*ix2] & TSAR_MMU_COW ) return true;
-        else                            return false;
-    }
+	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     = (uint32_t*)GET_PTR( ppm_ppn2base( pt2_ppn ) );
+
+    // get pte2_attr
+    pte2_attr = pt2[2*ix2];
+
+if( (CURRENT_THREAD == 0xe0000) && (hal_time_stamp() > 5380000) )
+printk("\n@@@ %s : vpn = %X / attr = %X\n", __FUNCTION__ , vpn , tsar2gpt( pte2_attr ) );
+
+    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()
 
-
-
-
-
-
-
-
-
-
-
-
-/* deprecated : old hal_gpt_copy [AG]
- 
-    // scan the SRC_PT1
-	for( ix1 = 0 ; ix1 < 2048 ; ix1++ )
-	{
-        pte1 = src_pt1[ix1];
-		if( (pte1 & TSAR_MMU_MAPPED) != 0 )
+/////////////////////////////////////////
+void hal_gpt_flip_cow( bool_t  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   old_attr;
+    uint32_t   new_attr;
+
+    // get GPT cluster and local pointer
+    gpt_cxy = GET_CXY( gpt_xp );
+    gpt_ptr = (gpt_t *)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_lw( XPTR( gpt_cxy , &pt1[ix1] ) );
+
+        // only MAPPED & SMALL PTEs are modified
+	    if( (pte1 & TSAR_MMU_MAPPED) && (pte1 & TSAR_MMU_SMALL) )
         {
-            if( (pte1 & TSAR_MMU_SMALL) == 0 )  // PTE1 => big kernel page
+            // compute PT2 base address
+            pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
+            pt2     = (uint32_t*)GET_PTR( ppm_ppn2base( pt2_ppn ) );
+
+            assert( (GET_CXY( ppm_ppn2base( pt2_ppn ) ) == gpt_cxy ), __FUNCTION__,
+            "PT2 and PT1 must be in the same cluster\n");
+  
+            // get current PTE2 attributes
+            old_attr = hal_remote_lw( XPTR( gpt_cxy , &pt2[2*ix2] ) );
+
+            // only MAPPED PTEs are modified        
+            if( old_attr & TSAR_MMU_MAPPED ) 
             {
-                // big kernel pages are shared by all processes => copy it
-                dst_pt1[ix1] = pte1;
-            }
-            else                           // PTD1 => smal pages
-            {
-                // allocate one physical page for a PT2 in DST_GPT
-	            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 )
-                {
-                    // TODO release all memory allocated to DST_GPT
-			        printk("\n[ERROR] in %s : cannot allocate PT2\n", __FUNCTION__ );
-                    return ENOMEM;
+                if( (set_cow != 0) && (old_attr & TSAR_MMU_WRITABLE) )
+                { 
+                    new_attr = (old_attr | TSAR_MMU_COW) & (~TSAR_MMU_WRITABLE);
+                    hal_remote_sw( XPTR( gpt_cxy , &pt2[2*ix2] ) , new_attr );
                 }
-
-                // get extended pointer on page descriptor
-                page_xp = XPTR( local_cxy , page );
-
-                // get pointer on new PT2 in DST_GPT
-                xptr_t base_xp = ppm_page2base( page_xp );
-                dst_pt2 = (uint32_t *)GET_PTR( base_xp );
-
-                // set a new PTD1 in DST_GPT
-                dst_pt2_ppn  = (ppn_t)ppm_page2ppn( page_xp );
-                dst_pt1[ix1] = TSAR_MMU_MAPPED | TSAR_MMU_SMALL | dst_pt2_ppn;
-
-                // get pointer on PT2 in SRC_GPT
-                src_pt2_ppn = (ppn_t)TSAR_MMU_PTBA_FROM_PTE1( pte1 );
-                src_pt2     = (uint32_t *)GET_PTR( ppm_ppn2base( src_pt2_ppn ) );
-
-                // scan the SRC_PT2
-                for( ix2 = 0 ; ix2 < 512 ; ix2++ )
-                {
-                    // get attr & ppn from PTE2
-                    pte2_attr = TSAR_MMU_ATTR_FROM_PTE2( src_pt2[2 * ix2] );
-
-		            if( (pte2_attr & TSAR_MMU_MAPPED) != 0 )  // valid PTE2 in SRC_GPT
-                    {
-                        // get GPT_WRITABLE & PPN
-                        pte2_writable = pte2_attr & GPT_WRITABLE;
-                        pte2_ppn      = TSAR_MMU_PPN_FROM_PTE2(  src_pt2[2 * ix2 + 1] );
-
-                        // set a new PTE2 in DST_GPT
-                        dst_pt2[2*ix2]     = pte2_attr;
-                        dst_pt2[2*ix2 + 1] = pte2_ppn;
-                        
-                        // handle Copy-On-Write
-                        if( cow && pte2_writable )
-                        {
-                            // reset GPT_WRITABLE in both SRC_GPT and DST_GPT
-                            hal_atomic_and( &dst_pt2[2*ix2] , ~GPT_WRITABLE );
-                            hal_atomic_and( &src_pt2[2*ix2] , ~GPT_WRITABLE );
-
-                            // register PG_COW in page descriptor
-                            page = (page_t *)GET_PTR( ppm_ppn2page( pte2_ppn ) );
-                            hal_atomic_or( &page->flags , PG_COW );
-							hal_atomic_add( &page->fork_nr , 1 );
-                        }
-                    }
-                }  // end loop on ix2
-            } 
-        }
-    }  // end loop ix1
-
-    hal_fence();
-
-    return 0;
-
-}  // end hal_gpt_copy()
-
-*/
+                if( (set_cow == 0) && (old_attr & TSAR_MMU_COW ) )
+                { 
+                    new_attr = (old_attr | TSAR_MMU_WRITABLE) & (~TSAR_MMU_COW);
+                    hal_remote_sw( XPTR( gpt_cxy , &pt2[2*ix2] ) , new_attr );
+                }
+            }   // end if PTE2 mapped
+        }   // end if PTE1 mapped
+    }   // end loop on pages
+
+}  // end hal_gpt_flip_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 = (gpt_t *)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_lw( 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     = (uint32_t *)GET_PTR( ppm_ppn2base( pt2_ppn ) );
+
+    // reset PTE2
+	hal_remote_sw( XPTR( gpt_cxy, &pt2[2 * ix2]     ) , 0 );
+	hal_fence();
+
+    // set PTE2 in this order
+	hal_remote_sw( XPTR( gpt_cxy, &pt2[2 * ix2 + 1] ) , ppn );
+	hal_fence();
+	hal_remote_sw( XPTR( gpt_cxy, &pt2[2 * ix2]     ) , tsar_attr );
+	hal_fence();
+
+} // end hal_gpt_update_pte()
+
Index: trunk/hal/tsar_mips32/core/hal_interrupt.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_interrupt.c	(revision 407)
+++ trunk/hal/tsar_mips32/core/hal_interrupt.c	(revision 408)
@@ -29,7 +29,6 @@
 #include <soclib_pic.h>
 
-///////////////////////////////////////
-void hal_do_interrupt( thread_t * this, 
-		               reg_t    * regs_tbl ) 
+///////////////////////
+void hal_do_interrupt()
 {
 
Index: trunk/hal/tsar_mips32/core/hal_kentry.S
===================================================================
--- trunk/hal/tsar_mips32/core/hal_kentry.S	(revision 407)
+++ trunk/hal/tsar_mips32/core/hal_kentry.S	(revision 408)
@@ -40,25 +40,29 @@
 #define      UZ_T6           14
 #define      UZ_T7           15
-#define      UZ_T8           16
-#define      UZ_T9           17
-#define      UZ_S0           18
-#define      UZ_S1           19
-#define      UZ_S2           20
-#define      UZ_S3           21
-#define      UZ_S4           22
-#define      UZ_S5           23
-#define      UZ_S6           24
-#define      UZ_S7           25
-#define      UZ_S8           26
-#define      UZ_GP           27
-#define      UZ_RA           28
-#define      UZ_EPC          29
-#define      UZ_CR           30
-#define      UZ_SP           31
-#define      UZ_SR           32
-#define      UZ_LO           33
-#define      UZ_HI           34
-
-#define      UZ_REGS         35
+#define      UZ_S0           16
+#define      UZ_S1           17
+#define      UZ_S2           18
+#define      UZ_S3           19
+#define      UZ_S4           20
+#define      UZ_S5           21
+#define      UZ_S6           22
+#define      UZ_S7           23
+#define      UZ_T8           24
+#define      UZ_T9           25
+
+#define      UZ_LO           26
+#define      UZ_HI           27
+
+#define      UZ_GP           28
+#define      UZ_SP           29
+#define      UZ_S8           30
+#define      UZ_RA           31
+#define      UZ_PTPR         32
+#define      UZ_EPC          33
+#define      UZ_SR           34
+#define      UZ_TH           35
+#define      UZ_CR           36
+
+#define      UZ_REGS         37
 
 #include <kernel_config.h>
@@ -69,6 +73,7 @@
 	.extern    hal_do_exception
 	.extern    hal_do_syscall
-	.extern    cluster_core_kernel_enter
-	.extern    cluster_core_kentry_exit
+    .extern    puts
+    .extern    putx
+    .extern    putl
 
 	.org       0x180
@@ -80,9 +85,9 @@
 	.set       noreorder
 
-#---------------------------------------------------------------------------------
+#------------------------------------------------------------------------------------
 # Kernel Entry point for Interrupt / Exception / Syscall
 # The c2_dext and c2_iext CP2 registers must have been previously set
 # to "local_cxy", because the kernel run with MMU desactivated.
-#---------------------------------------------------------------------------------
+#------------------------------------------------------------------------------------
 
 hal_kentry_enter:
@@ -93,5 +98,5 @@
 	ori     $27,    $0,	  0x3           # $27 <= code for MMU OFF
 	
-#---------------------------------------------------------------------------------------	
+#------------------------------------------------------------------------------------
 # This code is executed when the core is in user mode:
 # - save current c2_mode in $26.
@@ -106,10 +111,10 @@
     move    $27,    $29                 # $27 <= user stack pointer
 	mfc0    $29,    $4,   2             # get pointer on thread descriptor from c0_th
-    addi    $29,    $29,    CONFIG_THREAD_DESC_SIZE
-    addi    $29,    $29,    -8          # $29 <= kernel stack pointer
+    addi    $29,    $29,  CONFIG_THREAD_DESC_SIZE
+    addi    $29,    $29,  -8            # $29 <= kernel stack pointer
     j       unified_mode
     nop
 
-#---------------------------------------------------------------------------------------	
+#------------------------------------------------------------------------------------
 # This code is executed when the core is already in kernel mode:
 # - save current c2_mode in $26.
@@ -123,5 +128,5 @@
     move    $27,    $29                 # $27 <= current kernel stack pointer
 
-#---------------------------------------------------------------------------------------	
+#------------------------------------------------------------------------------------	
 # This code is executed in both modes (user or kernel):
 # The assumptions are:
@@ -131,8 +136,7 @@
 # - $29 contains the kernel stack pointer.
 # We execute the following actions:
-# - allocate an uzone in kernel stack, incrementing $29
-# - save relevant registers to uzone.
+# - allocate an uzone in kernel stack, decrementing $29.
+# - save relevant GPR, CP0 and CP2 registers to uzone.
 # - set the SR in kernel mode: IRQ disabled, clear exl.
-# - signal the kernel entry.
 
 unified_mode:
@@ -166,42 +170,120 @@
 	sw      $25,	(UZ_T9*4)($29)
 
-	sw      $26,    (UZ_MODE*4)($29)    # save c2_mode
-	sw      $27,	(UZ_SP*4)($29)	    # save sp
-
-	sw	    $28,	(UZ_GP*4)($29)
-	sw	    $30,	(UZ_S8*4)($29)
-	sw	    $31,	(UZ_RA*4)($29)
-
-	mfc0	$16,    $14
-	sw      $16,	(UZ_EPC*4)($29)	    # save c0_epc
-	mflo	$14
-	sw      $14,	(UZ_LO*4)($29)      # save lo
-	mfhi	$15 
-	sw      $15,	(UZ_HI*4)($29)		# save hi
-	mfc0	$18,	$12 
-	sw	    $18,	(UZ_SR*4)($29)		# save c0_sr
-	mfc0    $17,    $13
-	sw      $17,	(UZ_CR*4)($29)		# save c0_cr
-	mfc2    $26,    $1
-
-	srl	    $3,     $18,  5
-	sll     $3,	    $3,   5	
-	mtc0	$3,	    $12			        # set new sr
-
-#---------------------------------------------------------------------------------------
-# This code call the relevant Interrupt / Exception / Syscall handler,
+	mflo	$1
+	sw      $1,     (UZ_LO*4)($29)      # save lo
+	mflo	$1
+	sw      $1, 	(UZ_HI*4)($29)	    # save hi
+
+	sw	    $28,	(UZ_GP*4)($29)      # save gp
+	sw	    $27,	(UZ_SP*4)($29)      # save previous sp (can be usp or ksp)
+	sw	    $30,	(UZ_S8*4)($29)      # save s8
+	sw	    $31,	(UZ_RA*4)($29)      # save ra
+
+	mfc0	$1,     $14
+	sw      $1,     (UZ_EPC*4)($29)	    # save c0_epc
+	mfc0	$1,	    $12 
+	sw	    $1,	    (UZ_SR*4)($29)		# save c0_sr
+	mfc0    $1,     $4,  2
+	sw      $1,	    (UZ_TH*4)($29)		# save c0_th
+	mfc0    $1,     $13   
+	sw      $1,	    (UZ_CR*4)($29)		# save c0_cr
+	mfc2    $1,     $0
+	sw      $1, 	(UZ_PTPR*4)($29)	# save c2_ptpr
+
+    sw      $26,    (UZ_MODE*4)($29)    # save previous c2_mode (can be user or kernel)
+
+    mfc0    $3,     $12 
+	srl	    $3,     $3,   5
+	sll     $3,	    $3,   5	            # reset 5 LSB bits
+	mtc0	$3,	    $12			        # set new c0_sr 
+
+#if CONFIG_KENTRY_DEBUG
+
+    # display "enter" message
+    la      $4,     msg_enter
+    jal     puts
+    nop
+    move    $4,     $29
+    jal     putx
+    nop
+    la      $4,     msg_crlf
+    jal     puts
+    nop    
+    # display saved SP value
+    la      $4,     msg_sp
+    jal     puts
+    nop
+    lw	    $4,  	(UZ_SP*4)($29)
+    jal     putx
+    nop
+    la      $4,     msg_crlf
+    jal     puts
+    nop    
+    # display saved RA value
+    la      $4,     msg_ra
+    jal     puts
+    nop
+    lw	    $4,  	(UZ_RA*4)($29)
+    jal     putx
+    nop
+    la      $4,     msg_crlf
+    jal     puts
+    nop    
+    # display saved TH value
+    la      $4,     msg_th
+    jal     puts
+    nop
+    lw	    $4,  	(UZ_TH*4)($29)
+    jal     putx
+    nop
+    la      $4,     msg_crlf
+    jal     puts
+    nop    
+    # display saved EPC value
+    la      $4,     msg_epc
+    jal     puts
+    nop
+    lw	    $4,  	(UZ_EPC*4)($29)
+    jal     putx
+    nop
+    la      $4,     msg_crlf
+    jal     puts
+    nop    
+    # display saved MODE value
+    la      $4,     msg_mode
+    jal     puts
+    nop
+    lw	    $4,  	(UZ_MODE*4)($29)
+    jal     putx
+    nop
+    la      $4,     msg_crlf
+    jal     puts
+    nop    
+    # display saved V0 value
+    la      $4,     msg_v0
+    jal     puts
+    nop
+    lw	    $4,  	(UZ_V0*4)($29)
+    jal     putx
+    nop
+    la      $4,     msg_crlf
+    jal     puts
+    nop    
+	
+#endif
+    
+#------------------------------------------------------------------------------------
+# This code update the uzone field in thread descriptor, 
+# and call the relevant Interrupt / Exception / Syscall handler,
 # depending on XCODE in CP0_CR.
 # assumption: $29 contains the kernel stack pointer, that is the uzone base.
-# The three handlers take the same two arguments: thread pointer and uzone pointer.
-# The uzone pointer is saved in $19 to be used by kentry_exit.
 
 	mfc0    $17,    $13                 # $17 <= CR
 	andi    $17,    $17,   0x3F         # $17 <= XCODE
 
-	mfc0    $4,     $4,   2             # $4 <= thread pointer (first arg)
-	or	    $5,	    $0,   $29		    # $5 <= uzone pointer (second arg)
-	or	    $19,    $0,	  $29	        # $19 <= &uzone (for kentry_exit)
-
-	ori	    $8,     $0,   0x20          # $8 <= cause syscall
+	mfc0    $4,     $4,   2             # $4 <= pointer on thread desc
+    sw      $29,    8($4)               # update uzone pointer in thread desc
+
+	ori	    $8,     $0,   0x20
     beq	    $8,	    $17,  cause_sys     # go to syscall handler
     nop
@@ -210,51 +292,116 @@
 
 cause_excp:
-	la      $1,	    hal_do_exception
-	jalr	$1	                        # call exception handler
-	addiu	$29,	$29,  -8	        # hal_do_exception has 2 args
-	addiu	$29,	$29,  8
+	jal     hal_do_exception            # call exception handler
+	nop
 	j       kentry_exit                 # jump to kentry_exit
     nop
 
 cause_sys:
-	la	    $1, 	hal_do_syscall
-	jalr	$1                          # call syscall handler                 
-	addiu	$29,	$29,  -8            # hal_do_syscall has 2 args
-	addiu	$29,	$29,  8
+	jal 	hal_do_syscall              # call syscall handler                 
+    nop
 	j	    kentry_exit                 # jump to kentry_exit
 	nop 
 	
 cause_int:
-	la	    $1,	    hal_do_interrupt
-	jalr    $1                          # call interrupt handler
-	addiu	$29,	$29,  -8            # hal_do_interrupt has 2 args
-	addiu	$29,	$29,  8
+	jal     hal_do_interrupt            # call interrupt handler
+    nop
 
 # -----------------------------------------------------------------------------------
 # Kernel exit
-# The pointer on uzone is supposed to be stored in $19
+# The pointer on uzone is supposed to be contained in $29
 # -----------------------------------------------------------------------------------
 kentry_exit:
 
+#if CONFIG_KENTRY_DEBUG
+
+    # display "exit" message
+    la      $4,     msg_exit
+    jal     puts
+    nop
+    move    $4,     $29
+    jal     putx
+    nop
+    la      $4,     msg_crlf
+    jal     puts
+    nop    
+    # display saved SP value
+    la      $4,     msg_sp
+    jal     puts
+    nop
+    lw	    $4,  	(UZ_SP*4)($29)
+    jal     putx
+    nop
+    la      $4,     msg_crlf
+    jal     puts
+    nop    
+    # display saved RA value
+    la      $4,     msg_ra
+    jal     puts
+    nop
+    lw	    $4,  	(UZ_RA*4)($29)
+    jal     putx
+    nop
+    la      $4,     msg_crlf
+    jal     puts
+    nop    
+    # display saved TH value
+    la      $4,     msg_th
+    jal     puts
+    nop
+    lw	    $4,  	(UZ_TH*4)($29)
+    jal     putx
+    nop
+    la      $4,     msg_crlf
+    jal     puts
+    nop    
+    # display saved EPC value
+    la      $4,     msg_epc
+    jal     puts
+    nop
+    lw	    $4,  	(UZ_EPC*4)($29)
+    jal     putx
+    nop
+    la      $4,     msg_crlf
+    jal     puts
+    nop    
+    # display saved MODE value
+    la      $4,     msg_mode
+    jal     puts
+    nop
+    lw	    $4,  	(UZ_MODE*4)($29)
+    jal     putx
+    nop
+    la      $4,     msg_crlf
+    jal     puts
+    nop    
+    # display saved V0 value
+    la      $4,     msg_v0
+    jal     puts
+    nop
+    lw	    $4,  	(UZ_V0*4)($29)
+    jal     putx
+    nop
+    la      $4,     msg_crlf
+    jal     puts
+    nop    
+	
+#endif
+    
 	# restore registers from uzone
-	or	    $27,    $0,	$19             # $27 <= &uzone
-
-	lw	    $29,	(UZ_SP*4)($27)		# restore SP from uzone
-	lw	    $16,	(UZ_EPC*4)($27)	       
-	mtc0	$16,	$14			        # restore EPC from uzone
-	lw	    $16,    (UZ_HI*4)($27)
-	mthi	$16				            # restore HI from uzone
-	lw	    $16,    (UZ_LO*4)($27)
-	mtlo	$16				            # restore LO from uzone
-
-	lw	    $17,	(UZ_SR*4)($27)		# get saved SR value from uzone
-	andi	$17,	$17,	0x1F        # keep only the 5 LSB bits
-	mfc0	$26,	$12			        # get current SR value from CP0
-	or	    $26,    $26,	$17         # merge the two values
-	mtc0	$26,    $12			        # setup new SR to CP0
+	or	    $27,    $0,	$29             # $27 <= ksp (contains &uzone)
+
+	lw	    $1,	    (UZ_EPC*4)($27)	       
+	mtc0	$1,	    $14			        # restore c0_epc from uzone
+	lw	    $1,	    (UZ_SR*4)($27)
+	mtc0	$1,     $12			        # restore c0_sr from uzone
+
+	lw	    $26,    (UZ_HI*4)($27)
+	mthi	$26				            # restore hi from uzone
+	lw	    $26,    (UZ_LO*4)($27)
+	mtlo	$26				            # restore lo from uzone
 
 	lw	    $1,     (UZ_AT*4)($27)		
-	lw	    $2,	    (UZ_V0*4)($27)
-	lw	    $3,	    (UZ_V1*4)($27)
+    lw	    $2,	    (UZ_V0*4)($27)
+    lw	    $3,	    (UZ_V1*4)($27)
 	lw	    $4,	    (UZ_A0*4)($27)
 	lw	    $5,     (UZ_A1*4)($27)
@@ -279,7 +426,9 @@
 	lw	    $24,    (UZ_T8*4)($27)
 	lw	    $25,    (UZ_T9*4)($27)	
-	lw	    $28,	(UZ_GP*4)($27)
-	lw	    $30,	(UZ_S8*4)($27)
-	lw	    $31,	(UZ_RA*4)($27)
+
+	lw	    $28,	(UZ_GP*4)($27)      # restore gp_28 from uzone
+	lw	    $29,	(UZ_SP*4)($27)		# restore sp_29 from uzone
+	lw	    $30,	(UZ_S8*4)($27)      # restore s8_30 from uzone
+	lw	    $31,	(UZ_RA*4)($27)      # restore ra_31 from uzone
 
 	lw	    $26,    (UZ_MODE*4)($27)    
@@ -291,6 +440,5 @@
 
 hal_kentry_eret:
-	nop
-    eret
+    eret                                # jump to EPC, reset EXL bit
 
     .set reorder
@@ -298,3 +446,32 @@
 
 #------------------------------------------------------------------------------------
-
+    .section .kdata
+
+msg_sp:
+    .align 2
+    .asciiz "- UZ_SP   = " 
+msg_ra:
+    .align 2
+    .asciiz "- UZ_RA   = " 
+msg_epc:
+    .align 2
+    .asciiz "- UZ_EPC  = " 
+msg_th:
+    .align 2
+    .asciiz "- UZ_TH   = " 
+msg_mode:
+    .align 2
+    .asciiz "- UZ_MODE = " 
+msg_v0:
+    .align 2
+    .asciiz "- UZ_V0   = " 
+msg_crlf:
+    .align 2
+    .asciiz "\n" 
+msg_enter:
+    .align 2
+    .asciiz "\nenter kernel : &uzone = " 
+msg_exit:
+    .align 2
+    .asciiz "\nexit kernel : &uzone = " 
+
Index: trunk/hal/tsar_mips32/core/hal_kentry.h
===================================================================
--- trunk/hal/tsar_mips32/core/hal_kentry.h	(revision 407)
+++ trunk/hal/tsar_mips32/core/hal_kentry.h	(revision 408)
@@ -36,6 +36,7 @@
 
 /****************************************************************************************
- * This structure defines the cpu_uzone for TSAR MIPS32, as well as the
- *  mnemonics used by the hal_kentry assembly code.
+ * This structure defines the cpu_uzone dynamically allocated in the kernel stack
+ * by the hal_kentry assembly code for the TSAR_MIPS32 architecture.
+ * WARNING : It is replicated in hal_kentry.S file.
  ***************************************************************************************/
 
@@ -56,41 +57,43 @@
 #define      UZ_T6           14   /* t6_14   */
 #define      UZ_T7           15   /* t7_15   */
-#define      UZ_T8           16   /* t8_24   */
-#define      UZ_T9           17   /* t9_25   */
-#define      UZ_S0           18   /* s0_16   */
-#define      UZ_S1           19   /* s1_17   */
-#define      UZ_S2           20   /* s2_18   */
-#define      UZ_S3           21   /* s3_19   */
-#define      UZ_S4           22   /* s4_20   */
-#define      UZ_S5           23   /* s5_21   */
-#define      UZ_S6           24   /* s6_22   */
-#define      UZ_S7           25   /* s7_23   */
-#define      UZ_S8           26   /* s8_30   */
-#define      UZ_GP           27   /* gp_28   */
-#define      UZ_RA           28   /* ra_31   */
-#define      UZ_EPC          29   /* c0_epc  */
-#define      UZ_CR           30   /* c0_cr   */
-#define      UZ_SP           31   /* sp_29   */
-#define      UZ_SR           32   /* c0_sr   */
-#define      UZ_LO           33
-#define      UZ_HI           34
+#define      UZ_S0           16   /* s0_16   */
+#define      UZ_S1           17   /* s1_17   */
+#define      UZ_S2           18   /* s2_18   */
+#define      UZ_S3           19   /* s3_19   */
+#define      UZ_S4           20   /* s4_20   */
+#define      UZ_S5           21   /* s5_21   */
+#define      UZ_S6           22   /* s6_22   */
+#define      UZ_S7           23   /* s7_23   */
+#define      UZ_T8           24   /* t8_24   */
+#define      UZ_T9           25   /* t9_25   */
 
-#define      UZ_REGS         35
+#define      UZ_LO           26
+#define      UZ_HI           27
+
+#define      UZ_GP           28   /* gp_28   */
+#define      UZ_SP           29   /* sp_29   */
+#define      UZ_S8           30   /* s8_30   */
+#define      UZ_RA           31   /* ra_31   */
+
+#define      UZ_PTPR         32   /* c2_ptpr */
+#define      UZ_EPC          33   /* c0_epc  */
+#define      UZ_SR           34   /* c0_sr   */
+#define      UZ_TH           35   /* c0_th   */
+#define      UZ_CR           36   /* c0_cr   */
+
+#define      UZ_REGS         37
 
 /*************************************************************************************
  * The hal_kentry_enter() function is the unique kernel entry point in case of 
  * exception, interrupt, or syscall for the TSAR_MIPS32 architecture.  
+ * It can be executed by a core in user mode (in case of exception or syscall),
+ * or by a core already in kernel mode (in case of interrupt).
  *
- * When we enter the kernel, we test the status register:
- * - If the core is in user mode, we desactivate the MMU, and we save
- *   the core context in the uzone of the calling thread descriptor.
- * - If the core is already in kernel mode (in case of interrupt), 
- *   we save the context in the kernel stack.
- * - In both cases, we increment the cores_in_kernel variable,
- *   and we call the relevant exception/interrupt/syscall handler
+ * In both cases it allocates an "uzone" space in the kernel stack to save the
+ * CPU registers values, desactivates the MMU, and calls the relevant handler 
+ * (exception/interrupt/syscall) 
  *
- * When we exit the kernel after handler execution:
- * - we restore the core context from the uzone and return to user space,
- *   calling the hal_kentry_eret()
+ * After handler execution, it restores the CPU context from the uzone and jumps 
+ * to address contained in EPC calling hal_kentry_eret()
  ************************************************************************************/
 void hal_kentry_enter();
@@ -98,5 +101,5 @@
 /*************************************************************************************
  * The hal_kentry_eret() function contains only the assembly "eret" instruction,
- * that and the EXL bit in the c0_sr register, and jump to the address 
+ * that reset the EXL bit in the c0_sr register, and jump to the address 
  * contained in the c0_epc register. 
  * ************************************************************************************/
Index: trunk/hal/tsar_mips32/core/hal_switch.S
===================================================================
--- trunk/hal/tsar_mips32/core/hal_switch.S	(revision 407)
+++ trunk/hal/tsar_mips32/core/hal_switch.S	(revision 408)
@@ -37,4 +37,6 @@
 hal_do_cpu_switch:
 
+    /* save old thread context */
+ 
     move    $26,   $4                  /* $26 <= ctx_old */
 
@@ -49,5 +51,4 @@
     sw      $6,    6*4($26)         
     sw      $7,    7*4($26)         
-
     sw      $8,    8*4($26)         
     sw      $9,    9*4($26)         
@@ -58,5 +59,4 @@
     sw      $14,  14*4($26)         
     sw      $15,  15*4($26)         
-
     sw      $16,  16*4($26)         
     sw      $17,  17*4($26)         
@@ -67,5 +67,4 @@
     sw      $22,  22*4($26)         
     sw      $23,  23*4($26)         
-
     sw      $24,  24*4($26)         
     sw      $25,  25*4($26)         
@@ -91,6 +90,6 @@
 	sw      $27,  33*4($26)           /* save c2_mode to slot 33 */
 
-    sync                            
-
+    /* restore new thread context */
+ 
     move    $26,   $5                  /* $26 <= ctx_new */
 
@@ -105,5 +104,4 @@
     lw      $6,    6*4($26)         
     lw      $7,    7*4($26)         
-
     lw      $8,    8*4($26)         
     lw      $9,    9*4($26)         
@@ -114,5 +112,4 @@
     lw      $14,  14*4($26)         
     lw      $15,  15*4($26)         
-
 	lw      $16,  16*4($26)         
 	lw      $17,  17*4($26)         
@@ -123,5 +120,4 @@
     lw      $22,  22*4($26)         
     lw      $23,  23*4($26)         
-
     lw      $24,  24*4($26)         
     lw      $25,  25*4($26)         
@@ -149,35 +145,20 @@
     mtc0	$26,  $12                  /* restore c0_sr from slot 34 */
 
+    sync                            
+
     jr      $31                        /* return to caller */
     nop
 
 #---------------------------------------------------------------------------------
-# The hal_do_cpu_save()function makes the following assumptions:
+# The hal_do_cpu_save()function makes the following assumption:
 # - register $4 contains a pointer on the target thread context.
-# - register $5 contains the target thread descriptor pointer.
-# - register $6 contains the offset to add to stack pointer.
 #---------------------------------------------------------------------------------
 hal_do_cpu_save:
 
-    move    $26,  $4                  /* $26 <= context */
-
-    move    $27,  $5
-	sw      $27,  35*4($26)           /* save child thread to slot 35 */
-
-    add     $27,  $6,  $29
-    sw      $27,  29*4($26)           /* save (sp_29 + offset) to slot 29 */
-
-    mfc0    $27,  $12               
-	sw      $27,  34*4($26)           /* save c0_sr to slot 34 */
-
-	mfc2    $27,  $0                
-	sw      $27,  32*4($26)           /* save c2_ptpr to slot 32 */
-
-	mfc2    $27,  $1                
-	sw      $27,  33*4($26)           /* save c2_mode to slot 33 */
-
-    mfc0    $27,   $14              
+    move    $26,  $4                  /* $26 <= &context */
+
+    mfc0    $27,  $14               
     sw      $27,   0*4($26)           /* save c0_epc to slot 0 */
- 
+
     sw      $1,    1*4($26)         
     sw      $2,    2*4($26)         
@@ -187,5 +168,4 @@
     sw      $6,    6*4($26)         
     sw      $7,    7*4($26)         
-
     sw      $8,    8*4($26)         
     sw      $9,    9*4($26)         
@@ -196,5 +176,4 @@
     sw      $14,  14*4($26)         
     sw      $15,  15*4($26)         
-
     sw      $16,  16*4($26)         
     sw      $17,  17*4($26)         
@@ -205,18 +184,25 @@
     sw      $22,  22*4($26)         
     sw      $23,  23*4($26)         
-
     sw      $24,  24*4($26)         
-    sw      $25,  25*4($26)         
-
+    sw      $25,  25*4($26)
+         
     mfhi    $27                     
-    sw      $27,  26*4($26)           /* save hi to slot 26 */
-
+    sw      $27,  26*4($26)           /* save hi      to slot 26 */
     mflo    $27                     
-    sw      $27,  27*4($26)           /* save lo to slot 27 */
-
-    sw      $28,  28*4($26)           /* save gp to slot 28 */
-
-    sw      $30,  30*4($26)           /* save s8 to slot 30 */
-    sw      $31,  31*4($26)           /* save ra to slot 31 */
+    sw      $27,  27*4($26)           /* save lo      to slot 27 */
+
+    sw      $28,  28*4($26)           /* save gp      to slot 28 */
+    sw      $29,  29*4($26)           /* save sp      to slot 29 */
+    sw      $30,  30*4($26)           /* save s8      to slot 30 */
+    sw      $31,  31*4($26)           /* save ra      to slot 31 */
+
+	mfc2    $27,  $0                
+	sw      $27,  32*4($26)           /* save c2_ptpr to slot 32 */
+	mfc2    $27,  $1                
+	sw      $27,  33*4($26)           /* save c2_mode to slot 33 */
+    mfc0    $27,  $12              
+	sw      $27,  34*4($26)           /* save c0_sr   to slot 34 */
+    mfc0    $27,  $4, 2              
+	sw      $27,  35*4($26)           /* save c0_th   to slot 35 */
 
     sync
Index: trunk/hal/tsar_mips32/core/hal_syscall.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_syscall.c	(revision 407)
+++ trunk/hal/tsar_mips32/core/hal_syscall.c	(revision 408)
@@ -30,28 +30,34 @@
 
 
-/////////////////////////////////////
-void hal_do_syscall( thread_t * this,
-                     reg_t    * regs_tbl )
+/////////////////////
+void hal_do_syscall()
 {
+    thread_t    * this;
 
-#if(CONFIG_SYSCALL_DEBUG & 0x1)
-printk("\n[DBG] %s : core[%x,%d] enter at cycle %d\n",
-__FUNCTION__ , local_cxy , this->core->lid , hal_time_stamp() );
-#endif
+    uint32_t    * enter_uzone;
+    uint32_t    * exit_uzone;
 
-	register reg_t      arg0;
-	register reg_t      arg1;
-	register reg_t      arg2;
-	register reg_t      arg3;
-	register reg_t      service_num;
-	register reg_t      retval;
+	uint32_t      arg0;
+	uint32_t      arg1;
+	uint32_t      arg2;
+	uint32_t      arg3;
+	uint32_t      service_num;
+	uint32_t      retval;
   
-	service_num = regs_tbl[UZ_V0];
+    // get pointer on enter_thread uzone
+    this        = CURRENT_THREAD;
+    enter_uzone = (uint32_t *)this->uzone;
 
-	arg0        = regs_tbl[UZ_A0];
-	arg1        = regs_tbl[UZ_A1];
-	arg2        = regs_tbl[UZ_A2];
-	arg3        = regs_tbl[UZ_A3];
+    // get syscall arguments from uzone
+	service_num = enter_uzone[UZ_V0];
+	arg0        = enter_uzone[UZ_A0];
+	arg1        = enter_uzone[UZ_A1];
+	arg2        = enter_uzone[UZ_A2];
+	arg3        = enter_uzone[UZ_A3];
  
+syscall_dmsg("\n[DBG] %s : core[%x,%d] enters for %s / &uzone %x / cycle %d \n",
+__FUNCTION__, local_cxy, this->core->lid, 
+syscall_str(service_num) , enter_uzone , (uint32_t)hal_get_cycles() );
+
     // call architecture independant syscall handler
 	retval = do_syscall( this,
@@ -62,12 +68,18 @@
                          service_num );
 
-	regs_tbl[UZ_V0]   = retval;
-	regs_tbl[UZ_V1]   = this->errno;
-	regs_tbl[UZ_EPC] += 4;
+    // get pointer on exit_thread uzone,
+    // exit_thread can be different from enter_thread
+    this       = CURRENT_THREAD;
+    exit_uzone = (uint32_t *)this->uzone;
 
-#if(CONFIG_SYSCALL_DEBUG & 0x1)
-printk("\n[DBG] %s : core[%x,%d] exit at cycle %d\n",
-__FUNCTION__ , local_cxy , this->core->lid , hal_time_stamp() );
-#endif
+    // set syscall return value to uzone 
+	exit_uzone[UZ_V0] = retval;
+
+    // update EPC in uzone
+	exit_uzone[UZ_EPC] += 4;
+
+syscall_dmsg("\n[DBG] %s : core[%x,%d] exit from %s / &uzone %x / cycle %d \n",
+__FUNCTION__, local_cxy, this->core->lid, 
+syscall_str(service_num) , exit_uzone , (uint32_t)hal_get_cycles() );
 
 }
Index: trunk/hal/tsar_mips32/core/hal_types.h
===================================================================
--- trunk/hal/tsar_mips32/core/hal_types.h	(revision 407)
+++ trunk/hal/tsar_mips32/core/hal_types.h	(revision 408)
@@ -134,5 +134,5 @@
  *  Address types and macros         !!!  hardware dependant  !!!
  ***************************************************************************
- * An extended pointer a 64 bits integer, structured in two fields :
+ * An extended pointer is a 64 bits integer, structured in two fields :
  * - cxy : cluster identifier.
  * - ptr : pointer in the virtual space of a single cluster.
