diff --git a/tasks/libposix/lseek.c b/tasks/libposix/lseek.c index 7df100f..68a6e7d 100644 --- a/tasks/libposix/lseek.c +++ b/tasks/libposix/lseek.c @@ -20,7 +20,7 @@ static inline off_t l4_lseek(int fildes, off_t offset, int whence) write_mr(L4SYS_ARG2, whence); /* Call pager with shmget() request. Check ipc error. */ - if ((offres = l4_sendrecv(VFS_TID, VFS_TID, L4_IPC_TAG_LSEEK)) < 0) { + if ((offres = l4_sendrecv(PAGER_TID, PAGER_TID, L4_IPC_TAG_LSEEK)) < 0) { printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, offres); return offres; } diff --git a/tasks/mm0/include/vm_area.h b/tasks/mm0/include/vm_area.h index 123ba45..abd9afc 100644 --- a/tasks/mm0/include/vm_area.h +++ b/tasks/mm0/include/vm_area.h @@ -213,6 +213,8 @@ struct page *page_init(struct page *page); /* To get currently mapped page of a virtual address on a task */ struct page *task_virt_to_page(struct tcb *t, unsigned long virtual); +int validate_task_range(struct tcb *t, unsigned long start, + unsigned long end, unsigned int vmflags); /* Main page fault entry point */ int page_fault_handler(l4id_t tid, fault_kdata_t *fkdata); diff --git a/tasks/mm0/main.c b/tasks/mm0/main.c index aa60c95..3b71a02 100644 --- a/tasks/mm0/main.c +++ b/tasks/mm0/main.c @@ -97,6 +97,10 @@ void handle_requests(void) sys_write(sender, (int)mr[0], (void *)mr[1], (int)mr[2]); break; + case L4_IPC_TAG_LSEEK: + sys_lseek(sender, (int)mr[0], (off_t)mr[1], (int)mr[2]); + break; + case L4_IPC_TAG_MMAP2: { struct sys_mmap_args *args = (struct sys_mmap_args *)mr[0]; sys_mmap(sender, args->start, args->length, args->prot, diff --git a/tasks/mm0/src/fault.c b/tasks/mm0/src/fault.c index 6a432ac..c3fe11a 100644 --- a/tasks/mm0/src/fault.c +++ b/tasks/mm0/src/fault.c @@ -231,7 +231,7 @@ struct vm_obj_link *vma_create_shadow(void) } /* Allocates a new page, copies the original onto it and returns. */ -struct page *copy_page(struct page *orig) +struct page *copy_to_new_page(struct page *orig) { void *new_vaddr, *vaddr, *paddr; struct page *new; @@ -349,7 +349,7 @@ struct page *copy_on_write(struct fault_data *fault) * Copy the page. This traverse and copy is like a page-in operation * of a pager, except that the page is moving along vm_objects. */ - new_page = copy_page(page); + new_page = copy_to_new_page(page); /* Update page details */ spin_lock(&new_page->lock); @@ -929,6 +929,28 @@ int page_fault_handler(l4id_t sender, fault_kdata_t *fkdata) return 0; } +/* Checks if an address range is a validly mapped area for a task */ +int validate_task_range(struct tcb *t, unsigned long start, + unsigned long end, unsigned int vmflags) +{ + struct vm_area *vma; + + start = page_align(start); + end = page_align_up(end); + + /* Find the vma that maps that virtual address */ + for (unsigned long vaddr = start; vaddr < end; vaddr += PAGE_SIZE) { + if (!(vma = find_vma(vaddr, &t->vm_area_list))) { + printf("%s: No VMA found for 0x%x on task: %d\n", + __FUNCTION__, vaddr, t->tid); + return -EINVAL; + } + if ((vma->flags & vmflags) != vmflags) + return -EINVAL; + } + return 0; +} + /* * Makes the virtual to page translation for a given user task. * It traverses the vm_objects and returns the first encountered @@ -979,8 +1001,8 @@ struct page *task_virt_to_page(struct tcb *t, unsigned long virtual) } /* Found it */ - printf("%s: %s: Found page with file_offset: 0x%x. vm object:\n", - __TASKNAME__, __FUNCTION__, (unsigned long)page, page->offset); + // printf("%s: %s: Found page with file_offset: 0x%x\n", + // __TASKNAME__, __FUNCTION__, page->offset); vm_object_print(vmo_link->obj); return page; diff --git a/tasks/mm0/src/file.c b/tasks/mm0/src/file.c index 1563ead..32eeb8b 100644 --- a/tasks/mm0/src/file.c +++ b/tasks/mm0/src/file.c @@ -18,6 +18,25 @@ /* List of all generic files */ LIST_HEAD(vm_file_list); + +/* Copy from one page's buffer into another page */ +int page_copy(struct page *dst, struct page *src, + unsigned long offset, unsigned long size) +{ + void *dstvaddr, *srcvaddr; + + BUG_ON(offset + size > PAGE_SIZE); + dstvaddr = l4_map_helper((void *)page_to_phys(dst), 1); + srcvaddr = l4_map_helper((void *)page_to_phys(src), 1); + + memcpy(dstvaddr + offset, srcvaddr + offset, size); + + l4_unmap_helper(dstvaddr, 1); + l4_unmap_helper(srcvaddr, 1); + + return 0; +} + int vfs_read(unsigned long vnum, unsigned long file_offset, unsigned long npages, void *pagebuf) { @@ -340,12 +359,12 @@ int vfs_write(unsigned long vnum, unsigned long file_offset, */ /* Writes user data in buffer into pages in cache */ -int write_cache_pages(struct vm_file *vmfile, void *buf, unsigned long pfn_start, - unsigned long pfn_end, unsigned long cursor_offset, int count) +int write_cache_pages(struct vm_file *vmfile, struct tcb *task, void *buf, + unsigned long pfn_start, unsigned long pfn_end, + unsigned long cursor_offset, int count) { struct page *head, *this; int copysize, left; - void *page_virtual; unsigned long last_offset; /* Last copied page's offset */ /* Find the head of consecutive pages */ @@ -354,22 +373,19 @@ int write_cache_pages(struct vm_file *vmfile, void *buf, unsigned long pfn_start goto copy; /* - * Page not found, this is a bug. - * The page range must have been ready. + * Page not found, this is a bug. The writeable page range + * must have been readied by read_file_pages()/new_file_pages(). */ BUG(); copy: left = count; - /* Map the page */ - page_virtual = l4_map_helper((void *)page_to_phys(head), 1); - /* Copy the first page and unmap. */ copysize = (left < PAGE_SIZE) ? left : PAGE_SIZE; - memcpy(page_virtual + cursor_offset, buf, copysize); + page_copy(head, task_virt_to_page(task, (unsigned long)buf), + cursor_offset, copysize); left -= copysize; - l4_unmap_helper(page_virtual, 1); last_offset = head->offset; /* Map the rest, copy and unmap. */ @@ -381,9 +397,9 @@ copy: BUG_ON(this->offset != last_offset + 1); copysize = (left < PAGE_SIZE) ? left : PAGE_SIZE; - page_virtual = l4_map_helper((void *)page_to_phys(this), 1); - memcpy(page_virtual, buf + count - left, copysize); - l4_unmap_helper(page_virtual, 1); + page_copy(this, task_virt_to_page(task, (unsigned long)buf + + count - left), + 0, copysize); left -= copysize; last_offset = this->offset; } @@ -392,14 +408,6 @@ copy: return count - left; } -/* - * TODO: - * Page in those writeable pages. - * Update them, - * Then page them out. - * - * If they're new, fs0 should allocate those pages accordingly. - */ int sys_write(l4id_t sender, int fd, void *buf, int count) { unsigned long pfn_wstart, pfn_wend; /* Write start/end */ @@ -407,24 +415,36 @@ int sys_write(l4id_t sender, int fd, void *buf, int count) unsigned long pfn_nstart, pfn_nend; /* New pages start/end */ unsigned long cursor, byte_offset; struct vm_file *vmfile; - struct tcb *t; - int err; + int err = 0, retval = 0; + struct tcb *task; - BUG_ON(!(t = find_task(sender))); + BUG_ON(!(task = find_task(sender))); - if ((err = check_access(t, buf, count)) < 0) { - l4_ipc_return(err); - return 0; + /* Check fd validity */ + if (fd < 0 || fd > TASK_FILES_MAX || !task->fd[fd].vmfile) { + retval = -EBADF; + goto out; } - /* TODO: Check user buffer, count and fd validity */ - if (fd < 0 || fd > TASK_FILES_MAX) { - l4_ipc_return(-EBADF); - return 0; + /* Check count validity */ + if (count < 0) { + retval = -EINVAL; + goto out; + } else if (!count) { + retval = 0; + goto out; } - vmfile = t->fd[fd].vmfile; - cursor = t->fd[fd].cursor; + /* Check user buffer validity. */ + if ((err = validate_task_range(task, (unsigned long)buf, + (unsigned long)(buf + count), + VM_WRITE | VM_READ)) < 0) { + retval = err; + goto out; + } + + vmfile = task->fd[fd].vmfile; + cursor = task->fd[fd].cursor; /* See what pages user wants to write */ pfn_wstart = __pfn(cursor); @@ -471,14 +491,14 @@ int sys_write(l4id_t sender, int fd, void *buf, int count) * Read in the portion that's already part of the file. */ if ((err = read_file_pages(vmfile, pfn_fstart, pfn_fend)) < 0) { - l4_ipc_return(err); - return 0; + retval = err; + goto out; } /* Create new pages for the part that's new in the file */ if ((err = new_file_pages(vmfile, pfn_nstart, pfn_nend)) < 0) { - l4_ipc_return(err); - return 0; + retval = err; + goto out; } /* @@ -486,10 +506,10 @@ int sys_write(l4id_t sender, int fd, void *buf, int count) * to be written are expected to be in the page cache. Write. */ byte_offset = PAGE_MASK & cursor; - if ((err = write_cache_pages(vmfile, buf, pfn_wstart, + if ((err = write_cache_pages(vmfile, task, buf, pfn_wstart, pfn_wend, byte_offset, count)) < 0) { - l4_ipc_return(err); - return 0; + retval = err; + goto out; } /* @@ -497,7 +517,11 @@ int sys_write(l4id_t sender, int fd, void *buf, int count) * when the file is flushed (e.g. via fflush() or close()) */ vmfile->length += count; + task->fd[fd].cursor += count; + retval = count; +out: + l4_ipc_return(retval); return 0; } diff --git a/tasks/test0/src/fileio.c b/tasks/test0/src/fileio.c index 3c7f470..d349288 100644 --- a/tasks/test0/src/fileio.c +++ b/tasks/test0/src/fileio.c @@ -23,17 +23,20 @@ int fileio(void) } printf("Created newfile.txt\n"); + printf("%s: write.\n", __TASKNAME__); if ((int)(cnt = write(fd, str, strlen(str))) < 0) { perror("WRITE"); return -1; } + printf("%s: lseek.\n", __TASKNAME__); if ((int)(offset = lseek(fd, 0, SEEK_SET)) < 0) { perror("LSEEK"); return -1; } + printf("%s: read.\n", __TASKNAME__); if ((int)(cnt = read(fd, buf, strlen(str))) < 0) { - perror("WRITE"); + perror("READ"); return -1; }