| [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 |  | 
|---|