Task initally exec'ing with success. Some errors need to be investigated.

- Directory creation, file read/write is OK.
- Cannot reuse old task's fds. They are not recycled for some reason.
- Problems with fork/clone/exit. They fail for a reason.
This commit is contained in:
Bahadir Balban
2008-12-01 13:53:50 +02:00
parent 783b1e025f
commit 05d8438f34
14 changed files with 239 additions and 79 deletions

View File

@@ -41,6 +41,7 @@ shmat
shmget
shmdt
mmap
munmap
read
readdir
write
@@ -51,19 +52,18 @@ creat
mkdir
mknod
fork
clone
execve
exit
getpid
Functions to be supported in the near future are:
munmap
link
unlink
getpid
execve
clone
wait
kill
exit
sbrk
getenv
setenv

View File

@@ -7,9 +7,7 @@
#ifndef __EXIT_H__
#define __EXIT_H__
#define EXIT_THREAD_DESTROY (1 << 0)
#define EXIT_UNMAP_ALL_SPACE (1 << 1)
void do_exit(struct tcb *task, int status);
int execve_recycle_task(struct tcb *task);
void do_exit(struct tcb *task, unsigned int flags, int status);
#endif /* __EXIT_H__ */

View File

@@ -25,7 +25,7 @@
/* POSIX minimum is 4Kb */
#define DEFAULT_ENV_SIZE SZ_4K
#define DEFAULT_STACK_SIZE SZ_16K
#define DEFAULT_STACK_SIZE SZ_32K
#define DEFAULT_UTCB_SIZE PAGE_SIZE
#define TCB_NO_SHARING 0
@@ -94,8 +94,6 @@ struct tcb {
unsigned long stack_end;
unsigned long heap_start;
unsigned long heap_end;
unsigned long env_start;
unsigned long env_end;
unsigned long args_start;
unsigned long args_end;
@@ -122,7 +120,8 @@ struct tcb *find_task(int tid);
void global_add_task(struct tcb *task);
void global_remove_task(struct tcb *task);
void task_map_prefault_utcb(struct tcb *mapper, struct tcb *owner);
int task_mmap_segments(struct tcb *task, struct vm_file *file, struct exec_file_desc *efd);
int task_mmap_segments(struct tcb *task, struct vm_file *file, struct exec_file_desc *efd,
struct args_struct *args, struct args_struct *env);
int task_setup_registers(struct tcb *task, unsigned int pc,
unsigned int sp, l4id_t pager);
struct tcb *tcb_alloc_init(unsigned int flags);

View File

@@ -128,7 +128,7 @@ int do_execve(struct tcb *sender, char *filename, struct args_struct *args,
* TODO: Set up parents for children's children
*/
list_for_each_entry(thread, &tgleader->children, child_ref)
do_exit(thread, EXIT_THREAD_DESTROY, 0);
do_exit(thread, 0);
} else {
/* Otherwise group leader is same as sender */
tgleader = sender;
@@ -139,22 +139,30 @@ int do_execve(struct tcb *sender, char *filename, struct args_struct *args,
new_task->spid = tgleader->spid;
new_task->tgid = tgleader->tgid;
new_task->pagerid = tgleader->pagerid;
new_task->utcb = tgleader->utcb;
/*
* Release all task resources, do everything done in
* exit() except destroying the actual thread.
*/
do_exit(tgleader, EXIT_UNMAP_ALL_SPACE, 0);
if ((err = execve_recycle_task(tgleader)) < 0) {
vm_file_put(vmfile);
kfree(new_task);
return err;
}
/* Map task's new segment markers as virtual memory regions */
if ((err = task_mmap_segments(new_task, vmfile, &efd)) < 0) {
if ((err = task_mmap_segments(new_task, vmfile, &efd, args, env)) < 0) {
vm_file_put(vmfile);
kfree(new_task);
return err;
}
/* Set up task registers via exchange_registers() */
task_setup_registers(new_task, 0, 0, new_task->pagerid);
task_setup_registers(new_task, 0, new_task->args_start, new_task->pagerid);
/* Add new task to global list */
global_add_task(new_task);
/* Start the task */
task_start(new_task);
@@ -186,7 +194,7 @@ Dynamic Linking.
* - Jump to the entry point of main executable.
*/
#endif
return -1;
return 0;
}
/*
@@ -253,6 +261,7 @@ int copy_user_buf(struct tcb *task, void *buf, char *user, int maxlength,
void *mapped = 0;
int (*copy_func)(void *, void *, int count);
/* This bit determines what size copier function to use. */
if (elem_size == sizeof(char))
copy_func = strncpy_page;
else if (elem_size == sizeof(unsigned long))
@@ -376,28 +385,37 @@ out:
int sys_execve(struct tcb *sender, char *pathname, char *argv[], char *envp[])
{
int ret;
char *path = kzalloc(PATH_MAX);
char *path;
struct args_struct args;
struct args_struct env;
if (!(path = kzalloc(PATH_MAX)))
return -ENOMEM;
memset(&args, 0, sizeof(args));
memset(&env, 0, sizeof(env));
/* Copy the executable path string */
if ((ret = copy_user_string(sender, path, pathname, PATH_MAX)) < 0)
return ret;
printf("%s: Copied pathname: %s\n", __FUNCTION__, path);
/* Copy the args */
if ((ret = copy_user_args(sender, &args, argv, ARGS_MAX)) < 0)
if (argv && ((ret = copy_user_args(sender, &args, argv, ARGS_MAX)) < 0))
goto out1;
/* Copy the env */
if ((ret = copy_user_args(sender, &env, envp, ARGS_MAX - args.size)))
if (envp && ((ret = copy_user_args(sender, &env, envp,
ARGS_MAX - args.size)) < 0))
goto out2;
ret = do_execve(sender, path, &args, &env);
kfree(env.argv);
if (env.argv)
kfree(env.argv);
out2:
kfree(args.argv);
if (args.argv)
kfree(args.argv);
out1:
kfree(path);
return ret;

View File

@@ -68,7 +68,37 @@ int task_close_files(struct tcb *task)
return err;
}
void do_exit(struct tcb *task, unsigned int flags, int status)
/* Prepare old task's environment for new task */
int execve_recycle_task(struct tcb *task)
{
int err;
struct task_ids ids = {
.tid = task->tid,
.spid = task->spid,
.tgid = task->tgid,
};
/* Flush all IO on task's files and close fds */
task_close_files(task);
/* Vfs still knows the thread */
/* Keep the utcb on vfs */
/* Ask the kernel to recycle the thread */
if ((err = l4_thread_control(THREAD_RECYCLE, &ids)) < 0) {
printf("%s: Suspending thread %d failed with %d.\n",
__FUNCTION__, task->tid, err);
return err;
}
/* Destroy the locally known tcb */
tcb_destroy(task);
return 0;
}
void do_exit(struct tcb *task, int status)
{
struct task_ids ids = {
.tid = task->tid,
@@ -89,14 +119,8 @@ void do_exit(struct tcb *task, unsigned int flags, int status)
/* Free task's local tcb */
tcb_destroy(task);
/* Ask the kernel to reset this thread's page tables */
if (flags & EXIT_UNMAP_ALL_SPACE)
l4_unmap((void *)UNMAP_ALL_SPACE,
UNMAP_ALL_SPACE, task->tid);
/* Ask the kernel to delete the thread from its records */
if (flags & EXIT_THREAD_DESTROY)
l4_thread_control(THREAD_DESTROY, &ids);
l4_thread_control(THREAD_DESTROY, &ids);
/* TODO: Wake up any waiters about task's destruction */
#if 0
@@ -111,6 +135,6 @@ void do_exit(struct tcb *task, unsigned int flags, int status)
void sys_exit(struct tcb *task, int status)
{
do_exit(task, EXIT_THREAD_DESTROY, status);
do_exit(task, status);
}

View File

@@ -223,8 +223,15 @@ int bootfile_release_pages(struct vm_object *vm_obj)
list_del(&p->list);
BUG_ON(p->refcnt);
/* Free the page structure */
kfree(p);
/* Reinitialise the page */
page_init(p);
/*
* We don't free the page because it doesn't
* come from the page allocator
*/
// free_page((void *)page_to_phys(p));
/* Reduce object page count */
BUG_ON(--vm_obj->npages < 0);
@@ -276,6 +283,10 @@ struct vm_pager bootfile_pager = {
},
};
void bootfile_destroy_priv_data(struct vm_file *bootfile)
{
}
/* From bare boot images, create mappable device files */
int init_boot_files(struct initdata *initdata)
@@ -292,6 +303,8 @@ int init_boot_files(struct initdata *initdata)
boot_file->priv_data = img;
boot_file->length = img->phys_end - img->phys_start;
boot_file->type = VM_FILE_BOOTFILE;
boot_file->destroy_priv_data =
bootfile_destroy_priv_data;
/* Initialise the vm object */
boot_file->vm_obj.flags = VM_OBJ_FILE;
@@ -300,6 +313,7 @@ int init_boot_files(struct initdata *initdata)
/* Add the file to initdata's bootfile list */
list_add_tail(&boot_file->list, &initdata->boot_file_list);
}
return 0;
}

View File

@@ -236,8 +236,6 @@ int copy_tcb(struct tcb *to, struct tcb *from, unsigned int flags)
to->stack_end = from->stack_end;
to->heap_start = from->heap_start;
to->heap_end = from->heap_end;
to->env_start = from->env_start;
to->env_end = from->env_end;
to->args_start = from->args_start;
to->args_end = from->args_end;
to->map_start = from->map_start;
@@ -343,6 +341,87 @@ struct tcb *task_create(struct tcb *parent, struct task_ids *ids,
return task;
}
/*
* Copy argument and environment strings into task's stack in a
* format that is expected by the C runtime.
*
* e.g. uclibc expects stack state:
*
* (low) |->argc|argv[0]|argv[1]|...|argv[argc] = 0|envp[0]|...|NULL| (high)
*
*/
int task_args_to_user(char *user_stack, struct args_struct *args,
struct args_struct *env)
{
BUG_ON((unsigned long)user_stack & 7);
/* Copy argc */
*((int *)user_stack) = args->argc;
user_stack += sizeof(int);
/* Copy argument strings one by one */
for (int i = 0; i < args->argc; i++) {
strcpy(user_stack, args->argv[i]);
user_stack += strlen(args->argv[i]) + 1;
}
/* Put the null terminator integer */
*((int *)user_stack) = 0;
user_stack = user_stack + sizeof(int);
/* Copy environment strings one by one */
for (int i = 0; i < env->argc; i++) {
strcpy(user_stack, env->argv[i]);
user_stack += strlen(env->argv[i]) + 1;
}
return 0;
}
int task_map_stack(struct vm_file *f, struct exec_file_desc *efd, struct tcb *task,
struct args_struct *args, struct args_struct *env)
{
/* First set up task's stack markers */
unsigned long stack_used = align_up(args->size + env->size, 8);
unsigned long arg_pages = __pfn(page_align_up(stack_used));
char *args_on_stack;
void *mapped;
task->stack_end = USER_AREA_END;
task->stack_start = USER_AREA_END - DEFAULT_STACK_SIZE;
task->args_end = task->stack_end;
task->args_start = task->stack_end - stack_used;
BUG_ON(stack_used > DEFAULT_STACK_SIZE);
/*
* mmap task's stack as anonymous memory.
* TODO: Add VMA_GROWSDOWN here so the stack can expand.
*/
if (IS_ERR(mapped = do_mmap(0, 0, task, task->stack_start,
VM_READ | VM_WRITE |
VMA_PRIVATE | VMA_ANONYMOUS,
__pfn(task->stack_end -
task->stack_start)))) {
printf("do_mmap: Mapping stack failed with %d.\n",
(int)mapped);
return (int)mapped;
}
/* Map the stack's part that will contain args and environment */
args_on_stack =
pager_validate_map_user_range2(task,
(void *)task->args_start,
stack_used, VM_READ | VM_WRITE);
/* Copy arguments and env */
task_args_to_user(args_on_stack, args, env);
/* Unmap task's those stack pages from pager */
pager_unmap_pages(args_on_stack, arg_pages);
return 0;
}
/*
* If bss comes consecutively after the data section, prefault the
* last page of the data section and zero out the bit that contains
@@ -411,10 +490,11 @@ int task_map_bss(struct vm_file *f, struct exec_file_desc *efd, struct tcb *task
return 0;
}
int task_mmap_segments(struct tcb *task, struct vm_file *file, struct exec_file_desc *efd)
int task_mmap_segments(struct tcb *task, struct vm_file *file, struct exec_file_desc *efd,
struct args_struct *args, struct args_struct *env)
{
void *mapped;
struct vm_file *shm;
//struct vm_file *shm;
int err;
/* mmap task's text to task's address space. */
@@ -442,33 +522,19 @@ int task_mmap_segments(struct tcb *task, struct vm_file *file, struct exec_file_
return err;
}
/* mmap task's environment as anonymous memory. */
if (IS_ERR(mapped = do_mmap(0, 0, task, task->env_start,
VM_READ | VM_WRITE |
VMA_PRIVATE | VMA_ANONYMOUS,
__pfn(task->env_end - task->env_start)))) {
printf("do_mmap: Mapping environment failed with %d.\n",
(int)mapped);
return (int)mapped;
/* mmap task's stack, writing in the arguments and environment */
if ((err = task_map_stack(file, efd, task, args, env)) < 0) {
printf("%s: Mapping task's stack has failed.\n",
__FUNCTION__);
return err;
}
/* mmap task's stack as anonymous memory. */
if (IS_ERR(mapped = do_mmap(0, 0, task, task->stack_start,
VM_READ | VM_WRITE |
VMA_PRIVATE | VMA_ANONYMOUS,
__pfn(task->stack_end -
task->stack_start)))) {
printf("do_mmap: Mapping stack failed with %d.\n",
(int)mapped);
return (int)mapped;
}
/* Task's utcb */
task->utcb = utcb_new_address();
/* Create a shared memory segment available for shmat() */
if (IS_ERR(shm = shm_new((key_t)task->utcb, __pfn(DEFAULT_UTCB_SIZE))))
return (int)shm;
/*
* Task already has recycled task's utcb. It will attach to it
* when it starts in userspace.
*/
//if (IS_ERR(shm = shm_new((key_t)task->utcb, __pfn(DEFAULT_UTCB_SIZE))))
// return (int)shm;
return 0;
}
@@ -483,7 +549,8 @@ int task_setup_registers(struct tcb *task, unsigned int pc,
if (!sp)
sp = align(task->stack_end - 1, 8);
if (!pc)
pc = task->entry;
if (!(pc = task->entry))
pc = task->text_start;
if (!pager)
pager = self_tid();
@@ -492,7 +559,7 @@ int task_setup_registers(struct tcb *task, unsigned int pc,
exregs_set_pc(&exregs, pc);
exregs_set_pager(&exregs, pager);
if ((err = l4_exchange_registers(&exregs, task->tid) < 0)) {
if ((err = l4_exchange_registers(&exregs, task->tid)) < 0) {
printf("l4_exchange_registers failed with %d.\n", err);
return err;
}