POK(kernelpart)
/home/jaouen/pok_official/pok/trunk/kernel/core/partition.c
Go to the documentation of this file.
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