MAP_VPAGETABLE support part 3/3.
authorMatthew Dillon <dillon@dragonflybsd.org>
Wed, 13 Sep 2006 17:10:42 +0000 (17:10 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Wed, 13 Sep 2006 17:10:42 +0000 (17:10 +0000)
Implement a new system call called mcontrol() which is an extension of
madvise(), adding an additional 64 bit argument.  Add two new advisories,
MADV_INVAL and MADV_SETMAP.

MADV_INVAL will invalidate the pmap for the specified virtual address
range.  You need to do this for the virtual addresses effected by changes
made in a virtual page table.

MADV_SETMAP sets the top-level page table entry for the virtual page table
governing the mapped range.  It only works for memory governed by a virtual
page table and strange things will happen if you only set the root
page table entry for part of the virtual range.

Further refine the virtual page table format.  Keep with 32 bit VPTE's for
the moment, but properly implement VPTE_PS and VPTE_V.  VPTE_PS can be
used to suport 4MB linear maps in the top level page table and it can also
be used when specifying the 'root' VPTE to disable the page table entirely
and just linear map the backing store.  VPTE_V is the 'valid' bit (before
it was inverted, now it is normal).

16 files changed:
lib/libc/sys/Makefile.inc
lib/libc/sys/madvise.2
sys/kern/init_sysent.c
sys/kern/syscalls.c
sys/kern/syscalls.master
sys/sys/mman.h
sys/sys/syscall-hide.h
sys/sys/syscall.h
sys/sys/syscall.mk
sys/sys/sysproto.h
sys/sys/sysunion.h
sys/sys/vkernel.h
sys/vm/vm_fault.c
sys/vm/vm_map.c
sys/vm/vm_map.h
sys/vm/vm_mmap.c

index 6c074ab..1d14167 100644 (file)
@@ -1,6 +1,6 @@
 #      @(#)Makefile.inc        8.3 (Berkeley) 10/24/94
 # $FreeBSD: src/lib/libc/sys/Makefile.inc,v 1.75.2.7 2003/04/22 17:31:18 trhodes Exp $
-# $DragonFly: src/lib/libc/sys/Makefile.inc,v 1.20 2006/07/27 00:43:42 corecode Exp $
+# $DragonFly: src/lib/libc/sys/Makefile.inc,v 1.21 2006/09/13 17:10:33 dillon Exp $
 
 # sys sources
 .PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/sys ${.CURDIR}/../libc/sys
@@ -97,6 +97,7 @@ MAN+= sched_get_priority_max.2 sched_setparam.2 \
 .endif
 
 MLINKS+=brk.2 sbrk.2
+MLINKS+=madvise.2 mcontrol.2
 MLINKS+=caps_sys_get.2 caps_sys_wait.2
 MLINKS+=chdir.2 fchdir.2
 MLINKS+=chflags.2 fchflags.2
index c75893e..3c88d12 100644 (file)
 .\"
 .\"    @(#)madvise.2   8.1 (Berkeley) 6/9/93
 .\" $FreeBSD: src/lib/libc/sys/madvise.2,v 1.17.2.8 2003/01/06 23:33:59 trhodes Exp $
-.\" $DragonFly: src/lib/libc/sys/madvise.2,v 1.2 2003/06/17 04:26:47 dillon Exp $
+.\" $DragonFly: src/lib/libc/sys/madvise.2,v 1.3 2006/09/13 17:10:33 dillon Exp $
 .\"
 .Dd July 19, 1996
 .Dt MADVISE 2
 .Os
 .Sh NAME
-.Nm madvise
+.Nm madvise ,
+.Nm mcontrol
 .Nd give advice about use of memory
 .Sh LIBRARY
 .Lb libc
@@ -46,6 +47,8 @@
 .In sys/mman.h
 .Ft int
 .Fn madvise "void *addr" "size_t len" "int behav"
+.Ft int
+.Fn mcontrol "void *addr" "size_t len" "int behav" "off_t value"
 .Sh DESCRIPTION
 The
 .Fn madvise
@@ -119,6 +122,19 @@ system calls.
 Region is not included in a core file.
 .It Dv MADV_CORE
 Include region in a core file.
+.It Dv MADV_INVAL
+Invalidate the hardware page table for a region of memory, forcing
+accesses to re-fault the pages. 
+This command is primarily meant to be used in areas of memory
+governed by a virtual page table after modifications have been made
+to it.
+.It Dv MADV_SETMAP
+Set the offset of the page directory page to
+.Fa value
+for the virtual page table governing
+the specified area of memory.  The entire memory area under virtual page table
+management should be specified.  You may encounter unexpected effects
+if you only set the page directory page for part of the mapping.
 .El
 .Sh RETURN VALUES
 .Rv -std madvise
index d3eb729..d43046e 100644 (file)
@@ -2,8 +2,8 @@
  * System call switch table.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $DragonFly: src/sys/kern/init_sysent.c,v 1.44 2006/09/03 17:11:48 dillon Exp $
- * created from DragonFly: src/sys/kern/syscalls.master,v 1.41 2006/08/06 18:56:44 dillon Exp 
+ * $DragonFly: src/sys/kern/init_sysent.c,v 1.45 2006/09/13 17:10:39 dillon Exp $
+ * created from DragonFly: src/sys/kern/syscalls.master,v 1.42 2006/09/03 17:11:48 dillon Exp 
  */
 
 #include "opt_compat.h"
@@ -524,4 +524,5 @@ struct sysent sysent[] = {
        { AS(vmspace_protect_args), (sy_call_t *)sys_vmspace_protect }, /* 487 = vmspace_protect */
        { AS(vmspace_read_args), (sy_call_t *)sys_vmspace_read },       /* 488 = vmspace_read */
        { AS(vmspace_write_args), (sy_call_t *)sys_vmspace_write },     /* 489 = vmspace_write */
+       { AS(mcontrol_args), (sy_call_t *)sys_mcontrol },       /* 490 = mcontrol */
 };
index 81a8c61..c9af0f2 100644 (file)
@@ -2,8 +2,8 @@
  * System call names.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $DragonFly: src/sys/kern/syscalls.c,v 1.43 2006/09/03 17:11:48 dillon Exp $
- * created from DragonFly: src/sys/kern/syscalls.master,v 1.41 2006/08/06 18:56:44 dillon Exp 
+ * $DragonFly: src/sys/kern/syscalls.c,v 1.44 2006/09/13 17:10:39 dillon Exp $
+ * created from DragonFly: src/sys/kern/syscalls.master,v 1.42 2006/09/03 17:11:48 dillon Exp 
  */
 
 char *syscallnames[] = {
@@ -499,4 +499,5 @@ char *syscallnames[] = {
        "vmspace_protect",                      /* 487 = vmspace_protect */
        "vmspace_read",                 /* 488 = vmspace_read */
        "vmspace_write",                        /* 489 = vmspace_write */
+       "mcontrol",                     /* 490 = mcontrol */
 };
index 1455577..18f72ef 100644 (file)
@@ -1,4 +1,4 @@
- $DragonFly: src/sys/kern/syscalls.master,v 1.42 2006/09/03 17:11:48 dillon Exp $
+ $DragonFly: src/sys/kern/syscalls.master,v 1.43 2006/09/13 17:10:39 dillon Exp $
 
 ; @(#)syscalls.master  8.2 (Berkeley) 1/13/94
 ; $FreeBSD: src/sys/kern/syscalls.master,v 1.72.2.10 2002/07/12 08:22:46 alfred Exp $
 488    STD     BSD     { int vmspace_read(void *id, void *ptr, int bytes); } 
 489    STD     BSD     { int vmspace_write(void *id, const void *ptr, \
                                          int bytes); } 
+490    STD     BSD     { int mcontrol(void *addr, size_t len, int behav, off_t value); }
index 20e1493..fffb96b 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)mman.h      8.2 (Berkeley) 1/9/95
  * $FreeBSD: src/sys/sys/mman.h,v 1.29.2.1 2001/08/25 07:25:43 dillon Exp $
- * $DragonFly: src/sys/sys/mman.h,v 1.5 2006/09/12 18:41:30 dillon Exp $
+ * $DragonFly: src/sys/sys/mman.h,v 1.6 2006/09/13 17:10:40 dillon Exp $
  */
 
 #ifndef _SYS_MMAN_H_
 #define        MADV_NOCORE     8       /* do not include these pages in a core file */
 #define        MADV_CORE       9       /* revert to including pages in a core file */
 #define MADV_INVAL     10      /* virt page tables have changed, inval pmap */
+#define MADV_SETMAP    11      /* set page table directory page for map */
+
+/*
+ * mcontrol() must be used for these functions instead of madvise()
+ */
+#define MADV_CONTROL_START     MADV_INVAL
+#define MADV_CONTROL_END       MADV_SETMAP
 
 /*
  * Return bits from mincore
index 3c638eb..b307c85 100644 (file)
@@ -2,8 +2,8 @@
  * System call hiders.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $DragonFly: src/sys/sys/syscall-hide.h,v 1.44 2006/09/03 17:11:50 dillon Exp $
- * created from DragonFly: src/sys/kern/syscalls.master,v 1.41 2006/08/06 18:56:44 dillon Exp 
+ * $DragonFly: src/sys/sys/syscall-hide.h,v 1.45 2006/09/13 17:10:40 dillon Exp $
+ * created from DragonFly: src/sys/kern/syscalls.master,v 1.42 2006/09/03 17:11:48 dillon Exp 
  */
 
 #ifdef COMPAT_43
@@ -320,3 +320,4 @@ HIDE_BSD(vmspace_map)
 HIDE_BSD(vmspace_protect)
 HIDE_BSD(vmspace_read)
 HIDE_BSD(vmspace_write)
+HIDE_BSD(mcontrol)
index 1d07115..1f4c9d1 100644 (file)
@@ -2,8 +2,8 @@
  * System call numbers.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $DragonFly: src/sys/sys/syscall.h,v 1.44 2006/09/03 17:11:50 dillon Exp $
- * created from DragonFly: src/sys/kern/syscalls.master,v 1.41 2006/08/06 18:56:44 dillon Exp 
+ * $DragonFly: src/sys/sys/syscall.h,v 1.45 2006/09/13 17:10:40 dillon Exp $
+ * created from DragonFly: src/sys/kern/syscalls.master,v 1.42 2006/09/03 17:11:48 dillon Exp 
  */
 
 #define        SYS_syscall     0
 #define        SYS_vmspace_protect     487
 #define        SYS_vmspace_read        488
 #define        SYS_vmspace_write       489
-#define        SYS_MAXSYSCALL  490
+#define        SYS_mcontrol    490
+#define        SYS_MAXSYSCALL  491
index ab8564a..1f4edf1 100644 (file)
@@ -1,7 +1,7 @@
 # DragonFly system call names.
 # DO NOT EDIT-- this file is automatically generated.
-# $DragonFly: src/sys/sys/syscall.mk,v 1.44 2006/09/03 17:11:50 dillon Exp $
-# created from DragonFly: src/sys/kern/syscalls.master,v 1.41 2006/08/06 18:56:44 dillon Exp 
+# $DragonFly: src/sys/sys/syscall.mk,v 1.45 2006/09/13 17:10:40 dillon Exp $
+# created from DragonFly: src/sys/kern/syscalls.master,v 1.42 2006/09/03 17:11:48 dillon Exp 
 MIASM =  \
        syscall.o \
        exit.o \
@@ -271,4 +271,5 @@ MIASM =  \
        vmspace_map.o \
        vmspace_protect.o \
        vmspace_read.o \
-       vmspace_write.o
+       vmspace_write.o \
+       mcontrol.o
index bab4880..56fca1b 100644 (file)
@@ -2,8 +2,8 @@
  * System call prototypes.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $DragonFly: src/sys/sys/sysproto.h,v 1.44 2006/09/03 17:11:50 dillon Exp $
- * created from DragonFly: src/sys/kern/syscalls.master,v 1.41 2006/08/06 18:56:44 dillon Exp 
+ * $DragonFly: src/sys/sys/sysproto.h,v 1.45 2006/09/13 17:10:40 dillon Exp $
+ * created from DragonFly: src/sys/kern/syscalls.master,v 1.42 2006/09/03 17:11:48 dillon Exp 
  */
 
 #ifndef _SYS_SYSPROTO_H_
@@ -2029,6 +2029,15 @@ struct   vmspace_write_args {
        const void *    ptr;    char ptr_[PAD_(const void *)];
        int     bytes;  char bytes_[PAD_(int)];
 };
+struct mcontrol_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       void *  addr;   char addr_[PAD_(void *)];
+       size_t  len;    char len_[PAD_(size_t)];
+       int     behav;  char behav_[PAD_(int)];
+       off_t   value;  char value_[PAD_(off_t)];
+};
 
 #ifdef COMPAT_43
 
@@ -2599,6 +2608,7 @@ int       sys_vmspace_map (struct vmspace_map_args *);
 int    sys_vmspace_protect (struct vmspace_protect_args *);
 int    sys_vmspace_read (struct vmspace_read_args *);
 int    sys_vmspace_write (struct vmspace_write_args *);
+int    sys_mcontrol (struct mcontrol_args *);
 
 #endif /* !_SYS_SYSPROTO_H_ */
 #undef PAD_
index afd1f55..4401a52 100644 (file)
@@ -2,8 +2,8 @@
  * Union of syscall args for messaging.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $DragonFly: src/sys/sys/sysunion.h,v 1.41 2006/09/03 17:11:50 dillon Exp $
- * created from DragonFly: src/sys/kern/syscalls.master,v 1.41 2006/08/06 18:56:44 dillon Exp 
+ * $DragonFly: src/sys/sys/sysunion.h,v 1.42 2006/09/13 17:10:40 dillon Exp $
+ * created from DragonFly: src/sys/kern/syscalls.master,v 1.42 2006/09/03 17:11:48 dillon Exp 
  */
 
 union sysunion {
@@ -376,4 +376,5 @@ union sysunion {
        struct  vmspace_protect_args vmspace_protect;
        struct  vmspace_read_args vmspace_read;
        struct  vmspace_write_args vmspace_write;
+       struct  mcontrol_args mcontrol;
 };
index db7005b..941d4b2 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/sys/vkernel.h,v 1.1 2006/09/12 22:03:11 dillon Exp $
+ * $DragonFly: src/sys/sys/vkernel.h,v 1.2 2006/09/13 17:10:40 dillon Exp $
  */
 
 #ifndef _SYS_VKERNEL_H_
 #ifndef _SYS_SPINLOCK_H_
 #include <sys/spinlock.h>
 #endif
-#ifndef _SYS_KTR_H_
-#include <sys/ktr.h>
-#endif
-
-#ifndef _VM_VM_MAP_H_
-#include <vm/vm_map.h>
-#endif
-
-#ifndef _SYS_THREAD2_H_
-#include <sys/thread2.h>
-#endif
-#ifndef _SYS_SPINLOCK2_H_
-#include <sys/spinlock2.h>
-#endif
 
 struct vmspace_rb_tree;
 struct vmspace_entry;
@@ -119,8 +105,10 @@ void vkernel_drop(struct vkernel *vk);
 typedef u_int32_t      vpte_t;
 
 #define VPTE_PAGE_ENTRIES      (PAGE_SIZE / sizeof(vpte_t))
+#define VPTE_PAGE_BITS         10
+#define VPTE_PAGE_MASK         ((1 << VPTE_PAGE_BITS) - 1)
 
-#define VPTE_IV                0x00000001      /* inverted valid bit (TEMPORARY) */
+#define VPTE_V         0x00000001      /* inverted valid bit (TEMPORARY) */
 #define VPTE_PS                0x00000002
 
 #endif
index 845f26b..35806f8 100644 (file)
@@ -67,7 +67,7 @@
  * rights to redistribute these changes.
  *
  * $FreeBSD: src/sys/vm/vm_fault.c,v 1.108.2.8 2002/02/26 05:49:27 silby Exp $
- * $DragonFly: src/sys/vm/vm_fault.c,v 1.27 2006/09/12 22:03:12 dillon Exp $
+ * $DragonFly: src/sys/vm/vm_fault.c,v 1.28 2006/09/13 17:10:42 dillon Exp $
  */
 
 /*
@@ -124,6 +124,7 @@ struct faultstate {
 };
 
 static int vm_fault_object(struct faultstate *fs, vm_prot_t);
+static int vm_fault_vpagetable(struct faultstate *fs, vpte_t vpte);
 static int vm_fault_additional_pages (vm_page_t, int, int, vm_page_t *, int *);
 static int vm_fault_ratelimit(struct vmspace *vmspace);
 
@@ -313,6 +314,7 @@ RetryFault:
 
        fs.lookup_still_valid = TRUE;
        fs.first_m = NULL;
+       fs.object = fs.first_object;    /* so unlock_and_deallocate works */
 
        /*
         * If the entry is wired we cannot change the page protection.
@@ -329,78 +331,13 @@ RetryFault:
         * ONLY
         */
        if (fs.entry->maptype == VM_MAPTYPE_VPAGETABLE) {
-               vpte_t vpte;
-               struct sf_buf *sf;
-
-               fs.object = fs.first_object;
-               fs.pindex = fs.entry->avail_ssize;      /* page directory */
-
-               /*
-                * Virtual page index must be addressable by the page table
-                */
-               if (fs.first_pindex > VPTE_PAGE_ENTRIES * VPTE_PAGE_ENTRIES) {
-                       unlock_and_deallocate(&fs);
-                       return (KERN_FAILURE);
-               }
-               result = vm_fault_object(&fs, VM_PROT_READ);
+               result = vm_fault_vpagetable(&fs, fs.entry->aux.master_pde);
                if (result == KERN_TRY_AGAIN)
                        goto RetryFault;
                if (result != KERN_SUCCESS)
                        return (result);
-
-               /*
-                * Process the returned fs.m to get the vpte from the page
-                * directory.
-                */
-               sf = sf_buf_alloc(fs.m, SFB_CPUPRIVATE);
-               vpte = *((vpte_t *)sf_buf_kva(sf) +
-                      (fs.first_pindex / VPTE_PAGE_ENTRIES));
-               sf_buf_free(sf);
-               vm_page_flag_set(fs.m, PG_REFERENCED);
-               vm_page_activate(fs.m);
-               vm_page_wakeup(fs.m);
-
-               if (vpte & VPTE_IV) {
-                       unlock_and_deallocate(&fs);
-                       return (KERN_FAILURE);
-               }
-
-               /*
-                * Handle the second-level page table
-                */
-               if (vpte & VPTE_PS) {
-                       fs.first_pindex = (vpte >> PAGE_SHIFT) +
-                                         (fs.first_pindex % VPTE_PAGE_ENTRIES);
-               } else {
-                       cleanup_successful_fault(&fs);
-                       fs.object = fs.first_object;
-                       fs.pindex = (vpte >> PAGE_SHIFT);
-                       result = vm_fault_object(&fs, VM_PROT_READ);
-                       if (result == KERN_TRY_AGAIN)
-                               goto RetryFault;
-                       if (result != KERN_SUCCESS)
-                               return (result);
-
-                       sf = sf_buf_alloc(fs.m, SFB_CPUPRIVATE);
-                       vpte = *((vpte_t *)sf_buf_kva(sf) +
-                              (fs.first_pindex % VPTE_PAGE_ENTRIES));
-                       sf_buf_free(sf);
-                       vm_page_flag_set(fs.m, PG_REFERENCED);
-                       vm_page_activate(fs.m);
-                       vm_page_wakeup(fs.m);
-
-                       if (vpte & VPTE_IV) {
-                               unlock_and_deallocate(&fs);
-                               return (KERN_FAILURE);
-                       }
-                       fs.first_pindex = (vpte >> PAGE_SHIFT);
-               }
-               cleanup_successful_fault(&fs);
        }
 
-       fs.object = fs.first_object;
-       fs.pindex = fs.first_pindex;
-
        /*
         * Now we have the actual (object, pindex), fault in the page.  If
         * vm_fault_object() fails it will unlock and deallocate the FS
@@ -408,7 +345,10 @@ RetryFault:
         * will have an additinal PIP count if it is not equal to
         * fs->first_object
         */
+       fs.object = fs.first_object;
+       fs.pindex = fs.first_pindex;
        result = vm_fault_object(&fs, fault_type);
+
        if (result == KERN_TRY_AGAIN)
                goto RetryFault;
        if (result != KERN_SUCCESS)
@@ -463,6 +403,65 @@ RetryFault:
        return (KERN_SUCCESS);
 }
 
+/*
+ * Translate the virtual page number (fs->first_pindex) that is relative
+ * to the address space into a logical page number that is relative to the
+ * backing object.  Use the virtual page table pointed to by (vpte).
+ *
+ * This implements an N-level page table.  Any level can terminate the
+ * scan by setting VPTE_PS.   A linear mapping is accomplished by setting
+ * VPTE_PS in the master page directory entry set via mcontrol(MADV_SETMAP).
+ */
+static
+int
+vm_fault_vpagetable(struct faultstate *fs, vpte_t vpte)
+{
+       struct sf_buf *sf;
+       int vshift = 32 - PAGE_SHIFT;   /* page index bits remaining */
+       int result;
+
+       for (;;) {
+               if ((vpte & VPTE_V) == 0) {
+                       unlock_and_deallocate(fs);
+                       return (KERN_FAILURE);
+               }
+               if ((vpte & VPTE_PS) || vshift == 0)
+                       break;
+               KKASSERT(vshift >= VPTE_PAGE_BITS);
+
+               /*
+                * Get the page table page
+                */
+               fs->object = fs->first_object;
+               fs->pindex = vpte >> PAGE_SHIFT;
+               result = vm_fault_object(fs, VM_PROT_READ);
+               if (result != KERN_SUCCESS)
+                       return (result);
+
+               /*
+                * Process the returned fs.m and look up the page table
+                * entry in the page table page.
+                */
+               vshift -= VPTE_PAGE_BITS;
+               sf = sf_buf_alloc(fs->m, SFB_CPUPRIVATE);
+               vpte = *((vpte_t *)sf_buf_kva(sf) +
+                      ((fs->first_pindex >> vshift) & VPTE_PAGE_MASK));
+               sf_buf_free(sf);
+               vm_page_flag_set(fs->m, PG_REFERENCED);
+               vm_page_activate(fs->m);
+               vm_page_wakeup(fs->m);
+               cleanup_successful_fault(fs);
+       }
+
+       /*
+        * Combine remaining address bits with the vpte.
+        */
+       fs->first_pindex = (vpte >> PAGE_SHIFT) +
+                         (fs->first_pindex & ((1 << vshift) - 1));
+       return (KERN_SUCCESS);
+}
+
+
 /*
  * Do all operations required to fault in (fs.object, fs.pindex).  Run
  * through the shadow chain as necessary and do required COW or virtual
index feae097..f8c3c0d 100644 (file)
@@ -62,7 +62,7 @@
  * rights to redistribute these changes.
  *
  * $FreeBSD: src/sys/vm/vm_map.c,v 1.187.2.19 2003/05/27 00:47:02 alc Exp $
- * $DragonFly: src/sys/vm/vm_map.c,v 1.48 2006/09/12 18:41:32 dillon Exp $
+ * $DragonFly: src/sys/vm/vm_map.c,v 1.49 2006/09/13 17:10:42 dillon Exp $
  */
 
 /*
@@ -768,7 +768,7 @@ vm_map_insert(vm_map_t map, int *countp,
        new_entry->eflags = protoeflags;
        new_entry->object.vm_object = object;
        new_entry->offset = offset;
-       new_entry->avail_ssize = 0;
+       new_entry->aux.master_pde = 0;
 
        new_entry->inheritance = VM_INHERIT_DEFAULT;
        new_entry->protection = prot;
@@ -802,7 +802,13 @@ vm_map_insert(vm_map_t map, int *countp,
        vm_map_simplify_entry(map, new_entry, countp);
 #endif
 
-       if (cow & (MAP_PREFAULT|MAP_PREFAULT_PARTIAL)) {
+       /*
+        * Try to pre-populate the page table.  Mappings governed by virtual
+        * page tables cannot be prepopulated without a lot of work, so
+        * don't try.
+        */
+       if ((cow & (MAP_PREFAULT|MAP_PREFAULT_PARTIAL)) &&
+           maptype != VM_MAPTYPE_VPAGETABLE) {
                pmap_object_init_pt(map->pmap, start, prot,
                                    object, OFF_TO_IDX(offset), end - start,
                                    cow & MAP_PREFAULT_PARTIAL);
@@ -1528,13 +1534,16 @@ vm_map_protect(vm_map_t map, vm_offset_t start, vm_offset_t end,
  *     system call.  Advisories are classified as either those effecting
  *     the vm_map_entry structure, or those effecting the underlying 
  *     objects.
+ *
+ *     The <value> argument is used for extended madvise calls.
  */
-
 int
-vm_map_madvise(vm_map_t map, vm_offset_t start, vm_offset_t end, int behav)
+vm_map_madvise(vm_map_t map, vm_offset_t start, vm_offset_t end,
+              int behav, off_t value)
 {
        vm_map_entry_t current, entry;
        int modify_map = 0;
+       int error = 0;
        int count;
 
        /*
@@ -1554,6 +1563,8 @@ vm_map_madvise(vm_map_t map, vm_offset_t start, vm_offset_t end, int behav)
        case MADV_AUTOSYNC:
        case MADV_NOCORE:
        case MADV_CORE:
+       case MADV_SETMAP:
+       case MADV_INVAL:
                modify_map = 1;
                vm_map_lock(map);
                break;
@@ -1564,7 +1575,7 @@ vm_map_madvise(vm_map_t map, vm_offset_t start, vm_offset_t end, int behav)
                break;
        default:
                vm_map_entry_release(count);
-               return (KERN_INVALID_ARGUMENT);
+               return (EINVAL);
        }
 
        /*
@@ -1618,7 +1629,43 @@ vm_map_madvise(vm_map_t map, vm_offset_t start, vm_offset_t end, int behav)
                        case MADV_CORE:
                                current->eflags &= ~MAP_ENTRY_NOCOREDUMP;
                                break;
+                       case MADV_INVAL:
+                               /*
+                                * Invalidate the related pmap entries, used
+                                * to flush portions of the real kernel's
+                                * pmap when the caller has removed or
+                                * modified existing mappings in a virtual
+                                * page table.
+                                */
+                               pmap_remove(map->pmap,
+                                           current->start, current->end);
+                               break;
+                       case MADV_SETMAP:
+                               /*
+                                * Set the page directory page for a map
+                                * governed by a virtual page table.  Mark
+                                * the entry as being governed by a virtual
+                                * page table if it is not.
+                                *
+                                * XXX the page directory page is stored
+                                * in the avail_ssize field if the map_entry.
+                                *
+                                * XXX the map simplification code does not
+                                * compare this field so weird things may
+                                * happen if you do not apply this function
+                                * to the entire mapping governed by the
+                                * virtual page table.
+                                */
+                               if (current->maptype != VM_MAPTYPE_VPAGETABLE) {
+                                       error = EINVAL;
+                                       break;
+                               }
+                               current->aux.master_pde = value;
+                               pmap_remove(map->pmap,
+                                           current->start, current->end);
+                               break;
                        default:
+                               error = EINVAL;
                                break;
                        }
                        vm_map_simplify_entry(map, current, &count);
@@ -1664,7 +1711,14 @@ vm_map_madvise(vm_map_t map, vm_offset_t start, vm_offset_t end, int behav)
 
                        vm_object_madvise(current->object.vm_object,
                                          pindex, count, behav);
-                       if (behav == MADV_WILLNEED) {
+
+                       /*
+                        * Try to populate the page table.  Mappings governed
+                        * by virtual page tables cannot be pre-populated
+                        * without a lot of work so don't try.
+                        */
+                       if (behav == MADV_WILLNEED &&
+                           current->maptype != VM_MAPTYPE_VPAGETABLE) {
                                pmap_object_init_pt(
                                    map->pmap, 
                                    useStart,
@@ -1679,7 +1733,7 @@ vm_map_madvise(vm_map_t map, vm_offset_t start, vm_offset_t end, int behav)
                vm_map_unlock_read(map);
        }
        vm_map_entry_release(count);
-       return(0);
+       return(error);
 }      
 
 
@@ -2902,7 +2956,7 @@ vm_map_stack (vm_map_t map, vm_offset_t addrbos, vm_size_t max_ssize,
                    new_stack_entry->start != addrbos + max_ssize - init_ssize)
                        panic ("Bad entry start/end for new stack entry");
                else 
-                       new_stack_entry->avail_ssize = max_ssize - init_ssize;
+                       new_stack_entry->aux.avail_ssize = max_ssize - init_ssize;
        }
 
        vm_map_unlock(map);
@@ -2945,7 +2999,7 @@ Retry:
        if ((stack_entry = prev_entry->next) == &map->header)
                goto done;
        if (prev_entry == &map->header) 
-               end = stack_entry->start - stack_entry->avail_ssize;
+               end = stack_entry->start - stack_entry->aux.avail_ssize;
        else
                end = prev_entry->end;
 
@@ -2956,15 +3010,15 @@ Retry:
         * If not growable stack, return success.  This signals the
         * caller to proceed as he would normally with normal vm.
         */
-       if (stack_entry->avail_ssize < 1 ||
+       if (stack_entry->aux.avail_ssize < 1 ||
            addr >= stack_entry->start ||
-           addr <  stack_entry->start - stack_entry->avail_ssize) {
+           addr <  stack_entry->start - stack_entry->aux.avail_ssize) {
                goto done;
        } 
        
        /* Find the minimum grow amount */
        grow_amount = roundup (stack_entry->start - addr, PAGE_SIZE);
-       if (grow_amount > stack_entry->avail_ssize) {
+       if (grow_amount > stack_entry->aux.avail_ssize) {
                rv = KERN_NO_SPACE;
                goto done;
        }
@@ -2984,7 +3038,7 @@ Retry:
                        goto Retry;
                }
                use_read_lock = 0;
-               stack_entry->avail_ssize = stack_entry->start - end;
+               stack_entry->aux.avail_ssize = stack_entry->start - end;
                rv = KERN_NO_SPACE;
                goto done;
        }
@@ -3002,8 +3056,8 @@ Retry:
 
        /* Round up the grow amount modulo SGROWSIZ */
        grow_amount = roundup (grow_amount, sgrowsiz);
-       if (grow_amount > stack_entry->avail_ssize) {
-               grow_amount = stack_entry->avail_ssize;
+       if (grow_amount > stack_entry->aux.avail_ssize) {
+               grow_amount = stack_entry->aux.avail_ssize;
        }
        if (is_procstack && (ctob(vm->vm_ssize) + grow_amount >
                             p->p_rlimit[RLIMIT_STACK].rlim_cur)) {
@@ -3030,7 +3084,7 @@ Retry:
         * to the available space.  Also, see the note above.
         */
        if (addr < end) {
-               stack_entry->avail_ssize = stack_entry->start - end;
+               stack_entry->aux.avail_ssize = stack_entry->start - end;
                addr = end;
        }
 
@@ -3049,9 +3103,9 @@ Retry:
                    new_stack_entry->start != addr)
                        panic ("Bad stack grow start/end in new stack entry");
                else {
-                       new_stack_entry->avail_ssize = stack_entry->avail_ssize -
-                                                       (new_stack_entry->end -
-                                                        new_stack_entry->start);
+                       new_stack_entry->aux.avail_ssize =
+                               stack_entry->aux.avail_ssize -
+                               (new_stack_entry->end - new_stack_entry->start);
                        if (is_procstack)
                                vm->vm_ssize += btoc(new_stack_entry->end -
                                                     new_stack_entry->start);
index 72ee879..1828e03 100644 (file)
@@ -62,7 +62,7 @@
  * rights to redistribute these changes.
  *
  * $FreeBSD: src/sys/vm/vm_map.h,v 1.54.2.5 2003/01/13 22:51:17 dillon Exp $
- * $DragonFly: src/sys/vm/vm_map.h,v 1.24 2006/09/12 18:41:32 dillon Exp $
+ * $DragonFly: src/sys/vm/vm_map.h,v 1.25 2006/09/13 17:10:42 dillon Exp $
  */
 
 /*
@@ -81,6 +81,9 @@
 #ifndef _SYS_LOCK_H_
 #include <sys/lock.h>
 #endif
+#ifndef _SYS_VKERNEL_H_
+#include <sys/vkernel.h>
+#endif
 #ifndef _VM_VM_H_
 #include <vm/vm.h>
 #endif
@@ -105,12 +108,16 @@ typedef u_int vm_eflags_t;
  *     another map (called a "sharing map") which denotes read-write
  *     sharing with other maps.
  */
-
 union vm_map_object {
        struct vm_object *vm_object;    /* object object */
        struct vm_map *sub_map;         /* belongs to another map */
 };
 
+union vm_map_aux {
+       vm_offset_t avail_ssize;        /* amt can grow if this is a stack */
+       vpte_t master_pde;              /* virtual page table root */
+};
+
 /*
  *     Address map entries consist of start and end addresses,
  *     a VM object (or sharing map) and offset into that object,
@@ -129,7 +136,7 @@ struct vm_map_entry {
        RB_ENTRY(vm_map_entry) rb_entry;
        vm_offset_t start;              /* start address */
        vm_offset_t end;                /* end address */
-       vm_offset_t avail_ssize;        /* amt can grow if this is a stack */
+       union vm_map_aux aux;           /* auxillary data */
        union vm_map_object object;     /* object I point to */
        vm_ooffset_t offset;            /* offset into object */
        vm_eflags_t eflags;             /* map entry flags */
@@ -449,7 +456,7 @@ int vm_map_protect (vm_map_t, vm_offset_t, vm_offset_t, vm_prot_t, boolean_t);
 int vm_map_remove (vm_map_t, vm_offset_t, vm_offset_t);
 void vm_map_startup (void);
 int vm_map_submap (vm_map_t, vm_offset_t, vm_offset_t, vm_map_t);
-int vm_map_madvise (vm_map_t, vm_offset_t, vm_offset_t, int);
+int vm_map_madvise (vm_map_t, vm_offset_t, vm_offset_t, int, off_t);
 void vm_map_simplify_entry (vm_map_t, vm_map_entry_t, int *);
 void vm_init2 (void);
 int vm_uiomove (vm_map_t, vm_object_t, off_t, int, vm_offset_t, int *);
index 012710e..ccbf029 100644 (file)
@@ -39,7 +39,7 @@
  *
  *     @(#)vm_mmap.c   8.4 (Berkeley) 1/12/94
  * $FreeBSD: src/sys/vm/vm_mmap.c,v 1.108.2.6 2002/07/02 20:06:19 dillon Exp $
- * $DragonFly: src/sys/vm/vm_mmap.c,v 1.32 2006/09/12 18:41:32 dillon Exp $
+ * $DragonFly: src/sys/vm/vm_mmap.c,v 1.33 2006/09/13 17:10:42 dillon Exp $
  */
 
 /*
@@ -185,7 +185,7 @@ kern_mmap(caddr_t uaddr, size_t ulen, int uprot, int uflags, int fd,
 
        /*
         * Virtual page tables cannot be used with MAP_STACK.  Apart from
-        * it not making any sense, the avail_ssize field is used by both
+        * it not making any sense, the aux union is used by both
         * types.
         *
         * Because the virtual page table is stored in the backing object
@@ -600,7 +600,7 @@ sys_madvise(struct madvise_args *uap)
        /*
         * Check for illegal behavior
         */
-       if (uap->behav < 0 || uap->behav > MADV_CORE)
+       if (uap->behav < 0 || uap->behav >= MADV_CONTROL_END)
                return (EINVAL);
        /*
         * Check for illegal addresses.  Watch out for address wrap... Note
@@ -623,11 +623,51 @@ sys_madvise(struct madvise_args *uap)
        start = trunc_page((vm_offset_t) uap->addr);
        end = round_page((vm_offset_t) uap->addr + uap->len);
        
-       if (vm_map_madvise(&p->p_vmspace->vm_map, start, end, uap->behav))
+       return (vm_map_madvise(&p->p_vmspace->vm_map, start, end,
+               uap->behav, 0));
+}
+
+/*
+ * mcontrol_args(void *addr, size_t len, int behav, off_t value)
+ */
+/* ARGSUSED */
+int
+sys_mcontrol(struct mcontrol_args *uap)
+{
+       struct proc *p = curproc;
+       vm_offset_t start, end;
+
+       /*
+        * Check for illegal behavior
+        */
+       if (uap->behav < 0 || uap->behav > MADV_CONTROL_END)
                return (EINVAL);
-       return (0);
+       /*
+        * Check for illegal addresses.  Watch out for address wrap... Note
+        * that VM_*_ADDRESS are not constants due to casts (argh).
+        */
+       if (VM_MAXUSER_ADDRESS > 0 &&
+               ((vm_offset_t) uap->addr + uap->len) > VM_MAXUSER_ADDRESS)
+               return (EINVAL);
+#ifndef i386
+       if (VM_MIN_ADDRESS > 0 && uap->addr < VM_MIN_ADDRESS)
+               return (EINVAL);
+#endif
+       if (((vm_offset_t) uap->addr + uap->len) < (vm_offset_t) uap->addr)
+               return (EINVAL);
+
+       /*
+        * Since this routine is only advisory, we default to conservative
+        * behavior.
+        */
+       start = trunc_page((vm_offset_t) uap->addr);
+       end = round_page((vm_offset_t) uap->addr + uap->len);
+       
+       return (vm_map_madvise(&p->p_vmspace->vm_map, start, end, 
+                             uap->behav, uap->value));
 }
 
+
 /*
  * mincore_args(const void *addr, size_t len, char *vec)
  */