Changeset 189 for soft/giet_vm/sys
- Timestamp:
- Aug 7, 2012, 6:37:49 PM (12 years ago)
- Location:
- soft/giet_vm/sys
- Files:
-
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
soft/giet_vm/sys/common.c
r166 r189 11 11 #include <sys_handler.h> 12 12 #include <common.h> 13 #include <ctx_handler.h> 13 14 #include <drivers.h> 14 15 #include <stdarg.h> 15 16 16 //////////////////////////////////////////////////////////////////////////// 17 // _get_lock() 17 /////////////////////////////////////////////////////////////////////////////////// 18 // Global variables 19 /////////////////////////////////////////////////////////////////////////////////// 20 21 // current context cache TODO 22 23 // SR save (used by _it_mask() / it_restore() 24 unsigned int _status_register_save; 25 26 /////////////////////////////////////////////////////////////////////////////////// 27 // _get_sched() 28 // Access CP0 and returns scheduler physical address. 29 /////////////////////////////////////////////////////////////////////////////////// 30 inline unsigned int _get_sched() 31 { 32 unsigned int ret; 33 asm volatile ( "mfc0 %0, $22" 34 : "=r"(ret) ); 35 return ret; 36 } 37 /////////////////////////////////////////////////////////////////////////////////// 38 // _get_ptpr() 39 // Access CP2 and returns PTPR register. 40 /////////////////////////////////////////////////////////////////////////////////// 41 inline unsigned int _get_ptpr() 42 { 43 unsigned int ret; 44 asm volatile ( "mfc2 %0, $0" 45 : "=r"(ret) ); 46 return ret; 47 } 48 /////////////////////////////////////////////////////////////////////////////////// 49 // _get_epc() 50 // Access CP0 and returns EPC register. 51 /////////////////////////////////////////////////////////////////////////////////// 52 inline unsigned int _get_epc() 53 { 54 unsigned int ret; 55 asm volatile ( "mfc0 %0, $14" 56 : "=r"(ret) ); 57 return ret; 58 } 59 /////////////////////////////////////////////////////////////////////////////////// 60 // _get_bar() 61 // Access CP0 and returns BAR register. 62 /////////////////////////////////////////////////////////////////////////////////// 63 inline unsigned int _get_bvar() 64 { 65 unsigned int ret; 66 asm volatile ( "mfc0 %0, $8" 67 : "=r"(ret) ); 68 return ret; 69 } 70 /////////////////////////////////////////////////////////////////////////////////// 71 // _get_cr() 72 // Access CP0 and returns CR register. 73 /////////////////////////////////////////////////////////////////////////////////// 74 inline unsigned int _get_cause() 75 { 76 unsigned int ret; 77 asm volatile ( "mfc0 %0, $13" 78 : "=r"(ret) ); 79 return ret; 80 } 81 /////////////////////////////////////////////////////////////////////////////////// 82 // _get_sr() 83 // Access CP0 and returns SR register. 84 /////////////////////////////////////////////////////////////////////////////////// 85 inline unsigned int _get_sr() 86 { 87 unsigned int ret; 88 asm volatile ( "mfc0 %0, $12" 89 : "=r"(ret) ); 90 return ret; 91 } 92 /////////////////////////////////////////////////////////////////////////////////// 93 // _it_mask() 94 // Access CP0 and mask IRQs 95 /////////////////////////////////////////////////////////////////////////////////// 96 inline void _it_mask() 97 { 98 unsigned int sr_value; 99 asm volatile( "li $3, 0xFFFFFFFE \n" 100 "mfc0 %0, $12 \n" 101 "and $3, $3, %0 \n" 102 "mtc0 $3, $12 \n" 103 : "=r"(sr_value) : : "$3" ); 104 _status_register_save = sr_value; 105 } 106 /////////////////////////////////////////////////////////////////////////////////// 107 // _it_enable() 108 // Access CP0 and enable IRQs 109 /////////////////////////////////////////////////////////////////////////////////// 110 inline void _it_restore() 111 { 112 unsigned int sr_value = _status_register_save; 113 asm volatile( "mtc0 %0, $12 \n" 114 : : "r"(sr_value) ); 115 } 116 //////////////////////////////////////////////////////////////////////////// 117 // _get_lock() 118 // Takes a lock with an ll/sc atomic access. 119 // A pseudo random delay is introduced before retry in case of miss 120 // (delay average value = 100 cycles) 18 121 //////////////////////////////////////////////////////////////////////////// 19 122 inline void _get_lock( unsigned int* plock ) 20 123 { 21 register unsigned int delay = ( _proctime() & 0xF) << 4;124 register unsigned int delay = ( _proctime() ^ _procid()<<4 ) & 0xFF; 22 125 23 126 asm volatile ( … … 49 152 50 153 //////////////////////////////////////////////////////////////////////////// 51 // _puts()52 // used for system code debug / it uses TTY0154 // _puts() 155 // display a string on TTY0 / used for system code debugand log 53 156 //////////////////////////////////////////////////////////////////////////// 54 157 void _puts(char *buffer) … … 64 167 } 65 168 //////////////////////////////////////////////////////////////////////////// 66 // _putw()67 // used for system code debug / it uses TTY0169 // _putw() 170 // display an int (hexa) on TTY0 / used for system code debug and log 68 171 //////////////////////////////////////////////////////////////////////////// 69 172 void _putw(unsigned int val) … … 85 188 } 86 189 //////////////////////////////////////////////////////////////////////////// 87 // _strncmp() 190 // _putd() 191 // display an int (decimal) on TTY0 / used for system code debug and log 192 //////////////////////////////////////////////////////////////////////////// 193 void _putd(unsigned int val) 194 { 195 static const char DecTab[] = "0123456789"; 196 char buf[11]; 197 unsigned int i; 198 unsigned int first; 199 200 buf[10] = 0; 201 202 for (i = 0; i < 10; i++) 203 { 204 if ((val != 0) || (i == 0)) 205 { 206 buf[9-i] = DecTab[val % 10]; 207 first = 9-i; 208 } 209 else 210 { 211 break; 212 } 213 val /= 10; 214 } 215 _puts( &buf[first] ); 216 } 217 //////////////////////////////////////////////////////////////////////////// 218 // _strncmp() 88 219 // compare two strings s1 & s2 (no more than n characters) 89 220 //////////////////////////////////////////////////////////////////////////// … … 101 232 } 102 233 //////////////////////////////////////////////////////////////////////////// 103 // _dcache_buf_invalidate()234 // _dcache_buf_invalidate() 104 235 // Invalidate all data cache lines corresponding to a memory 105 236 // buffer (identified by an address and a size). … … 126 257 } 127 258 } 128 /////////////////////////////////////////////////////////////////////////////////// 129 // _itoa_dec() 130 // Convert a 32-bit unsigned integer to a string of ten decimal characters. 131 /////////////////////////////////////////////////////////////////////////////////// 132 void _itoa_dec(unsigned int val, char *buf) 133 { 134 const static char dectab[] = "0123456789"; 135 unsigned int i; 136 137 for (i = 0; i < 10; i++) 138 { 139 if ((val != 0) || (i == 0)) 140 buf[9-i] = dectab[val % 10]; 141 else 142 buf[9-i] = 0x20; 143 val /= 10; 144 } 145 } 146 /////////////////////////////////////////////////////////////////////////////////// 147 // _itoa_hex() 148 // Convert a 32-bit unsigned integer to a string of eight hexadecimal characters. 149 /////////////////////////////////////////////////////////////////////////////////// 150 void _itoa_hex(unsigned int val, char *buf) 151 { 152 const static char hexatab[] = "0123456789ABCD"; 153 unsigned int i; 154 155 for (i = 0; i < 8; i++) 156 { 157 buf[7-i] = hexatab[val % 16]; 158 val /= 16; 159 } 160 } 161 /////////////////////////////////////////////////////////////////////////////////// 162 // _get_ptpr() 163 // Access CP2 and returns PTPR register. 164 /////////////////////////////////////////////////////////////////////////////////// 165 inline unsigned int _get_ptpr() 166 { 167 unsigned int ret; 168 asm volatile("mfc2 %0, $0" : "=r"(ret)); 169 return ret; 170 } 171 /////////////////////////////////////////////////////////////////////////////////// 172 // _get_epc() 173 // Access CP0 and returns EPC register. 174 /////////////////////////////////////////////////////////////////////////////////// 175 inline unsigned int _get_epc() 176 { 177 unsigned int ret; 178 asm volatile("mfc0 %0, $14" : "=r"(ret)); 179 return ret; 180 } 181 /////////////////////////////////////////////////////////////////////////////////// 182 // _get_bar() 183 // Access CP0 and returns BAR register. 184 /////////////////////////////////////////////////////////////////////////////////// 185 inline unsigned int _get_bar() 186 { 187 unsigned int ret; 188 asm volatile("mfc0 %0, $8" : "=r"(ret)); 189 return ret; 190 } 191 /////////////////////////////////////////////////////////////////////////////////// 192 // _get_cr() 193 // Access CP0 and returns CR register. 194 /////////////////////////////////////////////////////////////////////////////////// 195 inline unsigned int _get_cause() 196 { 197 unsigned int ret; 198 asm volatile("mfc0 %0, $13" : "=r"(ret)); 199 return ret; 200 } 201 202 /////////////////////////////////////////////////////////////////////////////////// 203 // _it_mask() 204 // Access CP0 and mask IRQs 205 /////////////////////////////////////////////////////////////////////////////////// 206 inline void _it_mask() 207 { 208 asm volatile( 209 "lui $27, 0xFFFF \n" 210 "ori $27, $27, 0xFFFE \n" 211 "mfc0 $26, $12 \n" 212 "and $26, $26, $27 \n" 213 "mtc0 $26, $12 \n" 214 ::: "$26", "$27" 215 ); 216 } 217 /////////////////////////////////////////////////////////////////////////////////// 218 // _it_enable() 219 // Access CP0 and enable IRQs 220 /////////////////////////////////////////////////////////////////////////////////// 221 inline void _it_enable() 222 { 223 asm volatile( 224 "mfc0 $26, $12 \n" 225 "ori $26, $26, 1 \n" 226 "mtc0 $26, $12 \n" 227 ::: "$26" 228 ); 259 //////////////////////////////////////////////////////////////////////////// 260 // _physical_read_access() 261 // This function makes a physical read access to a 32 bits word in memory, 262 // after a temporary DTLB desactivation. 263 //////////////////////////////////////////////////////////////////////////// 264 unsigned int _physical_read_access(unsigned int* paddr) 265 { 266 unsigned int value; 267 268 asm volatile( "li $3, 0xFFFFFFFE \n" 269 "mfc0 $2, $12 \n" /* $2 <= SR */ 270 "and $3, $3, $2 \n" 271 "mtc0 $3, $12 \n" /* interrupt masked */ 272 "li $3, 0xB \n" 273 "mtc2 $3, $1 \n" /* DTLB off */ 274 275 "lw %0, 0(%1) \n" /* entry <= *pslot */ 276 277 "li $3, 0xF \n" 278 "mtc2 $3, $1 \n" /* DTLB on */ 279 "mtc0 $2, $12 \n" /* restore SR */ 280 : "=r"(value) 281 : "r"(paddr) 282 : "$2", "$3" ); 283 return value; 284 } 285 //////////////////////////////////////////////////////////////////////////// 286 // _physical_write_access() 287 // This function makes a physical write access to a 32 bits word in memory, 288 // after a temporary DTLB desactivation. 289 //////////////////////////////////////////////////////////////////////////// 290 void _physical_write_access(unsigned int* paddr, unsigned int value) 291 { 292 asm volatile( "li $3, 0xFFFFFFFE \n" 293 "mfc0 $2, $12 \n" /* $26 <= SR */ 294 "and $3, $3, $2 \n" 295 "mtc0 $3, $12 \n" /* interrupt masked */ 296 "li $3, 0xB \n" 297 "mtc2 $3, $1 \n" /* DTLB off */ 298 299 "sw %0, 0(%1) \n" /* entry <= *pslot */ 300 301 "li $3, 0xF \n" 302 "mtc2 $3, $1 \n" /* DTLB on */ 303 "mtc0 $2, $12 \n" /* restore SR */ 304 : 305 : "r"(value), "r"(paddr) 306 : "$2", "$3" ); 307 } 308 //////////////////////////////////////////////////////////////////////////// 309 // _get_tasks_number() 310 // This function returns the number of tasks allocated to processor. 311 //////////////////////////////////////////////////////////////////////////// 312 unsigned int _get_tasks_number() 313 { 314 static_scheduler_t* psched = (static_scheduler_t*)_get_sched(); 315 return _physical_read_access( &(psched->tasks) ); 316 } 317 //////////////////////////////////////////////////////////////////////////// 318 // _get_current_task_id() 319 // This function returns the index of the currently running task. 320 //////////////////////////////////////////////////////////////////////////// 321 unsigned int _get_current_task_id() 322 { 323 static_scheduler_t* psched = (static_scheduler_t*)_get_sched(); 324 return _physical_read_access( &(psched->current) ); 325 } 326 /////////////////////////////////////////////////////////////////////////////// 327 // _get_current_context_slot() 328 // This function returns the global TTY index for the currently running task. 329 /////////////////////////////////////////////////////////////////////////////// 330 unsigned int _get_current_context_slot(unsigned int slot_id) 331 { 332 static_scheduler_t* psched = (static_scheduler_t*)_get_sched(); 333 unsigned int current = _physical_read_access( &(psched->current) ); 334 return _physical_read_access( &(psched->context[current][slot_id]) ); 335 } 336 /////////////////////////////////////////////i////////////////////////////////// 337 // _get_interrupt_vector_entry() 338 // This function returns the interrupt_vector entry defined by argument index. 339 //////////////////////////////////////////////////////////////////////////////// 340 unsigned int _get_interrupt_vector_entry( unsigned int index ) 341 { 342 static_scheduler_t* psched = (static_scheduler_t*)_get_sched(); 343 return _physical_read_access( &(psched->interrupt_vector[index]) ); 344 } 345 //////////////////////////////////////////////////////////////////////////// 346 // _set_current_task_id() 347 // This function returns the index of the currently running task. 348 //////////////////////////////////////////////////////////////////////////// 349 void _set_current_task_id( unsigned int value ) 350 { 351 static_scheduler_t* psched = (static_scheduler_t*)_get_sched(); 352 _physical_write_access( &(psched->current), value ); 229 353 } 230 354 … … 283 407 } 284 408 285 -
soft/giet_vm/sys/common.h
r166 r189 32 32 /////////////////////////////////////////////////////////////////////////////////// 33 33 34 void _puts(char *string); 35 void _putw(unsigned int val); 34 void _puts(char *string); 35 void _putw(unsigned int val); 36 void _putd(unsigned int val); 36 37 37 unsigned int 38 unsigned int _strncmp(const char* s1, const char* s2, unsigned int n); 38 39 39 void 40 void _dcache_buf_invalidate(const void *buffer, unsigned int size); 40 41 41 void 42 void 42 void _itoa_dec(unsigned int val, char* buf); 43 void _itoa_hex(unsigned int val, char* buf); 43 44 44 unsigned int _get_epc(); 45 unsigned int _get_ptpr(); 46 unsigned int _get_bar(); 47 unsigned int _get_cr(); 45 void _dtlb_off(void); 46 void _dtlb_on(void); 48 47 49 void _get_lock(unsigned int* lock); 50 void _release_lock(unsigned int* lock); 48 void _it_mask(void); 49 void _it_enable(void); 50 51 unsigned int _get_epc(void); 52 unsigned int _get_ptpr(void); 53 unsigned int _get_bvar(void); 54 unsigned int _get_cr(void); 55 unsigned int _get_sched(void); 56 57 unsigned int _get_current_context_slot(unsigned int index); 58 unsigned int _get_interrupt_vector_entry(unsigned int index); 59 unsigned int _get_current_task_id(void); 60 unsigned int _get_tasks_number(void); 61 62 void _set_current_task_id( unsigned int value); 63 64 void _get_lock(unsigned int* lock); 65 void _release_lock(unsigned int* lock); 51 66 52 67 mapping_cluster_t* _get_cluster_base( mapping_header_t* header ); -
soft/giet_vm/sys/ctx_handler.c
r167 r189 1 /////////////////////////////////////////////////////////////////////////////////// 1 /////////////////////////////////////////////////////////////////////////////////////// 2 2 // File : ctx_handler.c 3 3 // Date : 01/04/2012 4 4 // Authors : alain greiner & joel porquet 5 5 // Copyright (c) UPMC-LIP6 6 //////////////////////////////////////////////////////////////////////////////////// 7 // The ctx_handler.h and ctx_handler.c files are part of the GIET nano-kernel.6 /////////////////////////////////////////////////////////////////////////////////////// 7 // The ctx_handler.h and ctx_handler.c files are part of the GIET-VM nano-kernel. 8 8 // This code is used to support context switch when several tasks are executing 9 9 // in time multiplexing on a single processor. 10 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 // 18 // - It contains GPR[i], generally stored in slot (i). $0, *26 & $27 are not saved. 19 // - It contains HI & LO registers. 20 // - It contains CP0 registers: EPC, SR, CR. 21 // - It contains CP2 registers : PTPR and MODE. 22 // - It contains the TTY global index, the FBDMA global index, the virtual base 23 // address of the page table (PTAB), and the task global index (TASK). 24 // 25 // ctx[0]<- SR|ctx[8] <- $8 |ctx[16]<- $16|ctx[24]<- $24|ctx[32]<- EPC |ctx[40]<- TTY 26 // ctx[1]<- $1|ctx[9] <- $9 |ctx[17]<- $17|ctx[25]<- $25|ctx[33]<- CR |ctx[41]<- FBDMA 27 // ctx[2]<- $2|ctx[10]<- $10|ctx[18]<- $18|ctx[26]<- LO |ctx[34]<- *** |ctx[42]<- PTAB 28 // ctx[3]<- $3|ctx[11]<- $11|ctx[19]<- $19|ctx[27]<- HI |ctx[35]<- PTPR|ctx[43]<- TASK 29 // ctx[4]<- $4|ctx[12]<- $12|ctx[20]<- $20|ctx[28]<- $28|ctx[36]<- MODE|ctx[44]<- *** 30 // ctx[5]<- $5|ctx[13]<- $13|ctx[21]<- $21|ctx[29]<- SP |ctx[37]<- *** |ctx[45]<- *** 31 // ctx[6]<- $6|ctx[14]<- $14|ctx[22]<- $22|ctx[30]<- $30|ctx[38]<- *** |ctx[46]<- *** 32 // ctx[7]<- $7|ctx[15]<- $15|ctx[23]<- $23|ctx[31]<- RA |ctx[39]<- *** |ctx[47]<- *** 33 ///////////////////////////////////////////////////////////////////////////////////// 11 // there is one private scheduler per processor. 12 // Each sheduler contains up to 15 task contexts. 13 /////////////////////////////////////////////////////////////////////////////////////// 34 14 35 15 #include <giet_config.h> … … 40 20 #include <sys_handler.h> 41 21 42 extern void _task_switch(unsigned int *, unsigned int *); 43 44 ///////////////////////////////////////////////////////////////////////////////// 45 // Global variables : array of schedulers (one scheduler per processor) 46 ///////////////////////////////////////////////////////////////////////////////// 47 48 __attribute__((section (".kdata"))) static_scheduler_t _scheduler[NB_CLUSTERS * NB_PROCS]; 22 /////////////////////////////////////////////////////////////////////////////////////// 23 // A task context is an array of 64 words = 256 bytes. 24 // It contains copies of processor registers (when the task is preempted), 25 // and some general informations associated to the task. 26 // 27 // - It contains GPR[i], generally stored in slot (i). $0, *26 & $27 are not saved. 28 // - It contains HI & LO registers. 29 // - It contains CP0 registers: EPC, SR, CR, SCHED 30 // - It contains CP2 registers : PTPR and MODE. 31 // - It contains TTY global index, the FBDMA global index, the virtual base 32 // address of the page table (PTAB), and the task global index (TASK). 33 // 34 // ctx[0]<- SR|ctx[8] <- $8 |ctx[16]<- $16|ctx[24]<- $24|ctx[32]<- EPC |ctx[40]<- TTY 35 // ctx[1]<- $1|ctx[9] <- $9 |ctx[17]<- $17|ctx[25]<- $25|ctx[33]<- CR |ctx[41]<- FBDMA 36 // ctx[2]<- $2|ctx[10]<- $10|ctx[18]<- $18|ctx[26]<- LO |ctx[34]<- *** |ctx[42]<- PTAB 37 // ctx[3]<- $3|ctx[11]<- $11|ctx[19]<- $19|ctx[27]<- HI |ctx[35]<- PTPR|ctx[43]<- TASK 38 // ctx[4]<- $4|ctx[12]<- $12|ctx[20]<- $20|ctx[28]<- $28|ctx[36]<- MODE|ctx[44]<- SCHED 39 // ctx[5]<- $5|ctx[13]<- $13|ctx[21]<- $21|ctx[29]<- SP |ctx[37]<- *** |ctx[45]<- TIMER 40 // ctx[6]<- $6|ctx[14]<- $14|ctx[22]<- $22|ctx[30]<- $30|ctx[38]<- *** |ctx[46]<- *** 41 // ctx[7]<- $7|ctx[15]<- $15|ctx[23]<- $23|ctx[31]<- RA |ctx[39]<- *** |ctx[47]<- *** 42 //////////////////////////////////////////////////////////////////////////////////////// 43 44 extern void _task_switch(unsigned int*, unsigned int*); 49 45 50 46 ///////////////////////////////////////////////////////////////////////////////// … … 52 48 // This function performs a context switch between the running task 53 49 // and another task, using a round-robin sheduling policy. 54 // It use the global variable scheduler[] : array indexed by the procid, 55 // that contains NB_CLUSTERS * NB_PROCS entries. 56 // The return address contained in $31 is saved in the _current task context 50 // 51 // It desactivate the DTLB, to directly access the scheduler using 52 // the physical address stored in register CP0_SCHED. 53 // All the context switch procedure is executed with interrupts masked. 54 // 55 // The return address contained in $31 is saved in the current task context 57 56 // (in the ctx[31] slot), and the function actually returns to the address 58 // contained in the ctx[31] slot of the new task context. To perform the 59 // actual switch, it calls the _task_switch function written in assembly language. 57 // contained in the ctx[31] slot of the next task context. 60 58 ///////////////////////////////////////////////////////////////////////////////// 61 59 void _ctx_switch() 62 60 { 63 unsigned char curr_task_id; 64 unsigned char next_task_id; 65 66 unsigned int *curr_context; 67 unsigned int *next_context; 68 69 unsigned int proc_id = _procid(); 70 unsigned int tasks = _scheduler[proc_id].tasks; 71 72 // return if only one task */ 73 if ( tasks <= 1) return; 74 75 // compute the task context base address for the current task 76 curr_task_id = _scheduler[proc_id].current; 77 curr_context = &(_scheduler[proc_id].context[curr_task_id][0]); 61 unsigned int tasks; 62 unsigned int curr_task_id; 63 unsigned int next_task_id; 64 unsigned int *curr_ctx_paddr; 65 unsigned int *next_ctx_paddr; 66 67 // get scheduler physical address 68 static_scheduler_t* psched = (static_scheduler_t*)_get_sched(); 69 70 // get number of tasks allocated to scheduler 71 tasks = _get_tasks_number(); 72 73 // no switch if only one task 74 if ( tasks > 1) 75 { 76 // compute the context physical address for the current task 77 curr_task_id = _get_current_task_id(); 78 curr_ctx_paddr = &(psched->context[curr_task_id][0]); 78 79 79 // select the next task using a round-robin schedulingpolicy80 next_task_id = (curr_task_id + 1) % tasks;80 // select the next task using a round-robin policy 81 next_task_id = (curr_task_id + 1) % tasks; 81 82 82 // compute the task context base address for the next task 83 next_context = &(_scheduler[proc_id].context[next_task_id][0]); 83 // compute the context physical address for the next task 84 next_ctx_paddr = &(psched->context[next_task_id][0]); 85 86 // update the scheduler state 87 _set_current_task_id( next_task_id ); 84 88 85 89 #if GIET_DEBUG_SWITCH 86 90 _get_lock( &_tty_put_lock ); 87 91 _puts( "\n[GIET] Context switch for processor "); 88 _putw( proc_id);92 _putw( _procid() ); 89 93 _puts( " at cycle "); 90 94 _putw( _proctime() ); … … 102 106 #endif 103 107 104 // update the scheduler state, and makes the task switch 105 _scheduler[proc_id].current = next_task_id; 106 _task_switch( curr_context, next_context ); 107 108 // makes the task switch 109 _task_switch( curr_ctx_paddr, next_ctx_paddr ); 110 111 /* 112 asm volatile( "ori $27, $0, 0xB \n" 113 "mtc2 $27, $1 \n" // desactivate DTLB 114 115 "add $27, %0, $0 \n" // $27 <= &curr_ctx 116 117 "mfc0 $26, $12 \n" // $26 <= SR 118 "sw $26, 0*4($27) \n" // ctx[0] <= SR 119 ".set noat \n" 120 "sw $1, 1*4($27) \n" // ctx[1] <= $1 121 ".set at \n" 122 "sw $2, 2*4($27) \n" // ctx[2] <= $2 123 "sw $3, 3*4($27) \n" // ctx[3] <= $3 124 "sw $4, 4*4($27) \n" // ctx[4] <= $4 125 "sw $5, 5*4($27) \n" // ctx[5] <= $5 126 "sw $6, 6*4($27) \n" // ctx[6] <= $6 127 "sw $7, 7*4($27) \n" // ctx[7] <= $7 128 "sw $8, 8*4($27) \n" // ctx[8] <= $8 129 "sw $9, 9*4($27) \n" // ctx[9] <= $9 130 "sw $10, 10*4($27) \n" // ctx[10] <= $10 131 "sw $11, 11*4($27) \n" // ctx[11] <= $11 132 "sw $12, 12*4($27) \n" // ctx[12] <= $12 133 "sw $13, 13*4($27) \n" // ctx[13] <= $13 134 "sw $14, 14*4($27) \n" // ctx[14] <= $14 135 "sw $15, 15*4($27) \n" // ctx[15] <= $15 136 "sw $16, 16*4($27) \n" // ctx[16] <= $16 137 "sw $17, 17*4($27) \n" // ctx[17] <= $17 138 "sw $18, 18*4($27) \n" // ctx[18] <= $18 139 "sw $19, 19*4($27) \n" // ctx[19] <= $19 140 "sw $20, 20*4($27) \n" // ctx[20] <= $20 141 "sw $21, 21*4($27) \n" // ctx[21] <= $21 142 "sw $22, 22*4($27) \n" // ctx[22] <= $22 143 "sw $23, 23*4($27) \n" // ctx[23] <= $23 144 "sw $24, 24*4($27) \n" // ctx[24] <= $24 145 "sw $25, 25*4($27) \n" // ctx[25] <= $25 146 "mflo $26 \n" 147 "sw $26, 26*4($27) \n" // ctx[26] <= LO 148 "mfhi $26 \n" 149 "sw $26, 27*4($27) \n" // ctx[27] <= H1 150 "sw $28, 28*4($27) \n" // ctx[28] <= $28 151 "sw $29, 29*4($27) \n" // ctx[29] <= $29 152 "sw $30, 30*4($27) \n" // ctx[30] <= $30 153 "sw $31, 31*4($27) \n" // ctx[31] <= $31 154 "mfc0 $26, $14 \n" 155 "sw $26, 32*4($27) \n" // ctx[32] <= EPC 156 "mfc0 $26, $13 \n" 157 "sw $26, 33*4($27) \n" // ctx[33] <= CR 158 "mfc2 $26, $0 \n" 159 "sw $26, 35*4($27) \n" // ctx[35] <= PTPR 160 161 "add $27, %1, $0 \n" // $27<= &next_ctx 162 163 "lw $26, 35*4($27) \n" 164 "mtc2 $26, $0 \n" // restore PTPR 165 "lw $26, 0*4($27) \n" 166 "mtc0 $26, $12 \n" // restore SR 167 ".set noat \n" 168 "lw $1, 1*4($27) \n" // restore $1 169 ".set at \n" 170 "lw $2, 2*4($27) \n" // restore $2 171 "lw $3, 3*4($27) \n" // restore $3 172 "lw $4, 4*4($27) \n" // restore $4 173 "lw $5, 5*4($27) \n" // restore $5 174 "lw $6, 6*4($27) \n" // restore $6 175 "lw $7, 7*4($27) \n" // restore $7 176 "lw $8, 8*4($27) \n" // restore $8 177 "lw $9, 9*4($27) \n" // restore $9 178 "lw $10, 10*4($27) \n" // restore $10 179 "lw $11, 11*4($27) \n" // restore $11 180 "lw $12, 12*4($27) \n" // restore $12 181 "lw $13, 13*4($27) \n" // restore $13 182 "lw $14, 14*4($27) \n" // restore $14 183 "lw $15, 15*4($27) \n" // restore $15 184 "lw $16, 16*4($27) \n" // restore $16 185 "lw $17, 17*4($27) \n" // restore $17 186 "lw $18, 18*4($27) \n" // restore $18 187 "lw $19, 19*4($27) \n" // restore $19 188 "lw $20, 20*4($27) \n" // restore $20 189 "lw $21, 21*4($27) \n" // restore $21 190 "lw $22, 22*4($27) \n" // restore $22 191 "lw $23, 23*4($27) \n" // restore $23 192 "lw $24, 24*4($27) \n" // restore $24 193 "lw $25, 25*4($27) \n" // restore $25 194 "lw $26, 26*4($27) \n" 195 "mtlo $26 \n" // restore LO 196 "lw $26, 27*4($27) \n" 197 "mthi $26 \n" // restore HI 198 "lw $28, 28*4($27) \n" // restore $28 199 "lw $29, 29*4($27) \n" // restore $29 200 "lw $30, 30*4($27) \n" // restore $30 201 "lw $31, 31*4($27) \n" // restore $31 202 "lw $26, 32*4($27) \n" 203 "mtc0 $26, $14 \n" // restore EPC 204 "lw $26, 33*4($27) \n" 205 "mtc0 $26, $13 \n" // restore CR 206 207 "ori $27, $0, 0xF \n" 208 "mtc2 $27, $1 \n" // activate DTLB 209 : 210 : "r"(curr_ctx_paddr), "r"(next_ctx_paddr) 211 : "$1" , "$4" ,"$5" ,"$6" ,"$7" ,"$8" ,"$9" ,"$10", 212 "$11","$12","$13","$14","$15","$16","$17","$18","$19","$20", 213 "$21","$22","$23","$24","$25","$26","$27", "$29", 214 "$31" ); 215 */ 216 } 108 217 } // end _ctx_switch 109 218 -
soft/giet_vm/sys/ctx_handler.h
r167 r189 10 10 typedef struct static_scheduler_s 11 11 { 12 unsigned int context[GIET_NB_TASKS_MAX][64]; // task contexts 13 unsigned int tasks; // actual number of tasks 14 unsigned int current; // current task index 12 unsigned int context[15][64]; // at most 15 task contexts 13 unsigned int tasks; // actual number of tasks 14 unsigned int current; // current task index 15 unsigned int interrupt_vector[32]; // interrupt vector 15 16 } static_scheduler_t; 16 17 … … 32 33 #define CTX_PTAB_ID 42 33 34 #define CTX_TASK_ID 43 34 35 #define CTX_SCHED_ID 44 36 #define CTX_TIMER_ID 45 35 37 36 38 ////////////////////////////////////////////////////////////////////////////////// -
soft/giet_vm/sys/drivers.c
r169 r189 5 5 // Copyright (c) UPMC-LIP6 6 6 /////////////////////////////////////////////////////////////////////////////////// 7 // The drivers.c and drivers.h files are part ot the GIET nano kernel.7 // The drivers.c and drivers.h files are part ot the GIET-VM nano kernel. 8 8 // They contains the drivers for the peripherals available in the SoCLib library: 9 9 // - vci_multi_tty … … 11 11 // - vci_multi_dma 12 12 // - vci_multi_icu 13 // - vci_xicu 13 14 // - vci_gcd 14 15 // - vci_frame_buffer … … 16 17 // 17 18 // The following global parameters must be defined in the giet_config.h file: 18 // - NB_CLUSTERS : number of clusters 19 // - NB_PROCS : number of PROCS per cluster 20 // - NB_TIMERS : number of TIMERS per cluster 21 // - NB_DMAS : number of DMA channels 22 // - NB_TTYS : number of TTY terminals 23 // - NB_TIMERS : number of TIMERS per cluster 24 // - CLUSTER_SPAN : address increment between clusters 19 // - NB_CLUSTERS 20 // - NB_PROCS_MAX 21 // - NB_TIMERS_MAX 22 // - NB_DMAS_MAX 23 // - NB_TTYS 25 24 // 26 25 // The following base addresses must be defined in the sys.ld file: … … 43 42 #include <ctx_handler.h> 44 43 45 #if !defined(NB_PROCS)46 # error: You must define NB_PROCS in 'giet_config.h' file!47 #endif48 44 #if !defined(NB_CLUSTERS) 49 # error: You must define NB_CLUSTERS in 'giet_config.h' file! 50 #endif 45 # error: You must define NB_CLUSTERS in 'giet_config.h' file 46 #endif 47 48 #if !defined(NB_PROCS_MAX) 49 # error: You must define NB_PROCS_MAX in 'giet_config.h' file 50 #endif 51 52 #if (NB_PROCS_MAX > 8) 53 # error: NB_PROCS_MAX cannot be larger than 8! 54 #endif 55 51 56 #if !defined(CLUSTER_SPAN) 52 # error: You must define CLUSTER_SPAN in 'giet_config.h' file! 53 #endif 57 # error: You must define CLUSTER_SPAN in 'giet_config.h' file 58 #endif 59 54 60 #if !defined(NB_TTYS) 55 # error: You must define NB_TTYS in 'giet_config.h' file! 56 #endif 57 #if !defined(NB_DMAS) 58 # error: You must define NB_DMAS in 'giet_config.h' file! 59 #endif 60 #if !defined(NB_TIMERS) 61 # error: You must define NB_TIMERS in 'giet_config.h' file! 61 # error: You must define NB_TTYS in 'giet_config.h' file 62 62 #endif 63 63 … … 66 66 #endif 67 67 68 #if (NB_TIMERS < NB_PROCS) 69 # error: NB_TIMERS must be larger or equal to NB_PROCS! 70 #endif 71 72 #if (NB_PROCS > 8) 73 # error: NB_PROCS cannot be larger than 8! 74 #endif 75 76 #if (NB_DMAS < 1) 77 # error: NB_DMAS cannot be 0! 78 #endif 79 80 81 ///////////////////////////////////////////////////////////////////////////// 82 // Global (uncachable) variables 83 ///////////////////////////////////////////////////////////////////////////// 68 #if !defined(NB_DMAS_MAX) 69 # error: You must define NB_DMAS_MAX in 'giet_config.h' file 70 #endif 71 72 #if (NB_DMAS_MAX < 1) 73 # error: NB_DMAS_MAX cannot be 0! 74 #endif 75 76 #if !defined(NB_TIMERS_MAX) 77 # error: You must define NB_TIMERS_MAX in 'giet_config.h' file 78 #endif 79 80 #if ( (NB_TIMERS_MAX + NB_PROCS_MAX) > 32 ) 81 # error: NB_TIMERS_MAX + NB_PROCS_MAX cannot be larger than 32 82 #endif 83 84 #if !defined(NB_IOCS) 85 # error: You must define NB_IOCS in 'giet_config.h' file 86 #endif 87 88 #if ( NB_IOCS > 1 ) 89 # error: NB_IOCS cannot be larger than 1 90 #endif 91 84 92 85 93 #define in_unckdata __attribute__((section (".unckdata"))) 86 94 87 // IOC variables 88 in_unckdata volatile unsigned char _ioc_status = 0; 89 in_unckdata volatile unsigned char _ioc_done = 0; 90 in_unckdata unsigned int _ioc_lock = 0; 91 in_unckdata unsigned int _ioc_iommu_ix1 = 0; 92 in_unckdata unsigned int _ioc_iommu_npages; 93 94 // DMA variables 95 in_unckdata volatile unsigned int _dma_status[NB_DMAS]; 96 in_unckdata volatile unsigned char _dma_busy[NB_DMAS] = { [0 ... NB_DMAS-1] = 0 }; 97 in_unckdata volatile unsigned char _dma_iommu_ix1 = 1; 98 in_unckdata volatile unsigned char _dma_iommu_npages[NB_DMAS]; 95 96 ////////////////////////////////////////////////////////////////////////////// 97 // VciMultiTimer driver 98 ////////////////////////////////////////////////////////////////////////////// 99 // There is one multi_timer (or xicu) component per cluster. 100 // The global index is cluster_id*(NB_PROCS_MAX+NB_TIMERS_MAX) + local_id 101 // There is two types of timers: 102 // - "system" timers : one per processor, used for context switch. 103 // local_id in [0, NB_PROCS_MAX-1], 104 // - "user" timers : requested by the task in the mapping_info data structure. 105 // local_id in [NB_PROC_MAX, NB_PROCS_MAX+NB_TIMERS_MAX-1], 106 // For each user timer, the tty_id is stored in the context of the task 107 // and must be explicitely defined in the boot code. 108 // These timers can be implemented in a vci_multi_timer component 109 // or in a vci_xicu component (depending on the GIET_USE_XICU parameter). 110 ////////////////////////////////////////////////////////////////////////////// 111 112 // User Timer signaling variables 113 114 #if (NB_TIMERS_MAX > 0) 115 in_unckdata volatile unsigned char _user_timer_event[NB_CLUSTERS*NB_TIMERS_MAX] 116 = { [0 ... ((NB_CLUSTERS*NB_TIMERS_MAX)-1)] = 0 }; 117 #endif 118 119 ////////////////////////////////////////////////////////////////////////////// 120 // _timer_access() 121 // This function is the only way to access a timer device. 122 // It can be a multi-timer component or an xicu component. 123 // It can be used by the kernel to initialise a "system" timer, 124 // or by a task (through a system call) to configure an "user" timer. 125 // Returns 0 if success, > 0 if error. 126 ////////////////////////////////////////////////////////////////////////////// 127 unsigned int _timer_access( unsigned int read, 128 unsigned int cluster_id, 129 unsigned int local_id, 130 unsigned int register_id, 131 unsigned int* buffer ) 132 { 133 // parameters checking 134 if ( register_id >= TIMER_SPAN) return 1; 135 if ( cluster_id >= NB_CLUSTERS) return 1; 136 if ( local_id >= NB_TIMERS_MAX + NB_PROCS_MAX ) return 1; 137 138 #if GIET_USE_XICU 139 140 unsigned int* timer_address = //TODO 141 142 #else 143 144 unsigned int* timer_address = (unsigned int*)&seg_timer_base + 145 (cluster_id * CLUSTER_SPAN) + 146 (local_id * TIMER_SPAN); 147 #endif 148 149 if (read) *buffer = timer_address[register_id]; // read word 150 else timer_address[register_id] = *buffer; // write word 151 return 0; 152 } 153 ////////////////////////////////////////////////////////////////////////////// 154 // _timer_write() 155 // This function implements a write access to a "user" timer register. 156 // It gets the cluster_id and local_id from the global index stored in 157 // the task context and use the timer_access() function to make the write. 158 // Returns 0 if success, > 0 if error. 159 ////////////////////////////////////////////////////////////////////////////// 160 unsigned int _timer_write( unsigned int register_id, 161 unsigned int value ) 162 { 163 unsigned int buffer = value; 164 unsigned int timer_id = _get_current_context_slot(CTX_TIMER_ID); 165 unsigned int cluster_id = timer_id / (NB_PROCS_MAX + NB_TIMERS_MAX); 166 unsigned int local_id = timer_id % (NB_PROCS_MAX + NB_TIMERS_MAX); 167 168 // checking user timer 169 if ( local_id < NB_PROCS_MAX ) 170 { 171 return 2; 172 } 173 else 174 { 175 return _timer_access ( 0, // write access 176 cluster_id, 177 local_id, 178 register_id, 179 &buffer ); 180 } 181 } 182 ////////////////////////////////////////////////////////////////////////////// 183 // _timer_read() 184 // This function implements a read access to a "user" timer register. 185 // It gets the cluster_id and local_id from the global index stored in 186 // the task context and use the timer_access() function to make the read. 187 // Returns 0 if success, > 0 if error. 188 ////////////////////////////////////////////////////////////////////////////// 189 unsigned int _timer_read( unsigned int register_id, 190 unsigned int* buffer ) 191 { 192 unsigned int timer_id = _get_current_context_slot(CTX_TIMER_ID); 193 unsigned int cluster_id = timer_id / (NB_PROCS_MAX + NB_TIMERS_MAX); 194 unsigned int local_id = timer_id % (NB_PROCS_MAX + NB_TIMERS_MAX); 195 196 // checking user timer 197 if ( local_id < NB_PROCS_MAX ) 198 { 199 return 2; 200 } 201 else 202 { 203 return _timer_access ( 1, // read access 204 cluster_id, 205 local_id, 206 register_id, 207 buffer ); 208 } 209 } 210 ///////////////////////////////////////////////////////////////////////////////// 211 // _timer_check() 212 ///////////////////////////////////////////////////////////////////////////////// 213 214 ///////////////////////////////////////////////////////////////////////////////// 215 // VciMultiTty driver 216 ///////////////////////////////////////////////////////////////////////////////// 217 // There is only one multi_tty controler in the architecture. 218 // The total number of TTYs is defined by the configuration parameter NB_TTYS. 219 // The "system" terminal is TTY[0]. 220 // The "user" TTYs are allocated to applications by the GIET in the boot phase, 221 // as defined in the mapping_info data structure. The corresponding tty_id must 222 // be stored in the context of the task by the boot code. 223 // The TTY address is : seg_tty_base + tty_id*TTY_SPAN 224 ///////////////////////////////////////////////////////////////////////////////// 99 225 100 226 // TTY variables 101 227 in_unckdata volatile unsigned char _tty_get_buf[NB_TTYS]; 102 228 in_unckdata volatile unsigned char _tty_get_full[NB_TTYS] = { [0 ... NB_TTYS-1] = 0 }; 103 in_unckdata unsigned int _tty_put_lock = 0; 104 105 ////////////////////////////////////////////////////////////////////////////// 106 // VciMultiTimer driver 107 ////////////////////////////////////////////////////////////////////////////// 108 // There is one MULTI-TIMER component per cluster. 109 // The number of timers per cluster must be larger or equal to the number 110 // processors (NB_TIMERS >= NB_PROCS), because each processor uses a private 111 // yimer for context switch. 112 // The total number of timers is NB_CLUSTERS * NB_TIMERS 113 // The global timer index = cluster_id*NB_TIMERS + timer_id 114 ////////////////////////////////////////////////////////////////////////////// 115 116 ////////////////////////////////////////////////////////////////////////////// 117 // _timer_write() 118 // 119 // Write a 32-bit word in a memory mapped register of a timer device, 120 // identified by the cluster index and the local timer index. 121 // Returns 0 if success, > 0 if error. 122 ////////////////////////////////////////////////////////////////////////////// 123 unsigned int _timer_write( unsigned int cluster_index, 124 unsigned int timer_index, 125 unsigned int register_index, 126 unsigned int value ) 127 { 128 unsigned int* timer_address; 129 130 // parameters checking 131 if ( register_index >= TIMER_SPAN) return 1; 132 if ( cluster_index >= NB_CLUSTERS) return 1; 133 if ( timer_index >= NB_TIMERS ) return 1; 134 135 timer_address = (unsigned int*)&seg_timer_base + 136 ( cluster_index * CLUSTER_SPAN ) + 137 ( timer_index * TIMER_SPAN ); 138 139 timer_address[register_index] = value; // write word 140 141 return 0; 142 } 143 144 ////////////////////////////////////////////////////////////////////////////// 145 // _timer_read() 146 // 147 // Read a 32-bit word in a memory mapped register of a timer device, 148 // identified by the cluster index and the local timer index. 149 // Returns 0 if success, > 0 if error. 150 ////////////////////////////////////////////////////////////////////////////// 151 unsigned int _timer_read(unsigned int cluster_index, 152 unsigned int timer_index, 153 unsigned int register_index, 154 unsigned int *buffer) 155 { 156 unsigned int *timer_address; 157 158 // parameters checking 159 if ( register_index >= TIMER_SPAN) return 1; 160 if ( cluster_index >= NB_CLUSTERS) return 1; 161 if ( timer_index >= NB_TIMERS ) return 1; 162 163 timer_address = (unsigned int*)&seg_timer_base + 164 ( cluster_index * CLUSTER_SPAN ) + 165 ( timer_index * TIMER_SPAN ); 166 167 *buffer = timer_address[register_index]; // read word 168 169 return 0; 170 } 171 229 in_unckdata unsigned int _tty_put_lock = 0; // protect kernel TTY[0] 230 231 //////////////////////////////////////////////////////////////////////////////// 232 // _tty_error() 233 //////////////////////////////////////////////////////////////////////////////// 234 void _tty_error() 235 { 236 unsigned int task_id = _get_current_task_id(); 237 unsigned int proc_id = _procid(); 238 239 _get_lock(&_tty_put_lock); 240 _puts("\n[GIET ERROR] TTY index too large for task "); 241 _putw( task_id ); 242 _puts(" on processor "); 243 _putw( proc_id ); 244 _puts("\n"); 245 _release_lock(&_tty_put_lock); 246 } 172 247 ///////////////////////////////////////////////////////////////////////////////// 173 // VciMultiTty driver 174 ///////////////////////////////////////////////////////////////////////////////// 175 // The total number of TTYs is defined by the configuration parameter NB_TTYS. 176 // The system terminal is TTY[0]. 177 // The TTYs are allocated to applications by the GIET in the boot phase. 178 // The nummber of TTYs allocated to each application, and used by each 179 // task can be defined in the mapping_info data structure. 180 // For each user task, the tty_id is stored in the context of the task (slot 34), 181 // and must be explicitely defined in the boot code. 182 // The TTY address is always computed as : seg_tty_base + tty_id*TTY_SPAN 183 /////////////////////////////////////////////////////////////////////////////////// 184 185 ////////////////////////////////////////////////////////////////////////////// 186 // _tty_write() 187 // 248 // _tty_write() 188 249 // Write one or several characters directly from a fixed-length user buffer to 189 250 // the TTY_WRITE register of the TTY controler. … … 192 253 // the transfer as soon as the TTY_STATUS[WRITE] bit is set. 193 254 // The function returns the number of characters that have been written. 194 ////////////////////////////////////////////////////////////////////////////// 255 ///////////////////////////////////////////////////////////////////////////////// 195 256 unsigned int _tty_write( const char *buffer, 196 257 unsigned int length) 197 258 { 198 volatile unsigned int *tty_address; 199 200 unsigned int proc_id; 201 unsigned int task_id; 202 unsigned int tty_id; 203 unsigned int nwritten; 204 205 proc_id = _procid(); 206 207 task_id = _scheduler[proc_id].current; 208 tty_id = _scheduler[proc_id].context[task_id][CTX_TTY_ID]; 209 210 tty_address = (unsigned int*)&seg_tty_base + tty_id*TTY_SPAN; 259 unsigned int nwritten; 260 261 unsigned int tty_id = _get_current_context_slot(CTX_TTY_ID); 262 if ( tty_id >= NB_TTYS ) 263 { 264 _tty_error(); 265 return 0; 266 } 267 268 unsigned int* tty_address = (unsigned int*)&seg_tty_base + tty_id*TTY_SPAN; 211 269 212 270 for (nwritten = 0; nwritten < length; nwritten++) … … 221 279 return nwritten; 222 280 } 223 224 281 ////////////////////////////////////////////////////////////////////////////// 225 // _tty_read_irq() 226 // 282 // _tty_read_irq() 227 283 // This non-blocking function uses the TTY_GET_IRQ[tty_id] interrupt and 228 284 // the associated kernel buffer, that has been written by the ISR. … … 235 291 unsigned int length) 236 292 { 237 unsigned int proc_id; 238 unsigned int task_id; 239 unsigned int tty_id; 240 unsigned int ret; 241 242 proc_id = _procid(); 243 task_id = _scheduler[proc_id].current; 244 tty_id = _scheduler[proc_id].context[task_id][CTX_TTY_ID]; 293 unsigned int tty_id = _get_current_context_slot(CTX_TTY_ID); 294 295 if ( tty_id >= NB_TTYS ) 296 { 297 _tty_error(); 298 return 0; 299 } 245 300 246 301 if (_tty_get_full[tty_id] == 0) 247 302 { 248 ret =0;303 return 0; 249 304 } 250 305 else … … 252 307 *buffer = _tty_get_buf[tty_id]; 253 308 _tty_get_full[tty_id] = 0; 254 ret = 1; 255 } 256 return ret; 257 } 258 259 //////////////////////////////////////////////////////////////////////////////// 260 // _tty_read() 261 // 309 return 1; 310 } 311 } 312 //////////////////////////////////////////////////////////////////////////////// 313 // _tty_read() 262 314 // This non-blocking function fetches one character directly from the TTY_READ 263 315 // register of the TTY controler, and writes this character to the user buffer. … … 268 320 unsigned int length) 269 321 { 270 volatile unsigned int *tty_address; 271 272 unsigned int proc_id; 273 unsigned int task_id; 274 unsigned int tty_id; 275 276 proc_id = _procid(); 277 task_id = _scheduler[proc_id].current; 278 tty_id = _scheduler[proc_id].context[task_id][CTX_TTY_ID]; 279 280 tty_address = (unsigned int*)&seg_tty_base + tty_id*TTY_SPAN; 281 282 if ((tty_address[TTY_STATUS] & 0x1) != 0x1) return 0; 283 284 *buffer = (char)tty_address[TTY_READ]; 285 return 1; 286 } 287 288 //////////////////////////////////////////////////////////////////////////////// 289 // VciMultiIcu driver 290 //////////////////////////////////////////////////////////////////////////////// 291 // There is in principle one MULTI-ICU component per cluster, and the 292 // number of independant ICUs is equal to NB_PROCS, because there is 293 // one ICU per processor. 294 //////////////////////////////////////////////////////////////////////////////// 295 296 //////////////////////////////////////////////////////////////////////////////// 297 // _icu_write() 298 // 322 unsigned int tty_id = _get_current_context_slot(CTX_TTY_ID); 323 if ( tty_id >= NB_TTYS ) 324 { 325 _tty_error(); 326 return 0; 327 } 328 329 unsigned int* tty_address = (unsigned int*)&seg_tty_base + tty_id*TTY_SPAN; 330 331 if ((tty_address[TTY_STATUS] & 0x1) != 0x1) 332 { 333 return 0; 334 } 335 else 336 { 337 *buffer = (char)tty_address[TTY_READ]; 338 return 1; 339 } 340 } 341 342 //////////////////////////////////////////////////////////////////////////////// 343 // VciMultiIcu and VciXicu drivers 344 //////////////////////////////////////////////////////////////////////////////// 345 // There is in principle one vci_multi_icu (or vci_xicu) component per cluster, 346 // and the number of independant ICUs is equal to NB_PROCS_MAX, because there is 347 // one private interrupr controler per processor. 348 //////////////////////////////////////////////////////////////////////////////// 349 350 //////////////////////////////////////////////////////////////////////////////// 351 // _icu_write() 299 352 // Write a 32-bit word in a memory mapped register of the MULTI_ICU device, 300 353 // identified by the cluster index, and a processor local index. … … 306 359 unsigned int value ) 307 360 { 308 unsigned int *icu_address; 361 #if GIET_USE_XICU 362 363 #else 309 364 310 365 // parameters checking 311 366 if ( register_index >= ICU_SPAN) return 1; 312 367 if ( cluster_index >= NB_CLUSTERS) return 1; 313 if ( proc_index >= NB_PROCS )return 1;314 315 icu_address = (unsigned int*)&seg_icu_base +316 ( cluster_index * CLUSTER_SPAN) +317 ( proc_index * ICU_SPAN);368 if ( proc_index >= NB_PROCS_MAX ) return 1; 369 370 unsigned int *icu_address = (unsigned int*)&seg_icu_base + 371 (cluster_index * CLUSTER_SPAN) + 372 (proc_index * ICU_SPAN); 318 373 319 374 icu_address[register_index] = value; // write word 320 375 return 0; 321 } 322 323 //////////////////////////////////////////////////////////////////////////////// 324 // _icu_read()325 // 376 377 #endif 378 } 379 //////////////////////////////////////////////////////////////////////////////// 380 // _icu_read() 326 381 // Read a 32-bit word in a memory mapped register of the MULTI_ICU device, 327 382 // identified by the cluster index and a processor local index. … … 333 388 unsigned int* buffer ) 334 389 { 335 unsigned int *icu_address; 390 #if GIET_USE_XICU 391 392 #else 336 393 337 394 // parameters checking 338 395 if ( register_index >= ICU_SPAN) return 1; 339 396 if ( cluster_index >= NB_CLUSTERS) return 1; 340 if ( proc_index >= NB_PROCS )return 1;341 342 icu_address = (unsigned int*)&seg_icu_base +343 ( cluster_index * CLUSTER_SPAN) +344 ( proc_index * ICU_SPAN);397 if ( proc_index >= NB_PROCS_MAX ) return 1; 398 399 unsigned int *icu_address = (unsigned int*)&seg_icu_base + 400 (cluster_index * CLUSTER_SPAN) + 401 (proc_index * ICU_SPAN); 345 402 346 403 *buffer = icu_address[register_index]; // read word 347 404 return 0; 405 406 #endif 348 407 } 349 408 … … 357 416 358 417 //////////////////////////////////////////////////////////////////////////////// 359 // _gcd_write() 360 // 418 // _gcd_write() 361 419 // Write a 32-bit word in a memory mapped register of the GCD coprocessor. 362 420 // Returns 0 if success, > 0 if error. … … 376 434 return 0; 377 435 } 378 379 //////////////////////////////////////////////////////////////////////////////// 380 // _gcd_read() 381 // 436 //////////////////////////////////////////////////////////////////////////////// 437 // _gcd_read() 382 438 // Read a 32-bit word in a memory mapped register of the GCD coprocessor. 383 439 // Returns 0 if success, > 0 if error. … … 448 504 /////////////////////////////////////////////////////////////////////////////// 449 505 506 // IOC global variables 507 in_unckdata volatile unsigned int _ioc_status = 0; 508 in_unckdata volatile unsigned int _ioc_done = 0; 509 in_unckdata unsigned int _ioc_lock = 0; 510 in_unckdata unsigned int _ioc_iommu_ix1 = 0; 511 in_unckdata unsigned int _ioc_iommu_npages; 512 450 513 /////////////////////////////////////////////////////////////////////////////// 451 // _ioc_get_lock() 452 // 453 // This blocking helper is used by '_ioc_read()' and '_ioc_write()' functions 454 // to get _ioc_lock using atomic LL/SC. 455 /////////////////////////////////////////////////////////////////////////////// 456 static inline void _ioc_get_lock() 457 { 458 register unsigned int delay = (_proctime() & 0xF) << 4; 459 register unsigned int *plock = (unsigned int*)&_ioc_lock; 460 461 asm volatile ( 462 "_ioc_llsc: \n" 463 "ll $2, 0(%0) \n" /* $2 <= _ioc_lock current value */ 464 "bnez $2, _ioc_delay \n" /* delay if _ioc_lock already taken */ 465 "li $3, 1 \n" /* $3 <= argument for sc */ 466 "sc $3, 0(%0) \n" /* try to set _ioc_lock */ 467 "bnez $3, _ioc_ok \n" /* exit if atomic */ 468 "_ioc_delay: \n" 469 "move $4, %1 \n" /* $4 <= delay */ 470 "_ioc_loop: \n" 471 "beqz $4, _ioc_loop \n" /* test end delay */ 472 "addi $4, $4, -1 \n" /* $4 <= $4 - 1 */ 473 "j _ioc_llsc \n" /* retry ll */ 474 "nop \n" 475 "_ioc_ok: \n" 476 : 477 :"r"(plock), "r"(delay) 478 :"$2", "$3", "$4"); 479 } 480 481 /////////////////////////////////////////////////////////////////////////////// 482 // _ioc_access() 514 // _ioc_access() 483 515 // This function transfer data between a memory buffer and the block device. 484 516 // The buffer lentgth is (count*block_size) bytes. 485 //486 517 // Arguments are: 487 518 // - to_mem : from external storage to memory when non 0 … … 503 534 unsigned int ix2; // page index in IOMMU PT1 page table 504 535 unsigned int addr; // buffer address for IOC peripheral 505 unsigned int user_ptp; // page table pointer in user space506 unsigned int ko; // bool returned by _v2p_translate()507 536 unsigned int ppn_first; // first physical page number for user buffer 508 unsigned int ltid; // current task local index509 static_scheduler_t* psched; // pointer on the current task scheduler510 537 511 538 // check buffer alignment … … 517 544 518 545 // get user space page table virtual address 519 psched = &_scheduler[_procid()]; 520 ltid = psched->current; 521 user_ptp = psched->context[ltid][CTX_PTAB_ID]; 546 unsigned int user_pt_vbase = _get_current_context_slot(CTX_PTAB_ID); 522 547 523 548 user_vpn_min = user_vaddr >> 12; … … 529 554 { 530 555 // get ppn and flags for each vpn 531 ko = _v2p_translate( (page_table_t*)user_ptp,532 vpn,533 &ppn,534 &flags );556 unsigned int ko = _v2p_translate( (page_table_t*)user_pt_vbase, 557 vpn, 558 &ppn, 559 &flags ); 535 560 536 561 // check access rights … … 573 598 574 599 // get the lock on ioc device 575 _ ioc_get_lock();600 _get_lock( &_ioc_lock ); 576 601 577 602 // peripheral configuration … … 584 609 return 0; 585 610 } 586 587 611 ///////////////////////////////////////////////////////////////////////////////// 588 612 // _ioc_completed() … … 630 654 return ret; 631 655 } 632 633 656 /////////////////////////////////////////////////////////////////////////////// 634 // _ioc_read()657 // _ioc_read() 635 658 // Transfer data from the block device to a memory buffer in user space. 636 659 // - lba : first block index on the block device … … 643 666 unsigned int count ) 644 667 { 645 return _ioc_access( 1, // read 668 return _ioc_access( 1, // read access 646 669 lba, 647 670 (unsigned int)buffer, 648 671 count ); 649 672 } 650 651 673 /////////////////////////////////////////////////////////////////////////////// 652 // _ioc_write()674 // _ioc_write() 653 675 // Transfer data from a memory buffer in user space to the block device. 654 676 // - lba : first block index on the block device … … 661 683 unsigned int count ) 662 684 { 663 return _ioc_access( 0, // write 685 return _ioc_access( 0, // write access 664 686 lba, 665 687 (unsigned int)buffer, … … 668 690 669 691 ////////////////////////////////////////////////////////////////////////////////// 692 // VciMultiDma driver 693 ////////////////////////////////////////////////////////////////////////////////// 694 // The DMA controllers are physically distributed in the clusters. 695 // There is (NB_CLUSTERS * NB_DMAS_MAX) channels, indexed by a global index: 696 // dma_id = cluster_id * NB_DMA_MAX + loc_id 697 // 698 // As a DMA channel can be used by several tasks, each DMA channel is protected 699 // by a specific lock: _dma_lock[dma_id] 700 // The signalisation between the OS and the DMA uses the _dma_done[dma_id] 701 // synchronisation variables (set by the ISR, and reset by the OS). 702 // The transfer status is copied by the ISR in the _dma_status[dma_id] variables. 703 // 704 // These DMA channels can be used by the FB driver, or by the NIC driver. 705 ////////////////////////////////////////////////////////////////////////////////// 706 707 #if (NB_DMAS_MAX > 0) 708 in_unckdata unsigned int _dma_lock[NB_DMAS_MAX * NB_CLUSTERS] 709 = { [0 ... (NB_DMAS_MAX * NB_CLUSTERS)-1] = 0 }; 710 711 in_unckdata volatile unsigned int _dma_done[NB_DMAS_MAX * NB_CLUSTERS] 712 = { [0 ... (NB_DMAS_MAX * NB_CLUSTERS)-1] = 0 }; 713 714 in_unckdata volatile unsigned int _dma_status[NB_DMAS_MAX * NB_CLUSTERS]; 715 716 in_unckdata unsigned int _dma_iommu_ix1 = 1; 717 718 in_unckdata unsigned int _dma_iommu_npages[NB_DMAS_MAX * NB_CLUSTERS]; 719 #endif 720 721 ////////////////////////////////////////////////////////////////////////////////// 670 722 // VciFrameBuffer driver 671 723 ////////////////////////////////////////////////////////////////////////////////// 724 // The vci_frame_buffer device can be accessed directly by software with memcpy(), 725 // or it can be accessed through a multi-channels DMA component: 726 // 672 727 // The '_fb_sync_write' and '_fb_sync_read' functions use a memcpy strategy to 673 728 // implement the transfer between a data buffer (user space) and the frame … … 675 730 // 676 731 // The '_fb_write()', '_fb_read()' and '_fb_completed()' functions use the DMA 677 // coprocessor to transfer data between the user buffer and the frame buffer. 678 // These functions use a polling policy to test the global variables _dma_busy[i] 679 // and detect the transfer completion. 680 // There is NB_DMA channels, that are indexed by the dma_id stored in the 681 // task context. 682 // The _dma_busy[i] synchronisation variables (one per channel) are set by the OS, 683 // and reset by the DMA ISR. 732 // controlers (distributed in the clusters) to transfer data 733 // between the user buffer and the frame buffer. A DMA channel is 734 // allocated to each task requesting it in the mapping_info data structure. 684 735 ////////////////////////////////////////////////////////////////////////////////// 685 736 … … 697 748 unsigned int length ) 698 749 { 699 volatile unsigned char *fb_address;700 750 701 751 // buffer must be mapped in user space 702 752 if ( ((unsigned int)buffer + length ) >= 0x80000000 ) 753 { 703 754 return 1; 704 705 fb_address = (unsigned char*)&seg_fb_base + offset;706 707 // buffer copy708 memcpy((void*)fb_address, (void*)buffer, length);709 710 return 0;755 } 756 else 757 { 758 unsigned char *fb_address = (unsigned char*)&seg_fb_base + offset; 759 memcpy((void*)fb_address, (void*)buffer, length); 760 return 0; 761 } 711 762 } 712 763 … … 724 775 unsigned int length ) 725 776 { 726 volatile unsigned char *fb_address;727 728 777 // buffer must be mapped in user space 729 778 if ( ((unsigned int)buffer + length ) >= 0x80000000 ) 779 { 730 780 return 1; 731 732 fb_address = (unsigned char*)&seg_fb_base + offset;733 734 // buffer copy735 memcpy((void*)buffer, (void*)fb_address, length);736 737 return 0;738 } 739 740 ////////////////////////////////////////////////////////////////////////////////// 741 // _fb_ access()742 // Transfer data between a memory buffer and the frame_buffer deviceusing DMA.743 // - to_ mem : from frame buffer to memorywhen true.781 } 782 else 783 { 784 unsigned char *fb_address = (unsigned char*)&seg_fb_base + offset; 785 memcpy((void*)buffer, (void*)fb_address, length); 786 return 0; 787 } 788 } 789 790 ////////////////////////////////////////////////////////////////////////////////// 791 // _fb_dma_access() 792 // Transfer data between a user buffer and the frame_buffer using DMA. 793 // - to_user : from frame buffer to user buffer when true. 744 794 // - offset : offset (in bytes) in the frame buffer. 745 795 // - user_vaddr : virtual base address of the memory buffer. … … 747 797 // The memory buffer must be mapped in user address space and word-aligned. 748 798 // The user buffer length must be multiple of 4 bytes. 749 // Returns 0 if success, > 0 if error. 750 ////////////////////////////////////////////////////////////////////////////////// 751 unsigned int _fb_access( unsigned int to_mem, 752 unsigned int offset, 753 unsigned int user_vaddr, 754 unsigned int length ) 755 { 756 static_scheduler_t* psched; // pointer on the current task scheduler 757 unsigned char* fb_base; // frame buffer base address 758 unsigned int* dma_base; // dma component base address 759 unsigned int task_id; // task local index (for scheduler) 760 unsigned int dma_id; // DMA channel index 761 unsigned int vpn; // current virtual page number 762 unsigned int flags; // protection flags 763 unsigned int ppn; // current physical page number 764 unsigned int buf_base; // buffer base address for DMA access 765 unsigned int ppn_first; // first physical page index for user buffer 766 767 fb_base = (unsigned char*)&seg_fb_base + offset; 768 769 psched = &_scheduler[_procid()]; 770 task_id = psched->current; 771 dma_id = psched->context[task_id][CTX_FBDMA_ID]; 772 dma_base = (unsigned int*)&seg_dma_base + (dma_id * DMA_SPAN); 773 774 // check buffer address and ength alignment 775 if ( user_vaddr & 0x3 ) return 1; 776 if ( length & 0x3 ) return 1; 799 // Me must compute the physical base addresses for both the frame buffer 800 // and the user buffer before programming the DMA transfer. 801 // The GIET being fully static, we don't need to split the transfer in 4Kbytes 802 // pages, because the user buffer is contiguous in physical space. 803 // Returns 0 if success, > 0 if error. 804 ////////////////////////////////////////////////////////////////////////////////// 805 unsigned int _fb_dma_access( unsigned int to_user, 806 unsigned int offset, 807 unsigned int user_vaddr, 808 unsigned int length ) 809 { 810 unsigned int ko; // unsuccessfull V2P translation 811 unsigned int flags; // protection flags 812 unsigned int ppn; // physical page number 813 unsigned int user_pbase; // user buffer pbase address 814 unsigned int fb_pbase; // frame buffer pbase address 815 816 // get DMA channel and compute DMA vbase address 817 unsigned int dma_id = _get_current_context_slot(CTX_FBDMA_ID); 818 unsigned int cluster_id = dma_id / NB_DMAS_MAX; 819 unsigned int loc_id = dma_id % NB_DMAS_MAX; 820 unsigned int* dma_base = (unsigned int*)&seg_dma_base + 821 (cluster_id * CLUSTER_SPAN) + 822 (loc_id * DMA_SPAN); 823 824 // check user buffer address and length alignment 825 if ( (user_vaddr & 0x3) || (length & 0x3) ) 826 { 827 _puts("[GIET ERROR] in _fbdma_access() : user buffer not word aligned\n"); 828 return 1; 829 } 777 830 778 831 // get user space page table virtual address 779 unsigned int user_ptp = psched->context[task_id][CTX_PTAB_ID]; 780 832 unsigned int user_ptab = _get_current_context_slot(CTX_PTAB_ID); 833 834 // compute frame buffer pbase address 835 unsigned int fb_vaddr = (unsigned int)&seg_fb_base + offset; 836 837 ko = _v2p_translate( (page_table_t*)user_ptab, 838 (fb_vaddr >> 12), 839 &ppn, 840 &flags ); 841 fb_pbase = (ppn << 12) | (fb_vaddr & 0x00000FFF); 842 843 if ( ko ) 844 { 845 _puts("[GIET ERROR] in _fbdma_access() : frame buffer unmapped\n"); 846 return 2; 847 } 848 849 // Compute user buffer pbase address 850 ko = _v2p_translate( (page_table_t*)user_ptab, 851 (user_vaddr >> 12), 852 &ppn, 853 &flags ); 854 user_pbase = (ppn << 12) | (user_vaddr & 0x00000FFF); 855 856 if ( ko ) 857 { 858 _puts("[GIET ERROR] in _fbdma_access() : user buffer unmapped\n"); 859 return 3; 860 } 861 if ( (flags & PTE_U) == 0 ) 862 { 863 _puts("[GIET ERROR] in _fbdma_access() : user buffer not in user space\n"); 864 return 4; 865 } 866 if ( ( (flags & PTE_W) == 0 ) && to_user ) 867 { 868 _puts("[GIET ERROR] in _fbdma_access() : user buffer not writable\n"); 869 return 5; 870 } 871 872 873 874 /* 875 // loop on all virtual pages covering the user buffer 781 876 unsigned int user_vpn_min = user_vaddr >> 12; 782 877 unsigned int user_vpn_max = (user_vaddr + length - 1) >> 12; 783 878 unsigned int ix2 = 0; 784 879 unsigned int ix1 = _dma_iommu_ix1 + dma_id; 785 unsigned int ko; 786 unsigned int i; 787 788 // loop on all virtual pages covering the user buffer 880 789 881 for ( vpn = user_vpn_min ; vpn <= user_vpn_max ; vpn++ ) 790 882 { 791 883 // get ppn and flags for each vpn 792 ko = _v2p_translate( (page_table_t*)user_ptp,793 vpn,794 &ppn,795 &flags );884 unsigned int ko = _v2p_translate( (page_table_t*)user_pt_vbase, 885 vpn, 886 &ppn, 887 &flags ); 796 888 797 889 // check access rights 798 if ( ko ) return 2; // unmapped799 if ( (flags & PTE_U) == 0 ) return 3; // not in user space800 if ( ( (flags & PTE_W) == 0 ) && to_ mem ) return 4; // not writable890 if ( ko ) return 3; // unmapped 891 if ( (flags & PTE_U) == 0 ) return 4; // not in user space 892 if ( ( (flags & PTE_W) == 0 ) && to_user ) return 5; // not writable 801 893 802 894 // save first ppn value … … 816 908 else // no IOMMU : check that physical pages are contiguous 817 909 { 818 if ( (ppn - ppn_first) != ix2 ) return 5; // split physical buffer910 if ( (ppn - ppn_first) != ix2 ) return 6; // split physical buffer 819 911 } 820 912 … … 823 915 } // end for vpn 824 916 825 // register the number of pages to be unmapped 917 // register the number of pages to be unmapped if iommu activated 826 918 _dma_iommu_npages[dma_id] = (user_vpn_max - user_vpn_min) + 1; 827 919 920 */ 828 921 // invalidate data cache in case of memory write 829 if ( to_mem ) _dcache_buf_invalidate( (void*)user_vaddr, length ); 830 831 // compute buffer base address for DMA depending on IOMMU activation 832 if ( GIET_IOMMU_ACTIVE ) buf_base = ( ix1 ) << 21 | (user_vaddr & 0xFFF); 833 else buf_base = (ppn_first << 12) | (user_vaddr & 0xFFF); 834 835 836 // waiting until DMA device is available 837 while (_dma_busy[dma_id] != 0) 838 { 839 // busy wait with a pseudo random delay between bus access 840 unsigned int delay = (_proctime() & 0xF) << 4; 841 for (i = 0; i < delay; i++) 842 asm volatile("nop"); 843 } 844 845 _dma_busy[dma_id] = 1; 922 if ( to_user ) _dcache_buf_invalidate( (void*)user_vaddr, length ); 923 924 // get the lock 925 _get_lock( &_dma_lock[dma_id] ); 846 926 847 927 // DMA configuration 848 dma_base[DMA_IRQ_DISABLE] = 0; 849 if ( to_mem ) 850 { 851 dma_base[DMA_SRC] = (unsigned int)fb_base; 852 dma_base[DMA_DST] = (unsigned int)buf_base; 928 if ( to_user ) 929 { 930 dma_base[DMA_SRC] = (unsigned int)fb_pbase; 931 dma_base[DMA_DST] = (unsigned int)user_pbase; 853 932 } 854 933 else 855 934 { 856 dma_base[DMA_SRC] = (unsigned int) buf_base;857 dma_base[DMA_DST] = (unsigned int)fb_ base;935 dma_base[DMA_SRC] = (unsigned int)user_pbase; 936 dma_base[DMA_DST] = (unsigned int)fb_pbase; 858 937 } 859 938 dma_base[DMA_LEN] = (unsigned int)length; … … 873 952 unsigned int length ) 874 953 { 875 return _fb_ access( 0, // write to frame buffer876 offset,877 (unsigned int)buffer,878 length );954 return _fb_dma_access( 0, // write to frame buffer 955 offset, 956 (unsigned int)buffer, 957 length ); 879 958 } 880 959 … … 891 970 unsigned int length ) 892 971 { 893 return _fb_ access( 1, // read from frame buffer894 offset,895 (unsigned int)buffer,896 length );972 return _fb_dma_access( 1, // read from frame buffer 973 offset, 974 (unsigned int)buffer, 975 length ); 897 976 } 898 977 … … 906 985 unsigned int _fb_completed() 907 986 { 908 static_scheduler_t* psched = &_scheduler[_procid()]; 909 unsigned int task_id = psched->current; 910 911 volatile unsigned int dma_id = psched->context[task_id][CTX_FBDMA_ID]; 987 unsigned int dma_id = _get_current_context_slot(CTX_FBDMA_ID); 912 988 913 989 // busy waiting with a pseudo random delay between bus access 914 while (_dma_ busy[dma_id] != 0)990 while (_dma_done[dma_id] == 0) 915 991 { 916 992 unsigned int i; 917 unsigned int delay = ( _proctime() & 0xF) << 4;993 unsigned int delay = ( _proctime() ^ _procid()<<4 ) & 0xFF; 918 994 for (i = 0; i < delay; i++) 919 995 asm volatile("nop"); … … 938 1014 } 939 1015 1016 // reset synchronization variables 1017 _dma_lock[dma_id] = 0; 1018 _dma_done[dma_id] = 0; 1019 940 1020 return _dma_status[dma_id]; 941 1021 } -
soft/giet_vm/sys/drivers.h
r166 r189 10 10 11 11 /////////////////////////////////////////////////////////////////////////////////// 12 // Global variables for interaction with ISRs12 // Timer access functions (used for both vci_multi_timer and vci_xicu) 13 13 /////////////////////////////////////////////////////////////////////////////////// 14 14 15 extern volatile unsigned int _dma_status[]; 16 extern volatile unsigned char _dma_busy[]; 15 extern volatile unsigned char _timer_event[]; 17 16 18 extern volatile unsigned char _ioc_status; 19 extern volatile unsigned char _ioc_done; 20 extern unsigned int _ioc_lock; 17 unsigned int _timer_access( unsigned int read, // reas if non 0 18 unsigned int cluster_id, 19 unsigned int local_id, 20 unsigned int register_id, 21 unsigned int* buffer); 22 23 unsigned int _timer_read( unsigned int register_id, 24 unsigned int* buffer); 25 26 unsigned int _timer_write( unsigned int register_id, 27 unsigned int value); 28 29 /////////////////////////////////////////////////////////////////////////////////// 30 // TTY access functions and variables 31 /////////////////////////////////////////////////////////////////////////////////// 21 32 22 33 extern volatile unsigned char _tty_get_buf[]; 23 34 extern volatile unsigned char _tty_get_full[]; 24 35 extern unsigned int _tty_put_lock; 25 26 ///////////////////////////////////////////////////////////////////////////////////27 // Prototypes of the external functions.28 ///////////////////////////////////////////////////////////////////////////////////29 30 unsigned int _timer_write( unsigned int cluster_id,31 unsigned int timer_id,32 unsigned int register_id,33 unsigned int value);34 35 unsigned int _timer_read( unsigned int cluster_id,36 unsigned int timer_id,37 unsigned int register_id,38 unsigned int* buffer);39 40 unsigned int _icu_write( unsigned int cluster_id,41 unsigned int proc_id,42 unsigned int register_id,43 unsigned int value);44 45 unsigned int _icu_read( unsigned int cluster_id,46 unsigned int proc_id,47 unsigned int register_id,48 unsigned int* buffer);49 36 50 37 unsigned int _tty_write( const char* buffer, … … 56 43 unsigned int _tty_read_irq( char* buffer, 57 44 unsigned int length); 45 46 /////////////////////////////////////////////////////////////////////////////////// 47 // ICU access functions (both vci_multi_icu and vci_xicu) 48 /////////////////////////////////////////////////////////////////////////////////// 49 50 unsigned int _icu_read( unsigned int cluster_id, 51 unsigned int proc_id, 52 unsigned int register_id, 53 unsigned int* buffer); 54 55 unsigned int _icu_write( unsigned int cluster_id, 56 unsigned int proc_id, 57 unsigned int register_id, 58 unsigned int value ); 59 60 /////////////////////////////////////////////////////////////////////////////////// 61 // IOC access functions and variables (vci_block_device) 62 /////////////////////////////////////////////////////////////////////////////////// 63 64 extern volatile unsigned int _ioc_status; 65 extern volatile unsigned int _ioc_done; 66 extern unsigned int _ioc_lock; 67 extern unsigned int _ioc_iommu_ix1; 68 extern unsigned int _ioc_iommu_npages; 69 58 70 59 71 unsigned int _ioc_write( unsigned int lba, … … 67 79 unsigned int _ioc_completed(); 68 80 69 unsigned int _gcd_write( unsigned int register_index, 70 unsigned int value); 81 /////////////////////////////////////////////////////////////////////////////////// 82 // Multi DMA variables (vci_multi_dma) 83 /////////////////////////////////////////////////////////////////////////////////// 84 85 extern volatile unsigned int _dma_status[]; 86 extern volatile unsigned int _dma_done[]; 87 extern unsigned int _dma_lock[]; 88 extern unsigned int _dma_iommu_ix1; 89 extern unsigned int _dma_iommu_npages[]; 71 90 72 unsigned int _gcd_read( unsigned int register_index, 73 unsigned int* buffer); 74 91 /////////////////////////////////////////////////////////////////////////////////// 92 // Frame Buffer access functions (vci_frame_buffer) 93 /////////////////////////////////////////////////////////////////////////////////// 94 75 95 unsigned int _fb_sync_write(unsigned int offset, 76 96 const void* buffer, … … 91 111 unsigned int _fb_completed(); 92 112 113 /////////////////////////////////////////////////////////////////////////////////// 114 // GCD access functions 115 /////////////////////////////////////////////////////////////////////////////////// 116 117 unsigned int _gcd_write( unsigned int register_index, 118 unsigned int value); 119 120 unsigned int _gcd_read( unsigned int register_index, 121 unsigned int* buffer); 122 123 93 124 #endif 94 125 -
soft/giet_vm/sys/exc_handler.c
r158 r189 32 32 33 33 /////////////////////////////////////////////////////////////////////////////////// 34 // Initialize the exception vector according to CR code34 // Initialize the exception vector indexed by the CR XCODE field 35 35 /////////////////////////////////////////////////////////////////////////////////// 36 36 const _exc_func_t _cause_vector[16] = { … … 67 67 static void _cause(unsigned int msg_cause) 68 68 { 69 unsigned int epc;70 unsigned int bar;71 unsigned int cause;72 73 asm volatile("mfc0 %0, $14" : "=r"(epc));74 asm volatile("mfc0 %0, $8 " : "=r"(bar));75 asm volatile("mfc0 %0, $13" : "=r"(cause));76 77 69 _puts( (char*)(exc_message_causes[msg_cause]) ); 78 _puts("\nEPC = "); 79 _putw( epc ); 80 _puts("\nBAR = "); 81 _putw( bar ); 82 _puts("\nCAUSE = "); 83 _putw( cause ); 70 _puts("\n - Cycle : "); 71 _putd( _proctime() ); 72 _puts("\n - Processor : "); 73 _putd( _procid() ); 74 _puts("\n - Task : "); 75 _putd( _get_current_task_id() ); 76 _puts("\n - EPC : "); 77 _putw( _get_epc() ); 78 _puts("\n - BVAR : "); 79 _putw( _get_bvar() ); 84 80 _puts("\n"); 85 86 81 _exit(); 87 82 } -
soft/giet_vm/sys/giet.s
r165 r189 126 126 sw $27, 22*4($29) /* save EPC */ 127 127 128 la $26, _i nt_demux128 la $26, _irq_demux 129 129 jalr $26 /* jump to a C function to find the proper ISR */ 130 130 -
soft/giet_vm/sys/irq_handler.c
r169 r189 2 2 // File : irq_handler.c 3 3 // Date : 01/04/2012 4 // Author : alain greiner and joel porquet4 // Author : alain greiner 5 5 // Copyright (c) UPMC-LIP6 6 6 /////////////////////////////////////////////////////////////////////////////////// 7 // The irq_handler.c and irq_handler.h files are part of the GIET nano-kernel.8 // They contain the code of the _i nt_demux function that handle9 // the ICU (Interupt Controler Unit), and the various ISRs associated10 // to the CoCLibperipherals.7 // The irq_handler.c and irq_handler.h files are part of the GIET-VM nano-kernel. 8 // They contain the code of the _irq_demux() function that access the XICU or 9 // ICU component (Interupt Controler Unit), and the various ISRs (Interrupt 10 // Service Routine) associated to the peripherals. 11 11 /////////////////////////////////////////////////////////////////////////////////// 12 12 … … 20 20 21 21 /////////////////////////////////////////////////////////////////////////////////// 22 // Initialize the whole interrupt vector with the default ISR 23 /////////////////////////////////////////////////////////////////////////////////// 24 25 __attribute__((section (".kdata"))) _isr_func_t _interrupt_vector[32] = 26 { [0 ... 31] = &_isr_default }; 27 28 /////////////////////////////////////////////////////////////////////////////////// 29 // _int_demux() 30 // This functions uses an external ICU component (Interrupt Controler Unit) 31 // that concentrates up to 32 input interrupts lines. This component 32 // can support up to NB_PROCS output IRQ. 22 // _irq_demux() 23 // This function uses the ICU or XICU component (Interrupt Controler Unit) 24 // to get the interrupt vector entry. There is one ICU or XICU component per 25 // cluster, and this component can support up to NB_PROCS_MAX output IRQs. 26 // It returns the highest priority active interrupt index (smaller 27 // indexes have the highest priority). 28 // Any value larger than 31 means "no active interrupt", and no ISR is executed. 33 29 // 34 // Th is component returns the highest priority active interrupt index (smaller35 // indexes have the highest priority) by reading the ICU_IT_VECTOR register.36 // Any value larger than 31 means "no active interrupt", and the default ISR37 // (that does nothing) is executed.30 // There is one interrupt vector per processor (stored in the scheduler associated 31 // to the processor. Each interrupt vector entry contains two 16 bits fields: 32 // - isr_id : defines the type of ISR to be executed. 33 // - channel_id : defines the specific channel for multi-channels peripherals. 38 34 // 39 // The interrupt vector (32 ISR addresses array stored at _interrupt_vector 40 // address) is initialised with the default ISR address. The actual ISR 41 // addresses are supposed to be written in the interrupt vector array 42 // during system initialisation. 43 /////////////////////////////////////////////////////////////////////////////////// 44 void _int_demux(void) 45 { 46 int interrupt_index; 47 _isr_func_t isr; 48 unsigned int pid = _procid(); 49 50 // retrieves the highest priority active interrupt index 51 if (!_icu_read( pid / NB_PROCS, 52 pid % NB_PROCS, 35 // If the peripheral is replicated in clusters (TIMER or DMA), the channel_id is 36 // a global index : channel_id = cluster_id * NB_CHANNELS_MAX + loc_id 37 /////////////////////////////////////////////////////////////////////////////////// 38 void _irq_demux() 39 { 40 unsigned int pid = _procid(); 41 unsigned int irq_id; 42 43 // get the highest priority active IRQ index 44 45 #if GIET_USE_XICU 46 47 #else 48 49 if ( _icu_read( pid / NB_PROCS_MAX, 50 pid % NB_PROCS_MAX, 53 51 ICU_IT_VECTOR, 54 (unsigned int*)&interrupt_index) )52 &irq_id ) ) 55 53 { 56 if (interrupt_index == -1) // no interrupt is active 57 return; 58 59 isr = _interrupt_vector[interrupt_index]; 60 isr(); 61 } 62 else 63 { 64 _puts("\n[GIET ERROR] In _demux function : wrong arguments in _icu_read()\n"); 54 _puts("\n[GIET ERROR] wrong _icu_read in _irq_demux() function\n"); 65 55 _exit(); 66 56 } 57 58 #endif 59 60 if ( irq_id < 32 ) // do nothing if no interrupt active 61 { 62 unsigned int entry = _get_interrupt_vector_entry(irq_id); 63 unsigned int isr_id = entry & 0x000000FF; 64 unsigned int channel_id = (entry>>16) & 0x0000FFFF; 65 if ( isr_id == ISR_SWITCH ) _isr_switch(); 66 else if ( isr_id == ISR_IOC ) _isr_ioc(); 67 else if ( isr_id == ISR_DMA ) _isr_dma( channel_id ); 68 else if ( isr_id == ISR_TTY ) _isr_tty( channel_id ); 69 else if ( isr_id == ISR_TIMER ) _isr_timer( channel_id ); 70 else _isr_default(); 71 } 67 72 } 68 73 /////////////////////////////////////////////////////////////////////////////////// 69 74 // _isr_default() 70 75 // The default ISR is called when no specific ISR has been installed in the 71 // interrupt vector. It simply displays a message on TTY0.76 // interrupt vector. It simply displays a message on kernel TTY[0]. 72 77 /////////////////////////////////////////////////////////////////////////////////// 73 78 void _isr_default() 74 79 { 75 _puts("\n\n!!! Default ISR!!!\n");80 _puts("\n\n!!! Strange... Default ISR activated !!!\n"); 76 81 } 77 82 78 83 /////////////////////////////////////////////////////////////////////////////////// 79 84 // _isr_dma() 80 // This ISR handles up to 8 IRQs generated by 8 independant channels of the 81 // multi_dma component. It acknowledges the interrupt and reset the synchronisation 82 // variable _dma_busy[i], after copying the status into the _dma_status[i] variable. 83 /////////////////////////////////////////////////////////////////////////////////// 84 void _isr_dma_indexed( unsigned int dma_id ) 85 { 86 volatile unsigned int* dma_address; 85 // This ISR handles all IRQs generated by the multi-channels DMA controlers. 86 // The multi_dma components can be distributed in the clusters. 87 // The channel_id argument is the global DMA channel index. 88 // channel_id = cluster_id*NB_DMAS_MAX + loc_id 89 // - The ISR saves the transfert status in _dma_status[channel_id]. 90 // - It acknowledges the interrupt to reinitialize the DMA controler. 91 // - it resets the synchronisation variable _dma_busy[channel_id]. 92 /////////////////////////////////////////////////////////////////////////////////// 93 void _isr_dma( unsigned int channel_id ) 94 { 95 // compute cluster_id and loc_id 96 unsigned int cluster_id = channel_id / NB_DMAS_MAX; 97 unsigned int loc_id = channel_id % NB_DMAS_MAX; 87 98 88 99 // compute DMA channel address 89 dma_address = (unsigned int*)&seg_dma_base + (dma_id * DMA_SPAN); 100 unsigned int* dma_address = (unsigned int*)&seg_dma_base + 101 (loc_id * DMA_SPAN) + 102 (cluster_id * CLUSTER_SPAN); 90 103 91 104 // save DMA channel status 92 _dma_status[ dma_id] = dma_address[DMA_LEN]; /* save status */105 _dma_status[channel_id] = dma_address[DMA_LEN]; 93 106 94 107 // reset DMA channel 95 dma_address[DMA_RESET] = 0; /* reset IRQ */108 dma_address[DMA_RESET] = 0; 96 109 97 110 // release DMA channel 98 _dma_busy[dma_id] = 0; /* release DMA */ 99 } 100 101 void _isr_dma_0() { _isr_dma_indexed(0); } 102 void _isr_dma_1() { _isr_dma_indexed(1); } 103 void _isr_dma_2() { _isr_dma_indexed(2); } 104 void _isr_dma_3() { _isr_dma_indexed(3); } 105 void _isr_dma_4() { _isr_dma_indexed(4); } 106 void _isr_dma_5() { _isr_dma_indexed(5); } 107 void _isr_dma_6() { _isr_dma_indexed(6); } 108 void _isr_dma_7() { _isr_dma_indexed(7); } 111 _dma_done[channel_id] = 1; 112 } 109 113 110 114 /////////////////////////////////////////////////////////////////////////////////// 111 115 // _isr_ioc() 112 // There is only one IOC controler shared by all tasks. It acknowledge the IRQ113 // using the ioc base address, save the status, and set the _ioc_done variable114 // to signal completion.116 // There is only one IOC controler shared by all tasks. 117 // - The ISR save the status and acknowledge the IRQ. 118 // - It sets the _ioc_done variable to signal completion. 115 119 /////////////////////////////////////////////////////////////////////////////////// 116 120 void _isr_ioc() 117 121 { 118 volatile unsigned int* ioc_address; 119 120 ioc_address = (unsigned int*)&seg_ioc_base; 122 unsigned int* ioc_address = (unsigned int*)&seg_ioc_base; 121 123 122 124 _ioc_status = ioc_address[BLOCK_DEVICE_STATUS]; /* save status & reset IRQ */ … … 125 127 126 128 /////////////////////////////////////////////////////////////////////////////////// 127 // _isr_timer_* (* = 0,1,2,3,4,5,6,7) 128 // This ISR handles up to 8 IRQs generated by 8 independant timers. 129 // It acknowledges the IRQ on TIMER[*] and displays a message on TTY0 130 /////////////////////////////////////////////////////////////////////////////////// 131 void _isr_timer_indexed(unsigned int timer_id) 132 { 133 volatile unsigned int *timer_address; 134 135 timer_address = (unsigned int*)&seg_timer_base + (timer_id * TIMER_SPAN); 136 137 timer_address[TIMER_RESETIRQ] = 0; /* reset IRQ */ 138 139 _puts("\n\n!!! Interrupt timer received from timer "); 140 _putw( timer_id ); 141 _puts(" at cycle "); 142 _putw( _proctime() ); 143 _puts("\n\n"); 144 } 145 146 void _isr_timer_0() { _isr_timer_indexed(0); } 147 void _isr_timer_1() { _isr_timer_indexed(1); } 148 void _isr_timer_2() { _isr_timer_indexed(2); } 149 void _isr_timer_3() { _isr_timer_indexed(3); } 150 void _isr_timer_4() { _isr_timer_indexed(4); } 151 void _isr_timer_5() { _isr_timer_indexed(5); } 152 void _isr_timer_6() { _isr_timer_indexed(6); } 153 void _isr_timer_7() { _isr_timer_indexed(7); } 154 155 /////////////////////////////////////////////////////////////////////////////////// 156 // _isr_tty_get_* (* = 0,1,2,3,4,5,6,7,9,10,11,12,13,14,15) 157 // The Giet supports up to 16 TTY terminals. 158 // These 16 ISRs handle the up to 16 IRQs associated to 16 independant 159 // terminals, signaling that a character is available. 160 // There is one communication buffer _tty_get_buf[tty_id] per terminal. 161 // The sychronisation variable _tty_get_full[tty_id], is set by the ISR, 129 // _isr_timer() 130 // This ISR handles the IRQs generated by the "user" timers (the IRQs 131 // generated by the "system" timers should be handled by the _isr_switch(). 132 // These timers are distributed in all clusters, and can be implemented 133 // in a vci_multi_timer component, or in a vci_xicu component. 134 // The channel_id argument is the global channel index: 135 // channel_id = cluster_id*(NB_TIMERS_MAX+NB_PROCS_MAX) + loc_id 136 // The user timer local index is (loc_id - NB_PROCS_MAX). 137 // 138 // The ISR acknowledges the IRQ and registers the event in the proper entry 139 // of the _timer_event[] array. 140 // A log message is displayed on the kernel terminal. 141 /////////////////////////////////////////////////////////////////////////////////// 142 void _isr_timer(unsigned int channel_id) 143 { 144 145 unsigned int cluster_id = channel_id / (NB_TIMERS_MAX + NB_PROCS_MAX); 146 unsigned int loc_id = channel_id % (NB_TIMERS_MAX + NB_PROCS_MAX); 147 148 if (loc_id < NB_PROCS_MAX ) 149 { 150 _puts("[GIET ERROR] Receiving a user timer IRQ for a system timer\n"); 151 _puts(" cluster = "); 152 _putw(cluster_id); 153 _puts(" / local_id = "); 154 _putw(loc_id); 155 } 156 157 #if GIET_USE_XICU 158 159 // TODO 160 161 #else 162 163 // compute Timer address 164 unsigned int* timer_address = (unsigned int*)&seg_timer_base + 165 (loc_id * TIMER_SPAN) + 166 (cluster_id * CLUSTER_SPAN); 167 168 // reset IRQ 169 timer_address[TIMER_RESETIRQ] = 0; 170 171 #endif 172 173 #if NB_TIMERS_MAX 174 // register the event 175 _timer_event[(cluster_id*NB_TIMERS_MAX) + (loc_id - NB_PROCS_MAX)] = 1; 176 #endif 177 178 // display a message on TTY 0 179 _puts("[GIET] User Timer IRQ / cluster = "); 180 _putw(cluster_id); 181 _puts(" / timer = "); 182 _putw(loc_id - NB_PROCS_MAX); 183 _puts("\n"); 184 } 185 186 /////////////////////////////////////////////////////////////////////////////////// 187 // _isr_tty() 188 // This ISR handles the IRQs generated by the multi_tty controler, 189 // signaling that a character is available. 190 // There is one single multi_tty component controling all TTYs, and the tty_id 191 // argument is the global TTY index. 192 // There is one communication buffer _tty_buf[tty_id] per terminal. 193 // The sychronisation variable _tty_full[tty_id], is set by the ISR, 162 194 // and reset by the OS. 163 195 // A character is lost if the buffer is full when the ISR is executed. 164 196 /////////////////////////////////////////////////////////////////////////////////// 165 void _isr_tty_get_indexed(unsigned int tty_id) 166 { 167 volatile unsigned int *tty_address; 168 169 /* compute terminal base address */ 170 tty_address = (unsigned int*)&seg_tty_base + (tty_id * TTY_SPAN); 171 172 /* save character and reset IRQ */ 197 void _isr_tty(unsigned int tty_id) 198 { 199 // compute terminal base address 200 unsigned int *tty_address = (unsigned int*)&seg_tty_base + (tty_id * TTY_SPAN); 201 202 // save character and reset IRQ 173 203 _tty_get_buf[tty_id] = (unsigned char)tty_address[TTY_READ]; 174 204 175 / * signals character available */205 // signals character available 176 206 _tty_get_full[tty_id] = 1; 177 207 } 178 179 void _isr_tty_get_0() { _isr_tty_get_indexed(0); }180 void _isr_tty_get_1() { _isr_tty_get_indexed(1); }181 void _isr_tty_get_2() { _isr_tty_get_indexed(2); }182 void _isr_tty_get_3() { _isr_tty_get_indexed(3); }183 void _isr_tty_get_4() { _isr_tty_get_indexed(4); }184 void _isr_tty_get_5() { _isr_tty_get_indexed(5); }185 void _isr_tty_get_6() { _isr_tty_get_indexed(6); }186 void _isr_tty_get_7() { _isr_tty_get_indexed(7); }187 void _isr_tty_get_8() { _isr_tty_get_indexed(8); }188 void _isr_tty_get_9() { _isr_tty_get_indexed(9); }189 void _isr_tty_get_10() { _isr_tty_get_indexed(10); }190 void _isr_tty_get_11() { _isr_tty_get_indexed(11); }191 void _isr_tty_get_12() { _isr_tty_get_indexed(12); }192 void _isr_tty_get_13() { _isr_tty_get_indexed(13); }193 void _isr_tty_get_14() { _isr_tty_get_indexed(14); }194 void _isr_tty_get_15() { _isr_tty_get_indexed(15); }195 208 196 209 ///////////////////////////////////////////////////////////////////////////////////// 197 210 // _isr_switch 198 // This ISR is in charge of context switch. 199 // It acknowledges the IRQ on TIMER[proc_id] and calls the _ctx_switch() function. 211 // This ISR is in charge of context switch, and handle the IRQs generated by 212 // the "system" timers. 213 // The IRQs can be generated by the MULTI_TIMER component or by the XICU component, 214 // that are distributed in all clusters. 215 // The ISR acknowledges the IRQ and calls the _ctx_switch() function. 200 216 ///////////////////////////////////////////////////////////////////////////////////// 201 217 void _isr_switch() 202 218 { 203 volatile unsigned int *timer_address; 204 unsigned int proc_id; 205 206 proc_id = _procid(); 207 timer_address = (unsigned int*)&seg_timer_base + (proc_id * TIMER_SPAN); 208 209 timer_address[TIMER_RESETIRQ] = 0; /* reset IRQ */ 219 // get cluster index and proc local index 220 unsigned int pid = _procid(); 221 unsigned int loc_id = pid % NB_PROCS_MAX; 222 unsigned int cluster_id = pid / NB_PROCS_MAX; 223 224 #if GIET_USE_XICU 225 226 unsigned int* timer_address = // TODO 227 228 #else 229 230 // compute Timer address 231 unsigned int* timer_address = (unsigned int*)&seg_timer_base + 232 (loc_id * TIMER_SPAN) + 233 (cluster_id * CLUSTER_SPAN); 234 235 // reset IRQ 236 timer_address[TIMER_RESETIRQ] = 0; 237 238 #endif 239 240 // performs the context switch 210 241 _ctx_switch(); 211 } 212 242 243 } 244 -
soft/giet_vm/sys/irq_handler.h
r165 r189 2 2 #define _IRQ_HANDLER_H 3 3 4 /* 5 * Interrupt Vector Table (indexed by interrupt index) 6 * 7 * 32 entries corresponding to 32 ISR addresses 8 */ 4 enum 5 { 6 ISR_DEFAULT = 0, 7 ISR_SWITCH = 1, 8 ISR_TTY = 2, 9 ISR_DMA = 3, 10 ISR_IOC = 4, 11 ISR_TIMER = 5, 12 }; 9 13 10 typedef void (*_isr_func_t)(void);11 extern _isr_func_t _interrupt_vector[32];12 14 13 /* 14 * Prototypes of the Interrupt Service Routines (ISRs) supported by the GIET. 15 * - they must be installed in reset.s 16 */ 15 /////////////////////////////////////////////////////////////////////////////// 16 // Prototypes of the Interrupt Service Routines (ISRs) supported by the GIET. 17 /////////////////////////////////////////////////////////////////////////////// 18 19 void _irq_demux(); 17 20 18 21 void _isr_default(); 19 20 void _isr_dma_0();21 void _isr_dma_1();22 void _isr_dma_2();23 void _isr_dma_3();24 void _isr_dma_4();25 void _isr_dma_5();26 void _isr_dma_6();27 void _isr_dma_7();28 29 22 void _isr_ioc(); 30 31 void _isr_timer_0(); 32 void _isr_timer_1(); 33 void _isr_timer_2(); 34 void _isr_timer_3(); 35 void _isr_timer_4(); 36 void _isr_timer_5(); 37 void _isr_timer_6(); 38 void _isr_timer_7(); 39 40 void _isr_tty_get(); 41 void _isr_tty_get_0(); 42 void _isr_tty_get_1(); 43 void _isr_tty_get_2(); 44 void _isr_tty_get_3(); 45 void _isr_tty_get_4(); 46 void _isr_tty_get_5(); 47 void _isr_tty_get_6(); 48 void _isr_tty_get_7(); 49 void _isr_tty_get_8(); 50 void _isr_tty_get_9(); 51 void _isr_tty_get_10(); 52 void _isr_tty_get_11(); 53 void _isr_tty_get_12(); 54 void _isr_tty_get_13(); 55 void _isr_tty_get_14(); 56 void _isr_tty_get_15(); 57 23 void _isr_timer( unsigned int channel ); 24 void _isr_dma( unsigned int channel ); 25 void _isr_tty( unsigned int channel ); 58 26 void _isr_switch(); 59 27 -
soft/giet_vm/sys/kernel_init.c
r185 r189 5 5 // Copyright (c) UPMC-LIP6 6 6 //////////////////////////////////////////////////////////////////////////////////// 7 // FIXME8 7 // The kernel_init.c files is part of the GIET-VM nano-kernel. 9 // It contains the kernel entry point for the second phase of system initialisation:10 // all processors are jumping to _kernel_init, but P[0] is first because other11 // processors are blocked until P[0] complete initilisation of task contexts,12 // vobjs and peripherals.13 // All procs in this phase have their MMU activated, because each processor P[i]14 // must initialise registers SP, SR, PTPR and EPC with informations stored15 // in _scheduler[i].8 // It contains the kernel entry point for the last step of system initialisation. 9 // All procs in this phase have their MMU activated, and are running in parallel. 10 // - each processor updates its own scheduler, to replace the ISR index 11 // by the actual ISR virtual address, and set its own entry in the 12 // kernel _schedulers_paddr[] array. 13 // - each processor initialises the SP, SR, PTPR, EPC registers, and starts 14 // its private Timer, before jumping to the user code with an eret. 16 15 //////////////////////////////////////////////////////////////////////////////////// 17 16 18 17 #include <common.h> 18 #include <irq_handler.h> 19 19 #include <ctx_handler.h> 20 20 #include <sys_handler.h> … … 29 29 #include <drivers.h> 30 30 31 #define in_kinit __attribute__((section (".kinit")))32 33 31 /////////////////////////////////////////////////////////////////////////////////// 34 // array of pointers on the page tables 35 // (both physical and virtual addresses) 32 // Kernel Global variables 36 33 /////////////////////////////////////////////////////////////////////////////////// 37 34 38 __attribute__((section (".kdata"))) unsigned int _kernel_ptabs_paddr[GIET_NB_VSPACE_MAX];39 __attribute__((section (".kdata"))) unsigned int _kernel_ptabs_vaddr[GIET_NB_VSPACE_MAX];35 __attribute__((section (".kdata"))) 36 page_table_t* _ptabs_paddr[GIET_NB_VSPACE_MAX]; 40 37 41 /////////////////////////////////////////////////////////////////////////////////// 42 // declarations required to avoid forward references 43 /////////////////////////////////////////////////////////////////////////////////// 38 __attribute__((section (".kdata"))) 39 page_table_t* _ptabs_vaddr[GIET_NB_VSPACE_MAX]; 44 40 45 void _kernel_ptabs_init(void); 46 void _kernel_vobjs_init(void); 47 void _kernel_tasks_init(void); 48 void _kernel_peripherals_init(void); 49 void _kernel_interrupt_vector_init(void); 50 void _kernel_start_all_procs(void); 41 __attribute__((section (".kdata"))) 42 static_scheduler_t* _schedulers_paddr[NB_CLUSTERS*NB_PROCS_MAX]; 51 43 52 44 ////////////////////////////////////////////////////////////////////////////////// 53 // This function is the entry point for the secondstep of the boot sequence.45 // This function is the entry point for the last step of the boot sequence. 54 46 ////////////////////////////////////////////////////////////////////////////////// 55 in_kinitvoid _kernel_init()47 __attribute__((section (".kinit"))) void _kernel_init() 56 48 { 57 49 // values to be written in registers … … 61 53 unsigned int epc_value; 62 54 63 unsigned int pid = _procid(); 55 unsigned int proc_id = _procid(); 56 unsigned int cluster_id = proc_id / NB_PROCS_MAX; 57 unsigned int lpid = proc_id % NB_PROCS_MAX; 64 58 65 // only processor 0 executes system initialisation 66 if ( pid == 0 ) 59 // step 1 : Initialise scheduler physical addresses array 60 61 // get scheduler physical address from register 62 static_scheduler_t* psched = (static_scheduler_t*)_get_sched(); 63 _schedulers_paddr[proc_id] = psched; 64 65 #if GIET_DEBUG_INIT 66 _get_lock(&_tty_put_lock); 67 _puts("\n[GIET DEBUG] step 1 for processor "); 68 _putw( proc_id ); 69 _puts("\n"); 70 _puts("- scheduler pbase = "); 71 _putw( (unsigned int)psched ); 72 _puts("\n"); 73 _release_lock(&_tty_put_lock); 74 #endif 75 76 // step 2 : compute and set ICU mask 77 unsigned int irq_id; 78 unsigned int mask = 0; 79 for ( irq_id = 0 ; irq_id < 32 ; irq_id++ ) 67 80 { 68 _kernel_ptabs_init(); 69 /* must be called after the initialisation of ptabs */ 70 _kernel_vobjs_init(); 71 _kernel_tasks_init(); 72 _kernel_interrupt_vector_init(); 73 _kernel_peripherals_init(); 74 _kernel_start_all_procs(); 81 unsigned int entry = _get_interrupt_vector_entry(irq_id); 82 if ( entry ) mask = mask | 0x1<< irq_id; 75 83 } 84 _icu_write( cluster_id, 85 lpid, 86 ICU_MASK_SET, 87 mask ); 88 89 #if GIET_DEBUG_INIT 90 _get_lock(&_tty_put_lock); 91 _puts("\n[GIET DEBUG] step 2 for processor "); 92 _putw( proc_id ); 93 _puts("\n"); 94 _puts("- ICU mask = "); 95 _putw( mask ); 96 _puts("\n"); 97 _release_lock(&_tty_put_lock); 98 #endif 76 99 77 // each processor initialises it's SP, SR, PTPR, and EPC registers78 // from values defined in _scheduler[pid], starts it's private79 // context switch timer (if there is more than one task allocated)80 // and jumps to user code.81 // It does nothing, and keep idle if no task allocated.82 100 83 static_scheduler_t* sched = &_scheduler[pid];101 // step 3 : TODO initialise page table addresse arrays 84 102 85 if ( sched->tasks ) // at leat one task allocated 103 104 // step 4 : start TICK timer if more than one task 105 unsigned int tasks = _get_tasks_number(); 106 if ( tasks > 1 ) 107 { 108 unsigned int period = GIET_TICK_VALUE; 109 unsigned int mode = 0x3; 110 _timer_access( 0, // write access 111 cluster_id, 112 proc_id, 113 TIMER_PERIOD, 114 &period ); 115 _timer_access( 0, // write access 116 cluster_id, 117 proc_id, 118 TIMER_MODE, 119 &mode ); 120 121 #if GIET_DEBUG_INIT 122 _get_lock(&_tty_put_lock); 123 _puts("\n[GIET DEBUG] Step 4 for processor "); 124 _putw( proc_id ); 125 _puts("\n"); 126 _puts("- TICK period = "); 127 _putd( period ); 128 _puts("\n"); 129 _release_lock(&_tty_put_lock); 130 #endif 131 132 } 133 134 // step 5 : each processor initialises SP, SR, PTPR, EPC, registers 135 // with the values corresponding to the first allocated task, 136 // It does nothing, and keep idle if no task allocated. 137 138 if ( tasks ) // at leat one task allocated 86 139 { 87 140 // initialise registers 88 sp_value = sched->context[0][CTX_SP_ID];89 sr_value = sched->context[0][CTX_SR_ID];90 ptpr_value = sched->context[0][CTX_PTPR_ID];91 epc_value = sched->context[0][CTX_EPC_ID];141 sp_value = _get_current_context_slot(CTX_SP_ID); 142 sr_value = _get_current_context_slot(CTX_SR_ID); 143 ptpr_value = _get_current_context_slot(CTX_PTPR_ID); 144 epc_value = _get_current_context_slot(CTX_EPC_ID); 92 145 93 // start TICK timer 94 if ( sched->tasks > 1 ) 95 { 96 unsigned int cluster_id = pid / NB_PROCS; 97 unsigned int proc_id = pid % NB_PROCS; 98 _timer_write( cluster_id, proc_id, TIMER_PERIOD, GIET_TICK_VALUE ); 99 _timer_write( cluster_id, proc_id, TIMER_MODE , 0x3 ); 100 } 146 #if GIET_DEBUG_INIT 147 _get_lock(&_tty_put_lock); 148 _puts("\n[GIET DEBUG] step 5 for processor "); 149 _putw( proc_id ); 150 _puts("\n"); 151 _puts("- sp = "); 152 _putw( sp_value ); 153 _puts("\n"); 154 _puts("- sr = "); 155 _putw( sr_value ); 156 _puts("\n"); 157 _puts("- ptpr = "); 158 _putw( ptpr_value<<13 ); 159 _puts("\n"); 160 _puts("- epc = "); 161 _putw( epc_value ); 162 _puts("\n"); 163 _release_lock(&_tty_put_lock); 164 #endif 101 165 } 102 166 else // no task allocated … … 104 168 _get_lock( &_tty_put_lock ); 105 169 _puts("\n No task allocated to processor "); 106 _putw( p id );170 _putw( proc_id ); 107 171 _puts(" => keep idle\n"); 108 172 _release_lock ( &_tty_put_lock ); … … 117 181 } 118 182 183 // set critical registers and jump to user code 119 184 asm volatile ( 120 185 "move $29, %0 \n" /* SP <= ctx[CTX_SP_ID] */ … … 128 193 129 194 } // end _kernel_init() 130 131 //////////////////////////////////////////////////////////////////////////////////132 // This function wakeup all processors.133 // It should be executed by P[0] when the kernel initialisation is done.134 //////////////////////////////////////////////////////////////////////////////////135 in_kinit void _kernel_start_all_procs()136 {137 mapping_header_t* header = (mapping_header_t*)&seg_mapping_base;138 139 _puts("\n[INIT] Starting parallel execution at cycle : ");140 _putw( _proctime() );141 _puts("\n");142 143 header->signature = OUT_MAPPING_SIGNATURE;144 }145 146 //////////////////////////////////////////////////////////////////////////////////147 // _eret()148 // The address of this function is used to initialise the return address (RA)149 // in all task contexts (when the task has never been executed.150 //////////////////////////////////////////////////////////////////////////////////151 in_kinit void _eret()152 {153 asm volatile("eret \n"154 "nop");155 }156 157 ///////////////////////////////////////////////////////////////////////////////158 // used to access user space159 ///////////////////////////////////////////////////////////////////////////////160 void _set_ptpr(unsigned int vspace_id)161 {162 unsigned int ptpr = ((unsigned int)_kernel_ptabs_paddr[vspace_id]) >> 13;163 asm volatile("mtc2 %0, $0"::"r"(ptpr));164 }165 166 ///////////////////////////////////////////////////////////////////////////////167 // This function initialises the _kernel_ptabs_paddr[] array indexed by the vspace_id,168 // and containing the base addresses of all page tables.169 // This _kernel_ptabs_paddr[] array is used to initialise the task contexts.170 ///////////////////////////////////////////////////////////////////////////////171 in_kinit void _kernel_ptabs_init()172 {173 mapping_header_t* header = (mapping_header_t*)&seg_mapping_base;174 mapping_vspace_t* vspace = _get_vspace_base( header );175 mapping_vobj_t* vobj = _get_vobj_base( header );176 177 unsigned int vspace_id;178 unsigned int vobj_id;179 180 // loop on the vspaces181 for ( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )182 {183 char ptab_found = 0;184 185 #if INIT_DEBUG_CTX186 _puts("[INIT] --- ptabs initialisation in vspace ");187 _puts(vspace[vspace_id].name);188 _puts("\n");189 #endif190 // loop on the vobjs and get the ptpr191 for(vobj_id= vspace[vspace_id].vobj_offset;192 vobj_id < (vspace[vspace_id].vobj_offset+ vspace[vspace_id].vobjs);193 vobj_id++)194 {195 if(vobj[vobj_id].type == VOBJ_TYPE_PTAB)196 {197 if( ptab_found )198 {199 _puts("\n[INIT ERROR] Only one PTAB for by vspace ");200 _putw( vspace_id );201 _exit();202 }203 204 ptab_found = 1;205 _kernel_ptabs_paddr[vspace_id] = vobj[vobj_id].paddr;206 _kernel_ptabs_vaddr[vspace_id] = vobj[vobj_id].vaddr;207 208 #if INIT_DEBUG_CTX209 _puts("[INIT] PTAB address = ");210 _putw(_kernel_ptabs_paddr[vspace_id]);211 _puts("\n");212 #endif213 }214 215 }216 217 if( !ptab_found )218 {219 _puts("\n[INIT ERROR] Missing PTAB for vspace ");220 _putw( vspace_id );221 _exit();222 }223 }224 225 _puts("\n[INIT] Ptabs initialisation completed at cycle : ");226 _putw( _proctime() );227 _puts("\n");228 229 } // end kernel_ptabs_init()230 231 ///////////////////////////////////////////////////////////////////////////////232 // This function initializes all private vobjs defined in the vspaces,233 // such as mwmr channels, barriers and locks, depending on the vobj type.234 // (Most of the vobjs are not known, and not initialised by the compiler).235 ///////////////////////////////////////////////////////////////////////////////236 in_kinit void _kernel_vobjs_init()237 {238 mapping_header_t* header = (mapping_header_t*)&seg_mapping_base;239 mapping_vspace_t* vspace = _get_vspace_base( header );240 mapping_vobj_t* vobj = _get_vobj_base( header );241 242 unsigned int vspace_id;243 unsigned int vobj_id;244 245 // loop on the vspaces246 for ( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )247 {248 249 #if INIT_DEBUG_CTX250 _puts("[INIT] --- vobjs initialisation in vspace ");251 _puts(vspace[vspace_id].name);252 _puts("\n");253 #endif254 /** Set the current vspace ptpr to initialise the vobjs */255 _set_ptpr(vspace_id);256 257 // loop on the vobjs and get the ptpr258 for(vobj_id= vspace[vspace_id].vobj_offset;259 vobj_id < (vspace[vspace_id].vobj_offset+ vspace[vspace_id].vobjs);260 vobj_id++)261 {262 switch( vobj[vobj_id].type )263 {264 case VOBJ_TYPE_PTAB: // initialise page table pointers array265 {266 break;//already handled267 }268 case VOBJ_TYPE_MWMR: // storage capacity is (vobj.length/4 - 5) words269 {270 mwmr_channel_t* mwmr = (mwmr_channel_t*)(vobj[vobj_id].vaddr);271 mwmr->ptw = 0;272 mwmr->ptr = 0;273 mwmr->sts = 0;274 mwmr->depth = ((vobj[vobj_id].length>>2) - 6);//6= number of entry in the strucure275 mwmr->width = vobj[vobj_id].init;276 mwmr->lock = 0;277 #if INIT_DEBUG_CTX278 _puts("[INIT] MWMR channel ");279 _puts( vobj[vobj_id].name);280 _puts(" / depth = ");281 _putw( mwmr->depth );282 _puts("\n");283 #endif284 break;285 }286 case VOBJ_TYPE_ELF: // initialisation done by the loader287 {288 289 #if INIT_DEBUG_CTX290 _puts("[INIT] ELF section ");291 _puts( vobj[vobj_id].name);292 _puts(" / length = ");293 _putw( vobj[vobj_id].length );294 _puts("\n");295 #endif296 break;297 }298 case VOBJ_TYPE_BARRIER: // init is the number of participants299 {300 giet_barrier_t* barrier = (giet_barrier_t*)(vobj[vobj_id].vaddr);301 barrier->count = 0;302 barrier->init = vobj[vobj_id].init;303 #if INIT_DEBUG_CTX304 _puts(" BARRIER ");305 _puts( vobj[vobj_id].name);306 _puts(" / init_value = ");307 _putw( barrier->init );308 _puts("\n");309 #endif310 break;311 }312 case VOBJ_TYPE_LOCK: // init is "not taken"313 {314 unsigned int* lock = (unsigned int*)(vobj[vobj_id].vaddr);315 *lock = 0;316 #if INIT_DEBUG_CTX317 _puts(" LOCK ");318 _puts( vobj[vobj_id].name);319 _puts("\n");320 #endif321 break;322 }323 case VOBJ_TYPE_BUFFER: // nothing to do324 {325 326 #if INIT_DEBUG_CTX327 _puts(" BUFFER ");328 _puts( vobj[vobj_id].name);329 _puts(" / length = ");330 _putw( vobj[vobj_id].length );331 _puts("\n");332 #endif333 break;334 }335 default:336 {337 _puts("\n[INIT ERROR] illegal vobj of name ");338 _puts(vobj[vobj_id].name);339 _puts(" / in vspace = ");340 _puts(vobj[vobj_id].name);341 _puts("\n ");342 _exit();343 }344 } // end switch type345 } // end loop on vobjs346 } // end loop on vspaces347 348 _puts("\n[INIT] Vobjs initialisation completed at cycle : ");349 _putw( _proctime() );350 _puts("\n");351 352 } // end kernel_vobjs_init()353 354 ///////////////////////////////////////////////////////////////////////////////355 // This function maps a given task, defined in a given vspace356 // on the processor allocated in the mapping_info structure,357 // and initialises the task context.358 // There is one scheduler per processor, and processor can be shared359 // by several applications running in different vspaces.360 // There is one private context array handled by each scheduler.361 //362 // The following values must be initialised in all task contexts:363 // - sp stack pointer = stack_base + stack_length364 // - ra return address = &_eret365 // - epc start address = start_vector[task->startid]366 // - sr status register = OxFF13367 // - tty TTY terminal index (global index)368 // - fb FB_DMA channel index (global index)369 // - ptpr page table base address / 8K370 // - mode mmu_mode = 0xF (TLBs and caches activated)371 // - ptab page table virtual address372 ////////////////////////////////////////////////////////////////////////////////373 in_kinit void _task_map( unsigned int task_id, // global index374 unsigned int vspace_id, // global index375 unsigned int tty_id, // TTY index376 unsigned int fbdma_id ) // FBDMA index377 {378 mapping_header_t* header = (mapping_header_t*)&seg_mapping_base;379 380 mapping_task_t* task = _get_task_base(header);381 mapping_vspace_t* vspace = _get_vspace_base(header);382 mapping_vobj_t* vobj = _get_vobj_base( header );383 384 /** Set the current vspace ptpr before acessing the memory */385 _set_ptpr(vspace_id);386 387 // values to be initialised in task context388 unsigned int ra = (unsigned int)&_eret;389 unsigned int sr = 0x0000FF13;390 unsigned int tty = tty_id;391 unsigned int fb = fbdma_id;392 unsigned int ptpr = _kernel_ptabs_paddr[vspace_id] >> 13;393 unsigned int ptab = _kernel_ptabs_vaddr[vspace_id];394 unsigned int mode = 0xF;395 unsigned int sp;396 unsigned int epc;397 398 // EPC : Get the (virtual) base address of the start_vector containing399 // the start addresses for all tasks defined in a vspace.400 mapping_vobj_t* vobj_data = &vobj[vspace[vspace_id].vobj_offset +401 vspace[vspace_id].start_offset];402 unsigned int* start_vector = (unsigned int*)vobj_data->vaddr;403 epc = start_vector[task[task_id].startid];404 405 // SP : Get the vobj containing the stack406 unsigned int vobj_id = task[task_id].vobjlocid + vspace[vspace_id].vobj_offset;407 sp = vobj[vobj_id].vaddr + vobj[vobj_id].length;408 409 // compute global processor index410 unsigned int proc_id = task[task_id].clusterid * NB_PROCS + task[task_id].proclocid;411 412 // compute and check local task index413 unsigned int ltid = _scheduler[proc_id].tasks;414 if ( ltid >= GIET_NB_TASKS_MAX )415 {416 _puts("\n[INIT ERROR] : too much tasks allocated to processor ");417 _putw( proc_id );418 _puts("\n");419 _exit();420 }421 422 // update number of tasks allocated to scheduler423 _scheduler[proc_id].tasks = ltid + 1;424 425 // initializes the task context426 _scheduler[proc_id].context[ltid][CTX_SR_ID] = sr;427 _scheduler[proc_id].context[ltid][CTX_SP_ID] = sp;428 _scheduler[proc_id].context[ltid][CTX_RA_ID] = ra;429 _scheduler[proc_id].context[ltid][CTX_EPC_ID] = epc;430 _scheduler[proc_id].context[ltid][CTX_PTPR_ID] = ptpr;431 _scheduler[proc_id].context[ltid][CTX_MODE_ID] = mode;432 _scheduler[proc_id].context[ltid][CTX_TTY_ID] = tty;433 _scheduler[proc_id].context[ltid][CTX_FBDMA_ID] = fb;434 _scheduler[proc_id].context[ltid][CTX_PTAB_ID] = ptab;435 _scheduler[proc_id].context[ltid][CTX_TASK_ID] = task_id;436 437 #if INIT_DEBUG_CTX438 _puts("Task ");439 _puts( task[task_id].name );440 _puts(" allocated to processor ");441 _putw( proc_id );442 _puts(" / ltid = ");443 _putw( ltid );444 _puts("\n");445 446 _puts(" - SR = ");447 _putw( sr );448 _puts(" saved at ");449 _putw( (unsigned int)&_scheduler[proc_id].context[ltid][CTX_SR_ID] );450 _puts("\n");451 452 _puts(" - RA = ");453 _putw( ra );454 _puts(" saved at ");455 _putw( (unsigned int)&_scheduler[proc_id].context[ltid][CTX_RA_ID] );456 _puts("\n");457 458 _puts(" - SP = ");459 _putw( sp );460 _puts(" saved at ");461 _putw( (unsigned int)&_scheduler[proc_id].context[ltid][CTX_SP_ID] );462 _puts("\n");463 464 _puts(" - EPC = ");465 _putw( epc );466 _puts(" saved at ");467 _putw( (unsigned int)&_scheduler[proc_id].context[ltid][CTX_EPC_ID] );468 _puts("\n");469 470 _puts(" - PTPR = ");471 _putw( ptpr<<13 );472 _puts(" saved at ");473 _putw( (unsigned int)&_scheduler[proc_id].context[ltid][CTX_PTPR_ID] );474 _puts("\n");475 476 _puts(" - TTY = ");477 _putw( tty );478 _puts(" saved at ");479 _putw( (unsigned int)&_scheduler[proc_id].context[ltid][CTX_TTY_ID] );480 _puts("\n");481 482 _puts(" - FB = ");483 _putw( fb );484 _puts(" saved at ");485 _putw( (unsigned int)&_scheduler[proc_id].context[ltid][CTX_FBDMA_ID] );486 _puts("\n");487 488 _puts(" - PTAB = ");489 _putw( ptab );490 _puts(" saved at ");491 _putw( (unsigned int)&_scheduler[proc_id].context[ltid][CTX_PTAB_ID] );492 _puts("\n");493 #endif494 495 } // end _task_map()496 497 ///////////////////////////////////////////////////////////////////////////////498 // This function initialises all task contexts and processors schedulers.499 // It sets the default values for all schedulers (tasks <= 0, current <= 0).500 // Finally, it scan all tasks in all vspaces to initialise the schedulers,501 // and the tasks contexts, as defined in the mapping_info data structure.502 // A global TTY index and a global FB channel are allocated if required.503 // TTY[0] is reserved for the kernel.504 ///////////////////////////////////////////////////////////////////////////////505 in_kinit void _kernel_tasks_init()506 {507 mapping_header_t* header = (mapping_header_t*)&seg_mapping_base;508 mapping_cluster_t* cluster = _get_cluster_base( header );509 mapping_vspace_t* vspace = _get_vspace_base( header );510 mapping_task_t* task = _get_task_base( header );511 512 unsigned int base_tty_id = 1; // TTY index allocator513 unsigned int base_fb_id = 0; // FB channel index allocator514 515 unsigned int cluster_id;516 unsigned int proc_id;517 unsigned int vspace_id;518 unsigned int task_id;519 520 // initialise the schedulers (not done by the compiler)521 for ( cluster_id = 0 ; cluster_id < header->clusters ; cluster_id++ )522 {523 for ( proc_id = 0 ; proc_id < cluster[cluster_id].procs ; proc_id++ )524 {525 if ( proc_id >= NB_PROCS )526 {527 _puts("\n[INIT ERROR] The number of processors in cluster ");528 _putw( cluster_id );529 _puts(" is larger than NB_PROCS \n");530 _exit();531 }532 _scheduler[cluster_id*NB_PROCS+proc_id].tasks = 0;533 _scheduler[cluster_id*NB_PROCS+proc_id].current = 0;534 }535 }536 537 // loop on the virtual spaces538 for ( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )539 {540 541 #if INIT_DEBUG_CTX542 _puts("\n[INIT] mapping tasks in vspace ");543 _puts(vspace[vspace_id].name);544 _puts("\n");545 #endif546 // loop on the tasks547 for ( task_id = vspace[vspace_id].task_offset ;548 task_id < (vspace[vspace_id].task_offset + vspace[vspace_id].tasks) ;549 task_id++ )550 {551 unsigned int tty_id = 0xFFFFFFFF;552 unsigned int fb_id = 0xFFFFFFFF;553 if ( task[task_id].use_tty )554 {555 tty_id = base_tty_id;556 base_tty_id++;557 }558 if ( task[task_id].use_fb )559 {560 fb_id = base_fb_id;561 base_fb_id++;562 }563 _task_map( task_id, // global task index564 vspace_id, // vspace index565 tty_id, // global tty index566 fb_id ); // global fbdma index567 } // end loop on tasks568 } // end oop on vspaces569 570 _puts("\n[INIT] Task Contexts initialisation completed at cycle ");571 _putw( _proctime() );572 _puts("\n");573 574 #if INIT_DEBUG_CTX575 for ( cluster_id = 0 ; cluster_id < header->clusters ; cluster_id++ )576 {577 _puts("\nCluster ");578 _putw( cluster_id );579 _puts("\n");580 for ( proc_id = 0 ; proc_id < cluster[cluster_id].procs ; proc_id++ )581 {582 unsigned int ltid; // local task index583 unsigned int gtid; // global task index584 unsigned int pid = cluster_id * NB_PROCS + proc_id;585 586 _puts(" - processor ");587 _putw( pid );588 _puts("\n");589 for ( ltid = 0 ; ltid < _scheduler[pid].tasks ; ltid++ )590 {591 gtid = _scheduler[pid].context[ltid][CTX_TASK_ID];592 _puts(" task : ");593 _puts( task[gtid].name );594 _puts("\n");595 }596 }597 }598 #endif599 600 } // end _kernel_task_init()601 602 ////////////////////////////////////////////////////////////////////////////////603 // This function intializes the external periherals such as the IOB component604 // (I/O bridge, containing the IOMMU, the IOC (external disk controller),605 // the NIC (external network controller), the FBDMA (frame buffer controller),606 ////////////////////////////////////////////////////////////////////////////////607 in_kinit void _kernel_peripherals_init()608 {609 /////////////////////610 // IOC peripheral611 // we simply activate the IOC interrupts...612 if ( NB_IOC )613 {614 unsigned int* ioc_address = (unsigned int*)&seg_ioc_base;615 ioc_address[BLOCK_DEVICE_IRQ_ENABLE] = 1;616 }617 618 /////////////////////619 // FBDMA peripheral620 // we simply activate the DMA interrupts...621 if ( NB_DMAS )622 {623 unsigned int* dma_address = (unsigned int*)&seg_dma_base;624 dma_address[DMA_IRQ_DISABLE] = 0;625 }626 627 /////////////////////628 // IOB peripheral629 // must be initialised in case of IOMMU630 if ( GIET_IOMMU_ACTIVE )631 {632 unsigned int* iob_address = (unsigned int*)&seg_iob_base;633 634 // define IPI address mapping the IOC interrupt ...TODO...635 636 // set IOMMU page table address637 iob_address[IOB_IOMMU_PTPR] = (unsigned int)(&_iommu_ptab);638 639 // activate IOMMU640 iob_address[IOB_IOMMU_ACTIVE] = 1;641 }642 643 _puts("\n[INIT] Peripherals initialisation completed at cycle ");644 _putw( _proctime() );645 _puts("\n");646 647 } // end _kernel_peripherals_init()648 649 ////////////////////////////////////////////////////////////////////////////////650 // This function intialises the interrupt vector, and initialises651 // the ICU mask registers for all processors in all clusters.652 // It strongly depends on the actual peripheral hardware wiring.653 // In this peculiar version, all clusters are identical,654 // the number of processors per cluster cannot be larger than 8.655 // Processor 0 handle all interrupts corresponding to TTYs, DMAs and IOC656 // (ICU inputs from from IRQ[8] to IRQ[31]). Only the 8 TIMER interrupts657 // (ICU iputs IRQ[0] to IRQ[7]), that are used for context switching658 // are distributed to the 8 processors.659 ////////////////////////////////////////////////////////////////////////////////660 in_kinit void _kernel_interrupt_vector_init()661 {662 mapping_header_t* header = (mapping_header_t*)&seg_mapping_base;663 mapping_cluster_t* cluster = _get_cluster_base( header );664 665 unsigned int cluster_id;666 unsigned int proc_id;667 668 // ICU mask values (up to 8 processors per cluster)669 unsigned int icu_mask[8] = { 0xFFFFFF01,670 0x00000002,671 0x00000004,672 0x00000008,673 0x00000010,674 0x00000020,675 0x00000040,676 0x00000080 };677 678 // initialise ICUs for each processor in each cluster679 for ( cluster_id = 0 ; cluster_id < header->clusters ; cluster_id++ )680 {681 for ( proc_id = 0 ; proc_id < cluster[cluster_id].procs ; proc_id++ )682 {683 _icu_write( cluster_id, proc_id, ICU_MASK_SET, icu_mask[proc_id] );684 }685 }686 687 // initialize Interrupt vector688 689 _interrupt_vector[0] = &_isr_switch;690 _interrupt_vector[1] = &_isr_switch;691 _interrupt_vector[2] = &_isr_switch;692 _interrupt_vector[3] = &_isr_switch;693 _interrupt_vector[4] = &_isr_switch;694 _interrupt_vector[5] = &_isr_switch;695 _interrupt_vector[6] = &_isr_switch;696 _interrupt_vector[7] = &_isr_switch;697 698 _interrupt_vector[8] = &_isr_dma_0;699 _interrupt_vector[9] = &_isr_dma_1;700 _interrupt_vector[10] = &_isr_dma_2;701 _interrupt_vector[11] = &_isr_dma_3;702 _interrupt_vector[12] = &_isr_dma_4;703 _interrupt_vector[13] = &_isr_dma_5;704 _interrupt_vector[14] = &_isr_dma_6;705 _interrupt_vector[15] = &_isr_dma_7;706 707 _interrupt_vector[16] = &_isr_tty_get_0;708 _interrupt_vector[17] = &_isr_tty_get_1;709 _interrupt_vector[18] = &_isr_tty_get_2;710 _interrupt_vector[19] = &_isr_tty_get_3;711 _interrupt_vector[20] = &_isr_tty_get_4;712 _interrupt_vector[21] = &_isr_tty_get_5;713 _interrupt_vector[22] = &_isr_tty_get_6;714 _interrupt_vector[23] = &_isr_tty_get_7;715 _interrupt_vector[24] = &_isr_tty_get_8;716 _interrupt_vector[25] = &_isr_tty_get_9;717 _interrupt_vector[26] = &_isr_tty_get_10;718 _interrupt_vector[27] = &_isr_tty_get_11;719 _interrupt_vector[28] = &_isr_tty_get_12;720 _interrupt_vector[29] = &_isr_tty_get_13;721 _interrupt_vector[30] = &_isr_tty_get_14;722 723 _interrupt_vector[31] = &_isr_ioc;724 725 _puts("\n[INIT] Interrupt vector initialisation completed at cycle ");726 _putw( _proctime() );727 _puts("\n");728 729 } // end _kernel_interrup_vector_init() -
soft/giet_vm/sys/mips32_registers.h
r167 r189 53 53 #define CP0_EPC $14 54 54 #define CP0_PROCID $15,1 55 #define CP0_SCHED $22 55 56 56 57 /* CP2 registers */ -
soft/giet_vm/sys/switch.s
r158 r189 1 1 /****************************************************************************** 2 * This function receives two arguments representing addresses of task 3 * contexts, respectively for the current running task to be descheduled and 4 * for the next task to be scheduled. 2 * This function receives two arguments that are the current task context 3 * physical addresses and the next task context physical address. 5 4 ******************************************************************************/ 6 5 … … 11 10 _task_switch: 12 11 12 /* desactivate DTLB */ 13 ori $27, $0, 0xB 14 mtc2 $27, $1 /* DTLB desactivated */ 15 13 16 /* save _current task context */ 14 15 17 add $27, $4, $0 /* $27 <= &context[curr_task_id] */ 16 18 … … 58 60 mfc2 $26, $0 59 61 sw $26, 35*4($27) /* ctx[35] <= PTPR */ 60 mfc2 $26, $161 sw $26, 36*4($27) /* ctx[36] <= MODE */62 62 63 63 /* restore next task context */ 64 65 64 add $27, $5, $0 /* $27<= &context[next_task_id] */ 66 65 67 66 lw $26, 35*4($27) 68 67 mtc2 $26, $0 /* restore PTPR */ 69 lw $26, 36*4($27)70 mtc2 $26, $1 /* restore MODE */71 68 lw $26, 0*4($27) 72 69 mtc0 $26, $12 /* restore SR */ … … 111 108 mtc0 $26, $13 /* restore CR */ 112 109 113 jr $31 /* returns to caller */ 110 /* activate DTLB */ 111 ori $27, $0, 0xF 112 mtc2 $27, $1 113 114 /* returns to caller */ 115 jr $31 114 116 115 117 .endfunc -
soft/giet_vm/sys/sys_handler.c
r167 r189 75 75 void _exit() 76 76 { 77 /* 77 78 unsigned int date = _proctime(); 79 78 80 unsigned int proc_id = _procid(); 79 unsigned int task_id = _scheduler[proc_id].current; 81 82 unsigned int task_id = _get_current_task_id(); 80 83 81 84 // print death message 85 _get_lock(&_tty_put_lock); 82 86 _puts("\n\n!!! Exit task "); 83 87 _putw( task_id ); … … 87 91 _putw( date ); 88 92 _puts("\n\n"); 89 93 _release_lock(&_tty_put_lock); 94 */ 95 90 96 /* infinite loop */ 91 97 while (1) asm volatile("nop"); -
soft/giet_vm/sys/vm_handler.c
r184 r189 118 118 119 119 // gets ppn_value and flags_value, after temporary DTLB desactivation 120 asm volatile ( 121 "li $27, 0xFFFFFFFE \n" /* Mask for IE bits */ 122 "mfc0 $8, $12 \n" /* $8 <= SR */ 123 "and $26, $8, $27 \n" /* $26 <= SR && 0xFFFFFFE */ 124 "mtc0 $26, $12 \n" /* disable Interrupts */ 120 asm volatile ( "li $27, 0xFFFFFFFE \n" /* Mask for IE bits */ 121 "mfc0 $26, $12 \n" /* save SR */ 122 "and $27, $26, $27 \n" 123 "mtc0 $27, $12 \n" /* disable Interrupts */ 124 125 "li $27, 0xB \n" 126 "mtc2 $27, $1 \n" /* DTLB unactivated */ 125 127 126 128 "move $27, %2 \n" /* $27 <= pte2 */ 127 "li $26, 0xB \n" /* DTLB unactivated */128 "mtc2 $26, $1 \n"129 129 "lw %0, 0($27) \n" /* read flags */ 130 130 "lw %1, 4($27) \n" /* read ppn */ 131 "li $26, 0xF \n"132 "mtc2 $26, $1 \n" /* DTLB activated */133 131 134 "or $26, $8, $0 \n" /* SR previous state */ 132 "li $27, 0xF \n" 133 "mtc2 $27, $1 \n" /* DTLB activated */ 134 135 "mtc0 $26, $12 \n" /* restore SR */ 135 136 :"=r"(flags_value), "=r"(ppn_value) 136 137 :"r"(pte2) -
soft/giet_vm/sys/vm_handler.h
r180 r189 53 53 typedef struct PageTable 54 54 { 55 unsigned int pt1[PT1_SIZE/4]; // PT1 (index is ix1) 56 unsigned int pt2[1][PT2_SIZE/4]; // PT2s (index is 2*ix2) 57 /* The number `1` is onmy here to indicate to the compiler that this is a table 58 ** of two dimension and the actual value is computed dynamically(see boot_handler.c)*/ 55 unsigned int pt1[PT1_SIZE/4]; // PT1 (index is ix1) 56 unsigned int pt2[GIET_NB_PT2_MAX][PT2_SIZE/4]; // PT2s (index is 2*ix2) 59 57 } page_table_t; 60 58
Note: See TracChangeset
for help on using the changeset viewer.