source: trunk/hal/tsar_mips32/core/hal_context.c @ 626

Last change on this file since 626 was 625, checked in by alain, 5 years ago

Fix a bug in the vmm_remove_vseg() function: the physical pages
associated to an user DATA vseg were released to the kernel when
the target process descriptor was in the reference cluster.
This physical pages release should be done only when the page
forks counter value is zero.
All other modifications are cosmetic.

File size: 18.0 KB
Line 
1/*
2 * hal_context.c - implementation of Thread Context API for TSAR-MIPS32
3 *
4 * Author  Alain Greiner    (2016)
5 *
6 * Copyright (c)  UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH.is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH.is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH.; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <hal_kernel_types.h>
25#include <hal_switch.h>
26#include <memcpy.h>
27#include <thread.h>
28#include <string.h>
29#include <process.h>
30#include <printk.h>
31#include <vmm.h>
32#include <core.h>
33#include <cluster.h>
34#include <hal_context.h>
35#include <hal_kentry.h>
36
37/////////////////////////////////////////////////////////////////////////////////////////
38//       Define various SR initialisation values for TSAR-MIPS32
39/////////////////////////////////////////////////////////////////////////////////////////
40
41#define SR_USR_MODE       0x0000FF13
42#define SR_USR_MODE_FPU   0x2000FF13
43#define SR_SYS_MODE       0x0000FF01
44
45/////////////////////////////////////////////////////////////////////////////////////////
46// This structure defines the CPU context for TSAR MIPS32.
47// The following registers are saved/restored at each context switch:
48// - GPR : all, but (zero, k0, k1), plus (hi, lo)
49// - CP0 : c0_th , c0_sr , C0_epc
50// - CP2 : c2_ptpr , C2_mode
51//
52// WARNING : check the two CONFIG_CPU_CTX_SIZE & CONFIG_FPU_CTX_SIZE configuration
53//           parameterss when modifying this structure.
54/////////////////////////////////////////////////////////////////////////////////////////
55
56typedef struct hal_cpu_context_s
57{
58    uint32_t c0_epc;     // slot 0
59    uint32_t at_01;      // slot 1
60    uint32_t v0_02;      // slot 2
61    uint32_t v1_03;      // slot 3
62    uint32_t a0_04;      // slot 4
63    uint32_t a1_05;      // slot 5
64    uint32_t a2_06;      // slot 6
65    uint32_t a3_07;      // slot 7
66
67    uint32_t t0_08;      // slot 8
68    uint32_t t1_09;      // slot 9
69    uint32_t t2_10;      // slot 10
70    uint32_t t3_11;      // slot 11
71    uint32_t t4_12;      // slot 12
72    uint32_t t5_13;      // slot 13
73    uint32_t t6_14;      // slot 14
74    uint32_t t7_15;      // slot 15
75
76        uint32_t s0_16;      // slot 16
77        uint32_t s1_17;      // slot 17
78        uint32_t s2_18;      // slot 18
79        uint32_t s3_19;      // slot 19
80        uint32_t s4_20;      // slot 20
81        uint32_t s5_21;      // slot 21
82        uint32_t s6_22;      // slot 22
83        uint32_t s7_23;      // slot 23
84
85    uint32_t t8_24;      // slot 24
86    uint32_t t9_25;      // slot 25
87    uint32_t hi_26;      // slot 26
88    uint32_t lo_27;      // slot 27
89    uint32_t gp_28;      // slot 28
90        uint32_t sp_29;      // slot 29
91        uint32_t s8_30;      // slot 30
92        uint32_t ra_31;      // slot 31
93
94        uint32_t c2_ptpr;    // slot 32
95        uint32_t c2_mode;    // slot 33
96
97        uint32_t c0_sr;      // slot 34
98        uint32_t c0_th;      // slot 35
99} 
100hal_cpu_context_t;
101
102/////////////////////////////////////////////////////////////////////////////////////////
103// This structure defines the fpu_context for TSAR MIPS32.
104/////////////////////////////////////////////////////////////////////////////////////////
105
106typedef struct hal_fpu_context_s
107{
108        uint32_t   fpu_regs[32];     
109}
110hal_fpu_context_t;
111
112
113/////////////////////////////////////////////////////////////////////////////////////////
114//        CPU context related functions
115/////////////////////////////////////////////////////////////////////////////////////////
116
117
118//////////////////////////////////////////////////
119error_t hal_cpu_context_alloc( thread_t * thread )
120{
121    assert( (sizeof(hal_cpu_context_t) <= CONFIG_CPU_CTX_SIZE) ,
122    "illegal CPU context size" );
123
124    // allocate memory for cpu_context
125    kmem_req_t  req;
126    req.type   = KMEM_CPU_CTX;
127    req.flags  = AF_KERNEL | AF_ZERO;
128
129    hal_cpu_context_t * context = (hal_cpu_context_t *)kmem_alloc( &req );
130    if( context == NULL ) return -1;
131
132    // link to thread
133    thread->cpu_context = (void *)context;
134    return 0;
135
136}   // end hal_cpu_context_alloc()
137
138/////////////////////////////////////////////////
139// The following context slots are initialised
140// GPR : a0_04 / sp_29 / ra_31
141// CP0 : c0_sr / c0_th / c0_epc
142// CP2 : c2_ptpr / c2_mode
143/////////////////////////////////////////////////
144void hal_cpu_context_init( thread_t * thread )
145{
146    hal_cpu_context_t * context = (hal_cpu_context_t *)thread->cpu_context;
147
148    assert( (context != NULL ), "CPU context not allocated" );
149
150    // initialisation depends on thread type
151    if( thread->type == THREAD_USER )
152    {
153        context->a0_04   = (uint32_t)thread->entry_args;
154        context->sp_29   = (uint32_t)thread->user_stack_vseg->max - 8;
155        context->ra_31   = (uint32_t)&hal_kentry_eret;
156        context->c0_epc  = (uint32_t)thread->entry_func;
157        context->c0_sr   = SR_USR_MODE;
158            context->c0_th   = (uint32_t)thread; 
159            context->c2_ptpr = (uint32_t)((thread->process->vmm.gpt.ppn) >> 1);
160        context->c2_mode = 0xF;
161    }
162    else  // kernel thread
163    {
164        context->a0_04   = (uint32_t)thread->entry_args;
165        context->sp_29   = (uint32_t)thread->k_stack_base + (uint32_t)thread->k_stack_size - 8;
166        context->ra_31   = (uint32_t)thread->entry_func;
167        context->c0_sr   = SR_SYS_MODE;
168            context->c0_th   = (uint32_t)thread; 
169            context->c2_ptpr = (uint32_t)((thread->process->vmm.gpt.ppn) >> 1);
170        context->c2_mode = 0x3;
171    }
172}  // end hal_cpu_context_init()
173
174////////////////////////////////////////////
175void hal_cpu_context_fork( xptr_t child_xp )
176{
177    // get pointer on calling thread
178    thread_t * this = CURRENT_THREAD;
179
180    // allocate a local CPU context in parent kernel stack
181    hal_cpu_context_t  context;
182
183    // get local parent thread cluster and local pointer
184    cxy_t      parent_cxy = local_cxy;
185    thread_t * parent_ptr = CURRENT_THREAD;
186
187    // get remote child thread cluster and local pointer
188    cxy_t      child_cxy = GET_CXY( child_xp );
189    thread_t * child_ptr = GET_PTR( child_xp );
190
191    // get local pointer on remote child cpu context
192    char * child_context_ptr = hal_remote_lpt( XPTR(child_cxy , &child_ptr->cpu_context) );
193
194    // get local pointer on remote child process
195    process_t * process = hal_remote_lpt( XPTR(child_cxy , &child_ptr->process) );
196
197    // get ppn of remote child process page table
198    uint32_t pt_ppn = hal_remote_l32( XPTR(child_cxy , &process->vmm.gpt.ppn) );
199
200    // get local pointer on parent uzone from parent thread descriptor
201    uint32_t * parent_uzone = parent_ptr->uzone_current;
202
203    // compute  local pointer on child uzone
204    uint32_t * child_uzone  = (uint32_t *)( (intptr_t)parent_uzone +
205                                            (intptr_t)child_ptr    -
206                                            (intptr_t)parent_ptr  );
207
208    // update the uzone pointer in child thread descriptor
209    hal_remote_spt( XPTR( child_cxy , &child_ptr->uzone_current ) , child_uzone );
210
211#if DEBUG_HAL_CONTEXT
212uint32_t cycle = (uint32_t)hal_get_cycles();
213if( DEBUG_HAL_CONTEXT < cycle )
214printk("\n[%s] thread[%x,%x] parent_uzone %x / child_uzone %x / cycle %d\n",
215__FUNCTION__, this->process->pid, this->trdid, parent_uzone, child_uzone, cycle );
216#endif
217
218    // copy parent kernel stack to child thread descriptor
219    // (this includes the uzone, that is allocated in the kernel stack)
220    char * parent_ksp = (char *)hal_get_sp();
221    char * child_ksp  = (char *)((intptr_t)parent_ksp +
222                                 (intptr_t)child_ptr  - 
223                                 (intptr_t)parent_ptr );
224
225    uint32_t size = (uint32_t)parent_ptr + CONFIG_THREAD_DESC_SIZE - (uint32_t)parent_ksp;
226
227    hal_remote_memcpy( XPTR( child_cxy , child_ksp ),
228                       XPTR( local_cxy , parent_ksp ),
229                       size );
230
231#if DEBUG_HAL_CONTEXT
232cycle = (uint32_t)hal_get_cycles();
233printk("\n[%s] thread[%x,%x] copied kstack from parent %x to child %x / cycle %d\n",
234__FUNCTION__, this->process->pid, this->trdid, parent_ptr, child_ptr, cycle );
235#endif
236
237    // patch the user stack pointer slot in the child uzone[UZ_SP]
238    // because parent and child use the same offset to access the user stack,
239    // but parent and child do not have the same user stack base address.
240    uint32_t parent_us_base = parent_ptr->user_stack_vseg->min;
241    vseg_t * child_us_vseg  = hal_remote_lpt( XPTR( child_cxy , &child_ptr->user_stack_vseg ) );
242    uint32_t child_us_base  = hal_remote_l32( XPTR( child_cxy , &child_us_vseg->min ) );
243    uint32_t parent_usp     = parent_uzone[UZ_SP];
244    uint32_t child_usp      = parent_usp + child_us_base - parent_us_base;
245
246    hal_remote_s32( XPTR( child_cxy , &child_uzone[UZ_SP] ) , child_usp );
247
248#if DEBUG_HAL_CONTEXT
249cycle = (uint32_t)hal_get_cycles();
250printk("\n[%s] thread[%x,%x] parent_usp %x / child_usp %x / cycle %d\n",
251__FUNCTION__, this->process->pid, this->trdid, parent_usp, child_usp, cycle );
252#endif
253
254    // save current values of CPU registers to local CPU context
255    hal_do_cpu_save( &context );
256
257    // From this point, both parent and child can execute the following code,
258    // but child thread will only execute it after being unblocked by parent thread.
259    // They can be distinguished by the (CURRENT_THREAD,local_cxy) values,
260    // and we must re-initialise the calling thread pointer from c0_th register
261
262    this = CURRENT_THREAD;
263
264    if( (this == parent_ptr) && (local_cxy == parent_cxy) )   // parent thread
265    {
266        // patch 4 slots in the local CPU context: the sp_29 / c0_th / C0_sr / c2_ptpr
267        // slots are not identical in parent and child
268        context.sp_29   = context.sp_29 + (intptr_t)child_ptr - (intptr_t)parent_ptr;
269        context.c0_th   = (uint32_t)child_ptr;
270        context.c0_sr   = SR_SYS_MODE;
271        context.c2_ptpr = pt_ppn >> 1;
272
273        // copy this patched context to remote child context
274        hal_remote_memcpy( XPTR( child_cxy , child_context_ptr ),
275                           XPTR( local_cxy  , &context ) , 
276                           sizeof( hal_cpu_context_t ) );
277#if DEBUG_HAL_CONTEXT
278cycle = (uint32_t)hal_get_cycles();
279printk("\n[%s] thread[%x,%x] copied CPU context to child / cycle %d\n",
280__FUNCTION__, this->process->pid, this->trdid, cycle );
281#endif
282
283        // parent thread unblock child thread
284        thread_unblock( XPTR( child_cxy , child_ptr ) , THREAD_BLOCKED_GLOBAL );
285
286#if DEBUG_HAL_CONTEXT
287cycle = (uint32_t)hal_get_cycles();
288printk("\n[%s] thread[%x,%x] unblocked child thread / cycle %d\n",
289__FUNCTION__, this->process->pid, this->trdid, cycle );
290#endif
291
292    }
293
294}  // end hal_cpu_context_fork()
295
296//////////////////////////////////////////////
297void hal_cpu_context_exec( thread_t * thread )
298{
299    // re_initialize CPU context
300    hal_cpu_context_init( thread );
301
302    // restore CPU registers ... and jump to user code
303    hal_do_cpu_restore( (hal_cpu_context_t *)thread->cpu_context );
304
305} // end hal_cpu_context_exec()
306
307/////////////////////////////////////////////////
308void hal_cpu_context_display( xptr_t  thread_xp )
309{
310    hal_cpu_context_t * ctx;
311
312    // get thread cluster and local pointer
313    cxy_t      cxy = GET_CXY( thread_xp );
314    thread_t * ptr = GET_PTR( thread_xp );
315
316    // get context pointer
317    ctx = (hal_cpu_context_t *)hal_remote_lpt( XPTR( cxy , &ptr->cpu_context ) );
318
319    // get relevant context slots values
320    uint32_t sp_29   = hal_remote_l32( XPTR( cxy , &ctx->sp_29   ) );
321    uint32_t ra_31   = hal_remote_l32( XPTR( cxy , &ctx->ra_31   ) );
322    uint32_t c0_sr   = hal_remote_l32( XPTR( cxy , &ctx->c0_sr   ) );
323    uint32_t c0_epc  = hal_remote_l32( XPTR( cxy , &ctx->c0_epc  ) );
324    uint32_t c0_th   = hal_remote_l32( XPTR( cxy , &ctx->c0_th   ) );
325    uint32_t c2_ptpr = hal_remote_l32( XPTR( cxy , &ctx->c2_ptpr ) );
326    uint32_t c2_mode = hal_remote_l32( XPTR( cxy , &ctx->c2_mode ) );
327   
328    printk("\n***** CPU context for thread %x in process %x / cycle %d\n" 
329           " sp_29   = %X    ra_31   = %X\n" 
330           " c0_sr   = %X    c0_epc  = %X    c0_th = %X\n"
331           " c2_ptpr = %X    c2_mode = %X\n",
332           ptr, ptr->process->pid, (uint32_t)hal_get_cycles(),
333           sp_29   , ra_31,
334           c0_sr   , c0_epc  , c0_th,
335           c2_ptpr , c2_mode );
336
337}  // end hal_cpu_context_display()
338
339/////////////////////////////////////////////////
340void hal_cpu_context_destroy( thread_t * thread )
341{
342    kmem_req_t          req;
343
344    hal_cpu_context_t * ctx = thread->cpu_context;
345
346    // release CPU context if required
347    if( ctx != NULL )
348    {   
349        req.type = KMEM_CPU_CTX;
350        req.ptr  = ctx;
351        kmem_free( &req );
352    }
353
354}  // end hal_cpu_context_destroy()
355
356
357
358
359
360//////////////////////////////////////////////////
361error_t hal_fpu_context_alloc( thread_t * thread )
362{
363    assert( (sizeof(hal_fpu_context_t) <= CONFIG_FPU_CTX_SIZE) ,
364    "illegal CPU context size" );
365
366    // allocate memory for fpu_context
367    kmem_req_t  req;
368    req.type   = KMEM_FPU_CTX;
369    req.flags  = AF_KERNEL | AF_ZERO;
370
371    hal_fpu_context_t * context = (hal_fpu_context_t *)kmem_alloc( &req );
372    if( context == NULL ) return -1;
373
374    // link to thread
375    thread->fpu_context = (void *)context;
376    return 0;
377
378}   // end hal_fpu_context_alloc()
379
380//////////////////////////////////////////////
381void hal_fpu_context_init( thread_t * thread )
382{
383    hal_fpu_context_t * context = thread->fpu_context;
384
385    assert( (context != NULL) , "fpu context not allocated" );
386
387    memset( context , 0 , sizeof(hal_fpu_context_t) );
388}
389
390//////////////////////////////////////////
391void hal_fpu_context_copy( thread_t * dst,
392                           thread_t * src )
393{
394    assert( (src != NULL) , "src thread pointer is NULL\n");
395    assert( (dst != NULL) , "dst thread pointer is NULL\n");
396
397    // get fpu context pointers
398    hal_fpu_context_t * src_context = src->fpu_context;
399    hal_fpu_context_t * dst_context = dst->fpu_context;
400
401    // copy CPU context from src to dst
402    memcpy( dst_context , src_context , sizeof(hal_fpu_context_t) );
403
404}  // end hal_fpu_context_copy()
405
406/////////////////////////////////////////////////
407void hal_fpu_context_destroy( thread_t * thread )
408{
409    kmem_req_t  req;
410
411    hal_fpu_context_t * context = thread->fpu_context;
412
413    // release FPU context if required
414    if( context != NULL )
415    {   
416        req.type = KMEM_FPU_CTX;
417        req.ptr  = context;
418        kmem_free( &req );
419    }
420
421}  // end hal_fpu_context_destroy()
422
423//////////////////////////////////////////////
424void hal_fpu_context_save( xptr_t  thread_xp )
425{
426    // allocate a local FPU context in kernel stack
427    hal_fpu_context_t  src_context;
428
429    // get remote child cluster and local pointer
430    cxy_t      thread_cxy = GET_CXY( thread_xp );
431    thread_t * thread_ptr = GET_PTR( thread_xp );
432
433    asm volatile(
434    ".set noreorder           \n"
435    "swc1    $f0,    0*4(%0)  \n"   
436    "swc1    $f1,    1*4(%0)  \n"   
437    "swc1    $f2,    2*4(%0)  \n"   
438    "swc1    $f3,    3*4(%0)  \n"   
439    "swc1    $f4,    4*4(%0)  \n"   
440    "swc1    $f5,    5*4(%0)  \n"   
441    "swc1    $f6,    6*4(%0)  \n"   
442    "swc1    $f7,    7*4(%0)  \n"   
443    "swc1    $f8,    8*4(%0)  \n"   
444    "swc1    $f9,    9*4(%0)  \n"   
445    "swc1    $f10,  10*4(%0)  \n"   
446    "swc1    $f11,  11*4(%0)  \n"   
447    "swc1    $f12,  12*4(%0)  \n"   
448    "swc1    $f13,  13*4(%0)  \n"   
449    "swc1    $f14,  14*4(%0)  \n"   
450    "swc1    $f15,  15*4(%0)  \n"   
451    "swc1    $f16,  16*4(%0)  \n"   
452    "swc1    $f17,  17*4(%0)  \n"   
453    "swc1    $f18,  18*4(%0)  \n"   
454    "swc1    $f19,  19*4(%0)  \n"   
455    "swc1    $f20,  20*4(%0)  \n"   
456    "swc1    $f21,  21*4(%0)  \n"   
457    "swc1    $f22,  22*4(%0)  \n"   
458    "swc1    $f23,  23*4(%0)  \n"   
459    "swc1    $f24,  24*4(%0)  \n"   
460    "swc1    $f25,  25*4(%0)  \n"   
461    "swc1    $f26,  26*4(%0)  \n"   
462    "swc1    $f27,  27*4(%0)  \n"   
463    "swc1    $f28,  28*4(%0)  \n"   
464    "swc1    $f29,  29*4(%0)  \n"   
465    "swc1    $f30,  30*4(%0)  \n"   
466    "swc1    $f31,  31*4(%0)  \n"   
467    ".set reorder             \n"
468    : : "r"(&src_context) );
469
470    // get local pointer on target thread FPU context
471    void * dst_context = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->fpu_context ) );
472
473    // copy local context to remote child context)
474    hal_remote_memcpy( XPTR( thread_cxy , dst_context ),
475                       XPTR( local_cxy  , &src_context ), 
476                       sizeof( hal_fpu_context_t ) );
477
478}  // end hal_fpu_context_save()
479
480/////////////////////////////////////////////////
481void hal_fpu_context_restore( thread_t * thread )
482{
483    // get pointer on FPU context and cast to uint32_t
484    uint32_t ctx = (uint32_t)thread->fpu_context;
485
486    asm volatile(
487    ".set noreorder           \n"
488    "lwc1    $f0,    0*4(%0)  \n"   
489    "lwc1    $f1,    1*4(%0)  \n"   
490    "lwc1    $f2,    2*4(%0)  \n"   
491    "lwc1    $f3,    3*4(%0)  \n"   
492    "lwc1    $f4,    4*4(%0)  \n"   
493    "lwc1    $f5,    5*4(%0)  \n"   
494    "lwc1    $f6,    6*4(%0)  \n"   
495    "lwc1    $f7,    7*4(%0)  \n"   
496    "lwc1    $f8,    8*4(%0)  \n"   
497    "lwc1    $f9,    9*4(%0)  \n"   
498    "lwc1    $f10,  10*4(%0)  \n"   
499    "lwc1    $f11,  11*4(%0)  \n"   
500    "lwc1    $f12,  12*4(%0)  \n"   
501    "lwc1    $f13,  13*4(%0)  \n"   
502    "lwc1    $f14,  14*4(%0)  \n"   
503    "lwc1    $f15,  15*4(%0)  \n"   
504    "lwc1    $f16,  16*4(%0)  \n"   
505    "lwc1    $f17,  17*4(%0)  \n"   
506    "lwc1    $f18,  18*4(%0)  \n"   
507    "lwc1    $f19,  19*4(%0)  \n"   
508    "lwc1    $f20,  20*4(%0)  \n"   
509    "lwc1    $f21,  21*4(%0)  \n"   
510    "lwc1    $f22,  22*4(%0)  \n"   
511    "lwc1    $f23,  23*4(%0)  \n"   
512    "lwc1    $f24,  24*4(%0)  \n"   
513    "lwc1    $f25,  25*4(%0)  \n"   
514    "lwc1    $f26,  26*4(%0)  \n"   
515    "lwc1    $f27,  27*4(%0)  \n"   
516    "lwc1    $f28,  28*4(%0)  \n"   
517    "lwc1    $f29,  29*4(%0)  \n"   
518    "lwc1    $f30,  30*4(%0)  \n"   
519    "lwc1    $f31,  31*4(%0)  \n"   
520    ".set reorder             \n"
521    : : "r"(ctx) );
522
523} // end hal_cpu_context_restore()
524
525
Note: See TracBrowser for help on using the repository browser.