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

Last change on this file since 432 was 432, checked in by alain, 6 years ago

bloup

File size: 14.9 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_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) , __FUNCTION__ ,
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///////////////////////////////////////////////////
144error_t hal_cpu_context_create( thread_t * thread )
145{
146    // allocate memory for a CPU context
147    error_t error = hal_cpu_context_alloc( thread );
148
149    if( error ) return error;
150
151    hal_cpu_context_t * context = (hal_cpu_context_t *)thread->cpu_context;
152
153    // initialisation depends on thread type
154    if( thread->type == THREAD_USER )
155    {
156        context->a0_04   = (uint32_t)thread->entry_args;
157        context->sp_29   = (uint32_t)thread->u_stack_base + (uint32_t)thread->u_stack_size - 8;
158        context->ra_31   = (uint32_t)&hal_kentry_eret;
159        context->c0_epc  = (uint32_t)thread->entry_func;
160        context->c0_sr   = SR_USR_MODE;
161            context->c0_th   = (uint32_t)thread; 
162            context->c2_ptpr = (uint32_t)((thread->process->vmm.gpt.ppn) >> 1);
163        context->c2_mode = 0xF;
164    }
165    else  // kernel thread
166    {
167        context->a0_04   = (uint32_t)thread->entry_args;
168        context->sp_29   = (uint32_t)thread->k_stack_base + (uint32_t)thread->k_stack_size - 8;
169        context->ra_31   = (uint32_t)thread->entry_func;
170        context->c0_sr   = SR_SYS_MODE;
171            context->c0_th   = (uint32_t)thread; 
172            context->c2_ptpr = (uint32_t)((thread->process->vmm.gpt.ppn) >> 1);
173        context->c2_mode = 0x3;
174    }
175
176    return 0;
177
178}  // end hal_cpu_context_create()
179
180////////////////////////////////////////////
181void hal_cpu_context_fork( xptr_t child_xp )
182{
183    // allocate a local CPU context in kernel stack
184    // It is initialized from local parent context
185    // and from child specific values, and is copied in
186    // in the remote child context using a remote_memcpy()
187    hal_cpu_context_t  context;
188
189    // get local parent thread local pointer
190    thread_t * parent_ptr = CURRENT_THREAD;
191
192    // get remote child thread cluster and local pointer
193    cxy_t      child_cxy = GET_CXY( child_xp );
194    thread_t * child_ptr = (thread_t *)GET_PTR( child_xp );
195
196    // get remote child cpu_context local pointer
197    char * child_context_ptr = hal_remote_lpt( XPTR(child_cxy , &child_ptr->cpu_context) );
198
199    // get local pointer on remote child process
200    process_t * process = (process_t *)hal_remote_lpt( XPTR(child_cxy , &child_ptr->process) );
201
202    // get ppn of remote child process page table
203    uint32_t    pt_ppn = hal_remote_lw( XPTR(child_cxy , &process->vmm.gpt.ppn) );
204
205    // save CPU registers in local CPU context
206    hal_do_cpu_save( &context );
207
208    // From this point, both parent and child threads execute the following code.
209    // They can be distinguished by the CURRENT_THREAD value, and child will only
210    // execute it when it is unblocked by parent, after return to sys_fork().
211    // - parent thread copies user stack, and patch sp_29 / c0_th / C0_sr / c2_ptpr
212    // - child thread does nothing
213
214    thread_t * current = CURRENT_THREAD;
215
216    if( current == parent_ptr )    // current == parent thread
217    {
218        // get parent and child stack pointers
219        char * parent_sp = (char *)context.sp_29;
220        char * child_sp  = (char *)((intptr_t)parent_sp +
221                                    (intptr_t)child_ptr - 
222                                    (intptr_t)parent_ptr );
223 
224        // patch kernel_stack pointer, current thread, and status slots
225        context.sp_29   = (uint32_t)child_sp;
226        context.c0_th   = (uint32_t)child_ptr;
227        context.c0_sr   = SR_SYS_MODE;
228        context.c2_ptpr = pt_ppn >> 1;
229
230        // copy local context to remote child context)
231        hal_remote_memcpy( XPTR( child_cxy , child_context_ptr ),
232                           XPTR( local_cxy  , &context ) , 
233                           sizeof( hal_cpu_context_t ) );
234
235        // copy kernel stack content from local parent thread to remote child thread
236        uint32_t size = (uint32_t)parent_ptr + CONFIG_THREAD_DESC_SIZE - (uint32_t)parent_sp;
237        hal_remote_memcpy( XPTR( child_cxy , child_sp ),
238                           XPTR( local_cxy , parent_sp ),
239                           size );
240    }
241    else                           // current == child thread
242    {
243        assert( (current == child_ptr) , __FUNCTION__ , "current = %x / child = %x\n");
244    }
245
246}  // end hal_cpu_context_fork()
247
248/////////////////////////////////////////////////
249void hal_cpu_context_display( xptr_t  thread_xp )
250{
251    hal_cpu_context_t * ctx;
252
253    // get thread cluster and local pointer
254    cxy_t      cxy = GET_CXY( thread_xp );
255    thread_t * ptr = (thread_t *)GET_PTR( thread_xp );
256
257    // get context pointer
258    ctx = (hal_cpu_context_t *)hal_remote_lpt( XPTR( cxy , &ptr->cpu_context ) );
259
260    // get relevant context slots values
261    uint32_t sp_29   = hal_remote_lw( XPTR( cxy , &ctx->sp_29   ) );
262    uint32_t ra_31   = hal_remote_lw( XPTR( cxy , &ctx->ra_31   ) );
263    uint32_t c0_sr   = hal_remote_lw( XPTR( cxy , &ctx->c0_sr   ) );
264    uint32_t c0_epc  = hal_remote_lw( XPTR( cxy , &ctx->c0_epc  ) );
265    uint32_t c0_th   = hal_remote_lw( XPTR( cxy , &ctx->c0_th   ) );
266    uint32_t c2_ptpr = hal_remote_lw( XPTR( cxy , &ctx->c2_ptpr ) );
267    uint32_t c2_mode = hal_remote_lw( XPTR( cxy , &ctx->c2_mode ) );
268   
269    printk("\n***** CPU context for thread %x in process %x / cycle %d\n" 
270           " sp_29   = %X    ra_31   = %X\n" 
271           " c0_sr   = %X    c0_epc  = %X    c0_th = %X\n"
272           " c2_ptpr = %X    c2_mode = %X\n",
273           ptr, ptr->process->pid, (uint32_t)hal_get_cycles(),
274           sp_29   , ra_31,
275           c0_sr   , c0_epc  , c0_th,
276           c2_ptpr , c2_mode );
277
278}  // end hal_cpu_context_display()
279
280/////////////////////////////////////////////////
281void hal_cpu_context_destroy( thread_t * thread )
282{
283    kmem_req_t  req;
284
285    req.type = KMEM_CPU_CTX;
286    req.ptr  = thread->cpu_context;
287    kmem_free( &req );
288
289}  // end hal_cpu_context_destroy()
290
291
292
293
294
295//////////////////////////////////////////////////
296error_t hal_fpu_context_alloc( thread_t * thread )
297{
298    assert( (sizeof(hal_fpu_context_t) <= CONFIG_FPU_CTX_SIZE) , __FUNCTION__ ,
299    "illegal CPU context size" );
300
301    // allocate memory for fpu_context
302    kmem_req_t  req;
303    req.type   = KMEM_FPU_CTX;
304    req.flags  = AF_KERNEL | AF_ZERO;
305
306    hal_fpu_context_t * context = (hal_fpu_context_t *)kmem_alloc( &req );
307    if( context == NULL ) return -1;
308
309    // link to thread
310    thread->fpu_context = (void *)context;
311    return 0;
312
313}   // end hal_fpu_context_alloc()
314
315//////////////////////////////////////////
316void hal_fpu_context_copy( thread_t * dst,
317                           thread_t * src )
318{
319    assert( (src != NULL) , __FUNCTION__ , "src thread pointer is NULL\n"); 
320    assert( (dst != NULL) , __FUNCTION__ , "dst thread pointer is NULL\n"); 
321
322    // get fpu context pointers
323    hal_fpu_context_t * src_context = src->fpu_context;
324    hal_fpu_context_t * dst_context = dst->fpu_context;
325
326    // copy CPU context from src to dst
327    memcpy( dst_context , src_context , sizeof(hal_fpu_context_t) );
328
329}  // end hal_fpu_context_copy()
330
331/////////////////////////////////////////////////
332void hal_fpu_context_destroy( thread_t * thread )
333{
334    kmem_req_t  req;
335
336    req.type = KMEM_FPU_CTX;
337    req.ptr  = thread->fpu_context;
338    kmem_free( &req );
339
340}  // end hal_fpu_context_destroy()
341
342//////////////////////////////////////////////
343void hal_fpu_context_save( xptr_t  thread_xp )
344{
345    // allocate a local FPU context in kernel stack
346    hal_fpu_context_t  context;
347
348    // get remote child cluster and local pointer
349    cxy_t      thread_cxy = GET_CXY( thread_xp );
350    thread_t * thread_ptr = (thread_t *)GET_PTR( thread_xp );
351
352    asm volatile(
353    ".set noreorder           \n"
354    "swc1    $f0,    0*4(%0)  \n"   
355    "swc1    $f1,    1*4(%0)  \n"   
356    "swc1    $f2,    2*4(%0)  \n"   
357    "swc1    $f3,    3*4(%0)  \n"   
358    "swc1    $f4,    4*4(%0)  \n"   
359    "swc1    $f5,    5*4(%0)  \n"   
360    "swc1    $f6,    6*4(%0)  \n"   
361    "swc1    $f7,    7*4(%0)  \n"   
362    "swc1    $f8,    8*4(%0)  \n"   
363    "swc1    $f9,    9*4(%0)  \n"   
364    "swc1    $f10,  10*4(%0)  \n"   
365    "swc1    $f11,  11*4(%0)  \n"   
366    "swc1    $f12,  12*4(%0)  \n"   
367    "swc1    $f13,  13*4(%0)  \n"   
368    "swc1    $f14,  14*4(%0)  \n"   
369    "swc1    $f15,  15*4(%0)  \n"   
370    "swc1    $f16,  16*4(%0)  \n"   
371    "swc1    $f17,  17*4(%0)  \n"   
372    "swc1    $f18,  18*4(%0)  \n"   
373    "swc1    $f19,  19*4(%0)  \n"   
374    "swc1    $f20,  20*4(%0)  \n"   
375    "swc1    $f21,  21*4(%0)  \n"   
376    "swc1    $f22,  22*4(%0)  \n"   
377    "swc1    $f23,  23*4(%0)  \n"   
378    "swc1    $f24,  24*4(%0)  \n"   
379    "swc1    $f25,  25*4(%0)  \n"   
380    "swc1    $f26,  26*4(%0)  \n"   
381    "swc1    $f27,  27*4(%0)  \n"   
382    "swc1    $f28,  28*4(%0)  \n"   
383    "swc1    $f29,  29*4(%0)  \n"   
384    "swc1    $f30,  30*4(%0)  \n"   
385    "swc1    $f31,  31*4(%0)  \n"   
386    ".set reorder             \n"
387    : : "r"(&context) );
388
389    // copy local context to remote child context)
390    hal_remote_memcpy( XPTR( thread_cxy , &thread_ptr->fpu_context ),
391                       XPTR( local_cxy  , &context ) , 
392                       sizeof( hal_fpu_context_t ) );
393
394}  // end hal_fpu_context_save()
395
396/////////////////////////////////////////////////
397void hal_fpu_context_restore( thread_t * thread )
398{
399    uint32_t ctx = (uint32_t)thread->fpu_context;
400
401    asm volatile(
402    ".set noreorder           \n"
403    "lwc1    $f0,    0*4(%0)  \n"   
404    "lwc1    $f1,    1*4(%0)  \n"   
405    "lwc1    $f2,    2*4(%0)  \n"   
406    "lwc1    $f3,    3*4(%0)  \n"   
407    "lwc1    $f4,    4*4(%0)  \n"   
408    "lwc1    $f5,    5*4(%0)  \n"   
409    "lwc1    $f6,    6*4(%0)  \n"   
410    "lwc1    $f7,    7*4(%0)  \n"   
411    "lwc1    $f8,    8*4(%0)  \n"   
412    "lwc1    $f9,    9*4(%0)  \n"   
413    "lwc1    $f10,  10*4(%0)  \n"   
414    "lwc1    $f11,  11*4(%0)  \n"   
415    "lwc1    $f12,  12*4(%0)  \n"   
416    "lwc1    $f13,  13*4(%0)  \n"   
417    "lwc1    $f14,  14*4(%0)  \n"   
418    "lwc1    $f15,  15*4(%0)  \n"   
419    "lwc1    $f16,  16*4(%0)  \n"   
420    "lwc1    $f17,  17*4(%0)  \n"   
421    "lwc1    $f18,  18*4(%0)  \n"   
422    "lwc1    $f19,  19*4(%0)  \n"   
423    "lwc1    $f20,  20*4(%0)  \n"   
424    "lwc1    $f21,  21*4(%0)  \n"   
425    "lwc1    $f22,  22*4(%0)  \n"   
426    "lwc1    $f23,  23*4(%0)  \n"   
427    "lwc1    $f24,  24*4(%0)  \n"   
428    "lwc1    $f25,  25*4(%0)  \n"   
429    "lwc1    $f26,  26*4(%0)  \n"   
430    "lwc1    $f27,  27*4(%0)  \n"   
431    "lwc1    $f28,  28*4(%0)  \n"   
432    "lwc1    $f29,  29*4(%0)  \n"   
433    "lwc1    $f30,  30*4(%0)  \n"   
434    "lwc1    $f31,  31*4(%0)  \n"   
435    ".set reorder             \n"
436    : : "r"(ctx) );
437
438} // end hal_cpu_context_restore()
439
440
Note: See TracBrowser for help on using the repository browser.