[158] | 1 | /////////////////////////////////////////////////////////////////////////////////// |
---|
| 2 | // File : ctx_handler.c |
---|
| 3 | // Date : 01/04/2012 |
---|
| 4 | // Authors : alain greiner & joel porquet |
---|
| 5 | // Copyright (c) UPMC-LIP6 |
---|
| 6 | //////////////////////////////////////////////////////////////////////////////////// |
---|
| 7 | // The ctx_handler.h and ctx_handler.c files are part of the GIET nano-kernel. |
---|
| 8 | // This code is used to support context switch when several tasks are executing |
---|
| 9 | // in time multiplexing on a single processor. |
---|
| 10 | // The tasks must be statically allocated to a processor in the boot phase, and |
---|
| 11 | // there is one private scheduler per processor: NB_CLUSTERS * NB_PROCS |
---|
| 12 | // Each sheduler contains up to NB_TASKS_MAX contexts. |
---|
| 13 | //////////////////////////////////////////////////////////////////////////////////// |
---|
| 14 | // A task context is an array of 64 words = 256 bytes. |
---|
| 15 | // It contains copies of processor registers, when the task is not running, |
---|
| 16 | // and some general informations associated to the task. |
---|
| 17 | // - It contains GPR[i], generally stored in slot (i). $0, *26 & $27 are not saved. |
---|
| 18 | // - It contains HI & LO registers. |
---|
| 19 | // - It contains CP0 registers: EPC, SR, CR. |
---|
| 20 | // - It contains CP2 registers : PTPR and MODE. |
---|
| 21 | // - It contains the TTY index for the terminal allocated to the task. |
---|
| 22 | // ctx[0] <- SR ctx[8] <- $8 ctx[16]<- $16 ctx[24]<- $24 ctx[32]<- EPC |
---|
| 23 | // ctx[1] <- $1 ctx[9] <- $9 ctx[17]<- $17 ctx[25]<- $25 ctx[33]<- CR |
---|
| 24 | // ctx[2] <- $2 ctx[10]<- $10 ctx[18]<- $18 ctx[26]<- LO ctx[34]<- TTY |
---|
| 25 | // ctx[3] <- $3 ctx[11]<- $11 ctx[19]<- $19 ctx[27]<- HI ctx[35]<- PTPR |
---|
| 26 | // ctx[4] <- $4 ctx[12]<- $12 ctx[20]<- $20 ctx[28]<- $28 ctx[36]<- MODE |
---|
[165] | 27 | // ctx[5] <- $5 ctx[13]<- $13 ctx[21]<- $21 ctx[29]<- $29 ctx[37]<- FBDMA |
---|
[158] | 28 | // ctx[6] <- $6 ctx[14]<- $14 ctx[22]<- $22 ctx[30]<- $30 ctx[38]<- reserved |
---|
| 29 | // ctx[7] <- $7 ctx[15]<- $15 ctx[23]<- $23 ctx[31]<- $31 ctx[39]<- reserved |
---|
| 30 | ///////////////////////////////////////////////////////////////////////////////////// |
---|
| 31 | |
---|
| 32 | #include <giet_config.h> |
---|
[160] | 33 | #include <drivers.h> |
---|
| 34 | #include <common.h> |
---|
[158] | 35 | #include <ctx_handler.h> |
---|
[160] | 36 | #include <mapping_info.h> |
---|
[158] | 37 | #include <sys_handler.h> |
---|
| 38 | |
---|
| 39 | extern void _task_switch(unsigned int *, unsigned int *); |
---|
| 40 | |
---|
| 41 | ///////////////////////////////////////////////////////////////////////////////// |
---|
| 42 | // Global variables |
---|
| 43 | ///////////////////////////////////////////////////////////////////////////////// |
---|
| 44 | |
---|
| 45 | static_scheduler_t _scheduler[NB_CLUSTERS * NB_PROCS]; |
---|
| 46 | |
---|
| 47 | ///////////////////////////////////////////////////////////////////////////////// |
---|
| 48 | // _ctx_switch() |
---|
| 49 | // This function performs a context switch between the running task |
---|
| 50 | // and another task, using a round-robin sheduling policy. |
---|
| 51 | // It use the global variable scheduler[] : array indexed by the procid, |
---|
| 52 | // that contains NB_CLUSTERS * NB_PROCS entries. |
---|
| 53 | // The return address contained in $31 is saved in the _current task context |
---|
| 54 | // (in the ctx[31] slot), and the function actually returns to the address |
---|
| 55 | // contained in the ctx[31] slot of the new task context. To perform the |
---|
| 56 | // actual switch, it calls the _task_switch function written in assembly language. |
---|
| 57 | ///////////////////////////////////////////////////////////////////////////////// |
---|
| 58 | void _ctx_switch() |
---|
| 59 | { |
---|
| 60 | unsigned char curr_task_id; |
---|
| 61 | unsigned char next_task_id; |
---|
| 62 | |
---|
| 63 | unsigned int *curr_context; |
---|
| 64 | unsigned int *next_context; |
---|
| 65 | |
---|
[165] | 66 | unsigned int pid = _procid(); |
---|
| 67 | unsigned int time = _proctime(); |
---|
| 68 | unsigned int tasks = _scheduler[pid].tasks; |
---|
[158] | 69 | |
---|
| 70 | // return if only one task */ |
---|
| 71 | if ( tasks <= 1) return; |
---|
[160] | 72 | |
---|
[158] | 73 | // compute the task context base address for the current task |
---|
[165] | 74 | curr_task_id = _scheduler[pid].current; |
---|
| 75 | curr_context = &(_scheduler[pid].context[curr_task_id][0]); |
---|
[160] | 76 | |
---|
[158] | 77 | // select the next task using a round-robin scheduling policy |
---|
| 78 | next_task_id = (curr_task_id + 1) % tasks; |
---|
| 79 | |
---|
| 80 | // compute the task context base address for the next task |
---|
[165] | 81 | next_context = &(_scheduler[pid].context[next_task_id][0]); |
---|
[158] | 82 | |
---|
| 83 | #if GIET_DEBUG_SWITCH |
---|
[165] | 84 | _get_lock( &_tty_put_lock ); |
---|
[164] | 85 | _puts( "\n[GIET] Context switch for processor "); |
---|
[165] | 86 | _putw( pid ); |
---|
[164] | 87 | _puts( " at cycle "); |
---|
| 88 | _putw( time ); |
---|
| 89 | _puts("\n"); |
---|
| 90 | _puts( " - tasks = "); |
---|
| 91 | _putw( tasks ); |
---|
| 92 | _puts("\n"); |
---|
| 93 | _puts( " - curr_task_id = "); |
---|
| 94 | _putw( curr_task_id ); |
---|
| 95 | _puts("\n"); |
---|
| 96 | _puts( " - next_task_id = "); |
---|
| 97 | _putw( next_task_id ); |
---|
| 98 | _puts("\n"); |
---|
[165] | 99 | _release_lock( &_tty_put_lock ); |
---|
[158] | 100 | #endif |
---|
| 101 | |
---|
[165] | 102 | // update the scheduler state, and makes the task switch |
---|
| 103 | _scheduler[pid].current = next_task_id; |
---|
| 104 | _task_switch( curr_context, next_context ); |
---|
| 105 | |
---|
[158] | 106 | } // end _ctx_switch |
---|
| 107 | |
---|