Index: trunk/hal/tsar_mips32/core/hal_context.c
===================================================================
--- trunk/hal/tsar_mips32/core/hal_context.c	(revision 625)
+++ trunk/hal/tsar_mips32/core/hal_context.c	(revision 635)
@@ -2,5 +2,5 @@
  * hal_context.c - implementation of Thread Context API for TSAR-MIPS32
  * 
- * Author  Alain Greiner    (2016)
+ * Author  Alain Greiner    (2016,2017,2018,2019)
  *
  * Copyright (c)  UPMC Sorbonne Universites
@@ -30,4 +30,5 @@
 #include <printk.h>
 #include <vmm.h>
+#include <bits.h>
 #include <core.h>
 #include <cluster.h>
@@ -36,5 +37,5 @@
 
 /////////////////////////////////////////////////////////////////////////////////////////
-//       Define various SR initialisation values for TSAR-MIPS32 
+//       Define various SR initialisation values for the TSAR-MIPS32 architecture.
 /////////////////////////////////////////////////////////////////////////////////////////
 
@@ -44,5 +45,5 @@
 
 /////////////////////////////////////////////////////////////////////////////////////////
-// This structure defines the CPU context for TSAR MIPS32.
+// This structure defines the CPU context for the TSAR-MIPS32 architecture.
 // The following registers are saved/restored at each context switch:
 // - GPR : all, but (zero, k0, k1), plus (hi, lo)
@@ -51,5 +52,5 @@
 //
 // WARNING : check the two CONFIG_CPU_CTX_SIZE & CONFIG_FPU_CTX_SIZE configuration 
-//           parameterss when modifying this structure.
+//           parameters when modifying this structure.
 /////////////////////////////////////////////////////////////////////////////////////////
 
@@ -101,5 +102,5 @@
 
 /////////////////////////////////////////////////////////////////////////////////////////
-// This structure defines the fpu_context for TSAR MIPS32.
+// This structure defines the fpu_context for the TSAR MIPS32 architecture.
 /////////////////////////////////////////////////////////////////////////////////////////
 
@@ -124,8 +125,10 @@
     // allocate memory for cpu_context
     kmem_req_t  req;
-    req.type   = KMEM_CPU_CTX;
+    req.type   = KMEM_KCM;
+    req.order  = bits_log2( sizeof(hal_cpu_context_t) );
     req.flags  = AF_KERNEL | AF_ZERO;
 
-    hal_cpu_context_t * context = (hal_cpu_context_t *)kmem_alloc( &req );
+    hal_cpu_context_t * context = kmem_alloc( &req );
+
     if( context == NULL ) return -1;
 
