mirror of
https://github.com/drasko/codezero.git
synced 2026-01-18 05:43:16 +01:00
Multiple above-minor updates.
- fixed is_err(x), was evaluating x twice, resulting in calling a function x twice. - Divided task initialisation into multiple parts. - MM0 now creates a tcb for itself and maintains memory regions of its own. - MM0's tcb is used for mmapping other tasks' regions. MM0 mmaps and prefaults those regions, instead of the typical mmap() and fault approach used by non-pager tasks. For example there's an internal shmget_shmat() path to map in other tasks' shm utcbs. Those mappings are then prefaulted into mm0's address space using the default fault handling path. - FS0 now reads task data into its utcb from mm0 via a syscall. FS0 shmat()s to utcbs of other tasks, e.g. mm0 and test0. FS0 then crashes, that is to be fixed and where this commit is left last.
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
struct tcb {
|
||||
l4id_t tid;
|
||||
unsigned long utcb_address;
|
||||
int utcb_mapped; /* Set if we mapped their utcb */
|
||||
struct list_head list;
|
||||
int fd[TASK_OFILES_MAX];
|
||||
struct id_pool *fdpool;
|
||||
@@ -23,6 +24,11 @@ struct tcb {
|
||||
struct vnode *rootdir;
|
||||
};
|
||||
|
||||
static inline int task_is_utcb_mapped(struct tcb *t)
|
||||
{
|
||||
return t->utcb_mapped;
|
||||
}
|
||||
|
||||
struct tcb *find_task(int tid);
|
||||
int init_task_data(void);
|
||||
|
||||
|
||||
@@ -12,7 +12,10 @@
|
||||
#include <lib/malloc.h>
|
||||
#include <task.h>
|
||||
#include <vfs.h>
|
||||
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
struct tcb_head {
|
||||
struct list_head list;
|
||||
@@ -119,6 +122,36 @@ struct tcb *create_tcb(void)
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Attaches to task's utcb. FIXME: Add SHM_RDONLY and test it. */
|
||||
int task_utcb_attach(struct tcb *t)
|
||||
{
|
||||
int shmid;
|
||||
void *shmaddr;
|
||||
|
||||
/* Use it as a key to create a shared memory region */
|
||||
if ((shmid = shmget((key_t)t->utcb_address, PAGE_SIZE, 0)) == -1)
|
||||
goto out_err;
|
||||
|
||||
/* Attach to the region */
|
||||
if ((int)(shmaddr = shmat(shmid, (void *)t->utcb_address, 0)) == -1)
|
||||
goto out_err;
|
||||
|
||||
/* Ensure address is right */
|
||||
if ((unsigned long)shmaddr != t->utcb_address)
|
||||
return -EINVAL;
|
||||
|
||||
printf("%s: Mapped utcb of task %d @ 0x%x\n",
|
||||
__TASKNAME__, t->tid, shmaddr);
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
printf("%s: Mapping utcb of task %d failed with err: %d.\n",
|
||||
__TASKNAME__, t->tid, errno);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
int init_task_structs(struct task_data_head *tdata_head)
|
||||
{
|
||||
struct tcb *t;
|
||||
@@ -134,6 +167,15 @@ int init_task_structs(struct task_data_head *tdata_head)
|
||||
/* Initialise vfs specific fields. */
|
||||
t->rootdir = vfs_root.pivot;
|
||||
t->curdir = vfs_root.pivot;
|
||||
|
||||
/* Print task information */
|
||||
printf("%s: Task info received from mm0:\n", __TASKNAME__);
|
||||
printf("%s: task id: %d, utcb address: 0x%x\n",
|
||||
__TASKNAME__, t->tid, t->utcb_address);
|
||||
|
||||
/* shm attach to the utcbs for all these tasks except own */
|
||||
if (t->tid != self_tid())
|
||||
task_utcb_attach(t);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -25,6 +25,7 @@ int do_munmap(void *vaddr, unsigned long size, struct tcb *task);
|
||||
int do_mmap(struct vm_file *mapfile, unsigned long f_offset, struct tcb *t,
|
||||
unsigned long map_address, unsigned int flags, unsigned int pages);
|
||||
|
||||
int mmap_address_validate(unsigned long map_address, unsigned int vm_flags);
|
||||
int mmap_address_validate(struct tcb *t, unsigned long map_address,
|
||||
unsigned int vm_flags);
|
||||
|
||||
#endif /* __MM0_MMAP_H__ */
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
#include <l4/api/space.h>
|
||||
#include <l4/macros.h>
|
||||
#include <l4lib/types.h>
|
||||
#include <task.h>
|
||||
#include <posix/sys/ipc.h>
|
||||
#include <posix/sys/shm.h>
|
||||
#include <posix/sys/types.h>
|
||||
|
||||
struct shm_descriptor {
|
||||
int key;
|
||||
@@ -39,4 +43,7 @@ struct shm_descriptor {
|
||||
/* Initialises shared memory bookkeeping structures */
|
||||
void shm_init();
|
||||
|
||||
void *shmat_shmget_internal(key_t key, void *shmaddr);
|
||||
struct vm_file *shm_new(key_t key, unsigned long npages);
|
||||
|
||||
#endif /* __SHM_H__ */
|
||||
|
||||
@@ -48,6 +48,10 @@ struct tcb {
|
||||
/* Related task ids */
|
||||
unsigned int pagerid; /* Task's pager */
|
||||
|
||||
/* Task's main address space region, usually USER_AREA_START/END */
|
||||
unsigned long start;
|
||||
unsigned long end;
|
||||
|
||||
/* Page aligned program segment marks, ends exclusive as usual */
|
||||
unsigned long text_start;
|
||||
unsigned long text_end;
|
||||
@@ -69,8 +73,7 @@ struct tcb {
|
||||
unsigned long map_end;
|
||||
|
||||
/* UTCB information */
|
||||
unsigned long utcb_address;
|
||||
int utcb_mapped;
|
||||
void *utcb;
|
||||
|
||||
/* Virtual memory areas */
|
||||
struct list_head vm_area_list;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* mmap/munmap and friends.
|
||||
*
|
||||
* Copyright (C) 2007 Bahadir Balban
|
||||
* Copyright (C) 2007, 2008 Bahadir Balban
|
||||
*/
|
||||
#include <vm_area.h>
|
||||
#include <kmalloc/kmalloc.h>
|
||||
@@ -394,13 +394,13 @@ unsigned long find_unmapped_area(unsigned long npages, struct tcb *task)
|
||||
|
||||
/* If no vmas, first map slot is available. */
|
||||
if (list_empty(&task->vm_area_list))
|
||||
return USER_AREA_START;
|
||||
return task->start;
|
||||
|
||||
/* First vma to check our range against */
|
||||
vma = list_entry(task->vm_area_list.next, struct vm_area, list);
|
||||
|
||||
/* Start searching from task's end of data to start of stack */
|
||||
while (pfn_end <= __pfn(USER_AREA_END)) {
|
||||
while (pfn_end <= __pfn(task->end)) {
|
||||
|
||||
/* If intersection, skip the vma and fast-forward to next */
|
||||
if (vma_intersect(pfn_start, pfn_end, vma)) {
|
||||
@@ -414,7 +414,7 @@ unsigned long find_unmapped_area(unsigned long npages, struct tcb *task)
|
||||
* Are we out of task map area?
|
||||
*/
|
||||
if (vma->list.next == &task->vm_area_list) {
|
||||
if (pfn_end > __pfn(USER_AREA_END))
|
||||
if (pfn_end > __pfn(task->end))
|
||||
break; /* Yes, fail */
|
||||
else /* No, success */
|
||||
return __pfn_to_addr(pfn_start);
|
||||
@@ -425,22 +425,24 @@ unsigned long find_unmapped_area(unsigned long npages, struct tcb *task)
|
||||
struct vm_area, list);
|
||||
continue;
|
||||
}
|
||||
BUG_ON(pfn_start + npages > __pfn(USER_AREA_END));
|
||||
BUG_ON(pfn_start + npages > __pfn(task->end));
|
||||
return __pfn_to_addr(pfn_start);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Validate an address that is a possible candidate for an mmap() region */
|
||||
int mmap_address_validate(unsigned long map_address, unsigned int vm_flags)
|
||||
int mmap_address_validate(struct tcb *task, unsigned long map_address,
|
||||
unsigned int vm_flags)
|
||||
{
|
||||
if (map_address == 0)
|
||||
return 0;
|
||||
|
||||
/* Private mappings can only go in task address space */
|
||||
if (vm_flags & VMA_PRIVATE) {
|
||||
if (map_address >= USER_AREA_START ||
|
||||
map_address < USER_AREA_END) {
|
||||
if (map_address >= task->start ||
|
||||
map_address < task->end) {
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
@@ -451,8 +453,8 @@ int mmap_address_validate(unsigned long map_address, unsigned int vm_flags)
|
||||
} else if (vm_flags & VMA_SHARED) {
|
||||
if ((map_address >= UTCB_AREA_START &&
|
||||
map_address < UTCB_AREA_END) ||
|
||||
(map_address >= USER_AREA_START &&
|
||||
map_address < USER_AREA_END) ||
|
||||
(map_address >= task->start &&
|
||||
map_address < task->end) ||
|
||||
(map_address >= SHM_AREA_START &&
|
||||
map_address < SHM_AREA_END))
|
||||
return 1;
|
||||
@@ -507,7 +509,7 @@ int do_mmap(struct vm_file *mapfile, unsigned long file_offset,
|
||||
}
|
||||
|
||||
/* Check invalid map address */
|
||||
if (!mmap_address_validate(map_address, flags)) {
|
||||
if (!mmap_address_validate(task, map_address, flags)) {
|
||||
/* Get new map address for region of this size */
|
||||
map_address = find_unmapped_area(npages, task);
|
||||
if ((int)map_address < 0)
|
||||
@@ -585,7 +587,7 @@ int sys_mmap(l4id_t sender, void *start, size_t length, int prot,
|
||||
if ((fd < 0 && !(flags & MAP_ANONYMOUS)) || fd > TASK_FILES_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (base < USER_AREA_START || base >= USER_AREA_END)
|
||||
if (base < task->start || base >= task->end)
|
||||
return -EINVAL;
|
||||
|
||||
/* Exclude task's stack, text and data from mmappable area in task's space */
|
||||
|
||||
@@ -83,7 +83,8 @@ static void *do_shmat(struct vm_file *shm_file, void *shm_addr, int shmflg,
|
||||
|
||||
/* First user? */
|
||||
if (!shm_file->vm_obj.refcnt)
|
||||
if (mmap_address_validate((unsigned long)shm_addr, vmflags))
|
||||
if (mmap_address_validate(task, (unsigned long)shm_addr,
|
||||
vmflags))
|
||||
shm->shm_addr = shm_addr;
|
||||
else
|
||||
shm->shm_addr = address_new(&shm_vaddr_pool,
|
||||
@@ -121,8 +122,10 @@ int sys_shmat(l4id_t requester, l4id_t shmid, void *shmaddr, int shmflg)
|
||||
* the task makes a syscall to mm0 without first
|
||||
* faulting the utcb.
|
||||
*/
|
||||
/*
|
||||
if ((unsigned long)shmaddr == task->utcb_address)
|
||||
utcb_prefault(task, VM_READ | VM_WRITE);
|
||||
*/
|
||||
|
||||
l4_ipc_return((int)shmaddr);
|
||||
return 0;
|
||||
@@ -174,7 +177,7 @@ int sys_shmdt(l4id_t requester, const void *shmaddr)
|
||||
|
||||
|
||||
/* Creates an shm area and glues its details with shm pager and devzero */
|
||||
static struct vm_file *shm_new(key_t key, unsigned long npages)
|
||||
struct vm_file *shm_new(key_t key, unsigned long npages)
|
||||
{
|
||||
struct shm_descriptor *shm_desc;
|
||||
struct vm_file *shm_file;
|
||||
@@ -187,14 +190,14 @@ static struct vm_file *shm_new(key_t key, unsigned long npages)
|
||||
|
||||
if (!(shm_desc = kzalloc(sizeof(struct shm_descriptor)))) {
|
||||
kfree(shm_file);
|
||||
return 0;
|
||||
return PTR_ERR(-ENOMEM);
|
||||
}
|
||||
|
||||
/* Initialise the shm descriptor */
|
||||
if ((shm_desc->shmid = id_new(shm_ids)) < 0) {
|
||||
if (IS_ERR(shm_desc->shmid = id_new(shm_ids))) {
|
||||
kfree(shm_file);
|
||||
kfree(shm_desc);
|
||||
return 0;
|
||||
return PTR_ERR(shm_desc->shmid);
|
||||
}
|
||||
shm_desc->key = (int)key;
|
||||
shm_desc->npages = npages;
|
||||
@@ -214,6 +217,26 @@ static struct vm_file *shm_new(key_t key, unsigned long npages)
|
||||
return shm_file;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fast internal path to do shmget/shmat() together for mm0's
|
||||
* convenience. Works for existing areas.
|
||||
*/
|
||||
void *shmat_shmget_internal(key_t key, void *shmaddr)
|
||||
{
|
||||
struct vm_file *shm_file;
|
||||
struct shm_descriptor *shm_desc;
|
||||
|
||||
list_for_each_entry(shm_file, &shm_file_list, list) {
|
||||
shm_desc = shm_file_to_desc(shm_file);
|
||||
/* Found the key, shmat that area */
|
||||
if (shm_desc->key == key)
|
||||
return do_shmat(shm_file, shmaddr,
|
||||
0, find_task(self_tid()));
|
||||
}
|
||||
|
||||
return PTR_ERR(-EEXIST);
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: Make sure hostile tasks don't subvert other tasks' utcbs
|
||||
* by early-registring their utcb address here.
|
||||
|
||||
@@ -23,145 +23,12 @@
|
||||
#include <memory.h>
|
||||
#include <file.h>
|
||||
#include <utcb.h>
|
||||
#include <proc.h>
|
||||
#include <task.h>
|
||||
#include <shm.h>
|
||||
|
||||
/* A separate list than the generic file list that keeps just the boot files */
|
||||
LIST_HEAD(boot_file_list);
|
||||
|
||||
#if 0
|
||||
int start_boot_tasks(struct initdata *initdata, struct tcb_head *tcbs)
|
||||
{
|
||||
int err;
|
||||
unsigned int sp, pc;
|
||||
struct tcb *task;
|
||||
struct task_ids ids;
|
||||
struct vm_object *vm_obj;
|
||||
|
||||
bd = initdata->bootdesc;
|
||||
INIT_LIST_HEAD(&tcb_head.list);
|
||||
|
||||
for (int i = 0; i < bd->total_images; i++) {
|
||||
img = &bd->images[i];
|
||||
|
||||
/* Skip self */
|
||||
if (!strcmp(img->name, __PAGERNAME__))
|
||||
continue;
|
||||
|
||||
/* Set up task ids */
|
||||
if (!strcmp(img->name, __VFSNAME__)) {
|
||||
ids.tid = VFS_TID;
|
||||
ids.spid = VFS_TID;
|
||||
} else {
|
||||
ids.tid = -1;
|
||||
ids.spid = -1;
|
||||
}
|
||||
|
||||
printf("Creating new thread.\n");
|
||||
/* Create the thread structures and address space */
|
||||
if ((err = l4_thread_control(THREAD_CREATE, &ids)) < 0) {
|
||||
printf("l4_thread_control failed with %d.\n", err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Create a task and use returned space and thread ids. */
|
||||
printf("New task with id: %d, space id: %d\n", ids.tid, ids.spid);
|
||||
task = tcb_alloc_init(tcbs);
|
||||
task->tid = ids.tid;
|
||||
task->spid = ids.spid;
|
||||
|
||||
/* Allocate a utcb virtual address */
|
||||
task->utcb_address = (unsigned long)utcb_vaddr_new();
|
||||
|
||||
/* Prepare environment boundaries. Posix minimum is 4Kb */
|
||||
task->env_end = USER_AREA_END;
|
||||
task->env_start = task->env_end - PAGE_SIZE;
|
||||
task->args_start = task->env_start;
|
||||
task->args_end = task->env_start;
|
||||
|
||||
/*
|
||||
* Prepare the task environment file and data.
|
||||
* Currently it only has the utcb address. The env pager
|
||||
* when faulted, simply copies the task env data to the
|
||||
* allocated page.
|
||||
*/
|
||||
if (task_prepare_proc_files(task) < 0) {
|
||||
printf("Could not create environment file.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Task stack starts right after the environment,
|
||||
* and is of 4 page size.
|
||||
*/
|
||||
task->stack_end = task->env_start;
|
||||
task->stack_start = task->stack_end - PAGE_SIZE * 4;
|
||||
|
||||
/* Currently RO text and RW data are one region */
|
||||
task->data_start = USER_AREA_START;
|
||||
task->data_end = USER_AREA_START + file->length;
|
||||
task->text_start = task->data_start;
|
||||
task->text_end = task->data_end;
|
||||
|
||||
/* Set up task's registers */
|
||||
sp = align(task->stack_end - 1, 8);
|
||||
pc = task->text_start;
|
||||
|
||||
/* mmap each task's physical image to task's address space. */
|
||||
if ((err = do_mmap(file, 0, task, USER_AREA_START,
|
||||
VM_READ | VM_WRITE,
|
||||
__pfn(page_align_up(file->length)))) < 0) {
|
||||
printf("do_mmap: failed with %d.\n", err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* mmap each task's environment from its env file. */
|
||||
if ((err = do_mmap(task->proc_files->env_file, 0, task,
|
||||
task->env_start, VM_READ | VM_WRITE,
|
||||
__pfn(task->env_end - task->env_start)) < 0)) {
|
||||
printf("do_mmap: Mapping environment failed with %d.\n",
|
||||
err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* mmap each task's stack as 4-page anonymous memory. */
|
||||
if ((err = do_mmap(0, 0, task, task->stack_start,
|
||||
VM_READ | VM_WRITE | VMA_ANON,
|
||||
__pfn(task->stack_end - task->stack_start)) < 0)) {
|
||||
printf("do_mmap: Mapping stack failed with %d.\n", err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* mmap each task's utcb as single page anonymous memory. */
|
||||
printf("%s: Mapping utcb for new task at: 0x%x\n", __TASKNAME__,
|
||||
task->utcb_address);
|
||||
if ((err = do_mmap(0, 0, task, task->utcb_address,
|
||||
VM_READ | VM_WRITE | VMA_ANON, 1) < 0)) {
|
||||
printf("do_mmap: Mapping utcb failed with %d.\n", err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Set up the task's thread details, (pc, sp, pager etc.) */
|
||||
if ((err = l4_exchange_registers(pc, sp, self_tid(), task->tid) < 0)) {
|
||||
printf("l4_exchange_registers failed with %d.\n", err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
printf("Starting task with id %d\n", task->tid);
|
||||
|
||||
/* Start the thread */
|
||||
if ((err = l4_thread_control(THREAD_RUN, &ids) < 0)) {
|
||||
printf("l4_thread_control failed with %d\n", err);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
BUG();
|
||||
}
|
||||
#endif
|
||||
|
||||
struct tcb_head {
|
||||
struct list_head list;
|
||||
int total; /* Total threads */
|
||||
@@ -171,9 +38,13 @@ struct tcb *find_task(int tid)
|
||||
{
|
||||
struct tcb *t;
|
||||
|
||||
list_for_each_entry(t, &tcb_head.list, list)
|
||||
if (t->tid == tid)
|
||||
list_for_each_entry(t, &tcb_head.list, list) {
|
||||
/* A temporary precaution */
|
||||
BUG_ON(t->tid != t->spid);
|
||||
if (t->tid == tid) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -195,11 +66,232 @@ struct tcb *tcb_alloc_init(void)
|
||||
return task;
|
||||
}
|
||||
|
||||
|
||||
struct tcb *task_create(struct task_ids *ids)
|
||||
{
|
||||
struct tcb *task;
|
||||
int err;
|
||||
|
||||
/* Create the thread structures and address space */
|
||||
printf("Creating new thread with ids: %d, %d.\n", ids->tid, ids->spid);
|
||||
if ((err = l4_thread_control(THREAD_CREATE, ids)) < 0) {
|
||||
printf("l4_thread_control failed with %d.\n", err);
|
||||
return PTR_ERR(err);
|
||||
}
|
||||
|
||||
/* Create a task and use given space and thread ids. */
|
||||
printf("New task with id: %d, space id: %d\n", ids->tid, ids->spid);
|
||||
if (IS_ERR(task = tcb_alloc_init()))
|
||||
return PTR_ERR(task);
|
||||
|
||||
task->tid = ids->tid;
|
||||
task->spid = ids->spid;
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
|
||||
int task_mmap_regions(struct tcb *task, struct vm_file *file)
|
||||
{
|
||||
int err;
|
||||
|
||||
/*
|
||||
* mmap each task's physical image to task's address space.
|
||||
* TODO: Map data and text separately when available from bootdesc.
|
||||
*/
|
||||
if ((err = do_mmap(file, 0, task, task->text_start,
|
||||
VM_READ | VM_WRITE | VM_EXEC | VMA_PRIVATE,
|
||||
__pfn(page_align_up(task->text_end) -
|
||||
task->text_start))) < 0) {
|
||||
printf("do_mmap: failed with %d.\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* mmap each task's environment as anonymous memory. */
|
||||
if ((err = do_mmap(0, 0, task, task->env_start,
|
||||
VM_READ | VM_WRITE | VMA_PRIVATE | VMA_ANONYMOUS,
|
||||
__pfn(task->env_end - task->env_start))) < 0) {
|
||||
printf("do_mmap: Mapping environment failed with %d.\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* mmap each task's stack as anonymous memory. */
|
||||
if ((err = do_mmap(0, 0, task, task->stack_start,
|
||||
VM_READ | VM_WRITE | VMA_PRIVATE | VMA_ANONYMOUS,
|
||||
__pfn(task->stack_end - task->stack_start))) < 0) {
|
||||
printf("do_mmap: Mapping stack failed with %d.\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int task_setup_regions(struct vm_file *file, struct tcb *task,
|
||||
unsigned long task_start, unsigned long task_end)
|
||||
{
|
||||
struct vm_file *shm;
|
||||
|
||||
/*
|
||||
* Set task's main address space boundaries. Not all tasks
|
||||
* run in the default user boundaries, e.g. mm0 pager.
|
||||
*/
|
||||
task->start = task_start;
|
||||
task->end = task_end;
|
||||
|
||||
/* Prepare environment boundaries. */
|
||||
task->env_end = task->end;
|
||||
task->env_start = task->env_end - DEFAULT_ENV_SIZE;
|
||||
task->args_end = task->env_start;
|
||||
task->args_start = task->env_start;
|
||||
|
||||
/* Task stack starts right after the environment. */
|
||||
task->stack_end = task->env_start;
|
||||
task->stack_start = task->stack_end - DEFAULT_STACK_SIZE;
|
||||
|
||||
/* Currently RO text and RW data are one region. TODO: Fix this */
|
||||
task->data_start = task->start;
|
||||
task->data_end = task->start + page_align_up(file->length);
|
||||
task->text_start = task->data_start;
|
||||
task->text_end = task->data_end;
|
||||
|
||||
/* Task's region available for mmap */
|
||||
task->map_start = task->data_end;
|
||||
task->map_end = task->stack_start;
|
||||
|
||||
/* Task's utcb */
|
||||
task->utcb = utcb_vaddr_new();
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
int task_setup_registers(struct tcb *task, unsigned int pc,
|
||||
unsigned int sp, l4id_t pager)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Set up task's registers to default. */
|
||||
if (!sp)
|
||||
sp = align(task->stack_end - 1, 8);
|
||||
if (!pc)
|
||||
pc = task->text_start;
|
||||
if (!pager)
|
||||
pager = self_tid();
|
||||
|
||||
/* Set up the task's thread details, (pc, sp, pager etc.) */
|
||||
if ((err = l4_exchange_registers(pc, sp, pager, task->tid) < 0)) {
|
||||
printf("l4_exchange_registers failed with %d.\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int task_start(struct tcb *task, struct task_ids *ids)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Start the thread */
|
||||
printf("Starting task with id %d\n", task->tid);
|
||||
if ((err = l4_thread_control(THREAD_RUN, ids)) < 0) {
|
||||
printf("l4_thread_control failed with %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A specialised function for setting up the task environment of mm0.
|
||||
* Essentially all the memory regions are set up but a new task isn't
|
||||
* created, registers aren't assigned, and thread not started, since
|
||||
* these are all already done by the kernel. But we do need a memory
|
||||
* environment for mm0, hence this function.
|
||||
*/
|
||||
int mm0_task_init(struct vm_file *f, unsigned long task_start,
|
||||
unsigned long task_end, struct task_ids *ids)
|
||||
{
|
||||
int err;
|
||||
struct tcb *task;
|
||||
|
||||
/*
|
||||
* The thread itself is already known by the kernel, so we just
|
||||
* allocate a local task structure.
|
||||
*/
|
||||
BUG_ON(IS_ERR(task = tcb_alloc_init()));
|
||||
|
||||
task->tid = ids->tid;
|
||||
task->spid = ids->spid;
|
||||
|
||||
if ((err = task_setup_regions(f, task, task_start, task_end)) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = task_mmap_regions(task, f)) < 0)
|
||||
return err;
|
||||
|
||||
/* Add the task to the global task list */
|
||||
list_add_tail(&task->list, &tcb_head.list);
|
||||
tcb_head.total++;
|
||||
|
||||
/* Add the file to global vm lists */
|
||||
list_del_init(&f->list);
|
||||
list_del_init(&f->vm_obj.list);
|
||||
list_add(&f->list, &vm_file_list);
|
||||
list_add(&f->vm_obj.list, &vm_object_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main entry point for the creation, initialisation and
|
||||
* execution of a new task.
|
||||
*/
|
||||
int task_exec(struct vm_file *f, unsigned long task_region_start,
|
||||
unsigned long task_region_end, struct task_ids *ids)
|
||||
{
|
||||
struct tcb *task;
|
||||
int err;
|
||||
|
||||
if (IS_ERR(task = task_create(ids)))
|
||||
return (int)task;
|
||||
|
||||
if ((err = task_setup_regions(f, task, task_region_start,
|
||||
task_region_end)) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = task_mmap_regions(task, f)) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = task_setup_registers(task, 0, 0, 0)) < 0)
|
||||
return err;
|
||||
|
||||
/* Add the task to the global task list */
|
||||
list_add_tail(&task->list, &tcb_head.list);
|
||||
tcb_head.total++;
|
||||
|
||||
/* Add the file to global vm lists */
|
||||
list_del_init(&f->list);
|
||||
list_del_init(&f->vm_obj.list);
|
||||
list_add(&f->list, &vm_file_list);
|
||||
list_add(&f->vm_obj.list, &vm_object_list);
|
||||
|
||||
if ((err = task_start(task, ids)) < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Creates a process environment, mmaps the given file along
|
||||
* with any other necessary segment, and executes it as a task.
|
||||
*/
|
||||
int start_boot_task(struct vm_file *file, struct task_ids *ids)
|
||||
int start_boot_task(struct vm_file *file, unsigned long task_start,
|
||||
unsigned long task_end, struct task_ids *ids)
|
||||
{
|
||||
int err;
|
||||
struct tcb *task;
|
||||
@@ -219,7 +311,7 @@ int start_boot_task(struct vm_file *file, struct task_ids *ids)
|
||||
task->spid = ids->spid;
|
||||
|
||||
/* Prepare environment boundaries. */
|
||||
task->env_end = USER_AREA_END;
|
||||
task->env_end = task_end;
|
||||
task->env_start = task->env_end - DEFAULT_ENV_SIZE;
|
||||
task->args_end = task->env_start;
|
||||
task->args_start = task->env_start;
|
||||
@@ -229,8 +321,8 @@ int start_boot_task(struct vm_file *file, struct task_ids *ids)
|
||||
task->stack_start = task->stack_end - DEFAULT_STACK_SIZE;
|
||||
|
||||
/* Currently RO text and RW data are one region. TODO: Fix this */
|
||||
task->data_start = USER_AREA_START;
|
||||
task->data_end = USER_AREA_START + page_align_up(file->length);
|
||||
task->data_start = task_start;
|
||||
task->data_end = task_start + page_align_up(file->length);
|
||||
task->text_start = task->data_start;
|
||||
task->text_end = task->data_end;
|
||||
|
||||
@@ -238,6 +330,12 @@ int start_boot_task(struct vm_file *file, struct task_ids *ids)
|
||||
task->map_start = task->data_end;
|
||||
task->map_end = task->stack_start;
|
||||
|
||||
/* Task's utcb */
|
||||
task->utcb = utcb_vaddr_new();
|
||||
|
||||
/* Create a shared memory segment available for shmat() */
|
||||
shm_new((key_t)task->utcb, __pfn(DEFAULT_UTCB_SIZE));
|
||||
|
||||
/* Set up task's registers */
|
||||
sp = align(task->stack_end - 1, 8);
|
||||
pc = task->text_start;
|
||||
@@ -293,13 +391,14 @@ int start_boot_task(struct vm_file *file, struct task_ids *ids)
|
||||
error:
|
||||
BUG();
|
||||
}
|
||||
#endif
|
||||
|
||||
struct vm_file *initdata_next_bootfile(struct initdata *initdata)
|
||||
{
|
||||
struct vm_file *file, *n;
|
||||
list_for_each_entry_safe(file, n, &initdata->boot_file_list,
|
||||
list) {
|
||||
list_del(&file->list);
|
||||
list_del_init(&file->list);
|
||||
return file;
|
||||
}
|
||||
return 0;
|
||||
@@ -311,41 +410,66 @@ struct vm_file *initdata_next_bootfile(struct initdata *initdata)
|
||||
*/
|
||||
int start_boot_tasks(struct initdata *initdata)
|
||||
{
|
||||
struct vm_file *file;
|
||||
struct vm_file *file, *fs0, *mm0, *n;
|
||||
struct svc_image *img;
|
||||
struct task_ids ids;
|
||||
struct list_head files;
|
||||
int total = 0;
|
||||
|
||||
INIT_LIST_HEAD(&tcb_head.list);
|
||||
INIT_LIST_HEAD(&files);
|
||||
|
||||
/* Separate out special server tasks and regular files */
|
||||
do {
|
||||
file = initdata_next_bootfile(initdata);
|
||||
|
||||
if (file) {
|
||||
BUG_ON(file->type != VM_FILE_BOOTFILE);
|
||||
img = file->priv_data;
|
||||
if (!strcmp(img->name, __PAGERNAME__)) {
|
||||
continue;
|
||||
}
|
||||
/* Set up task ids */
|
||||
if (!strcmp(img->name, __VFSNAME__)) {
|
||||
ids.tid = VFS_TID;
|
||||
ids.spid = VFS_TID;
|
||||
} else {
|
||||
ids.tid = -1;
|
||||
ids.spid = -1;
|
||||
}
|
||||
if (!strcmp(img->name, __PAGERNAME__))
|
||||
mm0 = file;
|
||||
else if (!strcmp(img->name, __VFSNAME__))
|
||||
fs0 = file;
|
||||
else
|
||||
list_add(&file->list, &files);
|
||||
} else
|
||||
break;
|
||||
|
||||
/* Add the file to global vm lists */
|
||||
list_add(&file->list, &vm_file_list);
|
||||
list_add(&file->vm_obj.list, &vm_object_list);
|
||||
|
||||
/* Start the file as a task */
|
||||
start_boot_task(file, &ids);
|
||||
total++;
|
||||
} while (1);
|
||||
|
||||
/* MM0 needs partial initialisation, since its already running. */
|
||||
printf("%s: Initialising mm0 tcb.\n", __TASKNAME__);
|
||||
ids.tid = PAGER_TID;
|
||||
ids.tid = PAGER_TID;
|
||||
if (mm0_task_init(mm0, INITTASK_AREA_START, INITTASK_AREA_END, &ids) < 0)
|
||||
BUG();
|
||||
total++;
|
||||
|
||||
/* Initialise vfs with its predefined id */
|
||||
ids.tid = VFS_TID;
|
||||
ids.spid = VFS_TID;
|
||||
printf("%s: Initialising fs0\n",__TASKNAME__);
|
||||
if (task_exec(fs0, USER_AREA_START, USER_AREA_END, &ids) < 0)
|
||||
BUG();
|
||||
total++;
|
||||
|
||||
/* Initialise other tasks */
|
||||
list_for_each_entry_safe(file, n, &files, list) {
|
||||
printf("%s: Initialising new boot task.\n", __TASKNAME__);
|
||||
ids.tid = TASK_ID_INVALID;
|
||||
ids.spid = TASK_ID_INVALID;
|
||||
if (task_exec(file, USER_AREA_START, USER_AREA_END, &ids) < 0)
|
||||
BUG();
|
||||
total++;
|
||||
}
|
||||
{
|
||||
struct tcb *t;
|
||||
printf("Tasks:\n========\n");
|
||||
list_for_each_entry(t, &tcb_head.list, list) {
|
||||
printf("Task tid: %d, spid: %d\n", t->tid, t->spid);
|
||||
BUG_ON(t->tid != t->spid);
|
||||
}
|
||||
}
|
||||
|
||||
if (!total) {
|
||||
printf("%s: Could not start any tasks.\n", __TASKNAME__);
|
||||
BUG();
|
||||
@@ -376,8 +500,8 @@ struct task_data_head {
|
||||
*/
|
||||
int send_task_data(l4id_t requester)
|
||||
{
|
||||
int li, err;
|
||||
struct tcb *t, *vfs;
|
||||
int li = 0, err;
|
||||
struct tcb *t, *vfs, *self;
|
||||
struct task_data_head *tdata_head;
|
||||
|
||||
if (requester != VFS_TID) {
|
||||
@@ -388,29 +512,27 @@ int send_task_data(l4id_t requester)
|
||||
}
|
||||
|
||||
BUG_ON(!(vfs = find_task(requester)));
|
||||
BUG_ON(!vfs->utcb_address);
|
||||
BUG_ON(!(self = find_task(self_tid())));
|
||||
BUG_ON(!vfs->utcb);
|
||||
|
||||
/*
|
||||
* When task does shmat() for its utcb, mm0 prefaults and maps it
|
||||
* to itself, and sets this flag. Check that this has occured
|
||||
* to ensure we have access to it. Otherwise return error.
|
||||
*/
|
||||
if (!vfs->utcb_mapped) {
|
||||
l4_ipc_return(-ENOENT);
|
||||
return 0;
|
||||
}
|
||||
/* Attach mm0 to vfs's utcb segment just like a normal task */
|
||||
BUG_ON(IS_ERR(shmat_shmget_internal((key_t)vfs->utcb, vfs->utcb)));
|
||||
|
||||
/* Prefault those pages to self. */
|
||||
for (int i = 0; i < __pfn(DEFAULT_UTCB_SIZE); i++)
|
||||
prefault_page(self, (unsigned long)vfs->utcb + __pfn_to_addr(i),
|
||||
VM_READ | VM_WRITE);
|
||||
|
||||
/* Write all requested task information to utcb's user buffer area */
|
||||
tdata_head = (struct task_data_head *)vfs->utcb_address;
|
||||
tdata_head = (struct task_data_head *)vfs->utcb;
|
||||
|
||||
/* First word is total number of tcbs */
|
||||
tdata_head->total = tcb_head.total;
|
||||
|
||||
/* Write per-task data for all tasks */
|
||||
li = 0;
|
||||
list_for_each_entry(t, &tcb_head.list, list) {
|
||||
tdata_head->tdata[li].tid = t->tid;
|
||||
tdata_head->tdata[li].utcb_address = t->utcb_address;
|
||||
tdata_head->tdata[li].utcb_address = (unsigned long)t->utcb;
|
||||
li++;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,11 +50,10 @@ int task_send_utcb_address(l4id_t sender, l4id_t taskid)
|
||||
* but only because the requester is requesting for its
|
||||
* own utcb.
|
||||
*/
|
||||
if (!task->utcb_address)
|
||||
task->utcb_address = (unsigned long)utcb_vaddr_new();
|
||||
BUG_ON(!task->utcb);
|
||||
|
||||
/* Return it to requester */
|
||||
return l4_ipc_return(task->utcb_address);
|
||||
return l4_ipc_return((int)task->utcb);
|
||||
|
||||
/* A task is asking for someone else's utcb */
|
||||
} else {
|
||||
@@ -65,12 +64,15 @@ int task_send_utcb_address(l4id_t sender, l4id_t taskid)
|
||||
* none allocated so far, requester gets 0. We don't
|
||||
* allocate one here.
|
||||
*/
|
||||
return l4_ipc_return(task->utcb_address);
|
||||
return l4_ipc_return((int)task->utcb);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
To be ditched
|
||||
/*
|
||||
* Triggered during a sys_shmat() by a client task when mapping its utcb.
|
||||
* This prefaults the utcb and maps it in to mm0 so that it can freely
|
||||
@@ -108,4 +110,4 @@ int utcb_prefault(struct tcb *task, unsigned int vmflags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user