source: soft/giet_vm/giet_kernel/ctx_handler.c @ 706

Last change on this file since 706 was 706, checked in by guerin, 9 years ago

kernel: _ctx_switch: acknowledge signal before treating it

Just to be sure we do it once

  • Property svn:executable set to *
File size: 12.6 KB
Line 
1//////////////////////////////////////////////////////////////////////////////////
2// File     : ctx_handler.c
3// Date     : 01/04/2012
4// Authors  : alain greiner & joel porquet
5// Copyright (c) UPMC-LIP6
6//////////////////////////////////////////////////////////////////////////////////
7
8#include <ctx_handler.h>
9#include <sys_handler.h>
10#include <giet_config.h>
11#include <hard_config.h>
12#include <utils.h>
13#include <tty0.h>
14#include <xcu_driver.h>
15#include <fat32.h>
16#include <elf-types.h>
17
18/////////////////////////////////////////////////////////////////////////////////
19//     Extern variables and functions
20/////////////////////////////////////////////////////////////////////////////////
21
22// defined in giet_kernel/switch.s file
23extern void _task_switch(unsigned int *, unsigned int *);
24
25// allocated in boot.c or kernel_init.c files
26extern static_scheduler_t* _schedulers[X_SIZE][Y_SIZE][NB_PROCS_MAX];
27
28
29///////////////////////////////////////////////
30static void _ctx_kill_task( unsigned int ltid )
31{
32    // get scheduler address
33    static_scheduler_t* psched = (static_scheduler_t*)_get_sched();
34
35    // pretend the task to kill is scheduled (required for sys_handler calls)
36    unsigned int cur_task = psched->current;
37    psched->current = ltid;
38
39    // release private TTY terminal if required
40    if ( psched->context[ltid][CTX_TTY_ID] < NB_TTY_CHANNELS )
41    {
42        _sys_tty_release();
43        psched->context[ltid][CTX_TTY_ID] = -1;
44    }
45
46    // release private TIM channel if required
47    if ( psched->context[ltid][CTX_TIM_ID] < NB_TIM_CHANNELS )
48    {
49        _sys_tim_release();
50        psched->context[ltid][CTX_TIM_ID] = -1;
51    }
52
53    // release private NIC_RX channel if required
54    if ( psched->context[ltid][CTX_NIC_RX_ID] < NB_NIC_CHANNELS )
55    {
56        _sys_nic_release( 1 );
57        psched->context[ltid][CTX_NIC_RX_ID] = -1;
58    }
59
60    // release private NIC_TX channel if required
61    if ( psched->context[ltid][CTX_NIC_TX_ID] < NB_NIC_CHANNELS )
62    {
63        _sys_nic_release( 0 );
64        psched->context[ltid][CTX_NIC_TX_ID] = -1;
65    }
66
67    // release private FBF_CMA channel if required
68    if ( psched->context[ltid][CTX_CMA_FB_ID] < NB_CMA_CHANNELS )
69    {
70        _sys_fbf_cma_release();
71        psched->context[ltid][CTX_CMA_FB_ID] = -1;
72    }
73
74    // restore scheduled task
75    psched->current = cur_task;
76
77    // set NORUN_MASK_TASK bit
78    _atomic_or( &psched->context[ltid][CTX_NORUN_ID], NORUN_MASK_TASK );
79
80} // end _ctx_kill_task()
81
82
83
84////////////////////////////////////////////////////////////////////////
85static unsigned int _load_writable_segments( mapping_vspace_t*  vspace )
86{
87
88#if GIET_DEBUG_SWITCH
89unsigned int gpid       = _get_procid();
90unsigned int cluster_xy = gpid >> P_WIDTH;
91unsigned int p          = gpid & ((1<<P_WIDTH)-1);
92unsigned int x          = cluster_xy >> Y_WIDTH;
93unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
94if ( _get_proctime() > GIET_DEBUG_SWITCH )
95_printf("\n[DEBUG SWITCH] P[%d,%d,%d] _load_writable_segments() : enters for %s\n",
96        x , y , p , vspace->name );
97#endif
98
99    mapping_header_t*  header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
100    mapping_vseg_t*    vseg    = _get_vseg_base(header);
101
102    // buffer to store one cluster
103    char  buf[4096];
104
105    // open the .elf file associated to vspace
106    unsigned int      vseg_id;
107    unsigned int      fd = 0;
108   
109    for (vseg_id = vspace->vseg_offset;
110         vseg_id < (vspace->vseg_offset + vspace->vsegs);
111         vseg_id++) 
112    {
113        if(vseg[vseg_id].type == VSEG_TYPE_ELF) 
114        {   
115            fd = _fat_open( vseg[vseg_id].binpath , O_RDONLY ); 
116
117#if GIET_DEBUG_SWITCH
118if ( _get_proctime() > GIET_DEBUG_SWITCH )
119_printf("\n[DEBUG SWITCH] P[%d,%d,%d] _load_writable_segments() : open %s / fd = %d\n",
120        x , y , p , vseg[vseg_id].binpath , fd );
121#endif
122
123            if ( fd < 0 ) return 1;
124            break;
125        }
126    }
127
128    // load Elf-Header into buffer from .elf file
129    if ( _fat_lseek( fd, 0, SEEK_SET ) < 0 ) return 1;
130    if ( _fat_read( fd, buf, 4096 ) < 0 ) return 1;
131
132#if GIET_DEBUG_SWITCH
133if ( _get_proctime() > GIET_DEBUG_SWITCH )
134_printf("\n[DEBUG SWITCH] P[%d,%d,%d] _load_writable_segments() : load Elf-Header\n",
135        x , y , p );
136#endif
137
138    // get nsegments and Program-Header-Table offset from Elf-Header
139    Elf32_Ehdr*  elf_header_ptr = (Elf32_Ehdr*)buf;
140    unsigned int offset         = elf_header_ptr->e_phoff;
141    unsigned int nsegments      = elf_header_ptr->e_phnum;
142
143    // load Program-Header-Table from .elf file
144    if ( _fat_lseek( fd, offset, SEEK_SET ) < 0 ) return 1;
145    if ( _fat_read( fd, buf, 4096 ) < 0 ) return 1;
146
147#if GIET_DEBUG_SWITCH
148if ( _get_proctime() > GIET_DEBUG_SWITCH )
149_printf("\n[DEBUG SWITCH] P[%d,%d,%d] _load_writable_segments() : "
150        "load Program-Header-Table\n", x , y , p );
151#endif
152
153    // set Program-Header-Table pointer
154    Elf32_Phdr*  elf_pht_ptr = (Elf32_Phdr*)buf;
155   
156    // scan segments to  load all loadable & writable segments
157    unsigned int seg_id;
158    for (seg_id = 0 ; seg_id < nsegments ; seg_id++)
159    {
160        if ( (elf_pht_ptr[seg_id].p_type == PT_LOAD) &&    // loadable
161             (elf_pht_ptr[seg_id].p_flags & PF_W) )        // writable
162        {
163            // Get segment attributes
164            unsigned int seg_vaddr  = elf_pht_ptr[seg_id].p_vaddr;
165            unsigned int seg_offset = elf_pht_ptr[seg_id].p_offset;
166            unsigned int seg_size   = elf_pht_ptr[seg_id].p_filesz;
167
168            // load the segment
169            if ( _fat_lseek( fd, seg_offset, SEEK_SET ) < 0 ) return 1;
170            if ( _fat_read( fd, (void*)seg_vaddr, seg_size ) < 0 ) return 1;
171
172#if GIET_DEBUG_SWITCH
173if ( _get_proctime() > GIET_DEBUG_SWITCH )
174_printf("\n[DEBUG SWITCH] P[%d,%d,%d] _load_writable_segments() : load segment %x\n",
175        x , y , p , seg_vaddr );
176#endif
177
178        }
179    }  // end loop on writable & loadable segments
180
181    // close .elf file
182    _fat_close( fd );
183
184    return 0;
185}  // end load_writable_segments()
186                             
187
188
189///////////////////////////////////////////////
190static void _ctx_exec_task( unsigned int ltid )
191{
192    // get pointers in mapping
193    mapping_header_t * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
194    mapping_task_t   * task    = _get_task_base(header);
195    mapping_vseg_t   * vseg    = _get_vseg_base(header);
196    mapping_vspace_t * vspace  = _get_vspace_base(header);
197
198    // get scheduler address for processor running the calling task
199    static_scheduler_t* psched = (static_scheduler_t*)_get_sched();
200
201    // get global task index, vspace index, and stack vseg index
202    unsigned int task_id       = psched->context[ltid][CTX_GTID_ID];
203    unsigned int vspace_id     = psched->context[ltid][CTX_VSID_ID];
204    unsigned int vseg_id       = task[task_id].stack_vseg_id;
205
206#if GIET_DEBUG_SWITCH
207unsigned int gpid       = _get_procid();
208unsigned int cluster_xy = gpid >> P_WIDTH;
209unsigned int p          = gpid & ((1<<P_WIDTH)-1);
210unsigned int x          = cluster_xy >> Y_WIDTH;
211unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
212if ( _get_proctime() > GIET_DEBUG_SWITCH )
213_printf("\n[DEBUG SWITCH] P[%d,%d,%d] _ctx_exec_task() : enters for %s\n",
214        x , y , p , task[task_id].name );
215#endif
216
217    // reload writable segments
218    if ( _load_writable_segments( &vspace[vspace_id] ) )
219    {
220         _printf("[GIET ERROR] in _ctx_exec_task() for task %s\n",
221                 task[task_id].name );
222         return;
223    } 
224
225    // find initial stack pointer
226    unsigned int sp_value      = vseg[vseg_id].vbase + vseg[vseg_id].length;
227
228    // reset task context: RA / SR / SP / EPC / NORUN
229    psched->context[ltid][CTX_RA_ID]    = (unsigned int)&_ctx_eret;
230    psched->context[ltid][CTX_SR_ID]    = GIET_SR_INIT_VALUE;
231    psched->context[ltid][CTX_SP_ID]    = sp_value;
232    psched->context[ltid][CTX_EPC_ID]   = psched->context[ltid][CTX_ENTRY_ID];
233    psched->context[ltid][CTX_NORUN_ID] = 0;
234}
235
236
237//////////////////////////////////
238void _ctx_display( unsigned int x,
239                   unsigned int y,
240                   unsigned int p,
241                   unsigned int ltid,
242                   char*        string )
243{
244    static_scheduler_t* psched = _schedulers[x][y][p];
245    _printf("\n########## task[%d,%d,%d,%d] context\n"
246            " - CTX_EPC   = %x\n"
247            " - CTX_PTAB  = %x\n"
248            " - CTX_PTPR  = %x\n"
249            " - CTX_VSID  = %x\n"
250            " - CTX_SR    = %x\n"
251            " - CTX_RA    = %x\n"
252            " - CTX_SP    = %x\n"
253            " - CTX_NORUN = %x\n"
254            " - CTX_SIG   = %x\n"
255            "########## %s\n",
256            x , y , p , ltid ,
257            psched->context[ltid][CTX_EPC_ID], 
258            psched->context[ltid][CTX_PTAB_ID], 
259            psched->context[ltid][CTX_PTPR_ID], 
260            psched->context[ltid][CTX_VSID_ID], 
261            psched->context[ltid][CTX_SR_ID], 
262            psched->context[ltid][CTX_RA_ID], 
263            psched->context[ltid][CTX_SP_ID], 
264            psched->context[ltid][CTX_NORUN_ID],
265            psched->context[ltid][CTX_SIG_ID],
266            string );
267}  // _ctx_display()
268
269
270//////////////////
271void _ctx_switch() 
272{
273    unsigned int gpid       = _get_procid();
274    unsigned int cluster_xy = gpid >> P_WIDTH;
275    unsigned int lpid       = gpid & ((1<<P_WIDTH)-1);
276
277    // get scheduler address
278    static_scheduler_t* psched = (static_scheduler_t*)_get_sched();
279
280    // get number of tasks allocated to scheduler
281    unsigned int tasks = psched->tasks;
282
283    // get current task index
284    unsigned int curr_task_id = psched->current;
285
286    // select the next task using a round-robin policy
287    unsigned int next_task_id;
288    unsigned int tid;
289    unsigned int found = 0;
290
291    for (tid = curr_task_id + 1; tid < curr_task_id + 1 + tasks; tid++) 
292    {
293        next_task_id = tid % tasks;
294
295        // this task needs to be killed
296        if ( psched->context[next_task_id][CTX_SIG_ID] & SIG_MASK_KILL )
297        {
298            // acknowledge signal
299            _atomic_and( &psched->context[next_task_id][CTX_SIG_ID], ~SIG_MASK_KILL );
300
301            _ctx_kill_task( next_task_id );
302        }
303
304        // this task needs to be executed
305        if ( psched->context[next_task_id][CTX_SIG_ID] & SIG_MASK_EXEC )
306        {
307            // acknowledge signal
308            _atomic_and( &psched->context[next_task_id][CTX_SIG_ID], ~SIG_MASK_EXEC );
309
310            _ctx_exec_task( next_task_id );
311        }
312
313        // test if the task is runable
314        if ( psched->context[next_task_id][CTX_NORUN_ID] == 0 ) 
315        {
316            found = 1;
317            // TODO: don't break to process all pending signals.
318            break;
319        }
320    }
321
322    // launch "idle" task if no runable task
323    if (found == 0) next_task_id = IDLE_TASK_INDEX;
324
325#if ( GIET_DEBUG_SWITCH & 0x1 )
326unsigned int x = cluster_xy >> Y_WIDTH;
327unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
328if ( _get_proctime() > GIET_DEBUG_SWITCH )
329_printf("\n[DEBUG SWITCH] (%d) -> (%d) on processor[%d,%d,%d] at cycle %d\n",
330        curr_task_id, next_task_id, x, y , lpid, _get_proctime() );
331#endif
332
333    if (curr_task_id != next_task_id)  // actual task switch required
334    {
335        unsigned int* curr_ctx_vaddr = &(psched->context[curr_task_id][0]);
336        unsigned int* next_ctx_vaddr = &(psched->context[next_task_id][0]);
337
338        // reset TICK timer counter.
339        _xcu_timer_reset_cpt( cluster_xy, lpid );
340
341        // set current task index
342        psched->current = next_task_id;
343
344        // makes context switch
345        _task_switch( curr_ctx_vaddr , next_ctx_vaddr );
346    }
347} //end _ctx_switch()
348
349
350/////////////////
351void _idle_task() 
352{
353    unsigned int gpid       = _get_procid();
354    unsigned int cluster_xy = gpid >> P_WIDTH;
355    unsigned int x          = cluster_xy >> Y_WIDTH;
356    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
357    unsigned int p          = gpid & ((1<<P_WIDTH)-1);
358
359    while(1)
360    {
361        // initialize counter
362        unsigned int count = GIET_IDLE_TASK_PERIOD;
363
364        // decounting loop
365        asm volatile(
366                "move   $3,   %0              \n"
367                "_idle_task_loop:             \n"
368                "addi   $3,   $3,   -1        \n"
369                "bnez   $3,   _idle_task_loop \n"
370                "nop                          \n"
371                :
372                : "r"(count)
373                : "$3" ); 
374
375        // warning message
376        _printf("\n[GIET WARNING] Processor[%d,%d,%d] still idle at cycle %d",
377                x , y , p , _get_proctime() );
378    }
379} // end ctx_idle()
380
381
382////////////////
383void _ctx_eret() 
384{
385    asm volatile("eret");
386}
387
388
389// Local Variables:
390// tab-width: 4
391// c-basic-offset: 4
392// c-file-offsets:((innamespace . 0)(inline-open . 0))
393// indent-tabs-mode: nil
394// End:
395// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
396
Note: See TracBrowser for help on using the repository browser.