35,10 → 35,8 |
* @brief Task management. |
*/ |
|
#include <main/uinit.h> |
#include <proc/thread.h> |
#include <proc/task.h> |
#include <proc/uarg.h> |
#include <mm/as.h> |
#include <mm/slab.h> |
#include <atomic.h> |
46,24 → 44,16 |
#include <synch/waitq.h> |
#include <arch.h> |
#include <arch/barrier.h> |
#include <panic.h> |
#include <adt/avl.h> |
#include <adt/btree.h> |
#include <adt/list.h> |
#include <ipc/ipc.h> |
#include <ipc/ipcrsc.h> |
#include <security/cap.h> |
#include <memstr.h> |
#include <print.h> |
#include <lib/elf.h> |
#include <errno.h> |
#include <func.h> |
#include <syscall/copy.h> |
|
#ifndef LOADED_PROG_STACK_PAGES_NO |
#define LOADED_PROG_STACK_PAGES_NO 1 |
#endif |
|
/** Spinlock protecting the tasks_tree AVL tree. */ |
SPINLOCK_INITIALIZE(tasks_lock); |
|
81,13 → 71,6 |
|
static task_id_t task_counter = 0; |
|
/** |
* Points to the binary image used as the program loader. All non-initial |
* tasks are created from this executable image. |
*/ |
void *program_loader = NULL; |
|
|
/** Initialize tasks |
* |
* Initialize kernel tasks support. |
242,137 → 225,6 |
TASK = NULL; |
} |
|
/** Create new task with 1 thread and run it |
* |
* @param as Address space containing a binary program image. |
* @param entry_addr Program entry-point address in program address space. |
* @param name Program name. |
* |
* @return Task of the running program or NULL on error. |
*/ |
task_t *task_create_from_as(as_t *as, uintptr_t entry_addr, char *name, |
thread_t **thr) |
{ |
as_area_t *a; |
thread_t *t; |
task_t *task; |
uspace_arg_t *kernel_uarg; |
|
kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0); |
kernel_uarg->uspace_entry = (void *) entry_addr; |
kernel_uarg->uspace_stack = (void *) USTACK_ADDRESS; |
kernel_uarg->uspace_thread_function = NULL; |
kernel_uarg->uspace_thread_arg = NULL; |
kernel_uarg->uspace_uarg = NULL; |
|
task = task_create(as, name); |
ASSERT(task); |
|
/* |
* Create the data as_area. |
*/ |
a = as_area_create(as, AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE, |
LOADED_PROG_STACK_PAGES_NO * PAGE_SIZE, USTACK_ADDRESS, |
AS_AREA_ATTR_NONE, &anon_backend, NULL); |
|
/* |
* Create the main thread. |
*/ |
t = thread_create(uinit, kernel_uarg, task, THREAD_FLAG_USPACE, |
"uinit", false); |
ASSERT(t); |
|
*thr = t; |
|
return task; |
} |
|
/** Parse an executable image in the physical memory. |
* |
* If the image belongs to a program loader, it is registered as such, |
* (and *task is set to NULL). Otherwise a task is created from the |
* executable image. The task is returned in *task. |
* |
* @param program_addr Address of program executable image. |
* @param name Program name. |
* @param task Where to store the pointer to the newly created task. |
* |
* @return EOK on success or negative error code. |
*/ |
int task_parse_initial(void *program_addr, char *name, thread_t **t) |
{ |
as_t *as; |
unsigned int rc; |
task_t *task; |
|
as = as_create(0); |
ASSERT(as); |
|
rc = elf_load((elf_header_t *) program_addr, as, 0); |
if (rc != EE_OK) { |
as_destroy(as); |
*t = NULL; |
if (rc != EE_LOADER) |
return ENOTSUP; |
|
/* Register image as the program loader */ |
ASSERT(program_loader == NULL); |
program_loader = program_addr; |
return EOK; |
} |
|
task = task_create_from_as(as, ((elf_header_t *) program_addr)->e_entry, |
name, t); |
|
return EOK; |
} |
|
/** Create a task from the program loader image. |
* |
* @param name Program name. |
* @param t Buffer for storing pointer to the newly created task. |
* |
* @return Task of the running program or NULL on error. |
*/ |
int task_create_from_loader(char *name, task_t **t) |
{ |
as_t *as; |
unsigned int rc; |
void *loader; |
thread_t *thr; |
|
as = as_create(0); |
ASSERT(as); |
|
loader = program_loader; |
if (!loader) return ENOENT; |
|
rc = elf_load((elf_header_t *) program_loader, as, ELD_F_LOADER); |
if (rc != EE_OK) { |
as_destroy(as); |
return ENOENT; |
} |
|
*t = task_create_from_as( |
as, ((elf_header_t *) program_loader)->e_entry, name, &thr); |
|
return EOK; |
} |
|
/** Make task ready. |
* |
* Switch task's thread to the ready state. |
* |
* @param ta Task to make ready. |
*/ |
void task_ready(task_t *t) |
{ |
thread_t *th; |
|
th = list_get_instance(t->th_head.next, thread_t, th_link); |
thread_ready(th); |
} |
|
/** Syscall for reading task ID from userspace. |
* |
* @param uspace_task_id Userspace address of 8-byte buffer where to store |
390,58 → 242,6 |
sizeof(TASK->taskid)); |
} |
|
/** Syscall for creating a new task from userspace. |
* |
* Creates a new task from the program loader image, connects a phone |
* to it and stores the phone id into the provided buffer. |
* |
* @param uspace_phone_id Userspace address where to store the phone id. |
* |
* @return 0 on success or an error code from @ref errno.h. |
*/ |
unative_t sys_task_spawn_loader(int *uspace_phone_id) |
{ |
task_t *t; |
int fake_id; |
int rc; |
int phone_id; |
|
fake_id = 0; |
|
/* Before we even try creating the task, see if we can write the id */ |
rc = (unative_t) copy_to_uspace(uspace_phone_id, &fake_id, |
sizeof(fake_id)); |
if (rc != 0) |
return rc; |
|
phone_id = phone_alloc(); |
if (phone_id < 0) |
return ELIMIT; |
|
rc = task_create_from_loader("loader", &t); |
if (rc != 0) |
return rc; |
|
phone_connect(phone_id, &t->answerbox); |
|
/* No need to aquire lock before task_ready() */ |
rc = (unative_t) copy_to_uspace(uspace_phone_id, &phone_id, |
sizeof(phone_id)); |
if (rc != 0) { |
/* Ooops */ |
ipc_phone_hangup(&TASK->phones[phone_id]); |
task_kill(t->taskid); |
return rc; |
} |
|
// FIXME: control the capabilities |
cap_set(t, cap_get(TASK)); |
|
task_ready(t); |
|
return EOK; |
} |
|
/** Find task structure corresponding to task ID. |
* |
* The tasks_lock must be already held by the caller of this function |