mirror of
https://github.com/drasko/codezero.git
synced 2026-02-27 01:03:14 +01:00
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:
@@ -1,7 +1,5 @@
|
|||||||
#ifndef __API_SPACE_H__
|
#ifndef __API_SPACE_H__
|
||||||
#define __API_SPACE_H__
|
#define __API_SPACE_H__
|
||||||
|
|
||||||
#define UNMAP_ALL_SPACE 0xFFFFFFFF
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __API_SPACE_H__ */
|
#endif /* __API_SPACE_H__ */
|
||||||
|
|||||||
@@ -21,5 +21,6 @@
|
|||||||
#define THREAD_SUSPEND 0x0002
|
#define THREAD_SUSPEND 0x0002
|
||||||
#define THREAD_RESUME 0x0003
|
#define THREAD_RESUME 0x0003
|
||||||
#define THREAD_DESTROY 0x0004
|
#define THREAD_DESTROY 0x0004
|
||||||
|
#define THREAD_RECYCLE 0x0005
|
||||||
|
|
||||||
#endif /* __THREAD_H__ */
|
#endif /* __THREAD_H__ */
|
||||||
|
|||||||
@@ -39,6 +39,8 @@
|
|||||||
|
|
||||||
/* Align to given size */
|
/* Align to given size */
|
||||||
#define align(addr, size) (((unsigned int)(addr)) & (~(size-1)))
|
#define align(addr, size) (((unsigned int)(addr)) & (~(size-1)))
|
||||||
|
#define align_up(addr, size) ((((unsigned long)(addr)) + \
|
||||||
|
((size) - 1)) & (~((size) - 1)))
|
||||||
|
|
||||||
/* The bytes left until the end of the page that x is in */
|
/* The bytes left until the end of the page that x is in */
|
||||||
#define TILL_PAGE_ENDS(x) (PAGE_SIZE - ((unsigned long)(x) & PAGE_MASK))
|
#define TILL_PAGE_ENDS(x) (PAGE_SIZE - ((unsigned long)(x) & PAGE_MASK))
|
||||||
@@ -57,7 +59,6 @@
|
|||||||
#define BITWISE_GETWORD(x) ((x) >> WORD_BITS_LOG2) /* Divide by 32 */
|
#define BITWISE_GETWORD(x) ((x) >> WORD_BITS_LOG2) /* Divide by 32 */
|
||||||
#define BITWISE_GETBIT(x) (1 << ((x) % WORD_BITS))
|
#define BITWISE_GETBIT(x) (1 << ((x) % WORD_BITS))
|
||||||
|
|
||||||
#define align_up(addr, size) ((((unsigned long)(addr)) + ((size) - 1)) & (~((size) - 1)))
|
|
||||||
|
|
||||||
/* Endianness conversion */
|
/* Endianness conversion */
|
||||||
static inline void be32_to_cpu(unsigned int x)
|
static inline void be32_to_cpu(unsigned int x)
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#define SZ_1K 1024
|
#define SZ_1K 1024
|
||||||
#define SZ_4K 0x1000
|
#define SZ_4K 0x1000
|
||||||
#define SZ_16K 0x4000
|
#define SZ_16K 0x4000
|
||||||
|
#define SZ_32K 0x8000
|
||||||
#define SZ_64K 0x10000
|
#define SZ_64K 0x10000
|
||||||
#define SZ_1MB 0x100000
|
#define SZ_1MB 0x100000
|
||||||
#define SZ_8MB (8*SZ_1MB)
|
#define SZ_8MB (8*SZ_1MB)
|
||||||
|
|||||||
@@ -59,16 +59,6 @@ int sys_unmap(syscall_context_t *regs)
|
|||||||
else if (!(target = find_task(tid)))
|
else if (!(target = find_task(tid)))
|
||||||
return -ESRCH;
|
return -ESRCH;
|
||||||
|
|
||||||
/*
|
|
||||||
* These special values mean unmap all the mappings
|
|
||||||
* from task space except the kernel mappings
|
|
||||||
*/
|
|
||||||
if (virtual == UNMAP_ALL_SPACE &&
|
|
||||||
npages == UNMAP_ALL_SPACE) {
|
|
||||||
remove_mapping_pgd_all_user(target->pgd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < npages; i++) {
|
for (int i = 0; i < npages; i++) {
|
||||||
ret = remove_mapping_pgd(virtual + i * PAGE_SIZE, target->pgd);
|
ret = remove_mapping_pgd(virtual + i * PAGE_SIZE, target->pgd);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ void do_exchange_registers(struct ktcb *task, struct exregs_data *exregs)
|
|||||||
* the register context of a thread. The thread's registers can be
|
* the register context of a thread. The thread's registers can be
|
||||||
* set only when the thread is in user mode. A newly created thread
|
* set only when the thread is in user mode. A newly created thread
|
||||||
* that is the copy of another thread (forked or cloned) will also
|
* that is the copy of another thread (forked or cloned) will also
|
||||||
* be given its user mode context on the first chance to execute so
|
* be given its user mode context on the first chance to execute so
|
||||||
* such threads can also be modified by this call before execution.
|
* such threads can also be modified by this call before execution.
|
||||||
*
|
*
|
||||||
* A thread executing in the kernel cannot be modified since this
|
* A thread executing in the kernel cannot be modified since this
|
||||||
@@ -119,6 +119,9 @@ int sys_exchange_registers(syscall_context_t *regs)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
A suspended thread implies it cannot do any harm
|
||||||
|
even if it is in kernel mode.
|
||||||
/*
|
/*
|
||||||
* The thread must be in user mode for its context
|
* The thread must be in user mode for its context
|
||||||
* to be modified.
|
* to be modified.
|
||||||
@@ -127,6 +130,7 @@ int sys_exchange_registers(syscall_context_t *regs)
|
|||||||
err = -EPERM;
|
err = -EPERM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Copy registers */
|
/* Copy registers */
|
||||||
do_exchange_registers(task, exregs);
|
do_exchange_registers(task, exregs);
|
||||||
|
|||||||
@@ -49,6 +49,47 @@ int thread_suspend(struct task_ids *ids)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int arch_clear_thread(struct ktcb *task)
|
||||||
|
{
|
||||||
|
memset(&task->context, 0, sizeof(task->context));
|
||||||
|
task->context.spsr = ARM_MODE_USR;
|
||||||
|
|
||||||
|
/* Clear the page tables */
|
||||||
|
remove_mapping_pgd_all_user(task->pgd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int thread_recycle(struct task_ids *ids)
|
||||||
|
{
|
||||||
|
struct ktcb *task;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!(task = find_task(ids->tid)))
|
||||||
|
return -ESRCH;
|
||||||
|
|
||||||
|
if ((ret = thread_suspend(ids)) < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there are any sleepers on any of the task's
|
||||||
|
* waitqueues, we need to wake those tasks up.
|
||||||
|
*/
|
||||||
|
wake_up_all(&task->wqh_send, 0);
|
||||||
|
wake_up_all(&task->wqh_recv, 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The thread cannot have a pager waiting for it
|
||||||
|
* since we ought to be the pager.
|
||||||
|
*/
|
||||||
|
BUG_ON(task->wqh_pager.sleepers > 0);
|
||||||
|
|
||||||
|
/* Clear the task's tcb */
|
||||||
|
arch_clear_thread(task);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int thread_destroy(struct task_ids *ids)
|
int thread_destroy(struct task_ids *ids)
|
||||||
{
|
{
|
||||||
struct ktcb *task;
|
struct ktcb *task;
|
||||||
@@ -292,6 +333,10 @@ int sys_thread_control(syscall_context_t *regs)
|
|||||||
break;
|
break;
|
||||||
case THREAD_DESTROY:
|
case THREAD_DESTROY:
|
||||||
ret = thread_destroy(ids);
|
ret = thread_destroy(ids);
|
||||||
|
break;
|
||||||
|
case THREAD_RECYCLE:
|
||||||
|
ret = thread_recycle(ids);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ shmat
|
|||||||
shmget
|
shmget
|
||||||
shmdt
|
shmdt
|
||||||
mmap
|
mmap
|
||||||
|
munmap
|
||||||
read
|
read
|
||||||
readdir
|
readdir
|
||||||
write
|
write
|
||||||
@@ -51,19 +52,18 @@ creat
|
|||||||
mkdir
|
mkdir
|
||||||
mknod
|
mknod
|
||||||
fork
|
fork
|
||||||
|
clone
|
||||||
|
execve
|
||||||
|
exit
|
||||||
|
getpid
|
||||||
|
|
||||||
|
|
||||||
Functions to be supported in the near future are:
|
Functions to be supported in the near future are:
|
||||||
|
|
||||||
munmap
|
|
||||||
link
|
link
|
||||||
unlink
|
unlink
|
||||||
getpid
|
|
||||||
execve
|
|
||||||
clone
|
|
||||||
wait
|
wait
|
||||||
kill
|
kill
|
||||||
exit
|
|
||||||
sbrk
|
sbrk
|
||||||
getenv
|
getenv
|
||||||
setenv
|
setenv
|
||||||
|
|||||||
@@ -7,9 +7,7 @@
|
|||||||
#ifndef __EXIT_H__
|
#ifndef __EXIT_H__
|
||||||
#define __EXIT_H__
|
#define __EXIT_H__
|
||||||
|
|
||||||
#define EXIT_THREAD_DESTROY (1 << 0)
|
void do_exit(struct tcb *task, int status);
|
||||||
#define EXIT_UNMAP_ALL_SPACE (1 << 1)
|
int execve_recycle_task(struct tcb *task);
|
||||||
|
|
||||||
|
|
||||||
void do_exit(struct tcb *task, unsigned int flags, int status);
|
|
||||||
#endif /* __EXIT_H__ */
|
#endif /* __EXIT_H__ */
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
/* POSIX minimum is 4Kb */
|
/* POSIX minimum is 4Kb */
|
||||||
#define DEFAULT_ENV_SIZE SZ_4K
|
#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 DEFAULT_UTCB_SIZE PAGE_SIZE
|
||||||
|
|
||||||
#define TCB_NO_SHARING 0
|
#define TCB_NO_SHARING 0
|
||||||
@@ -94,8 +94,6 @@ struct tcb {
|
|||||||
unsigned long stack_end;
|
unsigned long stack_end;
|
||||||
unsigned long heap_start;
|
unsigned long heap_start;
|
||||||
unsigned long heap_end;
|
unsigned long heap_end;
|
||||||
unsigned long env_start;
|
|
||||||
unsigned long env_end;
|
|
||||||
unsigned long args_start;
|
unsigned long args_start;
|
||||||
unsigned long args_end;
|
unsigned long args_end;
|
||||||
|
|
||||||
@@ -122,7 +120,8 @@ struct tcb *find_task(int tid);
|
|||||||
void global_add_task(struct tcb *task);
|
void global_add_task(struct tcb *task);
|
||||||
void global_remove_task(struct tcb *task);
|
void global_remove_task(struct tcb *task);
|
||||||
void task_map_prefault_utcb(struct tcb *mapper, struct tcb *owner);
|
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,
|
int task_setup_registers(struct tcb *task, unsigned int pc,
|
||||||
unsigned int sp, l4id_t pager);
|
unsigned int sp, l4id_t pager);
|
||||||
struct tcb *tcb_alloc_init(unsigned int flags);
|
struct tcb *tcb_alloc_init(unsigned int flags);
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ int do_execve(struct tcb *sender, char *filename, struct args_struct *args,
|
|||||||
* TODO: Set up parents for children's children
|
* TODO: Set up parents for children's children
|
||||||
*/
|
*/
|
||||||
list_for_each_entry(thread, &tgleader->children, child_ref)
|
list_for_each_entry(thread, &tgleader->children, child_ref)
|
||||||
do_exit(thread, EXIT_THREAD_DESTROY, 0);
|
do_exit(thread, 0);
|
||||||
} else {
|
} else {
|
||||||
/* Otherwise group leader is same as sender */
|
/* Otherwise group leader is same as sender */
|
||||||
tgleader = 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->spid = tgleader->spid;
|
||||||
new_task->tgid = tgleader->tgid;
|
new_task->tgid = tgleader->tgid;
|
||||||
new_task->pagerid = tgleader->pagerid;
|
new_task->pagerid = tgleader->pagerid;
|
||||||
|
new_task->utcb = tgleader->utcb;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Release all task resources, do everything done in
|
* Release all task resources, do everything done in
|
||||||
* exit() except destroying the actual thread.
|
* 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 */
|
/* 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);
|
vm_file_put(vmfile);
|
||||||
kfree(new_task);
|
kfree(new_task);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set up task registers via exchange_registers() */
|
/* 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 */
|
/* Start the task */
|
||||||
task_start(new_task);
|
task_start(new_task);
|
||||||
@@ -186,7 +194,7 @@ Dynamic Linking.
|
|||||||
* - Jump to the entry point of main executable.
|
* - Jump to the entry point of main executable.
|
||||||
*/
|
*/
|
||||||
#endif
|
#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;
|
void *mapped = 0;
|
||||||
int (*copy_func)(void *, void *, int count);
|
int (*copy_func)(void *, void *, int count);
|
||||||
|
|
||||||
|
/* This bit determines what size copier function to use. */
|
||||||
if (elem_size == sizeof(char))
|
if (elem_size == sizeof(char))
|
||||||
copy_func = strncpy_page;
|
copy_func = strncpy_page;
|
||||||
else if (elem_size == sizeof(unsigned long))
|
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 sys_execve(struct tcb *sender, char *pathname, char *argv[], char *envp[])
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
char *path = kzalloc(PATH_MAX);
|
char *path;
|
||||||
struct args_struct args;
|
struct args_struct args;
|
||||||
struct args_struct env;
|
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 */
|
/* Copy the executable path string */
|
||||||
if ((ret = copy_user_string(sender, path, pathname, PATH_MAX)) < 0)
|
if ((ret = copy_user_string(sender, path, pathname, PATH_MAX)) < 0)
|
||||||
return ret;
|
return ret;
|
||||||
printf("%s: Copied pathname: %s\n", __FUNCTION__, path);
|
printf("%s: Copied pathname: %s\n", __FUNCTION__, path);
|
||||||
|
|
||||||
/* Copy the args */
|
/* 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;
|
goto out1;
|
||||||
|
|
||||||
/* Copy the env */
|
/* 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;
|
goto out2;
|
||||||
|
|
||||||
ret = do_execve(sender, path, &args, &env);
|
ret = do_execve(sender, path, &args, &env);
|
||||||
|
|
||||||
kfree(env.argv);
|
if (env.argv)
|
||||||
|
kfree(env.argv);
|
||||||
out2:
|
out2:
|
||||||
kfree(args.argv);
|
if (args.argv)
|
||||||
|
kfree(args.argv);
|
||||||
out1:
|
out1:
|
||||||
kfree(path);
|
kfree(path);
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -68,7 +68,37 @@ int task_close_files(struct tcb *task)
|
|||||||
return err;
|
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 = {
|
struct task_ids ids = {
|
||||||
.tid = task->tid,
|
.tid = task->tid,
|
||||||
@@ -89,14 +119,8 @@ void do_exit(struct tcb *task, unsigned int flags, int status)
|
|||||||
/* Free task's local tcb */
|
/* Free task's local tcb */
|
||||||
tcb_destroy(task);
|
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 */
|
/* 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 */
|
/* TODO: Wake up any waiters about task's destruction */
|
||||||
#if 0
|
#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)
|
void sys_exit(struct tcb *task, int status)
|
||||||
{
|
{
|
||||||
do_exit(task, EXIT_THREAD_DESTROY, status);
|
do_exit(task, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -223,8 +223,15 @@ int bootfile_release_pages(struct vm_object *vm_obj)
|
|||||||
list_del(&p->list);
|
list_del(&p->list);
|
||||||
BUG_ON(p->refcnt);
|
BUG_ON(p->refcnt);
|
||||||
|
|
||||||
/* Free the page structure */
|
/* Reinitialise the page */
|
||||||
kfree(p);
|
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 */
|
/* Reduce object page count */
|
||||||
BUG_ON(--vm_obj->npages < 0);
|
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 */
|
/* From bare boot images, create mappable device files */
|
||||||
int init_boot_files(struct initdata *initdata)
|
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->priv_data = img;
|
||||||
boot_file->length = img->phys_end - img->phys_start;
|
boot_file->length = img->phys_end - img->phys_start;
|
||||||
boot_file->type = VM_FILE_BOOTFILE;
|
boot_file->type = VM_FILE_BOOTFILE;
|
||||||
|
boot_file->destroy_priv_data =
|
||||||
|
bootfile_destroy_priv_data;
|
||||||
|
|
||||||
/* Initialise the vm object */
|
/* Initialise the vm object */
|
||||||
boot_file->vm_obj.flags = VM_OBJ_FILE;
|
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 */
|
/* Add the file to initdata's bootfile list */
|
||||||
list_add_tail(&boot_file->list, &initdata->boot_file_list);
|
list_add_tail(&boot_file->list, &initdata->boot_file_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -236,8 +236,6 @@ int copy_tcb(struct tcb *to, struct tcb *from, unsigned int flags)
|
|||||||
to->stack_end = from->stack_end;
|
to->stack_end = from->stack_end;
|
||||||
to->heap_start = from->heap_start;
|
to->heap_start = from->heap_start;
|
||||||
to->heap_end = from->heap_end;
|
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_start = from->args_start;
|
||||||
to->args_end = from->args_end;
|
to->args_end = from->args_end;
|
||||||
to->map_start = from->map_start;
|
to->map_start = from->map_start;
|
||||||
@@ -343,6 +341,87 @@ struct tcb *task_create(struct tcb *parent, struct task_ids *ids,
|
|||||||
return task;
|
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
|
* If bss comes consecutively after the data section, prefault the
|
||||||
* last page of the data section and zero out the bit that contains
|
* 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;
|
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;
|
void *mapped;
|
||||||
struct vm_file *shm;
|
//struct vm_file *shm;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* mmap task's text to task's address space. */
|
/* 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;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mmap task's environment as anonymous memory. */
|
/* mmap task's stack, writing in the arguments and environment */
|
||||||
if (IS_ERR(mapped = do_mmap(0, 0, task, task->env_start,
|
if ((err = task_map_stack(file, efd, task, args, env)) < 0) {
|
||||||
VM_READ | VM_WRITE |
|
printf("%s: Mapping task's stack has failed.\n",
|
||||||
VMA_PRIVATE | VMA_ANONYMOUS,
|
__FUNCTION__);
|
||||||
__pfn(task->env_end - task->env_start)))) {
|
return err;
|
||||||
printf("do_mmap: Mapping environment failed with %d.\n",
|
|
||||||
(int)mapped);
|
|
||||||
return (int)mapped;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mmap task's stack as anonymous memory. */
|
/*
|
||||||
if (IS_ERR(mapped = do_mmap(0, 0, task, task->stack_start,
|
* Task already has recycled task's utcb. It will attach to it
|
||||||
VM_READ | VM_WRITE |
|
* when it starts in userspace.
|
||||||
VMA_PRIVATE | VMA_ANONYMOUS,
|
*/
|
||||||
__pfn(task->stack_end -
|
//if (IS_ERR(shm = shm_new((key_t)task->utcb, __pfn(DEFAULT_UTCB_SIZE))))
|
||||||
task->stack_start)))) {
|
// return (int)shm;
|
||||||
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;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -483,7 +549,8 @@ int task_setup_registers(struct tcb *task, unsigned int pc,
|
|||||||
if (!sp)
|
if (!sp)
|
||||||
sp = align(task->stack_end - 1, 8);
|
sp = align(task->stack_end - 1, 8);
|
||||||
if (!pc)
|
if (!pc)
|
||||||
pc = task->entry;
|
if (!(pc = task->entry))
|
||||||
|
pc = task->text_start;
|
||||||
if (!pager)
|
if (!pager)
|
||||||
pager = self_tid();
|
pager = self_tid();
|
||||||
|
|
||||||
@@ -492,7 +559,7 @@ int task_setup_registers(struct tcb *task, unsigned int pc,
|
|||||||
exregs_set_pc(&exregs, pc);
|
exregs_set_pc(&exregs, pc);
|
||||||
exregs_set_pager(&exregs, pager);
|
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);
|
printf("l4_exchange_registers failed with %d.\n", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user