POK(kernelpart)
partition.c
Go to the documentation of this file.
1 /*
2  * POK header
3  *
4  * The following file is a part of the POK project. Any modification should
5  * made according to the POK licence. You CANNOT use this file or a part of
6  * this file is this part of a file for your own project
7  *
8  * For more information on the POK licence, please see our LICENCE FILE
9  *
10  * Please follow the coding guidelines described in doc/CODING_GUIDELINES
11  *
12  * Copyright (c) 2007-2009 POK team
13  *
14  * Created by julien on Thu Jan 15 23:34:13 2009
15  */
16 
27 #ifdef POK_NEEDS_PARTITIONS
28 
29 #include <arch.h>
30 #include <bsp.h>
31 #include <errno.h>
32 #include <dependencies.h>
33 #include <core/sched.h>
34 #include <core/error.h>
35 #include <core/debug.h>
36 #include <core/thread.h>
37 #include <core/loader.h>
38 #include <core/partition.h>
39 #include <core/instrumentation.h>
40 
41 #include <libc.h>
42 
46 pok_partition_t pok_partitions[POK_CONFIG_NB_PARTITIONS];
47 
48 
49 uint8_t pok_partitions_index = 0;
50 
51 extern uint64_t pok_sched_slots[];
52 
53 
57 void pok_partition_setup_scheduler (const uint8_t pid)
58 {
59 #ifdef POK_CONFIG_PARTITIONS_SCHEDULER
60  switch (((pok_sched_t[])POK_CONFIG_PARTITIONS_SCHEDULER)[pid])
61  {
62 #ifdef POK_NEEDS_SCHED_RMS
63  case POK_SCHED_RMS:
64  pok_partitions[pid].sched_func = &pok_sched_part_rms;
65  break;
66 #endif
67 
68  /*
69  * Default scheduling algorithm is Round Robin.
70  * Yes, it sucks
71  */
72  default:
73  pok_partitions[pid].sched_func = &pok_sched_part_rr;
74  break;
75  }
76 #else
77  pok_partitions[pid].sched_func = &pok_sched_part_rr;
78 #endif
79 }
80 
88 #ifdef POK_NEEDS_ERROR_HANDLING
89 void pok_partition_reinit (const uint8_t pid)
90 {
91  uint32_t tmp;
92  /*
93  * FIXME: reset queueing/sampling ports too
94  */
95  pok_partition_setup_scheduler (pid);
96 
97  pok_partitions[pid].thread_index = 0;
98  pok_partitions[pid].current_thread = pok_partitions[pid].thread_index_low;
99  pok_partitions[pid].prev_current_thread = IDLE_THREAD;
100 
101 #ifdef POK_NEEDS_ERROR_HANDLING
102  pok_partitions[pid].thread_error = 0;
103  pok_partitions[pid].error_status.failed_thread = 0;
104  pok_partitions[pid].error_status.failed_addr = 0;
105  pok_partitions[pid].error_status.error_kind = POK_ERROR_KIND_INVALID;
106  pok_partitions[pid].error_status.msg_size = 0;
107 #endif
108 
109  pok_loader_load_partition (pid, pok_partitions[pid].base_addr - pok_partitions[pid].base_vaddr, &tmp);
110 
111  pok_partitions[pid].thread_main_entry = tmp;
112 
113  pok_partition_setup_main_thread (pid);
114 }
115 #endif
116 
120 void pok_partition_setup_main_thread (const uint8_t pid)
121 {
122  uint32_t main_thread;
123  pok_thread_attr_t attr;
124 
125  attr.entry = (uint32_t*)pok_partitions[pid].thread_main_entry;
126  attr.priority = 1;
127  attr.deadline = 0;
128  attr.period = 0;
129  attr.time_capacity = 0;
130 
131  pok_partition_thread_create (&main_thread, &attr, pid);
132  pok_partitions[pid].thread_main = main_thread;
133 }
134 
141 pok_ret_t pok_partition_init ()
142 {
143  uint8_t i;
144  uint32_t threads_index = 0;
145 
146  const uint32_t partition_size[POK_CONFIG_NB_PARTITIONS] = POK_CONFIG_PARTITIONS_SIZE;
147 #ifdef POK_CONFIG_PARTITIONS_LOADADDR
148  const uint32_t program_loadaddr[POK_CONFIG_NB_PARTITIONS]
149  = POK_CONFIG_PROGRAM_LOADADDR;
150 #endif
151 #ifdef POK_NEEDS_LOCKOBJECTS
152  uint8_t lockobj_index = 0;
153 #endif
154 
155  for (i = 0 ; i < POK_CONFIG_NB_PARTITIONS ; i++)
156  {
157  uint32_t size = partition_size[i];
158 #ifndef POK_CONFIG_PARTITIONS_LOADADDR
159  uint32_t base_addr = (uint32_t)pok_bsp_mem_alloc(partition_size[i]);
160 #else
161  uint32_t base_addr = program_loadaddr[i];
162 #endif
163  uint32_t program_entry;
164  uint32_t base_vaddr = pok_space_base_vaddr(base_addr);
165 
166  pok_partitions[i].base_addr = base_addr;
167  pok_partitions[i].size = size;
168  pok_partitions[i].sched = POK_SCHED_RR;
169 
170 #ifdef POK_NEEDS_COVERAGE_INFOS
171 #include <libc.h>
172  printf ("[XCOV] Partition %d loaded at addr virt=|%x|, phys=|%x|\n", i, base_vaddr, base_addr);
173 #endif
174 
175  pok_partition_setup_scheduler (i);
176 
177  pok_create_space (i, base_addr, size);
178 
179  pok_partitions[i].base_vaddr = base_vaddr;
180  /* Set the memory space and so on */
181 
182  pok_partitions[i].thread_index_low = threads_index;
183  pok_partitions[i].nthreads = ((uint32_t[]) POK_CONFIG_PARTITIONS_NTHREADS) [i];
184 
185 #ifdef POK_NEEDS_ERROR_HANDLING
186  if (pok_partitions[i].nthreads <= 1)
187  {
188  pok_partition_error (i, POK_ERROR_KIND_PARTITION_CONFIGURATION);
189  }
190 #endif
191 
192 #ifdef POK_CONFIG_PARTITIONS_SCHEDULER
193  pok_partitions[i].sched = ((pok_sched_t[]) POK_CONFIG_PARTITIONS_SCHEDULER) [i];
194 #endif
195 
196  pok_partitions[i].thread_index_high = pok_partitions[i].thread_index_low + ((uint32_t[]) POK_CONFIG_PARTITIONS_NTHREADS) [i];
197  pok_partitions[i].activation = 0;
198  pok_partitions[i].period = 0;
199  pok_partitions[i].thread_index = 0;
200  pok_partitions[i].thread_main = 0;
201  pok_partitions[i].current_thread = IDLE_THREAD;
202  pok_partitions[i].prev_current_thread = IDLE_THREAD;
203 
204 #ifdef POK_NEEDS_SCHED_HFPPS
205  pok_partitions[i].payback = 0;
206 #endif /* POK_NEEDS_SCHED_HFPPS */
207 
208  threads_index = threads_index + pok_partitions[i].nthreads;
209  /* Initialize the threading stuff */
210 
211  pok_partitions[i].mode = POK_PARTITION_MODE_INIT_WARM;
212 
213 #ifdef POK_NEEDS_LOCKOBJECTS
214  pok_partitions[i].lockobj_index_low = lockobj_index;
215  pok_partitions[i].lockobj_index_high = lockobj_index + ((uint8_t[]) POK_CONFIG_PARTITIONS_NLOCKOBJECTS[i]);
216  pok_partitions[i].nlockobjs = ((uint8_t[]) POK_CONFIG_PARTITIONS_NLOCKOBJECTS[i]);
217  lockobj_index = lockobj_index + pok_partitions[i].nlockobjs;
218  /* Initialize mutexes stuff */
219 #endif
220 
221 #ifdef POK_NEEDS_ERROR_HANDLING
222  pok_partitions[i].thread_error = 0;
223  pok_partitions[i].error_status.failed_thread = 0;
224  pok_partitions[i].error_status.failed_addr = 0;
225  pok_partitions[i].error_status.error_kind = POK_ERROR_KIND_INVALID;
226  pok_partitions[i].error_status.msg_size = 0;
227 #endif
228 
229  pok_loader_load_partition (i, base_addr - base_vaddr, &program_entry);
230  /*
231  * Load the partition in its address space
232  */
233  pok_partitions[i].thread_main_entry = program_entry;
234 
235  pok_partitions[i].lock_level = 0;
236  pok_partitions[i].start_condition = NORMAL_START;
237 
238 #ifdef POK_NEEDS_INSTRUMENTATION
239  pok_instrumentation_partition_archi (i);
240 #endif
241 
242  pok_partition_setup_main_thread (i);
243  }
244 
245  return POK_ERRNO_OK;
246 }
247 
254 pok_ret_t pok_partition_set_mode (const uint8_t pid, const pok_partition_mode_t mode)
255 {
256  switch (mode)
257  {
258  case POK_PARTITION_MODE_NORMAL:
259  /*
260  * We first check that a partition that wants to go
261  * to the NORMAL mode is currently in the INIT mode
262  */
263 
264  if (pok_partitions[pid].mode == POK_PARTITION_MODE_IDLE)
265  {
267  }
268 
269  if (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_main)
270  {
272  }
273 
274  pok_partitions[pid].mode = mode; /* Here, we change the mode */
275 
276  pok_sched_stop_thread (pok_partitions[pid].thread_main);
277  /* We stop the thread that call this change. All the time,
278  * the thread that init this request is the init thread.
279  * When it calls this function, the partition is ready and
280  * this thread does not need no longer to be executed
281  */
282 
283  pok_sched ();
284  /*
285  * Reschedule, baby, reschedule !
286  * In fact, the init thread is stopped, we need to execute
287  * the other threads.
288  */
289  break;
290 
291 #ifdef POK_NEEDS_ERROR_HANDLING
292  case POK_PARTITION_MODE_STOPPED:
293 
294  /*
295  * Only the error thread can stop the partition
296  */
297  if ((POK_CURRENT_PARTITION.thread_error == 0 ) ||
298  (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_error))
299  {
301  }
302 
303  pok_partitions[pid].mode = mode; /* Here, we change the mode */
304  pok_sched ();
305  break;
306 
307  case POK_PARTITION_MODE_INIT_WARM:
308  case POK_PARTITION_MODE_INIT_COLD:
309  if (pok_partitions[pid].mode == POK_PARTITION_MODE_INIT_COLD && mode == POK_PARTITION_MODE_INIT_WARM)
310  {
312  }
313 
314  /*
315  * Check that only the error thread can restart the partition
316  */
317  if ((POK_CURRENT_PARTITION.thread_error == 0 ) ||
318  (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_error))
319  {
321  }
322 
323  /*
324  * The partition fallback in the INIT_WARM mode when it
325  * was in the NORMAL mode. So, we check the previous mode
326  */
327 
328  pok_partitions[pid].mode = mode; /* Here, we change the mode */
329 
330  pok_partition_reinit (pid);
331 
332  pok_sched ();
333 
334  break;
335 #endif
336 
337  default:
339  break;
340  }
341  return POK_ERRNO_OK;
342 }
343 
347 pok_ret_t pok_partition_set_mode_current (const pok_partition_mode_t mode)
348 {
349 #ifdef POK_NEEDS_ERROR_HANDLING
350  if ((POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_main) &&
351  (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_error))
352 #else
353  if (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_main)
354 #endif
355  {
356  return POK_ERRNO_THREAD;
357  }
358 
359  /*
360  * Here, we check which thread call this function.
361  * In fact, only two threads can change the partition mode : the init thread
362  * and the error thread. If ANY other thread try to change the partition
363  * mode, this is an error !
364  */
365  return (pok_partition_set_mode (POK_SCHED_CURRENT_PARTITION, mode));
366 }
367 
371 pok_ret_t pok_current_partition_get_id (uint8_t *id)
372 {
373  *id = POK_SCHED_CURRENT_PARTITION;
374  return POK_ERRNO_OK;
375 }
376 
377 pok_ret_t pok_current_partition_get_period (uint64_t *period)
378 {
379  *period = POK_CURRENT_PARTITION.period;
380  return POK_ERRNO_OK;
381 }
382 
383 pok_ret_t pok_current_partition_get_duration (uint64_t *duration)
384 {
385  *duration = pok_sched_slots[POK_SCHED_CURRENT_PARTITION];
386  return POK_ERRNO_OK;
387 }
388 
389 pok_ret_t pok_current_partition_get_operating_mode (pok_partition_mode_t *op_mode)
390 {
391  *op_mode = POK_CURRENT_PARTITION.mode;
392  return POK_ERRNO_OK;
393 }
394 
395 pok_ret_t pok_current_partition_get_lock_level (uint32_t *lock_level)
396 {
397  *lock_level = POK_CURRENT_PARTITION.lock_level;
398  return POK_ERRNO_OK;
399 }
400 
401 pok_ret_t pok_current_partition_get_start_condition (pok_start_condition_t *start_condition)
402 {
403  *start_condition = POK_CURRENT_PARTITION.start_condition;
404  return POK_ERRNO_OK;
405 }
406 
407 #ifdef POK_NEEDS_ERROR_HANDLING
408 
415 pok_ret_t pok_partition_stop_thread (const uint32_t tid)
416 {
417  if (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_error)
418  {
419  return POK_ERRNO_THREAD;
420  }
421  /*
422  * We check which thread try to call this function. Only the error handling
423  * thread can stop other threads.
424  */
425 
426  pok_sched_stop_thread (tid + POK_CURRENT_PARTITION.thread_index_low);
427  pok_sched ();
428  return (POK_ERRNO_OK);
429 }
430 
434 pok_ret_t pok_partition_restart_thread (const uint32_t tid)
435 {
436  if (POK_SCHED_CURRENT_THREAD != POK_CURRENT_PARTITION.thread_error)
437  {
438  return POK_ERRNO_THREAD;
439  }
440  /*
441  * We check which thread try to call this function. Only the error handling
442  * thread can stop other threads.
443  */
444 
445  pok_thread_restart (tid + POK_CURRENT_PARTITION.thread_index_low);
446  pok_sched ();
447  return (POK_ERRNO_OK);
448 }
449 #endif
450 
451 #endif