/branches/dynload/kernel/generic/include/proc/task.h |
---|
112,15 → 112,21 |
SPINLOCK_EXTERN(tasks_lock); |
extern avltree_t tasks_tree; |
extern void *program_loader; |
extern void task_init(void); |
extern void task_done(void); |
extern task_t *task_create(as_t *as, char *name); |
extern void task_destroy(task_t *t); |
extern task_t *task_run_program(void *program_addr, char *name); |
extern task_t *task_create_from_as(as_t *as, uintptr_t entry_addr, char *name); |
extern int task_parse_initial(void *program_addr, char *name, task_t **task); |
extern task_t *task_create_from_loader(char *name); |
extern void task_ready(task_t *t); |
extern task_t *task_find_by_id(task_id_t id); |
extern int task_kill(task_id_t id); |
extern uint64_t task_get_accounting(task_t *t); |
extern void cap_set(task_t *t, cap_t caps); |
extern cap_t cap_get(task_t *t); |
133,6 → 139,7 |
#endif |
extern unative_t sys_task_get_id(task_id_t *uspace_task_id); |
extern unative_t sys_task_spawn(task_id_t *uspace_task_id); |
#endif |
/branches/dynload/kernel/generic/include/lib/elf.h |
---|
114,7 → 114,8 |
#define EE_MEMORY 2 /* Cannot allocate address space */ |
#define EE_INCOMPATIBLE 3 /* ELF image is not compatible with current architecture */ |
#define EE_UNSUPPORTED 4 /* Non-supported ELF (e.g. dynamic ELFs) */ |
#define EE_IRRECOVERABLE 5 |
#define EE_LOADER 5 /* The image is actually a program loader */ |
#define EE_IRRECOVERABLE 6 |
/** |
* ELF section types |
338,6 → 339,10 |
extern char *elf_error(unsigned int rc); |
/* Interpreter string used to recognize the program loader */ |
#define ELF_INTERP_ZSTR "kernel" |
#define ELF_INTERP_ZLEN sizeof(ELF_INTERP_ZSTR) |
#endif |
/** @} |
/branches/dynload/kernel/generic/include/mm/as.h |
---|
300,8 → 300,14 |
extern mem_backend_t elf_backend; |
extern mem_backend_t phys_backend; |
extern unsigned int elf_load(elf_header_t *header, as_t *as); |
/** |
* This flags is passed when running the loader, otherwise elf_load() |
* would return with a EE_LOADER error code. |
*/ |
#define ELD_F_LOADER 1 |
extern unsigned int elf_load(elf_header_t *header, as_t *as, int flags); |
/* Address space area related syscalls. */ |
extern unative_t sys_as_area_create(uintptr_t address, size_t size, int flags); |
extern unative_t sys_as_area_resize(uintptr_t address, size_t size, int flags); |
/branches/dynload/kernel/generic/include/syscall/syscall.h |
---|
42,6 → 42,7 |
SYS_THREAD_EXIT, |
SYS_THREAD_GET_ID, |
SYS_TASK_GET_ID, |
SYS_TASK_SPAWN, |
SYS_FUTEX_SLEEP, |
SYS_FUTEX_WAKEUP, |
SYS_AS_AREA_CREATE, |
/branches/dynload/kernel/generic/src/main/kinit.c |
---|
157,7 → 157,10 |
count_t i; |
for (i = 0; i < init.cnt; i++) { |
/* |
* Run user tasks, load RAM disk images. |
* Parse initial images |
* - Run user tasks |
* - load RAM disk images. |
* - register program loader |
*/ |
if (init.tasks[i].addr % FRAME_SIZE) { |
165,19 → 168,27 |
continue; |
} |
task_t *utask = task_run_program((void *) init.tasks[i].addr, |
"uspace"); |
task_t *utask; |
int rc = task_parse_initial((void *) init.tasks[i].addr, |
"uspace", &utask); |
if (utask) { |
if (rc == 0 && utask) { |
/* Make the task ready */ |
task_ready(utask); |
/* |
* Set capabilities to init userspace tasks. |
*/ |
cap_set(utask, CAP_CAP | CAP_MEM_MANAGER | |
CAP_IO_MANAGER | CAP_PREEMPT_CONTROL | CAP_IRQ_REG); |
if (!ipc_phone_0) |
ipc_phone_0 = &utask->answerbox; |
} else if (rc == 0) { |
/* It was the program loader and was registered */ |
} else { |
/* RAM disk image */ |
int rd = init_rd((rd_header *) init.tasks[i].addr, |
init.tasks[i].size); |
/branches/dynload/kernel/generic/src/proc/task.c |
---|
79,6 → 79,13 |
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. |
235,32 → 242,21 |
/** Create new task with 1 thread and run it |
* |
* @param program_addr Address of program executable image. |
* @param name Program name. |
* @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_run_program(void *program_addr, char *name) |
task_t *task_create_from_as(as_t *as, uintptr_t entry_addr, char *name) |
{ |
as_t *as; |
as_area_t *a; |
unsigned int rc; |
thread_t *t; |
task_t *task; |
uspace_arg_t *kernel_uarg; |
as = as_create(0); |
ASSERT(as); |
rc = elf_load((elf_header_t *) program_addr, as); |
if (rc != EE_OK) { |
as_destroy(as); |
return NULL; |
} |
kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0); |
kernel_uarg->uspace_entry = |
(void *) ((elf_header_t *) program_addr)->e_entry; |
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; |
283,11 → 279,87 |
"uinit", false); |
ASSERT(t); |
thread_ready(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, task_t **task) |
{ |
as_t *as; |
unsigned int rc; |
as = as_create(0); |
ASSERT(as); |
rc = elf_load((elf_header_t *) program_addr, as, 0); |
if (rc != EE_OK) { |
as_destroy(as); |
*task = 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); |
return EOK; |
} |
/** Create a task from the program loader image. |
* |
* @param program_addr Address of program executable image. |
* @param name Program name. |
* |
* @return Task of the running program or NULL on error. |
*/ |
task_t *task_create_from_loader(char *name) |
{ |
as_t *as; |
unsigned int rc; |
as = as_create(0); |
ASSERT(as); |
rc = elf_load((elf_header_t *) program_loader, as, ELD_F_LOADER); |
if (rc != EE_OK) { |
as_destroy(as); |
return NULL; |
} |
return task_create_from_as( |
as, ((elf_header_t *) program_loader)->e_entry, name); |
} |
/** 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 |
305,6 → 377,44 |
sizeof(TASK->taskid)); |
} |
/** Syscall for creating a new task from userspace. |
* |
* Creates a new task from the program loader image and stores its |
* task id into the provided buffer. |
* |
* @param uspace_task_id Userspace address of 8-byte buffer where to store |
* current task ID. |
* |
* @return 0 on success or an error code from @ref errno.h. |
*/ |
unative_t sys_task_spawn(task_id_t *uspace_task_id) |
{ |
task_t *t; |
task_id_t fake_id; |
int rc; |
/* Before we even try creating the task, see if we can write the id */ |
rc = (unative_t) copy_to_uspace(uspace_task_id, &fake_id, |
sizeof(fake_id)); |
if (rc != 0) |
return rc; |
t = task_create_from_loader("loader"); |
/* No need to aquire lock before task_ready() */ |
rc = (unative_t) copy_to_uspace(uspace_task_id, &t->taskid, |
sizeof(t->taskid)); |
if (rc != 0) { |
/* Ooops */ |
task_kill(t->taskid); |
return rc; |
} |
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 |
/branches/dynload/kernel/generic/src/lib/elf.c |
---|
57,7 → 57,7 |
}; |
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf, |
as_t *as); |
as_t *as, int flags); |
static int section_header(elf_section_header_t *entry, elf_header_t *elf, |
as_t *as); |
static int load_segment(elf_segment_header_t *entry, elf_header_t *elf, |
67,9 → 67,10 |
* |
* @param header Pointer to ELF header in memory |
* @param as Created and properly mapped address space |
* @param flags A combination of ELD_F_* |
* @return EE_OK on success |
*/ |
unsigned int elf_load(elf_header_t *header, as_t * as) |
unsigned int elf_load(elf_header_t *header, as_t * as, int flags) |
{ |
int i, rc; |
106,7 → 107,7 |
seghdr = &((elf_segment_header_t *)(((uint8_t *) header) + |
header->e_phoff))[i]; |
rc = segment_header(seghdr, header, as); |
rc = segment_header(seghdr, header, as, flags); |
if (rc != EE_OK) |
return rc; |
} |
147,8 → 148,10 |
* @return EE_OK on success, error code otherwise. |
*/ |
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf, |
as_t *as) |
as_t *as, int flags) |
{ |
char *interp; |
switch (entry->p_type) { |
case PT_NULL: |
case PT_PHDR: |
158,6 → 161,14 |
break; |
case PT_DYNAMIC: |
case PT_INTERP: |
interp = (char *)elf + entry->p_offset; |
if (memcmp(interp, ELF_INTERP_ZSTR, ELF_INTERP_ZLEN) != 0) { |
return EE_UNSUPPORTED; |
} |
if ((flags & ELD_F_LOADER) == 0) { |
return EE_LOADER; |
} |
break; |
case PT_SHLIB: |
case PT_NOTE: |
case PT_LOPROC: |
/branches/dynload/kernel/generic/src/syscall/syscall.c |
---|
128,6 → 128,7 |
(syshandler_t) sys_thread_exit, |
(syshandler_t) sys_thread_get_id, |
(syshandler_t) sys_task_get_id, |
(syshandler_t) sys_task_spawn, |
/* Synchronization related syscalls. */ |
(syshandler_t) sys_futex_sleep_timeout, |