diff --git a/.gdbinit b/.gdbinit index 64df7f5..a21fbea 100644 --- a/.gdbinit +++ b/.gdbinit @@ -5,4 +5,4 @@ sym final.axf break break_virtual continue stepi -sym start.axf +sym /opt/codezero/tasks/mm0/mm0.axf diff --git a/src/arch/arm/exception.c b/src/arch/arm/exception.c index 77176d0..33a12af 100644 --- a/src/arch/arm/exception.c +++ b/src/arch/arm/exception.c @@ -18,7 +18,7 @@ #include INC_SUBARCH(mm.h) /* Abort debugging conditions */ -// #define DEBUG_ABORTS + #define DEBUG_ABORTS #if defined (DEBUG_ABORTS) #define dbg_abort(...) dprintk(__VA_ARGS__) #else diff --git a/tasks/mm0/include/syscalls.h b/tasks/mm0/include/syscalls.h index 5697f57..54219b1 100644 --- a/tasks/mm0/include/syscalls.h +++ b/tasks/mm0/include/syscalls.h @@ -23,27 +23,12 @@ struct sys_mmap_args { off_t offset; }; -void *sys_mmap(struct tcb *sender, void *start, size_t length, int prot, - int flags, int fd, off_t pfn); - +void *sys_mmap(struct tcb *task, struct sys_mmap_args *args); int sys_munmap(struct tcb *sender, void *vaddr, unsigned long size); int sys_msync(struct tcb *task, void *start, unsigned long length, int flags); - -struct sys_shmat_args { - l4id_t shmid; - const void *shmaddr; - int shmflg; -}; - -void *sys_shmat(struct tcb *requester, l4id_t shmid, const void *shmaddr, int shmflg); +void *sys_shmat(struct tcb *task, l4id_t shmid, const void *shmadr, int shmflg); int sys_shmdt(struct tcb *requester, const void *shmaddr); -struct sys_shmget_args { - key_t key; - int size; - int shmflg; -}; - int sys_shmget(key_t key, int size, int shmflg); int sys_fork(struct tcb *parent); diff --git a/tasks/mm0/include/user.h b/tasks/mm0/include/user.h new file mode 100644 index 0000000..fc0206b --- /dev/null +++ b/tasks/mm0/include/user.h @@ -0,0 +1,12 @@ +#ifndef __USER_H__ +#define __USER_H__ + +#include + +int pager_validate_user_range(struct tcb *user, void *userptr, unsigned long size, + unsigned int vm_flags); +void *pager_validate_map_user_range(struct tcb *user, void *userptr, + unsigned long size, unsigned int vm_flags); +void pager_unmap_user_range(void *mapped_ptr, unsigned long size); + +#endif /* __USER_H__ */ diff --git a/tasks/mm0/main.c b/tasks/mm0/main.c index 34c753e..96c34fd 100644 --- a/tasks/mm0/main.c +++ b/tasks/mm0/main.c @@ -71,14 +71,12 @@ void handle_requests(void) break; case L4_IPC_TAG_SHMGET: { - struct sys_shmget_args *args = (struct sys_shmget_args *)&mr[0]; - ret = sys_shmget(args->key, args->size, args->shmflg); + ret = sys_shmget((key_t)mr[0], (int)mr[1], (int)mr[2]); break; } case L4_IPC_TAG_SHMAT: { - struct sys_shmat_args *args = (struct sys_shmat_args *)&mr[0]; - ret = (int)sys_shmat(sender, args->shmid, args->shmaddr, args->shmflg); + ret = (int)sys_shmat(sender, (l4id_t)mr[0], (void *)mr[1], (int)mr[2]); break; } @@ -112,8 +110,7 @@ void handle_requests(void) case L4_IPC_TAG_MMAP: { struct sys_mmap_args *args = (struct sys_mmap_args *)mr[0]; - ret = (int)sys_mmap(sender, args->start, args->length, args->prot, - args->flags, args->fd, args->offset); + ret = (int)sys_mmap(sender, args); } case L4_IPC_TAG_MUNMAP: { ret = sys_munmap(sender, (void *)mr[0], (unsigned long)mr[1]); diff --git a/tasks/mm0/src/fault.c b/tasks/mm0/src/fault.c index cc187e5..ab52306 100644 --- a/tasks/mm0/src/fault.c +++ b/tasks/mm0/src/fault.c @@ -855,28 +855,6 @@ int page_fault_handler(struct tcb *sender, fault_kdata_t *fkdata) return err; } -/* 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_head->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 diff --git a/tasks/mm0/src/file.c b/tasks/mm0/src/file.c index b6fde70..a8dcac9 100644 --- a/tasks/mm0/src/file.c +++ b/tasks/mm0/src/file.c @@ -15,6 +15,7 @@ #include #include #include +#include /* Copy from one page's buffer into another page */ int page_copy(struct page *dst, struct page *src, @@ -613,10 +614,10 @@ int sys_read(struct tcb *task, int fd, void *buf, int count) return 0; /* Check user buffer validity. */ - if ((ret = validate_task_range(task, (unsigned long)buf, + if ((ret = pager_validate_user_range(task, buf, (unsigned long)(buf + count), VM_READ)) < 0) - return ret; + return -EFAULT; vmfile = task->files->fd[fd].vmfile; cursor = task->files->fd[fd].cursor; @@ -683,10 +684,10 @@ int sys_write(struct tcb *task, int fd, void *buf, int count) /* Check user buffer validity. */ - if ((ret = validate_task_range(task, (unsigned long)buf, - (unsigned long)(buf + count), - VM_WRITE | VM_READ)) < 0) - return ret; + if ((ret = pager_validate_user_range(task, buf, + (unsigned long)(buf + count), + VM_WRITE | VM_READ)) < 0) + return -EINVAL; vmfile = task->files->fd[fd].vmfile; cursor = task->files->fd[fd].cursor; diff --git a/tasks/mm0/src/mmap.c b/tasks/mm0/src/mmap.c index 90b897b..3eeaae1 100644 --- a/tasks/mm0/src/mmap.c +++ b/tasks/mm0/src/mmap.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include struct vm_area *vma_new(unsigned long pfn_start, unsigned long npages, unsigned int flags, unsigned long file_offset) @@ -259,8 +261,8 @@ void *do_mmap(struct vm_file *mapfile, unsigned long file_offset, } /* mmap system call implementation */ -void *sys_mmap(struct tcb *task, void *start, size_t length, int prot, - int flags, int fd, unsigned long pfn) +void *__sys_mmap(struct tcb *task, void *start, size_t length, int prot, + int flags, int fd, unsigned long pfn) { unsigned long npages = __pfn(page_align_up(length)); unsigned long base = (unsigned long)start; @@ -319,6 +321,25 @@ void *sys_mmap(struct tcb *task, void *start, size_t length, int prot, return do_mmap(file, __pfn_to_addr(pfn), task, base, vmflags, npages); } +void *sys_mmap(struct tcb *task, struct sys_mmap_args *args) +{ + + struct sys_mmap_args *mapped_args; + void *ret; + + if (!(mapped_args = pager_validate_map_user_range(task, args, + sizeof(*args), + VM_READ | VM_WRITE))) + return PTR_ERR(-EINVAL); + + ret = __sys_mmap(task, args->start, args->length, args->prot, + args->flags, args->fd, args->offset); + + pager_unmap_user_range(mapped_args, sizeof(*args)); + + return ret; +} + /* Sets the end of data segment for sender */ int sys_brk(struct tcb *sender, void *ds_end) { diff --git a/tasks/mm0/src/user.c b/tasks/mm0/src/user.c new file mode 100644 index 0000000..18addea --- /dev/null +++ b/tasks/mm0/src/user.c @@ -0,0 +1,73 @@ +/* + * Functions to validate, map and unmap user buffers. + * + * Copyright (C) 2008 Bahadir Balban + */ +#include +#include +#include +#include + +/* + * Checks if the given user virtual address range is + * validly owned by that user with given flags. + * + * FIXME: This scans the vmas page by page, we can do it faster + * by leaping from one vma to next. + */ +int pager_validate_user_range(struct tcb *user, void *userptr, unsigned long size, + unsigned int vmflags) +{ + struct vm_area *vma; + unsigned long start = page_align(userptr); + unsigned long end = page_align_up(userptr + size); + + /* Find the vma that maps that virtual address */ + for (unsigned long vaddr = start; vaddr < end; vaddr += PAGE_SIZE) { + if (!(vma = find_vma(vaddr, &user->vm_area_head->list))) { + printf("%s: No VMA found for 0x%x on task: %d\n", + __FUNCTION__, vaddr, user->tid); + return -1; + } + if ((vma->flags & vmflags) != vmflags) + return -1; + } + + return 0; +} + +/* + * Validates and maps the user virtual address range to the pager. + * Every virtual page needs to be mapped individually because it's + * not guaranteed pages are physically contiguous. + */ +void *pager_validate_map_user_range(struct tcb *user, void *userptr, + unsigned long size, unsigned int vm_flags) +{ + unsigned long start = page_align(userptr); + unsigned long end = page_align_up(userptr + size); + void *mapped = 0; + + /* Validate that user task owns this address range */ + if (pager_validate_user_range(user, userptr, size, vm_flags) < 0) + return 0; + + /* Map first page and calculate the mapped address of pointer */ + mapped = l4_map_helper((void *)page_to_phys(task_virt_to_page(user, start)), 1); + mapped = (void *)(((unsigned long)mapped) | + ((unsigned long)(PAGE_MASK & (unsigned long)userptr))); + + /* Map the rest of the pages, if any */ + for (unsigned long i = start + PAGE_SIZE; i < end; i += PAGE_SIZE) + l4_map_helper((void *)page_to_phys(task_virt_to_page(user, + start + i)), 1); + + return mapped; +} + +void pager_unmap_user_range(void *mapped_ptr, unsigned long size) +{ + l4_unmap_helper((void *)page_align(mapped_ptr), + __pfn(page_align(mapped_ptr) + page_align_up(size))); +} + diff --git a/tasks/test0/main.c b/tasks/test0/main.c index 4f81193..3c3b558 100644 --- a/tasks/test0/main.c +++ b/tasks/test0/main.c @@ -22,9 +22,10 @@ void wait_pager(l4id_t partner) // printf("Pager synced with us.\n"); } +pid_t pid; + void main(void) { - pid_t pid; printf("\n%s: Started with tid %d.\n", __TASKNAME__, self_tid()); /* Sync with pager */ @@ -32,12 +33,16 @@ void main(void) dirtest(); + /* Check mmap/munmap */ + mmaptest(); + printf("Forking...\n"); if ((pid = fork()) < 0) printf("Error forking...\n"); if (pid == 0) { + pid = getpid(); printf("Child: file IO test 1.\n"); if (fileio() == 0) printf("-- PASSED --\n"); @@ -56,12 +61,10 @@ void main(void) else printf("-- FAILED --\n"); } + while (1) wait_pager(0); #if 0 - /* Check mmap/munmap */ - mmaptest(); - /* Check shmget/shmat/shmdt */ shmtest(); #endif diff --git a/tasks/test0/src/forktest.c b/tasks/test0/src/forktest.c index 3db49b8..9d83806 100644 --- a/tasks/test0/src/forktest.c +++ b/tasks/test0/src/forktest.c @@ -8,6 +8,7 @@ #include int global = 0; +extern pid_t pid; int forktest(void) { @@ -18,6 +19,7 @@ int forktest(void) fork(); myid = getpid(); + pid = myid; if (global != 0) { printf("-- FAILED --\n"); goto out;