POK(kernelpart)
|
00001 /* 00002 * POK header 00003 * 00004 * The following file is a part of the POK project. Any modification should 00005 * made according to the POK licence. You CANNOT use this file or a part of 00006 * this file is this part of a file for your own project 00007 * 00008 * For more information on the POK licence, please see our LICENCE FILE 00009 * 00010 * Please follow the coding guidelines described in doc/CODING_GUIDELINES 00011 * 00012 * Copyright (c) 2007-2009 POK team 00013 * 00014 * Created by julien on Thu Jan 15 23:34:13 2009 00015 */ 00016 00027 #ifdef POK_NEEDS_PARTITIONS 00028 00029 #include <arch.h> 00030 #include <bsp.h> 00031 #include <errno.h> 00032 #include <dependencies.h> 00033 #include <core/sched.h> 00034 #include <core/error.h> 00035 #include <core/debug.h> 00036 #include <core/thread.h> 00037 #include <core/loader.h> 00038 #include <core/partition.h> 00039 #include <core/instrumentation.h> 00040 #include <core/time.h> 00041 00042 #include <libc.h> 00043 00047 pok_partition_t pok_partitions[POK_CONFIG_NB_PARTITIONS]; 00048 00049 00050 uint8_t pok_partitions_index = 0; 00051 00052 extern uint64_t pok_sched_slots[]; 00053 00054 00058 void pok_partition_setup_scheduler (const uint8_t pid) 00059 { 00060 #ifdef POK_CONFIG_PARTITIONS_SCHEDULER 00061 switch (((pok_sched_t[])POK_CONFIG_PARTITIONS_SCHEDULER)[pid]) 00062 { 00063 #ifdef POK_NEEDS_SCHED_RMS 00064 case POK_SCHED_RMS: 00065 pok_partitions[pid].sched_func = &pok_sched_part_rms; 00066 break; 00067 #endif 00068 00069 /* 00070 * Default scheduling algorithm is Round Robin. 00071 * Yes, it sucks 00072 */ 00073 default: 00074 pok_partitions[pid].sched_func = &pok_sched_part_rr; 00075 break; 00076 } 00077 #else 00078 pok_partitions[pid].sched_func = &pok_sched_part_rr; 00079 #endif 00080 } 00081 00089 #ifdef POK_NEEDS_ERROR_HANDLING 00090 void pok_partition_reinit (const uint8_t pid) 00091 { 00092 uint32_t tmp; 00093 /* 00094 * FIXME: reset queueing/sampling ports too 00095 */ 00096 pok_partition_setup_scheduler (pid); 00097 00098 pok_partitions[pid].thread_index = 0; 00099 pok_partitions[pid].current_thread = pok_partitions[pid].thread_index_low; 00100 pok_partitions[pid].prev_thread = IDLE_THREAD; // breaks the rule of prev_thread not being idle, but it's just for init 00101 00102 #ifdef POK_NEEDS_ERROR_HANDLING 00103 pok_partitions[pid].thread_error = 0; 00104 pok_partitions[pid].error_status.failed_thread = 0; 00105 pok_partitions[pid].error_status.failed_addr = 0; 00106 pok_partitions[pid].error_status.error_kind = POK_ERROR_KIND_INVALID; 00107 pok_partitions[pid].error_status.msg_size = 0; 00108 #endif 00109 00110 pok_loader_load_partition (pid, pok_partitions[pid].base_addr - pok_partitions[pid].base_vaddr, &tmp); 00111 00112 pok_partitions[pid].thread_main_entry = tmp; 00113 00114 pok_partition_setup_main_thread (pid); 00115 } 00116 #endif 00117 00121 void pok_partition_setup_main_thread (const uint8_t pid) 00122 { 00123 uint32_t main_thread; 00124 pok_thread_attr_t attr; 00125 00126 attr.entry = (uint32_t*)pok_partitions[pid].thread_main_entry; 00127 attr.priority = 1; 00128 attr.deadline = 0; 00129 attr.period = 0; 00130 attr.time_capacity = 0; 00131 00132 pok_partition_thread_create (&main_thread, &attr, pid); 00133 pok_partitions[pid].thread_main = main_thread; 00134 } 00135 00142 pok_ret_t pok_partition_init () 00143 { 00144 uint8_t i; 00145 uint32_t threads_index = 0; 00146 00147 const uint32_t partition_size[POK_CONFIG_NB_PARTITIONS] = POK_CONFIG_PARTITIONS_SIZE; 00148 #ifdef POK_CONFIG_PARTITIONS_LOADADDR 00149 const uint32_t program_loadaddr[POK_CONFIG_NB_PARTITIONS] 00150 = POK_CONFIG_PROGRAM_LOADADDR; 00151 #endif 00152 #ifdef POK_NEEDS_LOCKOBJECTS 00153 uint8_t lockobj_index = 0; 00154 #endif 00155 00156 for (i = 0 ; i < POK_CONFIG_NB_PARTITIONS ; i++) 00157 { 00158 uint32_t size = partition_size[i]; 00159 #ifndef POK_CONFIG_PARTITIONS_LOADADDR 00160 uint32_t base_addr = (uint32_t)pok_bsp_mem_alloc(partition_size[i]); 00161 #else 00162 uint32_t base_addr = program_loadaddr[i]; 00163 #endif 00164 uint32_t program_entry; 00165 uint32_t base_vaddr = pok_space_base_vaddr(base_addr); 00166 00167 pok_partitions[i].base_addr = base_addr; 00168 pok_partitions[i].size = size; 00169 pok_partitions[i].sched = POK_SCHED_RR; 00170 00171 #ifdef POK_NEEDS_COVERAGE_INFOS 00172 #include <libc.h> 00173 printf ("[XCOV] Partition %d loaded at addr virt=|%x|, phys=|%x|\n", i, base_vaddr, base_addr); 00174 #endif 00175 00176 pok_partition_setup_scheduler (i); 00177 00178 pok_create_space (i, base_addr, size); 00179 00180 pok_partitions[i].base_vaddr = base_vaddr; 00181 /* Set the memory space and so on */ 00182 00183 pok_partitions[i].thread_index_low = threads_index; 00184 pok_partitions[i].nthreads = ((uint32_t[]) POK_CONFIG_PARTITIONS_NTHREADS) [i]; 00185 00186 #ifdef POK_NEEDS_ERROR_HANDLING 00187 if (pok_partitions[i].nthreads <= 1) 00188 { 00189 pok_partition_error (i, POK_ERROR_KIND_PARTITION_CONFIGURATION); 00190 } 00191 #endif 00192 00193 #ifdef POK_CONFIG_PARTITIONS_SCHEDULER 00194 pok_partitions[i].sched = ((pok_sched_t[]) POK_CONFIG_PARTITIONS_SCHEDULER) [i]; 00195 #endif 00196 00197 pok_partitions[i].thread_index_high = pok_partitions[i].thread_index_low + ((uint32_t[]) POK_CONFIG_PARTITIONS_NTHREADS) [i]; 00198 pok_partitions[i].activation = 0; 00199 pok_partitions[i].period = 0; 00200 pok_partitions[i].thread_index = 0; 00201 pok_partitions[i].thread_main = 0; 00202 pok_partitions[i].current_thread = IDLE_THREAD; 00203 pok_partitions[i].prev_thread = IDLE_THREAD; // breaks the rule of prev_thread not being idle, but it's just for init 00204 00205 #ifdef POK_NEEDS_SCHED_HFPPS 00206 pok_partitions[i].payback = 0; 00207 #endif /* POK_NEEDS_SCHED_HFPPS */ 00208 00209 threads_index = threads_index + pok_partitions[i].nthreads; 00210 /* Initialize the threading stuff */ 00211 00212 pok_partitions[i].mode = POK_PARTITION_MODE_INIT_WARM; 00213 00214 #ifdef POK_NEEDS_LOCKOBJECTS 00215 pok_partitions[i].lockobj_index_low = lockobj_index; 00216 pok_partitions[i].lockobj_index_high = lockobj_index + ((uint8_t[]) POK_CONFIG_PARTITIONS_NLOCKOBJECTS[i]); 00217 pok_partitions[i].nlockobjs = ((uint8_t[]) POK_CONFIG_PARTITIONS_NLOCKOBJECTS[i]); 00218 lockobj_index = lockobj_index + pok_partitions[i].nlockobjs; 00219 /* Initialize mutexes stuff */ 00220 #endif 00221 00222 #ifdef POK_NEEDS_ERROR_HANDLING 00223 pok_partitions[i].thread_error = 0; 00224 pok_partitions[i].error_status.failed_thread = 0; 00225 pok_partitions[i].error_status.failed_addr = 0; 00226 pok_partitions[i].error_status.error_kind = POK_ERROR_KIND_INVALID; 00227 pok_partitions[i].error_status.msg_size = 0; 00228 #endif 00229 00230 pok_loader_load_partition (i, base_addr - base_vaddr, &program_entry); 00231 /* 00232 * Load the partition in its address space 00233 */ 00234 pok_partitions[i].thread_main_entry = program_entry; 00235 00236 pok_partitions[i].lock_level = 0; 00237 pok_partitions[i].start_condition = NORMAL_START; 00238 00239 #ifdef POK_NEEDS_INSTRUMENTATION 00240 pok_instrumentation_partition_archi (i); 00241 #endif 00242 00243 pok_partition_setup_main_thread (i); 00244 pok_partitions[i].current_thread = pok_partitions[i].thread_main; 00245 } 00246 00247 return POK_ERRNO_OK; 00248 } 00249 00256 pok_ret_t pok_partition_set_mode (const uint8_t pid, const pok_partition_mode_t mode) 00257 { 00258 switch (mode) 00259 { 00260 case POK_PARTITION_MODE_NORMAL: 00261 /* 00262 * We first check that a partition that wants to go 00263 * to the NORMAL mode is currently in the INIT mode 00264 */ 00265 00266 if (pok_partitions[pid].mode == POK_PARTITION_MODE_IDLE) 00267 { 00268 return POK_ERRNO_PARTITION_MODE; 00269 } 00270 00271 if (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_main) 00272 { 00273 return POK_ERRNO_PARTITION_MODE; 00274 } 00275 00276 pok_partitions[pid].mode = mode; /* Here, we change the mode */ 00277 00278 pok_thread_t* thread; 00279 unsigned int i; 00280 for (i = 0; i < pok_partitions[pid].nthreads; i++) 00281 { 00282 thread = &(pok_threads[POK_CURRENT_PARTITION.thread_index_low + i]); 00283 if ((long long)thread->period == -1) {//-1 <==> ARINC INFINITE_TIME_VALUE 00284 if(thread->state == POK_STATE_DELAYED_START) { // delayed start, the delay is in the wakeup time 00285 if(!thread->wakeup_time) { 00286 thread->state = POK_STATE_RUNNABLE; 00287 } else { 00288 thread->state = POK_STATE_WAITING; 00289 } 00290 thread->wakeup_time += POK_GETTICK(); 00291 thread->end_time = thread->wakeup_time + thread->time_capacity; 00292 } 00293 } else { 00294 if(thread->state == POK_STATE_DELAYED_START) { // delayed start, the delay is in the wakeup time 00295 thread->next_activation = thread->wakeup_time + POK_CONFIG_SCHEDULING_MAJOR_FRAME + POK_CURRENT_PARTITION.activation; 00296 thread->end_time = thread->next_activation + thread->time_capacity; 00297 thread->state = POK_STATE_WAIT_NEXT_ACTIVATION; 00298 } 00299 } 00300 } 00301 pok_sched_stop_thread (pok_partitions[pid].thread_main); 00302 /* We stop the thread that call this change. All the time, 00303 * the thread that init this request is the init thread. 00304 * When it calls this function, the partition is ready and 00305 * this thread does not need no longer to be executed 00306 */ 00307 00308 pok_sched (); 00309 /* 00310 * Reschedule, baby, reschedule ! 00311 * In fact, the init thread is stopped, we need to execute 00312 * the other threads. 00313 */ 00314 break; 00315 00316 #ifdef POK_NEEDS_ERROR_HANDLING 00317 case POK_PARTITION_MODE_STOPPED: 00318 00319 /* 00320 * Only the error thread can stop the partition 00321 */ 00322 if ((POK_CURRENT_PARTITION.thread_error == 0 ) || 00323 (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_error)) 00324 { 00325 return POK_ERRNO_PARTITION_MODE; 00326 } 00327 00328 pok_partitions[pid].mode = mode; /* Here, we change the mode */ 00329 pok_sched (); 00330 break; 00331 00332 case POK_PARTITION_MODE_INIT_WARM: 00333 case POK_PARTITION_MODE_INIT_COLD: 00334 if (pok_partitions[pid].mode == POK_PARTITION_MODE_INIT_COLD && mode == POK_PARTITION_MODE_INIT_WARM) 00335 { 00336 return POK_ERRNO_PARTITION_MODE; 00337 } 00338 00339 /* 00340 * Check that only the error thread can restart the partition 00341 */ 00342 if ((POK_CURRENT_PARTITION.thread_error == 0 ) || 00343 (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_error)) 00344 { 00345 return POK_ERRNO_PARTITION_MODE; 00346 } 00347 00348 /* 00349 * The partition fallback in the INIT_WARM mode when it 00350 * was in the NORMAL mode. So, we check the previous mode 00351 */ 00352 00353 pok_partitions[pid].mode = mode; /* Here, we change the mode */ 00354 00355 pok_partition_reinit (pid); 00356 00357 pok_sched (); 00358 00359 break; 00360 #endif 00361 00362 default: 00363 return POK_ERRNO_PARTITION_MODE; 00364 break; 00365 } 00366 return POK_ERRNO_OK; 00367 } 00368 00372 pok_ret_t pok_partition_set_mode_current (const pok_partition_mode_t mode) 00373 { 00374 #ifdef POK_NEEDS_ERROR_HANDLING 00375 if ((POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_main) && 00376 (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_error)) 00377 #else 00378 if (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_main) 00379 #endif 00380 { 00381 return POK_ERRNO_THREAD; 00382 } 00383 00384 /* 00385 * Here, we check which thread call this function. 00386 * In fact, only two threads can change the partition mode : the init thread 00387 * and the error thread. If ANY other thread try to change the partition 00388 * mode, this is an error ! 00389 */ 00390 return (pok_partition_set_mode (POK_SCHED_CURRENT_PARTITION, mode)); 00391 } 00392 00396 pok_ret_t pok_current_partition_get_id (uint8_t *id) 00397 { 00398 *id = POK_SCHED_CURRENT_PARTITION; 00399 return POK_ERRNO_OK; 00400 } 00401 00402 pok_ret_t pok_current_partition_get_period (uint64_t *period) 00403 { 00404 *period = POK_CURRENT_PARTITION.period; 00405 return POK_ERRNO_OK; 00406 } 00407 00408 pok_ret_t pok_current_partition_get_duration (uint64_t *duration) 00409 { 00410 *duration = pok_sched_slots[POK_SCHED_CURRENT_PARTITION]; 00411 return POK_ERRNO_OK; 00412 } 00413 00414 pok_ret_t pok_current_partition_get_operating_mode (pok_partition_mode_t *op_mode) 00415 { 00416 *op_mode = POK_CURRENT_PARTITION.mode; 00417 return POK_ERRNO_OK; 00418 } 00419 00420 pok_ret_t pok_current_partition_get_lock_level (uint32_t *lock_level) 00421 { 00422 *lock_level = POK_CURRENT_PARTITION.lock_level; 00423 return POK_ERRNO_OK; 00424 } 00425 00426 pok_ret_t pok_current_partition_get_start_condition (pok_start_condition_t *start_condition) 00427 { 00428 *start_condition = POK_CURRENT_PARTITION.start_condition; 00429 return POK_ERRNO_OK; 00430 } 00431 00432 #ifdef POK_NEEDS_ERROR_HANDLING 00433 00440 pok_ret_t pok_partition_stop_thread (const uint32_t tid) 00441 { 00442 if (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_error) 00443 { 00444 return POK_ERRNO_THREAD; 00445 } 00446 /* 00447 * We check which thread try to call this function. Only the error handling 00448 * thread can stop other threads. 00449 */ 00450 00451 pok_sched_stop_thread (tid + POK_CURRENT_PARTITION.thread_index_low); 00452 pok_sched (); 00453 return (POK_ERRNO_OK); 00454 } 00455 00459 pok_ret_t pok_partition_restart_thread (const uint32_t tid) 00460 { 00461 if (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_error) 00462 { 00463 return POK_ERRNO_THREAD; 00464 } 00465 /* 00466 * We check which thread try to call this function. Only the error handling 00467 * thread can stop other threads. 00468 */ 00469 00470 pok_thread_restart (tid + POK_CURRENT_PARTITION.thread_index_low); 00471 pok_sched (); 00472 return (POK_ERRNO_OK); 00473 } 00474 #endif 00475 00476 #endif