@@ -175,34 +178,52 @@
 void hal_cpu_context_fork( xptr_t child_xp )
 {
-    // get pointer on calling thread
-    thread_t * this = CURRENT_THREAD;
-
+    cxy_t               parent_cxy;        // parent thread cluster
+    thread_t          * parent_ptr;        // local pointer on parent thread
+    hal_cpu_context_t * parent_context;    // local pointer on parent cpu_context
+    uint32_t          * parent_uzone;      // local_pointer on parent uzone (in kernel stack)
+    char              * parent_ksp;        // kernel stack pointer on parent kernel stack
+    uint32_t            parent_us_base;    // parent user stack base value
+
+    cxy_t               child_cxy;         // parent thread cluster
+    thread_t          * child_ptr;         // local pointer on child thread
+    hal_cpu_context_t * child_context;     // local pointer on child cpu_context
+    uint32_t          * child_uzone;       // local_pointer on child uzone (in kernel stack)
+    char              * child_ksp;         // kernel stack pointer on child kernel stack
+    uint32_t            child_us_base;     // child user stack base value
+
+    process_t         * child_process;     // local pointer on child processs
+    uint32_t            child_pt_ppn;      // PPN of child process PT1 
+    vseg_t            * child_us_vseg;     // local pointer on child user stack vseg
+    
     // allocate a local CPU context in parent kernel stack
-    hal_cpu_context_t  context;
-
-    // get local parent thread cluster and local pointer
-    cxy_t      parent_cxy = local_cxy;
-    thread_t * parent_ptr = CURRENT_THREAD;
-
-    // get remote child thread cluster and local pointer
-    cxy_t      child_cxy = GET_CXY( child_xp );
-    thread_t * child_ptr = GET_PTR( child_xp );
-
-    // get local pointer on remote child cpu context
-    char * child_context_ptr = hal_remote_lpt( XPTR(child_cxy , &child_ptr->cpu_context) );
+    hal_cpu_context_t context;
+
+    // get (local) parent thread cluster and local pointer
+    parent_cxy = local_cxy;
+    parent_ptr = CURRENT_THREAD;
+
+    // get (remote) child thread cluster and local pointer
+    child_cxy = GET_CXY( child_xp );
+    child_ptr = GET_PTR( child_xp );
+
+    // get local pointer on (local) parent CPU context
+    parent_context = parent_ptr->cpu_context;
+
+    // get local pointer on (remote) child CPU context
+    child_context = hal_remote_lpt( XPTR(child_cxy , &child_ptr->cpu_context) );
 
     // get local pointer on remote child process
-    process_t * process = hal_remote_lpt( XPTR(child_cxy , &child_ptr->process) );
+    child_process = hal_remote_lpt( XPTR(child_cxy , &child_ptr->process) );
 
     // get ppn of remote child process page table
-    uint32_t pt_ppn = hal_remote_l32( XPTR(child_cxy , &process->vmm.gpt.ppn) );
-
-    // get local pointer on parent uzone from parent thread descriptor
-    uint32_t * parent_uzone = parent_ptr->uzone_current;
-
-    // compute  local pointer on child uzone 
-    uint32_t * child_uzone  = (uint32_t *)( (intptr_t)parent_uzone +
-                                            (intptr_t)child_ptr    -
-                                            (intptr_t)parent_ptr  );
+    child_pt_ppn = hal_remote_l32( XPTR(child_cxy , &child_process->vmm.gpt.ppn) );
+
+    // get local pointer on local parent uzone (in parent kernel stack)
+    parent_uzone = parent_ptr->uzone_current;
+
+    // compute local pointer on remote child uzone (in child kernel stack)
+    child_uzone  = (uint32_t *)( (intptr_t)parent_uzone +
+                                 (intptr_t)child_ptr    -
+                                 (intptr_t)parent_ptr  );
 
     // update the uzone pointer in child thread descriptor
@@ -213,16 +234,39 @@
 if( DEBUG_HAL_CONTEXT < cycle )
 printk("\n[%s] thread[%x,%x] parent_uzone %x / child_uzone %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, parent_uzone, child_uzone, cycle );
-#endif
-
-    // copy parent kernel stack to child thread descriptor
+__FUNCTION__, parent_ptr->process->pid, parent_ptr->trdid, parent_uzone, child_uzone, cycle );
+#endif
+
+    // get user stack base for parent thread
+    parent_us_base = parent_ptr->user_stack_vseg->min;
+
+    // get user stack base for child thread
+    child_us_vseg  = hal_remote_lpt( XPTR( child_cxy , &child_ptr->user_stack_vseg ) );
+    child_us_base  = hal_remote_l32( XPTR( child_cxy , &child_us_vseg->min ) );
+
+#if DEBUG_HAL_CONTEXT
+if( DEBUG_HAL_CONTEXT < cycle )
+printk("\n[%s] thread[%x,%x] parent_ustack_base %x / child_ustack_base %x\n",
+__FUNCTION__, parent_ptr->process->pid, parent_ptr->trdid, parent_us_base, child_us_base );
+#endif
+
+    // get current value of kernel stack pointer in parent kernel stack
+    parent_ksp = (char *)hal_get_sp();
+
+    // compute value of kernel stack pointer in child kernel stack 
+    child_ksp  = (char *)((intptr_t)parent_ksp +
+                          (intptr_t)child_ptr  - 
+                          (intptr_t)parent_ptr );
+
+#if DEBUG_HAL_CONTEXT
+if( DEBUG_HAL_CONTEXT < cycle )
+printk("\n[%s] thread[%x,%x] parent_ksp %x / child_ksp %x\n",
+__FUNCTION__, parent_ptr->process->pid, parent_ptr->trdid, parent_ksp, child_ksp );
+#endif
+
+    // compute number of bytes to be copied, depending on current value of parent_ksp
+    uint32_t size = (uint32_t)parent_ptr + CONFIG_THREAD_DESC_SIZE - (uint32_t)parent_ksp;    
+
+    // copy parent kernel stack content to child thread descriptor
     // (this includes the uzone, that is allocated in the kernel stack)
-    char * parent_ksp = (char *)hal_get_sp();
-    char * child_ksp  = (char *)((intptr_t)parent_ksp +
-                                 (intptr_t)child_ptr  - 
-                                 (intptr_t)parent_ptr );
-
-    uint32_t size = (uint32_t)parent_ptr + CONFIG_THREAD_DESC_SIZE - (uint32_t)parent_ksp;
-
     hal_remote_memcpy( XPTR( child_cxy , child_ksp ),
                        XPTR( local_cxy , parent_ksp ),
@@ -230,62 +274,67 @@
 
 #if DEBUG_HAL_CONTEXT
-cycle = (uint32_t)hal_get_cycles();
-printk("\n[%s] thread[%x,%x] copied kstack from parent %x to child %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, parent_ptr, child_ptr, cycle );
-#endif
-
-    // patch the user stack pointer slot in the child uzone[UZ_SP]
-    // because parent and child use the same offset to access the user stack,
-    // but parent and child do not have the same user stack base address.
-    uint32_t parent_us_base = parent_ptr->user_stack_vseg->min;
-    vseg_t * child_us_vseg  = hal_remote_lpt( XPTR( child_cxy , &child_ptr->user_stack_vseg ) );
-    uint32_t child_us_base  = hal_remote_l32( XPTR( child_cxy , &child_us_vseg->min ) );
-    uint32_t parent_usp     = parent_uzone[UZ_SP];
-    uint32_t child_usp      = parent_usp + child_us_base - parent_us_base;
-
-    hal_remote_s32( XPTR( child_cxy , &child_uzone[UZ_SP] ) , child_usp );
-
-#if DEBUG_HAL_CONTEXT
-cycle = (uint32_t)hal_get_cycles();
-printk("\n[%s] thread[%x,%x] parent_usp %x / child_usp %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, parent_usp, child_usp, cycle );
-#endif
-
-    // save current values of CPU registers to local CPU context
+if( DEBUG_HAL_CONTEXT < cycle )
+printk("\n[%s] thread[%x,%x] copied kstack from parent (%x) to child (%x)\n",
+__FUNCTION__, parent_ptr->process->pid, parent_ptr->trdid, parent_ptr, child_ptr );
+#endif
+
+    // save current values of CPU registers to local copy of CPU context
     hal_do_cpu_save( &context );
 
-    // From this point, both parent and child can execute the following code,
+    // update  three slots in this local CPU context
+    context.sp_29   = (uint32_t)child_ksp;
+    context.c0_th   = (uint32_t)child_ptr;
+    context.c2_ptpr = (uint32_t)child_pt_ppn >> 1;
+
+    // From this point, both parent and child execute the following code,
     // but child thread will only execute it after being unblocked by parent thread.
     // They can be distinguished by the (CURRENT_THREAD,local_cxy) values,
     // and we must re-initialise the calling thread pointer from c0_th register
 
-    this = CURRENT_THREAD;
+    thread_t * this = CURRENT_THREAD;
 
     if( (this == parent_ptr) && (local_cxy == parent_cxy) )   // parent thread
     {
-        // patch 4 slots in the local CPU context: the sp_29 / c0_th / C0_sr / c2_ptpr
-        // slots are not identical in parent and child
-        context.sp_29   = context.sp_29 + (intptr_t)child_ptr - (intptr_t)parent_ptr;
-        context.c0_th   = (uint32_t)child_ptr;
-        context.c0_sr   = SR_SYS_MODE;
-        context.c2_ptpr = pt_ppn >> 1;
-
-        // copy this patched context to remote child context
-        hal_remote_memcpy( XPTR( child_cxy , child_context_ptr ),
+        // parent thread must update four slots in child uzone 
+        // - UZ_TH   : parent and child have different threads descriptors
+        // - UZ_SP   : parent and child have different user stack base addresses.
+        // - UZ_PTPR : parent and child use different Generic Page Tables
+
+        // parent thread computes values for child thread
+        uint32_t child_sp    = parent_uzone[UZ_SP]  + child_us_base - parent_us_base;
+        uint32_t child_th    = (uint32_t)child_ptr;
+        uint32_t child_ptpr  = (uint32_t)child_pt_ppn >> 1;
+
+#if DEBUG_HAL_CONTEXT
+if( DEBUG_HAL_CONTEXT < cycle )
+printk("\n[%s] thread[%x,%x] : parent_uz_sp %x / child_uz_sp %x\n",
+__FUNCTION__, parent_ptr->process->pid, parent_ptr->trdid,
+parent_uzone[UZ_SP], child_sp );
+#endif
+
+        // parent thread updates the child uzone
+        hal_remote_s32( XPTR( child_cxy , &child_uzone[UZ_SP]   ) , child_sp );
+        hal_remote_s32( XPTR( child_cxy , &child_uzone[UZ_TH]   ) , child_th );
+        hal_remote_s32( XPTR( child_cxy , &child_uzone[UZ_PTPR] ) , child_ptpr );
+
+        // parent thread copies the local context to remote child context
+        hal_remote_memcpy( XPTR( child_cxy , child_context ),
                            XPTR( local_cxy  , &context ) , 
                            sizeof( hal_cpu_context_t ) );
 #if DEBUG_HAL_CONTEXT
+if( DEBUG_HAL_CONTEXT < cycle )
+printk("\n[%s] thread[%x,%x] copied parent CPU context to child CPU context\n",
+__FUNCTION__, parent_ptr->process->pid, parent_ptr->trdid );
+#endif
+
+        // parent thread unblocks child thread
+        thread_unblock( XPTR( child_cxy , child_ptr ) , THREAD_BLOCKED_GLOBAL );
+
+#if DEBUG_HAL_CONTEXT
 cycle = (uint32_t)hal_get_cycles();
-printk("\n[%s] thread[%x,%x] copied CPU context to child / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, cycle );
-#endif
-
-        // parent thread unblock child thread
-        thread_unblock( XPTR( child_cxy , child_ptr ) , THREAD_BLOCKED_GLOBAL );
-
-#if DEBUG_HAL_CONTEXT
-cycle = (uint32_t)hal_get_cycles();
-printk("\n[%s] thread[%x,%x] unblocked child thread / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, cycle );
+trdid_t child_trdid = hal_remote_l32( XPTR( child_cxy , &child_ptr->trdid ) );
+pid_t   child_pid   = hal_remote_l32( XPTR( child_cxy , &child_process->pid ) );
+printk("\n[%s] thread[%x,%x] unblocked child thread[%x,%x] / cycle %d\n",
+__FUNCTION__, parent_ptr->process->pid, parent_ptr->trdid, child_pid, child_trdid, cycle );
 #endif
 
@@ -347,5 +396,5 @@
     if( ctx != NULL )
     {    
-        req.type = KMEM_CPU_CTX;
+        req.type = KMEM_KCM;
         req.ptr  = ctx;
         kmem_free( &req );
@@ -366,8 +415,10 @@
     // allocate memory for fpu_context
     kmem_req_t  req;
-    req.type   = KMEM_FPU_CTX;
+    req.type   = KMEM_KCM;
     req.flags  = AF_KERNEL | AF_ZERO;
-
-    hal_fpu_context_t * context = (hal_fpu_context_t *)kmem_alloc( &req );
+    req.order  = bits_log2( sizeof(hal_fpu_context_t) );
+
+    hal_fpu_context_t * context = kmem_alloc( &req );
+
     if( context == NULL ) return -1;
 
@@ -414,5 +465,5 @@
     if( context != NULL )
     {    
-        req.type = KMEM_FPU_CTX;
+        req.type = KMEM_KCM;
         req.ptr  = context;
         kmem_free( &req );
