Rev 3191 | Rev 3403 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 3191 | Rev 3203 | ||
|---|---|---|---|
| Line 33... | Line 33... | ||
| 33 | /** |
33 | /** |
| 34 | * @file |
34 | * @file |
| 35 | * @brief Task management. |
35 | * @brief Task management. |
| 36 | */ |
36 | */ |
| 37 | 37 | ||
| 38 | #include <main/uinit.h> |
- | |
| 39 | #include <proc/thread.h> |
38 | #include <proc/thread.h> |
| 40 | #include <proc/task.h> |
39 | #include <proc/task.h> |
| 41 | #include <proc/uarg.h> |
- | |
| 42 | #include <mm/as.h> |
40 | #include <mm/as.h> |
| 43 | #include <mm/slab.h> |
41 | #include <mm/slab.h> |
| 44 | #include <atomic.h> |
42 | #include <atomic.h> |
| 45 | #include <synch/spinlock.h> |
43 | #include <synch/spinlock.h> |
| 46 | #include <synch/waitq.h> |
44 | #include <synch/waitq.h> |
| 47 | #include <arch.h> |
45 | #include <arch.h> |
| 48 | #include <arch/barrier.h> |
46 | #include <arch/barrier.h> |
| 49 | #include <panic.h> |
- | |
| 50 | #include <adt/avl.h> |
47 | #include <adt/avl.h> |
| 51 | #include <adt/btree.h> |
48 | #include <adt/btree.h> |
| 52 | #include <adt/list.h> |
49 | #include <adt/list.h> |
| 53 | #include <ipc/ipc.h> |
50 | #include <ipc/ipc.h> |
| 54 | #include <ipc/ipcrsc.h> |
51 | #include <ipc/ipcrsc.h> |
| 55 | #include <security/cap.h> |
- | |
| 56 | #include <memstr.h> |
- | |
| 57 | #include <print.h> |
52 | #include <print.h> |
| 58 | #include <lib/elf.h> |
- | |
| 59 | #include <errno.h> |
53 | #include <errno.h> |
| 60 | #include <func.h> |
54 | #include <func.h> |
| 61 | #include <syscall/copy.h> |
55 | #include <syscall/copy.h> |
| 62 | 56 | ||
| 63 | #ifndef LOADED_PROG_STACK_PAGES_NO |
- | |
| 64 | #define LOADED_PROG_STACK_PAGES_NO 1 |
- | |
| 65 | #endif |
- | |
| 66 | - | ||
| 67 | /** Spinlock protecting the tasks_tree AVL tree. */ |
57 | /** Spinlock protecting the tasks_tree AVL tree. */ |
| 68 | SPINLOCK_INITIALIZE(tasks_lock); |
58 | SPINLOCK_INITIALIZE(tasks_lock); |
| 69 | 59 | ||
| 70 | /** AVL tree of active tasks. |
60 | /** AVL tree of active tasks. |
| 71 | * |
61 | * |
| Line 79... | Line 69... | ||
| 79 | */ |
69 | */ |
| 80 | avltree_t tasks_tree; |
70 | avltree_t tasks_tree; |
| 81 | 71 | ||
| 82 | static task_id_t task_counter = 0; |
72 | static task_id_t task_counter = 0; |
| 83 | 73 | ||
| 84 | /** |
- | |
| 85 | * Points to the binary image used as the program loader. All non-initial |
- | |
| 86 | * tasks are created from this executable image. |
- | |
| 87 | */ |
- | |
| 88 | void *program_loader = NULL; |
- | |
| 89 | - | ||
| 90 | - | ||
| 91 | /** Initialize tasks |
74 | /** Initialize tasks |
| 92 | * |
75 | * |
| 93 | * Initialize kernel tasks support. |
76 | * Initialize kernel tasks support. |
| 94 | * |
77 | * |
| 95 | */ |
78 | */ |
| Line 240... | Line 223... | ||
| 240 | 223 | ||
| 241 | free(t); |
224 | free(t); |
| 242 | TASK = NULL; |
225 | TASK = NULL; |
| 243 | } |
226 | } |
| 244 | 227 | ||
| 245 | /** Create new task with 1 thread and run it |
- | |
| 246 | * |
- | |
| 247 | * @param as Address space containing a binary program image. |
- | |
| 248 | * @param entry_addr Program entry-point address in program address space. |
- | |
| 249 | * @param name Program name. |
- | |
| 250 | * |
- | |
| 251 | * @return Task of the running program or NULL on error. |
- | |
| 252 | */ |
- | |
| 253 | task_t *task_create_from_as(as_t *as, uintptr_t entry_addr, char *name, |
- | |
| 254 | thread_t **thr) |
- | |
| 255 | { |
- | |
| 256 | as_area_t *a; |
- | |
| 257 | thread_t *t; |
- | |
| 258 | task_t *task; |
- | |
| 259 | uspace_arg_t *kernel_uarg; |
- | |
| 260 | - | ||
| 261 | kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0); |
- | |
| 262 | kernel_uarg->uspace_entry = (void *) entry_addr; |
- | |
| 263 | kernel_uarg->uspace_stack = (void *) USTACK_ADDRESS; |
- | |
| 264 | kernel_uarg->uspace_thread_function = NULL; |
- | |
| 265 | kernel_uarg->uspace_thread_arg = NULL; |
- | |
| 266 | kernel_uarg->uspace_uarg = NULL; |
- | |
| 267 | - | ||
| 268 | task = task_create(as, name); |
- | |
| 269 | ASSERT(task); |
- | |
| 270 | - | ||
| 271 | /* |
- | |
| 272 | * Create the data as_area. |
- | |
| 273 | */ |
- | |
| 274 | a = as_area_create(as, AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE, |
- | |
| 275 | LOADED_PROG_STACK_PAGES_NO * PAGE_SIZE, USTACK_ADDRESS, |
- | |
| 276 | AS_AREA_ATTR_NONE, &anon_backend, NULL); |
- | |
| 277 | - | ||
| 278 | /* |
- | |
| 279 | * Create the main thread. |
- | |
| 280 | */ |
- | |
| 281 | t = thread_create(uinit, kernel_uarg, task, THREAD_FLAG_USPACE, |
- | |
| 282 | "uinit", false); |
- | |
| 283 | ASSERT(t); |
- | |
| 284 | - | ||
| 285 | *thr = t; |
- | |
| 286 | - | ||
| 287 | return task; |
- | |
| 288 | } |
- | |
| 289 | - | ||
| 290 | /** Parse an executable image in the physical memory. |
- | |
| 291 | * |
- | |
| 292 | * If the image belongs to a program loader, it is registered as such, |
- | |
| 293 | * (and *task is set to NULL). Otherwise a task is created from the |
- | |
| 294 | * executable image. The task is returned in *task. |
- | |
| 295 | * |
- | |
| 296 | * @param program_addr Address of program executable image. |
- | |
| 297 | * @param name Program name. |
- | |
| 298 | * @param task Where to store the pointer to the newly created task. |
- | |
| 299 | * |
- | |
| 300 | * @return EOK on success or negative error code. |
- | |
| 301 | */ |
- | |
| 302 | int task_parse_initial(void *program_addr, char *name, thread_t **t) |
- | |
| 303 | { |
- | |
| 304 | as_t *as; |
- | |
| 305 | unsigned int rc; |
- | |
| 306 | task_t *task; |
- | |
| 307 | - | ||
| 308 | as = as_create(0); |
- | |
| 309 | ASSERT(as); |
- | |
| 310 | - | ||
| 311 | rc = elf_load((elf_header_t *) program_addr, as, 0); |
- | |
| 312 | if (rc != EE_OK) { |
- | |
| 313 | as_destroy(as); |
- | |
| 314 | *t = NULL; |
- | |
| 315 | if (rc != EE_LOADER) |
- | |
| 316 | return ENOTSUP; |
- | |
| 317 | - | ||
| 318 | /* Register image as the program loader */ |
- | |
| 319 | ASSERT(program_loader == NULL); |
- | |
| 320 | program_loader = program_addr; |
- | |
| 321 | return EOK; |
- | |
| 322 | } |
- | |
| 323 | - | ||
| 324 | task = task_create_from_as(as, ((elf_header_t *) program_addr)->e_entry, |
- | |
| 325 | name, t); |
- | |
| 326 | - | ||
| 327 | return EOK; |
- | |
| 328 | } |
- | |
| 329 | - | ||
| 330 | /** Create a task from the program loader image. |
- | |
| 331 | * |
- | |
| 332 | * @param name Program name. |
- | |
| 333 | * @param t Buffer for storing pointer to the newly created task. |
- | |
| 334 | * |
- | |
| 335 | * @return Task of the running program or NULL on error. |
- | |
| 336 | */ |
- | |
| 337 | int task_create_from_loader(char *name, task_t **t) |
- | |
| 338 | { |
- | |
| 339 | as_t *as; |
- | |
| 340 | unsigned int rc; |
- | |
| 341 | void *loader; |
- | |
| 342 | thread_t *thr; |
- | |
| 343 | - | ||
| 344 | as = as_create(0); |
- | |
| 345 | ASSERT(as); |
- | |
| 346 | - | ||
| 347 | loader = program_loader; |
- | |
| 348 | if (!loader) return ENOENT; |
- | |
| 349 | - | ||
| 350 | rc = elf_load((elf_header_t *) program_loader, as, ELD_F_LOADER); |
- | |
| 351 | if (rc != EE_OK) { |
- | |
| 352 | as_destroy(as); |
- | |
| 353 | return ENOENT; |
- | |
| 354 | } |
- | |
| 355 | - | ||
| 356 | *t = task_create_from_as( |
- | |
| 357 | as, ((elf_header_t *) program_loader)->e_entry, name, &thr); |
- | |
| 358 | - | ||
| 359 | return EOK; |
- | |
| 360 | } |
- | |
| 361 | - | ||
| 362 | /** Make task ready. |
- | |
| 363 | * |
- | |
| 364 | * Switch task's thread to the ready state. |
- | |
| 365 | * |
- | |
| 366 | * @param ta Task to make ready. |
- | |
| 367 | */ |
- | |
| 368 | void task_ready(task_t *t) |
- | |
| 369 | { |
- | |
| 370 | thread_t *th; |
- | |
| 371 | - | ||
| 372 | th = list_get_instance(t->th_head.next, thread_t, th_link); |
- | |
| 373 | thread_ready(th); |
- | |
| 374 | } |
- | |
| 375 | - | ||
| 376 | /** Syscall for reading task ID from userspace. |
228 | /** Syscall for reading task ID from userspace. |
| 377 | * |
229 | * |
| 378 | * @param uspace_task_id Userspace address of 8-byte buffer where to store |
230 | * @param uspace_task_id Userspace address of 8-byte buffer where to store |
| 379 | * current task ID. |
231 | * current task ID. |
| 380 | * |
232 | * |
| Line 388... | Line 240... | ||
| 388 | */ |
240 | */ |
| 389 | return (unative_t) copy_to_uspace(uspace_task_id, &TASK->taskid, |
241 | return (unative_t) copy_to_uspace(uspace_task_id, &TASK->taskid, |
| 390 | sizeof(TASK->taskid)); |
242 | sizeof(TASK->taskid)); |
| 391 | } |
243 | } |
| 392 | 244 | ||
| 393 | /** Syscall for creating a new task from userspace. |
- | |
| 394 | * |
- | |
| 395 | * Creates a new task from the program loader image, connects a phone |
- | |
| 396 | * to it and stores the phone id into the provided buffer. |
- | |
| 397 | * |
- | |
| 398 | * @param uspace_phone_id Userspace address where to store the phone id. |
- | |
| 399 | * |
- | |
| 400 | * @return 0 on success or an error code from @ref errno.h. |
- | |
| 401 | */ |
- | |
| 402 | unative_t sys_task_spawn_loader(int *uspace_phone_id) |
- | |
| 403 | { |
- | |
| 404 | task_t *t; |
- | |
| 405 | int fake_id; |
- | |
| 406 | int rc; |
- | |
| 407 | int phone_id; |
- | |
| 408 | - | ||
| 409 | fake_id = 0; |
- | |
| 410 | - | ||
| 411 | /* Before we even try creating the task, see if we can write the id */ |
- | |
| 412 | rc = (unative_t) copy_to_uspace(uspace_phone_id, &fake_id, |
- | |
| 413 | sizeof(fake_id)); |
- | |
| 414 | if (rc != 0) |
- | |
| 415 | return rc; |
- | |
| 416 | - | ||
| 417 | phone_id = phone_alloc(); |
- | |
| 418 | if (phone_id < 0) |
- | |
| 419 | return ELIMIT; |
- | |
| 420 | - | ||
| 421 | rc = task_create_from_loader("loader", &t); |
- | |
| 422 | if (rc != 0) |
- | |
| 423 | return rc; |
- | |
| 424 | - | ||
| 425 | phone_connect(phone_id, &t->answerbox); |
- | |
| 426 | - | ||
| 427 | /* No need to aquire lock before task_ready() */ |
- | |
| 428 | rc = (unative_t) copy_to_uspace(uspace_phone_id, &phone_id, |
- | |
| 429 | sizeof(phone_id)); |
- | |
| 430 | if (rc != 0) { |
- | |
| 431 | /* Ooops */ |
- | |
| 432 | ipc_phone_hangup(&TASK->phones[phone_id]); |
- | |
| 433 | task_kill(t->taskid); |
- | |
| 434 | return rc; |
- | |
| 435 | } |
- | |
| 436 | - | ||
| 437 | // FIXME: control the capabilities |
- | |
| 438 | cap_set(t, cap_get(TASK)); |
- | |
| 439 | - | ||
| 440 | task_ready(t); |
- | |
| 441 | - | ||
| 442 | return EOK; |
- | |
| 443 | } |
- | |
| 444 | - | ||
| 445 | /** Find task structure corresponding to task ID. |
245 | /** Find task structure corresponding to task ID. |
| 446 | * |
246 | * |
| 447 | * The tasks_lock must be already held by the caller of this function |
247 | * The tasks_lock must be already held by the caller of this function |
| 448 | * and interrupts must be disabled. |
248 | * and interrupts must be disabled. |
| 449 | * |
249 | * |