Index: trunk/hal/tsar_mips32/core/hal_context.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_context.c	(revision 570)
+++ trunk/hal/tsar_mips32/core/hal_context.c	(revision 625)
@@ -152,5 +152,5 @@
     {
         context->a0_04   = (uint32_t)thread->entry_args;
-        context->sp_29   = (uint32_t)thread->u_stack_base + (uint32_t)thread->u_stack_size - 8;
+        context->sp_29   = (uint32_t)thread->user_stack_vseg->max - 8;
         context->ra_31   = (uint32_t)&hal_kentry_eret;
         context->c0_epc  = (uint32_t)thread->entry_func;
@@ -175,11 +175,12 @@
 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()
+    // get pointer on calling thread
+    thread_t * this = CURRENT_THREAD;
+
+    // allocate a local CPU context in parent kernel stack
     hal_cpu_context_t  context;
 
-    // get local parent thread local pointer
+    // get local parent thread cluster and local pointer
+    cxy_t      parent_cxy = local_cxy;
     thread_t * parent_ptr = CURRENT_THREAD;
 
@@ -188,53 +189,107 @@
     thread_t * child_ptr = GET_PTR( child_xp );
 
-    // get remote child cpu_context local pointer
+    // get local pointer on remote child cpu context
     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) );
+    process_t * 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) );
-
-    // save CPU registers in local CPU context
+    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  );
+
+    // update the uzone pointer in child thread descriptor
+    hal_remote_spt( XPTR( child_cxy , &child_ptr->uzone_current ) , child_uzone );
+
+#if DEBUG_HAL_CONTEXT
+uint32_t cycle = (uint32_t)hal_get_cycles();
+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
+    // (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 ),
+                       size );
+
+#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
     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
+    // From this point, both parent and child can 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;
+
+    if( (this == parent_ptr) && (local_cxy == parent_cxy) )   // 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;
+        // 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 local context to remote child context)
+        // copy this patched 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 );
+#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 );
+#endif
+
     }
-    else                           // current == child thread
-    {
-        assert( (current == child_ptr) , "current = %x / child = %x\n");
-    }
+
 }  // end hal_cpu_context_fork()
 
@@ -285,9 +340,15 @@
 void hal_cpu_context_destroy( thread_t * thread )
 {
-    kmem_req_t  req;
-
-    req.type = KMEM_CPU_CTX;
-    req.ptr  = thread->cpu_context;
-    kmem_free( &req );
+    kmem_req_t          req;
+
+    hal_cpu_context_t * ctx = thread->cpu_context;
+
+    // release CPU context if required
+    if( ctx != NULL )
+    {    
+        req.type = KMEM_CPU_CTX;
+        req.ptr  = ctx;
+        kmem_free( &req );
+    }
 
 }  // end hal_cpu_context_destroy()
@@ -348,7 +409,13 @@
     kmem_req_t  req;
 
-    req.type = KMEM_FPU_CTX;
-    req.ptr  = thread->fpu_context;
-    kmem_free( &req );
+    hal_fpu_context_t * context = thread->fpu_context;
+
+    // release FPU context if required
+    if( context != NULL )
+    {    
+        req.type = KMEM_FPU_CTX;
+        req.ptr  = context;
+        kmem_free( &req );
+    }
 
 }  // end hal_fpu_context_destroy()
