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

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

Introduce the math library, to support the floating point
data used by the multi-thread fft application.
Fix several bugs regarding the FPU context save/restore.
Introduce support for the %f format in printf.

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