Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3202 → Rev 3203

/branches/dynload/kernel/generic/src/proc/task.c
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