summaryrefslogtreecommitdiff
path: root/sys/vm/vm_map.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/vm/vm_map.c')
-rw-r--r--sys/vm/vm_map.c117
1 files changed, 92 insertions, 25 deletions
diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c
index b56e896..0ff3763 100644
--- a/sys/vm/vm_map.c
+++ b/sys/vm/vm_map.c
@@ -35,8 +35,10 @@
#include <sys/syscall.h>
#include <sys/syslog.h>
#include <sys/mman.h>
+#include <sys/filedesc.h>
#include <vm/dynalloc.h>
#include <vm/vm_pager.h>
+#include <vm/vm_device.h>
#include <vm/pmap.h>
#include <vm/map.h>
#include <vm/vm.h>
@@ -157,11 +159,14 @@ vm_map_modify(struct vas vas, vaddr_t va, paddr_t pa, vm_prot_t prot, bool unmap
* crashes.
*/
void *
-mmap_at(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
+mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
{
- struct vm_object *map_obj;
+ struct vm_object *map_obj = NULL;
+ struct cdevsw *cdevp;
struct vm_page *pg;
struct mmap_entry *ep;
+ struct vnode *vp;
+ struct filedesc *fdp;
struct proc *td;
struct vas vas;
int error, npgs;
@@ -172,32 +177,94 @@ mmap_at(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
misalign = len & (DEFAULT_PAGESIZE - 1);
len = ALIGN_UP(len + misalign, DEFAULT_PAGESIZE);
npgs = len / DEFAULT_PAGESIZE;
-
- if (addr == NULL) {
- pr_error("mmap: NULL addr not supported\n");
- return NULL;
- }
+ vas = pmap_read_vas();
/* Validate flags */
- if (ISSET(flags, MAP_FIXED | MAP_SHARED)) {
- pr_error("mmap: fixed/shared mappings not yet supported\n");
+ if (ISSET(flags, MAP_FIXED)) {
+ pr_error("mmap: fixed mappings not yet supported\n");
mmap_dbg(addr, len, prot, flags, fildes, off);
return NULL;
}
- map_obj = dynalloc(sizeof(*map_obj));
- if (map_obj == NULL) {
- kprintf("mmap: failed to allocate map object\n");
- return NULL;
+
+ /*
+ * Attempt to open the file if mapping
+ * is shared.
+ */
+ if (ISSET(flags, MAP_SHARED)) {
+ fdp = fd_get(fildes);
+ if (fdp == NULL) {
+ pr_error("mmap: no such fd (fd=%d)\n", fildes);
+ return NULL;
+ }
+
+ vp = fdp->vp;
+ if (vp->type != VCHR) {
+ /* TODO */
+ pr_error("mmap: only device files supported\n");
+ return NULL;
+ }
+
+ map_obj = dv_attach(vp->major, vp->dev, prot);
+ if (map_obj == NULL) {
+ kprintf("mmap: dv_attach() failure\n");
+ return NULL;
+ }
+
+ cdevp = map_obj->data;
+ if ((pa = cdevp->mmap(vp->dev, len, off, 0)) == 0) {
+ kprintf("mmap: dev mmap() gave 0\n");
+ return NULL;
+ }
+
+ /*
+ * If the address passed is NULL, just identity
+ * map everything.
+ *
+ * XXX: This is why the bounds check done in the
+ * cdev mmap() *must* be correct.
+ *
+ * TODO: Use copy-on-write for this instead. Since mapping
+ * certain devices may required a lot of memory to
+ * be referenced anyways, we could use a buffered
+ * copy-on-write technique where only a window of
+ * pages can be mapped on-demand and other pages
+ * freed when that window is exceeded.
+ */
+ if (addr == NULL) {
+ addr = (void *)pa;
+ }
+
+ va = ALIGN_DOWN((vaddr_t)addr, DEFAULT_PAGESIZE);
+ error = vm_map(vas, va, pa, prot, len);
+ if (error != 0) {
+ kprintf("mmap: map failed (error=%d)\n", error);
+ return NULL;
+ }
+
+ goto done;
}
- error = vm_obj_init(map_obj, &vm_anonops, 1);
- if (error < 0) {
- kprintf("mmap: vm_obj_init() returned %d\n", error);
- kprintf("mmap: failed to init object\n");
+
+ if (addr == NULL) {
+ pr_error("mmap: NULL addr not supported\n");
return NULL;
}
+ /* Only allocate new obj if needed */
+ if (map_obj == NULL) {
+ map_obj = dynalloc(sizeof(*map_obj));
+ if (map_obj == NULL) {
+ kprintf("mmap: failed to allocate map object\n");
+ return NULL;
+ }
+ error = vm_obj_init(map_obj, &vm_anonops, 1);
+ if (error < 0) {
+ kprintf("mmap: vm_obj_init() returned %d\n", error);
+ kprintf("mmap: failed to init object\n");
+ return NULL;
+ }
+ }
+
/* XXX: Assuming private */
- vas = pmap_read_vas();
va = ALIGN_DOWN((vaddr_t)addr, DEFAULT_PAGESIZE);
for (int i = 0; i < npgs; ++i) {
@@ -211,13 +278,13 @@ mmap_at(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
pa = pg->phys_addr;
error = vm_map(vas, va, pa, prot, len);
- pr_trace("va=%p, len=%d\n", va, len);
if (error < 0) {
pr_error("mmap: failed to map page (retval=%x)\n", error);
return NULL;
}
}
+done:
/* Add entry to ledger */
td = this_td();
ep = dynalloc(sizeof(*ep));
@@ -243,7 +310,7 @@ mmap_at(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
* multiple of the machine page size.
*/
int
-munmap_at(void *addr, size_t len)
+munmap(void *addr, size_t len)
{
int pgno;
vaddr_t va;
@@ -299,7 +366,7 @@ munmap_at(void *addr, size_t len)
* arg5 -> off
*/
scret_t
-mmap(struct syscall_args *scargs)
+sys_mmap(struct syscall_args *scargs)
{
void *addr;
size_t len;
@@ -308,11 +375,11 @@ mmap(struct syscall_args *scargs)
addr = (void *)scargs->arg0;
len = scargs->arg1;
- prot = scargs->arg2;
+ prot = scargs->arg2 | PROT_USER;
flags = scargs->arg3;
fildes = scargs->arg4;
off = scargs->arg5;
- return (scret_t)mmap_at(addr, len, prot, flags, fildes, off);
+ return (scret_t)mmap(addr, len, prot, flags, fildes, off);
}
/*
@@ -322,14 +389,14 @@ mmap(struct syscall_args *scargs)
* arg1 -> len
*/
scret_t
-munmap(struct syscall_args *scargs)
+sys_munmap(struct syscall_args *scargs)
{
void *addr;
size_t len;
addr = (void *)scargs->arg0;
len = scargs->arg1;
- return (scret_t)munmap_at(addr, len);
+ return (scret_t)munmap(addr, len);
}
/*