/branches/dynload/kernel/generic/src/main/kinit.c |
---|
47,6 → 47,7 |
#include <proc/scheduler.h> |
#include <proc/task.h> |
#include <proc/thread.h> |
#include <proc/program.h> |
#include <panic.h> |
#include <func.h> |
#include <cpu.h> |
159,7 → 160,7 |
* Create user tasks, load RAM disk images. |
*/ |
count_t i; |
thread_t *threads[CONFIG_INIT_TASKS]; |
program_t programs[CONFIG_INIT_TASKS]; |
for (i = 0; i < init.cnt; i++) { |
if (init.tasks[i].addr % FRAME_SIZE) { |
167,19 → 168,19 |
continue; |
} |
int rc = task_parse_initial((void *) init.tasks[i].addr, |
"uspace", &threads[i]); |
int rc = program_create_from_image((void *) init.tasks[i].addr, |
&programs[i]); |
if (rc == 0 && threads[i] != NULL) { |
if (rc == 0 && programs[i].task != NULL) { |
/* |
* Set capabilities to init userspace tasks. |
*/ |
cap_set(threads[i]->task, CAP_CAP | CAP_MEM_MANAGER | |
cap_set(programs[i].task, CAP_CAP | CAP_MEM_MANAGER | |
CAP_IO_MANAGER | CAP_PREEMPT_CONTROL | CAP_IRQ_REG); |
if (!ipc_phone_0) |
ipc_phone_0 = &threads[i]->task->answerbox; |
ipc_phone_0 = &programs[i].task->answerbox; |
} else if (rc == 0) { |
/* It was the program loader and was registered */ |
} else { |
197,9 → 198,9 |
* Run user tasks with reasonable delays |
*/ |
for (i = 0; i < init.cnt; i++) { |
if (threads[i] != NULL) { |
if (programs[i].task != NULL) { |
thread_usleep(50000); |
thread_ready(threads[i]); |
program_ready(&programs[i]); |
} |
} |
/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 |
/branches/dynload/kernel/generic/src/proc/program.c |
---|
0,0 → 1,236 |
/* |
* Copyright (c) 2001-2004 Jakub Jermar |
* Copyright (c) 2008 Jiri Svoboda |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup genericproc |
* @{ |
*/ |
/** |
* @file |
* @brief Running userspace programs. |
*/ |
#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 <arch.h> |
#include <adt/list.h> |
#include <ipc/ipc.h> |
#include <ipc/ipcrsc.h> |
#include <security/cap.h> |
#include <lib/elf.h> |
#include <errno.h> |
#include <syscall/copy.h> |
#include <proc/program.h> |
#ifndef LOADED_PROG_STACK_PAGES_NO |
#define LOADED_PROG_STACK_PAGES_NO 1 |
#endif |
/** |
* Points to the binary image used as the program loader. All non-initial |
* tasks are created from this executable image. |
*/ |
void *program_loader = 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. |
*/ |
void program_create(as_t *as, uintptr_t entry_addr, program_t *p) |
{ |
as_area_t *a; |
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; |
p->task = task_create(as, "app"); |
ASSERT(p->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. |
*/ |
p->main_thread = thread_create(uinit, kernel_uarg, p->task, |
THREAD_FLAG_USPACE, "uinit", false); |
ASSERT(p->main_thread); |
} |
/** 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 program_create_from_image(void *image_addr, program_t *p) |
{ |
as_t *as; |
unsigned int rc; |
as = as_create(0); |
ASSERT(as); |
rc = elf_load((elf_header_t *) image_addr, as, 0); |
if (rc != EE_OK) { |
as_destroy(as); |
p->task = NULL; |
p->main_thread = NULL; |
if (rc != EE_LOADER) |
return ENOTSUP; |
/* Register image as the program loader */ |
ASSERT(program_loader == NULL); |
program_loader = image_addr; |
return EOK; |
} |
program_create(as, ((elf_header_t *) image_addr)->e_entry, p); |
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 program_create_loader(program_t *p) |
{ |
as_t *as; |
unsigned int rc; |
void *loader; |
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; |
} |
program_create(as, ((elf_header_t *) program_loader)->e_entry, p); |
return EOK; |
} |
/** Make task ready. |
* |
* Switch task's thread to the ready state. |
* |
* @param ta Task to make ready. |
*/ |
void program_ready(program_t *p) |
{ |
thread_ready(p->main_thread); |
} |
/** 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_program_spawn_loader(int *uspace_phone_id) |
{ |
program_t p; |
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 = program_create_loader(&p); |
if (rc != 0) |
return rc; |
phone_connect(phone_id, &p.task->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(p.task->taskid); |
return rc; |
} |
// FIXME: control the capabilities |
cap_set(p.task, cap_get(TASK)); |
program_ready(&p); |
return EOK; |
} |
/** @} |
*/ |
/branches/dynload/kernel/generic/src/syscall/syscall.c |
---|
38,6 → 38,7 |
#include <syscall/syscall.h> |
#include <proc/thread.h> |
#include <proc/task.h> |
#include <proc/program.h> |
#include <mm/as.h> |
#include <print.h> |
#include <putchar.h> |
130,7 → 131,7 |
(syshandler_t) sys_thread_get_id, |
(syshandler_t) sys_task_get_id, |
(syshandler_t) sys_task_spawn_loader, |
(syshandler_t) sys_program_spawn_loader, |
/* Synchronization related syscalls. */ |
(syshandler_t) sys_futex_sleep_timeout, |