Index: trunk/hal/tsar_mips32/core/hal_exception.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_exception.c	(revision 587)
+++ trunk/hal/tsar_mips32/core/hal_exception.c	(revision 610)
@@ -158,6 +158,8 @@
 // This function is called when an MMU exception has been detected (IBE / DBE). 
 // It get the relevant exception arguments from the MMU.
-// It signal a fatal error in case of illegal access. In case of page unmapped
-// it checks that the faulty address belongs to a registered vseg. It update the local
+// It signal a fatal error in case of illegal access. In case of page unmapped,
+// it get the client process to access the relevant VMM: for a RPC thread, the client
+// process is NOT the calling thread process.
+// Then, it checks that the faulty address belongs to a registered vseg, update the local
 // vseg list from the reference cluster if required, and signal a fatal user error
 // in case of illegal virtual address. Finally, it updates the local page table from the
@@ -183,5 +185,15 @@
     uint32_t         bad_vaddr;
     uint32_t         excp_code;
-	
+
+    // check thread type
+    if( CURRENT_THREAD->type != THREAD_USER )
+    {
+        printk("\n[KERNEL 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;
 
@@ -207,6 +219,6 @@
 uint32_t cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_HAL_EXCEPTIONS < cycle )
-printk("\n[DBG] %s : thread[%x,%x] enter / is_ins %d / %s / vaddr %x / cycle %d\n",
-__FUNCTION__, process->pid, this->trdid,
+printk("\n[%s] thread[%x,%x] on core [%x,%x] enter / is_ins %d / %s / vaddr %x / cycle %d\n",
+__FUNCTION__, process->pid, this->trdid, local_cxy, this->core->lid,
 is_ins, hal_mmu_exception_str(excp_code), bad_vaddr, cycle);
 #endif
@@ -215,8 +227,8 @@
     switch( excp_code )
     {
-        case MMU_WRITE_PT1_UNMAPPED:      // non fatal
-        case MMU_WRITE_PT2_UNMAPPED:
-        case MMU_READ_PT1_UNMAPPED:
-        case MMU_READ_PT2_UNMAPPED:
+        case MMU_WRITE_PT1_UNMAPPED:      // can be non fatal 
+        case MMU_WRITE_PT2_UNMAPPED:      // can be non fatal
+        case MMU_READ_PT1_UNMAPPED:       // can be non fatal
+        case MMU_READ_PT2_UNMAPPED:       // can be non fatal
         {
             // try to map the unmapped PTE
@@ -230,6 +242,6 @@
 cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_HAL_EXCEPTIONS < cycle )
-printk("\n[DBG] %s : thread[%x,%x] exit / page-fault handled for vaddr = %x\n",
-__FUNCTION__, process->pid, this->trdid, bad_vaddr );
+printk("\n[%s] thread[%x,%x] on core [%x,%x] exit / page-fault handled for vaddr = %x\n",
+__FUNCTION__, process->pid, this->trdid, local_cxy, this->core->lid, bad_vaddr );
 #endif
   
@@ -238,7 +250,9 @@
             else if( error == EXCP_USER_ERROR )      // illegal vaddr
             {
-                printk("\n[USER ERROR] in %s for thread %x in process %x\n"
-                "   illegal vaddr = %x / is_ins %d / epc %x\n",
-                __FUNCTION__, this->trdid, this->process->pid, bad_vaddr, is_ins, excPC );
+                printk("\n[USER ERROR] in %s : thread[%x,%x] on core[%x,%x] / cycle %d\n"
+                "  %s : epc %x / badvaddr %x / is_ins %d\n",
+                __FUNCTION__, this->process->pid, this->trdid, local_cxy,
+                this->core->lid, (uint32_t)hal_get_cycles(),
+                hal_mmu_exception_str(excp_code), excPC, bad_vaddr, is_ins );
 
 		        return EXCP_USER_ERROR;
@@ -246,75 +260,69 @@
             else  // error == EXCP_KERNEL_PANIC  
             {
-                printk("\n[KERNEL ERROR] in %s for thread %x in process %x\n"
-                "   no memory to map vaddr = %x / is_ins %d / epc %x\n",
-                __FUNCTION__, this->trdid, this->process->pid, bad_vaddr, is_ins, excPC );
+                printk("\n[KERNEL PANIC] in %s : thread[%x,%x] on core[%x,%x] / cycle %d\n"
+                "  %s : epc %x / badvaddr %x / is_ins %d\n",
+                __FUNCTION__, this->process->pid, this->trdid, local_cxy,
+                this->core->lid, (uint32_t)hal_get_cycles(),
+                hal_mmu_exception_str(excp_code), excPC, bad_vaddr, is_ins );
 
 		        return EXCP_KERNEL_PANIC;
             } 
         }
-        case MMU_WRITE_PRIVILEGE_VIOLATION:  // illegal access user error
-        case MMU_READ_PRIVILEGE_VIOLATION:
-        {
-            printk("\n[USER ERROR] in %s : thread %x in process %x\n"
-            "   illegal user access to vaddr = %x / is_ins %d / epc %x\n",
-            __FUNCTION__, this->trdid, this->process->pid, bad_vaddr, is_ins, excPC );
+        case MMU_WRITE_PRIVILEGE_VIOLATION:  // illegal user error
+        case MMU_READ_PRIVILEGE_VIOLATION:   // illegal 
+        {
+            printk("\n[USER ERROR] in %s : thread[%x,%x] on core[%x,%x] / cycle %d\n"
+            "  %s : epc %x / badvaddr %x / is_ins %d\n",
+            __FUNCTION__, this->process->pid, this->trdid, local_cxy,
+            this->core->lid, (uint32_t)hal_get_cycles(),
+            hal_mmu_exception_str(excp_code), excPC, bad_vaddr, is_ins );
 
             return EXCP_USER_ERROR;
         }
-        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 ); 
-
-            if( cow )                        // Copy-on-Write 
-            {
-                // try to allocate and copy the page
-                error = vmm_handle_cow( process,
-                                        bad_vaddr >> CONFIG_PPM_PAGE_SHIFT );
-
-                if( error == EXCP_NON_FATAL )        // Copy on write successfull
-                {
+        case MMU_WRITE_ACCESS_VIOLATION:    // can be non fatal if COW
+        {
+            // try to handle a possible COW
+            error = vmm_handle_cow( process,
+                                    bad_vaddr >> CONFIG_PPM_PAGE_SHIFT );
+
+            if( error == EXCP_NON_FATAL )        // COW successfully handled
+            {
 
 #if DEBUG_HAL_EXCEPTIONS
 cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_HAL_EXCEPTIONS < cycle )
-printk("\n[DBG] %s : thread[%x,%x] exit / copy-on-write handled for vaddr = %x\n",
+printk("\n[%s] thread[%x,%x] exit / copy-on-write handled for vaddr = %x\n",
 __FUNCTION__, process->pid, this->trdid, bad_vaddr );
 #endif
-
-                    return EXCP_NON_FATAL;
-                } 
-                else if( error == EXCP_USER_ERROR )  // illegal user access
-                {
-                    printk("\n[USER ERROR] in %s : thread %x in process %x\n"
-                    "   cannot cow vaddr = %x / is_ins %d / epc %x\n",
-                    __FUNCTION__, this->trdid, this->process->pid, bad_vaddr, is_ins, excPC );
+                return EXCP_NON_FATAL;
+            } 
+            else if( error == EXCP_USER_ERROR )  // illegal write access
+            {
+                    printk("\n[USER ERROR] in %s : thread[%x,%x] on core[%x,%x] / cycle %d\n"
+                    "  %s : epc %x / badvaddr %x / is_ins %d\n",
+                    __FUNCTION__, this->process->pid, this->trdid, local_cxy,
+                    this->core->lid, (uint32_t)hal_get_cycles(),
+                    hal_mmu_exception_str(excp_code), excPC, bad_vaddr, is_ins );
 
 		            return EXCP_USER_ERROR;
-                }
-                else   // error == EXCP_KERNEL_PANIC
-                {
-                    printk("\n[KERNEL ERROR] in %s : thread %x in process %x\n"
-                    "   no memoty to cow vaddr = %x / is_ins %d / epc %x\n",
-                    __FUNCTION__, this->trdid, this->process->pid, bad_vaddr, is_ins, excPC );
-
-		            return EXCP_USER_ERROR;
-                }
             }
-            else                             // non writable user error
-            {
-                printk("\n[USER ERROR] in %s : thread %x in process %x\n"
-                "   non-writable vaddr = %x / is_ins %d / epc %x\n",
-                __FUNCTION__, this->trdid, this->process->pid, bad_vaddr, is_ins, excPC );
-
-                return EXCP_USER_ERROR;
+            else   // error == EXCP_KERNEL_PANIC
+            {
+                printk("\n[KERNEL PANIC] in %s : thread[%x,%x] on core[%x,%x] / cycle %d\n"
+                "  %s : epc %x / badvaddr %x / is_ins %d\n",
+                __FUNCTION__, this->process->pid, this->trdid, local_cxy,
+                this->core->lid, (uint32_t)hal_get_cycles(),
+                hal_mmu_exception_str(excp_code), excPC, bad_vaddr, is_ins );
+
+		        return EXCP_USER_ERROR;
             }
         }
         case MMU_READ_EXEC_VIOLATION:        // user error
         {
-            printk("\n[USER_ERROR] in %s : thread %x in process %x\n"
-            "   non-executable vaddr = %x / is_ins %d / epc %x\n",
-            __FUNCTION__, this->trdid, this->process->pid, bad_vaddr, is_ins, excPC );
+            printk("\n[USER ERROR] in %s : thread[%x,%x] on core[%x,%x] / cycle %d\n"
+            "  %s : epc %x / badvaddr %x / is_ins %d\n",
+            __FUNCTION__, this->process->pid, this->trdid, local_cxy,
+            this->core->lid, (uint32_t)hal_get_cycles(),
+            hal_mmu_exception_str(excp_code), excPC, bad_vaddr, is_ins );
 
             return EXCP_USER_ERROR;
@@ -322,7 +330,9 @@
         default:                             // this is a kernel error    
         {
-            printk("\n[KERNEL ERROR] in %s : thread %x in process %x\n"
-            "  epc %x / badvaddr %x / is_ins %d\n",
-            __FUNCTION__, this->trdid, this->process->pid, excPC, bad_vaddr, is_ins );
+            printk("\n[KERNEL PANIC] in %s : thread[%x,%x] on core[%x,%x] / cycle %d\n"
+            "  %s : epc %x / badvaddr %x / is_ins %d\n",
+            __FUNCTION__, this->process->pid, this->trdid, local_cxy,
+            this->core->lid, (uint32_t)hal_get_cycles(),
+            hal_mmu_exception_str(excp_code), excPC, bad_vaddr, is_ins );
 
             return EXCP_KERNEL_PANIC;
@@ -359,11 +369,11 @@
     if( error == EXCP_USER_ERROR )
     {
-        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() );
+        nolock_printk("\n=== USER ERROR / thread(%x,%x) / core[%d] / cycle %d ===\n",
+        process->pid, this->trdid, core->lid, (uint32_t)hal_get_cycles() );
     }
     else
     {
-        nolock_printk("\n=== KERNEL ERROR / 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("\n=== KERNEL PANIC / thread(%x,%x) / core[%d] / cycle %d ===\n",
+        process->pid, this->trdid, core->lid, (uint32_t)hal_get_cycles() );
     }
 
@@ -400,5 +410,5 @@
 }  // end hal_exception_dump()
 
-///////////////////////
+/////////////////////////////
 void hal_do_exception( void )
 {
@@ -420,6 +430,7 @@
 uint32_t cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_HAL_EXCEPTIONS < cycle )
-printk("\n[DBG] %s : thread %x in process %x enter / core[%x,%d] / epc %x / xcode %x / cycle %d\n",
-__FUNCTION__, this->trdid, this->process->pid, local_cxy, this->core->lid, excPC, excCode, cycle );
+printk("\n[%s] thread[%x,%x] enter / core[%x,%d] / epc %x / xcode %x / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid,
+local_cxy, this->core->lid, excPC, excCode, cycle );
 #endif
 
@@ -473,6 +484,6 @@
         {
             printk("\n[USER_ERROR] in %s for thread %x in process %x\n"
-            "   illegal data load address / epc %x\n",
-            __FUNCTION__, this->trdid, this->process->pid, excPC );
+            "   illegal data load address / epc %x / bad_address %x\n",
+            __FUNCTION__, this->trdid, this->process->pid, excPC, hal_get_bad_vaddr() );
 
 		    error = EXCP_USER_ERROR;
@@ -482,6 +493,6 @@
         {
             printk("\n[USER_ERROR] in %s for thread %x in process %x\n"
-            "   illegal data store address / epc %x\n",
-            __FUNCTION__, this->trdid, this->process->pid, excPC );
+            "   illegal data store address / epc %x / bad_address %x\n",
+            __FUNCTION__, this->trdid, this->process->pid, excPC, hal_get_bad_vaddr() );
 
 		    error = EXCP_USER_ERROR;
@@ -505,5 +516,5 @@
         hal_exception_dump( this , uzone , error );
 
-        assert( false , "Exception raised kernel panic see information below.\n" );
+        hal_core_sleep();
     }
 
@@ -511,6 +522,7 @@
 cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_HAL_EXCEPTIONS < cycle )
-printk("\n[DBG] %s : thread %x in process %x exit / core[%x,%d] / epc %x / xcode %x / cycle %d\n",
-__FUNCTION__, this->trdid, this->process->pid, local_cxy, this->core->lid, excPC, excCode, cycle );
+printk("\n[%s] thread[%x,%x] exit / core[%x,%d] / epc %x / xcode %x / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid,
+local_cxy, this->core->lid, excPC, excCode, cycle );
 #endif
 
Index: trunk/hal/tsar_mips32/core/hal_ppm.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_ppm.c	(revision 587)
+++ trunk/hal/tsar_mips32/core/hal_ppm.c	(revision 610)
@@ -2,5 +2,5 @@
  * hal_ppm.c - Generic Physical Page Manager API implementation for TSAR
  *
- * Authors  Alain Greiner (2016,2017)
+ * Authors  Alain Greiner (2016,2017,2018)
  *
  * Copyright (c) UPMC Sorbonne Universites
@@ -63,5 +63,5 @@
 
 	// initialize lock protecting the dirty_pages list
-	queuelock_init( &ppm->dirty_lock , LOCK_PPM_DIRTY );
+	remote_queuelock_init( XPTR( local_cxy , &ppm->dirty_lock ) , LOCK_PPM_DIRTY );
 
 	// initialize all free_pages[] lists as empty
Index: trunk/hal/tsar_mips32/core/hal_remote.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_remote.c	(revision 587)
+++ trunk/hal/tsar_mips32/core/hal_remote.c	(revision 610)
@@ -381,4 +381,9 @@
     uint32_t scxy = (uint32_t)GET_CXY( src );
 
+/*
+if( local_cxy == 1 )
+printk("\n@@@ %s : scxy %x / sptr %x / dcxy %x / dptr %x\n",
+__FUNCTION__, scxy, sptr, dcxy, dptr );
+*/
     hal_disable_irq( &save_sr );
 
Index: trunk/hal/tsar_mips32/core/hal_uspace.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_uspace.c	(revision 587)
+++ trunk/hal/tsar_mips32/core/hal_uspace.c	(revision 610)
@@ -43,4 +43,10 @@
     uint32_t dst = (uint32_t)k_dst;
 
+#if DEBUG_HAL_USPACE
+thread_t * this = CURRENT_THREAD;
+printk("\n[%s] thread[%x,%x] enter in cluster %x / u_src %x / k_dst %x / size %d\n", 
+__FUNCTION__, this->process->pid, this->trdid, local_cxy, u_src, k_dst, size );
+#endif
+
 	if( (dst & 0x3) || (src & 0x3) ) wsize = 0;          // do it all in bytes
     else                             wsize = size >> 2;
@@ -80,4 +86,9 @@
 
     hal_restore_irq( save_sr );
+
+#if DEBUG_HAL_USPACE
+printk("\n[%s] thread[%x,%x] exit\n", 
+__FUNCTION__, this->process->pid, this->trdid );
+#endif
 
 }  // end hal_copy_from_uspace()
@@ -94,4 +105,10 @@
     uint32_t dst = (uint32_t)u_dst;
 
+#if DEBUG_HAL_USPACE
+thread_t * this = CURRENT_THREAD;
+printk("\n[%s] thread[%x,%x] enter in cluster %x / k_src %x / u_dst %x / size %d\n", 
+__FUNCTION__, this->process->pid, this->trdid, local_cxy, k_src, u_dst, size );
+#endif
+
 	if( (dst & 0x3) || (src & 0x3) ) wsize = 0;          // not aligned
     else                             wsize = size >> 2;
@@ -118,5 +135,5 @@
         asm volatile(
         "mfc2   $15,   $1           \n"   /* save   MMU_MODE                */
-        "lw	    $13,   0(%0)        \n"   /* read data from kernel space    */
+        "lb	    $13,   0(%0)        \n"   /* read data from kernel space    */
         "ori    $14,   $0,  0x7	    \n"  
         "mtc2   $14,   $1			\n"   /* MMU_MODE <= DTLB ON            */
@@ -130,4 +147,9 @@
 
     hal_restore_irq( save_sr );
+
+#if DEBUG_HAL_USPACE
+printk("\n[%s] thread[%x,%x] exit\n", 
+__FUNCTION__, this->process->pid, this->trdid );
+#endif
 
 }  // end hal_copy_to_uspace()
