diff --git a/src/arch/arm/exception.c b/src/arch/arm/exception.c index ce9aba1..d3a4c4e 100644 --- a/src/arch/arm/exception.c +++ b/src/arch/arm/exception.c @@ -61,6 +61,12 @@ void fault_ipc_to_pager(u32 faulty_pc, u32 fsr, u32 far) */ } +/* + * When a task calls the kernel and the supplied user buffer is not mapped, the kernel + * generates a page fault to the task's pager so that the pager can make the decision + * on mapping the buffer. Remember that if a task maps its own user buffer to itself + * this way, the kernel can access it, since it shares that task's page table. + */ int pager_pagein_request(unsigned long addr, unsigned long size, unsigned int flags) { u32 abort; diff --git a/src/arch/arm/v5/mm.c b/src/arch/arm/v5/mm.c index 92ce586..231b76b 100644 --- a/src/arch/arm/v5/mm.c +++ b/src/arch/arm/v5/mm.c @@ -252,7 +252,7 @@ int check_mapping_pgd(unsigned long vaddr, unsigned long size, /* Convert generic map flags to pagetable-specific */ BUG_ON(!(flags = space_flags_to_ptflags(flags))); - + for (int i = 0; i < npages; i++) { pte = virt_to_pte(vaddr + i * PAGE_SIZE); diff --git a/tasks/fs0/include/task.h b/tasks/fs0/include/task.h index 0c76ade..1d30e52 100644 --- a/tasks/fs0/include/task.h +++ b/tasks/fs0/include/task.h @@ -15,6 +15,7 @@ /* Thread control block, fs0 portion */ struct tcb { l4id_t tid; + unsigned long utcb_address; struct list_head list; int fd[TASK_OFILES_MAX]; struct id_pool *fdpool; diff --git a/tasks/fs0/src/task.c b/tasks/fs0/src/task.c index a9d992d..fc46857 100644 --- a/tasks/fs0/src/task.c +++ b/tasks/fs0/src/task.c @@ -35,7 +35,7 @@ struct tcb *find_task(int tid) * registers are sufficient. First argument tells how many there are, the rest * tells the tids. */ -int receive_pager_taskdata(l4id_t *tdata) +int receive_pager_taskdata_orig(l4id_t *tdata) { int err; @@ -69,15 +69,51 @@ int receive_pager_taskdata(l4id_t *tdata) return 0; } +struct task_data { + unsigned long tid; + unsigned long utcb_address; +}; + +struct task_data_head { + unsigned long total; + struct task_data tdata[]; +}; + +/* Read task information into the utcb buffer, since it wont fit into mrs. */ +struct task_data_head *receive_pager_taskdata(void) +{ + int err; + + /* Ask pager to write the data at this address */ + write_mr(L4SYS_ARG0, (unsigned long)utcb->buf); + + /* Make the actual ipc call */ + if ((err = l4_sendrecv(PAGER_TID, PAGER_TID, + L4_IPC_TAG_TASKDATA)) < 0) { + printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err); + return PTR_ERR(err); + } + + /* Check if call itself was successful */ + if ((err = l4_get_retval()) < 0) { + printf("%s: Error: %d.\n", __FUNCTION__, err); + return PTR_ERR(err); + } + + printf("%s: %d Total tasks.\n", __FUNCTION__, + ((struct task_data_head *)utcb->buf)->total); + + return (struct task_data_head *)utcb->buf; +} + /* Allocate a task struct and initialise it */ -struct tcb *create_tcb(l4id_t tid) +struct tcb *create_tcb(void) { struct tcb *t; if (!(t = kmalloc(sizeof(*t)))) return PTR_ERR(-ENOMEM); - t->tid = tid; INIT_LIST_HEAD(&t->list); list_add_tail(&t->list, &tcb_head.list); tcb_head.total++; @@ -85,31 +121,37 @@ struct tcb *create_tcb(l4id_t tid) return t; } -int init_task_structs(l4id_t *tdata) +int init_task_structs(struct task_data_head *tdata_head) { struct tcb *t; - int total = tdata[0]; - for (int i = 0; i < total; i++) { - if (IS_ERR(t = create_tcb(tdata[1 + i]))) + for (int i = 0; i < tdata_head->total; i++) { + if (IS_ERR(t = create_tcb())) return (int)t; + + /* Initialise fields sent by pager */ + t->tid = tdata_head->tdata[i].tid; + t->utcb_address = tdata_head->tdata[i].utcb_address; + + /* Initialise vfs specific fields. */ t->rootdir = vfs_root.pivot; t->curdir = vfs_root.pivot; } + return 0; } int init_task_data(void) { - l4id_t tdata[MR_UNUSED_TOTAL]; + struct task_data_head *tdata_head; INIT_LIST_HEAD(&tcb_head.list); /* Read how many tasks and tids of each */ - BUG_ON(receive_pager_taskdata(tdata) < 0); + BUG_ON((tdata_head = receive_pager_taskdata()) < 0); /* Initialise local task structs using this info */ - BUG_ON(init_task_structs(tdata) < 0); + BUG_ON(init_task_structs(tdata_head) < 0); return 0; } diff --git a/tasks/libl4/include/l4lib/arch-arm/utcb.h b/tasks/libl4/include/l4lib/arch-arm/utcb.h index 71383e5..f9e949a 100644 --- a/tasks/libl4/include/l4lib/arch-arm/utcb.h +++ b/tasks/libl4/include/l4lib/arch-arm/utcb.h @@ -24,7 +24,7 @@ struct utcb { * For passing ipc data larger than mrs, * that is, if the callee is allowed to map it */ - char userbuf[]; + char buf[]; }; extern struct utcb *utcb; diff --git a/tasks/libposix/open.c b/tasks/libposix/open.c index cb57247..82a540d 100644 --- a/tasks/libposix/open.c +++ b/tasks/libposix/open.c @@ -14,11 +14,23 @@ #include #include +/* + * Arguments that are too large to fit in message registers are + * copied onto another area that is still on the utcb, and the servers + * map-in the task utcb and read those arguments from there. + */ +void *copy_to_utcb(void *arg, int size) +{ + BUG_ON(size > PAGE_SIZE); + memcpy(utcb->buf, arg, size); +} + static inline int l4_open(const char *pathname, int flags, mode_t mode) { int fd; - write_mr(L4SYS_ARG0, (unsigned long)pathname); + // write_mr(L4SYS_ARG0, (unsigned long)pathname); + copy_to_utcb(pathname, strlen(pathname)); write_mr(L4SYS_ARG1, flags); write_mr(L4SYS_ARG2, (u32)mode); diff --git a/tasks/mm0/src/fault.c b/tasks/mm0/src/fault.c index 6816a11..ab4b9e7 100644 --- a/tasks/mm0/src/fault.c +++ b/tasks/mm0/src/fault.c @@ -324,6 +324,17 @@ int do_anon_page(struct fault_data *fault) l4_map(paddr, (void *)page_align(fault->address), 1, MAP_USR_RW_FLAGS, fault->task->tid); + /*** DEBUG CODE FOR FS0 UTCB ***/ + if(page_align(fault->address) == 0xf8001000) { + printf("For FS0 utcb @ 0xf8001000, mapping page @ 0x%x, foffset: 0x%x, owned by vma @ 0x%x, vmfile @ 0x%x\n", + (unsigned long)page, page->f_offset, fault->vma, fault->vma->owner); + } + if(page_align(fault->address) == 0xf8002000) { + printf("For FS0 utcb @ 0xf8002000, mapping page @ 0x%x, foffset: 0x%x, owned by vma @ 0x%x, vmfile @ 0x%x\n", + (unsigned long)page, page->f_offset, fault->vma, fault->vma->owner); + } + /*** DEBUG CODE FOR FS0 UTCB ***/ + spin_lock(&page->lock); /* vma's swap file owns this page */ page->owner = fault->vma->owner; diff --git a/tasks/mm0/src/file.c b/tasks/mm0/src/file.c index f45ffcb..1e81b4b 100644 --- a/tasks/mm0/src/file.c +++ b/tasks/mm0/src/file.c @@ -168,6 +168,8 @@ int insert_page_olist(struct page *this, struct vm_file *f) /* Add to beginning if smaller */ else if (this->f_offset < before->f_offset) list_add(&this->list, &before->list); + else + BUG(); return 0; } @@ -177,6 +179,8 @@ int insert_page_olist(struct page *this, struct vm_file *f) list_add_tail(&this->list, &before->list); return 0; } + BUG_ON(this->f_offset == before->f_offset); + BUG_ON(this->f_offset == after->f_offset); } BUG(); } diff --git a/tasks/mm0/src/task.c b/tasks/mm0/src/task.c index 1487224..714746f 100644 --- a/tasks/mm0/src/task.c +++ b/tasks/mm0/src/task.c @@ -9,9 +9,11 @@ #include #include #include +#include #include INC_GLUE(memory.h) #include #include +#include #include #include #include @@ -221,6 +223,61 @@ void init_pm(struct initdata *initdata) start_boot_tasks(initdata, &tcb_head); } +/* + * Makes the virtual to page translation for a given user task. + */ +struct page *task_virt_to_page(struct tcb *t, unsigned long virtual) +{ + unsigned long vaddr_vma_offset; + unsigned long vaddr_file_offset; + struct vm_area *vma; + struct vm_file *vmfile; + struct page *page; + + /* First find the vma that maps that virtual address */ + if (!(vma = find_vma(virtual, &t->vm_area_list))) { + printf("%s: No VMA found for 0x%x on task: %d\n", + __FUNCTION__, virtual, t->tid); + return PTR_ERR(-EINVAL); + } + + /* Find the pfn offset of virtual address in this vma */ + BUG_ON(__pfn(virtual) < vma->pfn_start || + __pfn(virtual) > vma->pfn_end); + vaddr_vma_offset = __pfn(virtual) - vma->pfn_start; + + /* Find the file offset of virtual address in this file */ + vmfile = vma->owner; + vaddr_file_offset = vma->f_offset + vaddr_vma_offset; + + /* + * Find the page with the same file offset with that of the + * virtual address, that is, if the page is resident in memory. + */ + list_for_each_entry(page, &vmfile->page_cache_list, list) + if (vaddr_file_offset == page->f_offset) { + printf("%s: %s: Found page @ 0x%x, f_offset: 0x%x, with vma @ 0x%x, vmfile @ 0x%x\n", __TASKNAME__, + __FUNCTION__, (unsigned long)page, page->f_offset, vma, vma->owner); + return page; + } + + /* + * The page is not found, meaning that it is not mapped in + * yet, e.g. via a page fault. + */ + return 0; +} + +struct task_data { + unsigned long tid; + unsigned long utcb_address; +}; + +struct task_data_head { + unsigned long total; + struct task_data tdata[]; +}; + /* * During its initialisation FS0 wants to learn how many boot tasks * are running, and their tids, which includes itself. This function @@ -228,8 +285,10 @@ void init_pm(struct initdata *initdata) */ void send_task_data(l4id_t requester) { - struct tcb *t; int li, err; + struct tcb *t, *vfs; + struct utcb *vfs_utcb; + struct task_data_head *tdata_head; if (requester != VFS_TID) { printf("%s: Task data requested by %d, which is not " @@ -238,14 +297,26 @@ void send_task_data(l4id_t requester) return; } - /* First word is total number of tcbs */ - write_mr(L4SYS_ARG0, tcb_head.total); + BUG_ON(!(vfs = find_task(requester))); - /* Write each tcb's tid */ + /* Map in vfs's utcb. FIXME: Whatif it is already mapped? */ + l4_map((void *)page_to_phys(task_virt_to_page(vfs, vfs->utcb_address)), + (void *)vfs->utcb_address, 1, MAP_USR_RW_FLAGS, self_tid()); + + /* Get a handle on vfs utcb */ + vfs_utcb = (struct utcb *)vfs->utcb_address; + + /* Write all requested task information to utcb's user buffer area */ + tdata_head = (struct task_data_head *)vfs_utcb->buf; + + /* 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) { - BUG_ON(li >= MR_USABLE_TOTAL); - write_mr(L4SYS_ARG1 + li, t->tid); + tdata_head->tdata[li].tid = t->tid; + tdata_head->tdata[li].utcb_address = t->utcb_address; li++; }