added pmap_bootstrap_alloc() to deal with machine dependent
[unix-history] / usr / src / sys / vm / vm_page.c
index 1ce11be..5c446bc 100644 (file)
@@ -1,16 +1,39 @@
 /* 
 /* 
- * Copyright (c) 1985, Avadis Tevanian, Jr., Michael Wayne Young
- * Copyright (c) 1987 Carnegie-Mellon University
  * Copyright (c) 1991 Regents of the University of California.
  * All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * The Mach Operating System project at Carnegie-Mellon University.
  *
  * Copyright (c) 1991 Regents of the University of California.
  * All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * The Mach Operating System project at Carnegie-Mellon University.
  *
- * The CMU software License Agreement specifies the terms and conditions
- * for use and redistribution.
+ * %sccs.include.redist.c%
  *
  *
- *     @(#)vm_page.c   7.2 (Berkeley) %G%
+ *     @(#)vm_page.c   7.9 (Berkeley) %G%
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Avadis Tevanian, Jr., Michael Wayne Young
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
  */
 
 /*
  */
 
 /*
@@ -34,32 +57,22 @@ int         vm_page_bucket_count = 0;       /* How big is array? */
 int            vm_page_hash_mask;              /* Mask for hash function */
 simple_lock_data_t     bucket_lock;            /* lock for all buckets XXX */
 
 int            vm_page_hash_mask;              /* Mask for hash function */
 simple_lock_data_t     bucket_lock;            /* lock for all buckets XXX */
 
-vm_size_t      page_size  = 4096;
-vm_size_t      page_mask  = 4095;
-int            page_shift = 12;
-
 queue_head_t   vm_page_queue_free;
 queue_head_t   vm_page_queue_active;
 queue_head_t   vm_page_queue_inactive;
 simple_lock_data_t     vm_page_queue_lock;
 simple_lock_data_t     vm_page_queue_free_lock;
 
 queue_head_t   vm_page_queue_free;
 queue_head_t   vm_page_queue_active;
 queue_head_t   vm_page_queue_inactive;
 simple_lock_data_t     vm_page_queue_lock;
 simple_lock_data_t     vm_page_queue_free_lock;
 
+/* has physical page allocation been initialized? */
+boolean_t vm_page_startup_initialized;
+
 vm_page_t      vm_page_array;
 long           first_page;
 long           last_page;
 vm_offset_t    first_phys_addr;
 vm_offset_t    last_phys_addr;
 vm_page_t      vm_page_array;
 long           first_page;
 long           last_page;
 vm_offset_t    first_phys_addr;
 vm_offset_t    last_phys_addr;
-
-int    vm_page_free_count;
-int    vm_page_active_count;
-int    vm_page_inactive_count;
-int    vm_page_wire_count;
-int    vm_page_laundry_count;
-
-int    vm_page_free_target = 0;
-int    vm_page_free_min = 0;
-int    vm_page_inactive_target = 0;
-int    vm_page_free_reserved = 0;
+vm_size_t      page_mask;
+int            page_shift;
 
 /*
  *     vm_set_page_size:
 
 /*
  *     vm_set_page_size:
@@ -68,17 +81,18 @@ int vm_page_free_reserved = 0;
  *     size.  Must be called before any use of page-size
  *     dependent functions.
  *
  *     size.  Must be called before any use of page-size
  *     dependent functions.
  *
- *     Sets page_shift and page_mask from page_size.
+ *     Sets page_shift and page_mask from cnt.v_page_size.
  */
 void vm_set_page_size()
 {
  */
 void vm_set_page_size()
 {
-       page_mask = page_size - 1;
 
 
-       if ((page_mask & page_size) != 0)
+       if (cnt.v_page_size == 0)
+               cnt.v_page_size = DEFAULT_PAGE_SIZE;
+       page_mask = cnt.v_page_size - 1;
+       if ((page_mask & cnt.v_page_size) != 0)
                panic("vm_set_page_size: page size not a power of two");
                panic("vm_set_page_size: page size not a power of two");
-
        for (page_shift = 0; ; page_shift++)
        for (page_shift = 0; ; page_shift++)
-               if ((1 << page_shift) == page_size)
+               if ((1 << page_shift) == cnt.v_page_size)
                        break;
 }
 
                        break;
 }
 
@@ -92,19 +106,15 @@ void vm_set_page_size()
  *     for the object/offset-to-page hash table headers.
  *     Each page cell is initialized and placed on the free list.
  */
  *     for the object/offset-to-page hash table headers.
  *     Each page cell is initialized and placed on the free list.
  */
-vm_offset_t vm_page_startup(start, end, vaddr)
-       register vm_offset_t    start;
-       vm_offset_t     end;
-       register vm_offset_t    vaddr;
+void vm_page_startup(start, end)
+       vm_offset_t     *start;
+       vm_offset_t     *end;
 {
 {
-       register vm_offset_t    mapped;
        register vm_page_t      m;
        register queue_t        bucket;
        vm_size_t               npages;
        register vm_page_t      m;
        register queue_t        bucket;
        vm_size_t               npages;
-       register vm_offset_t    new_start;
        int                     i;
        vm_offset_t             pa;
        int                     i;
        vm_offset_t             pa;
-
        extern  vm_offset_t     kentry_data;
        extern  vm_size_t       kentry_data_size;
 
        extern  vm_offset_t     kentry_data;
        extern  vm_size_t       kentry_data_size;
 
@@ -126,7 +136,7 @@ vm_offset_t vm_page_startup(start, end, vaddr)
        queue_init(&vm_page_queue_inactive);
 
        /*
        queue_init(&vm_page_queue_inactive);
 
        /*
-        *      Allocate (and initialize) the hash table buckets.
+        *      Calculate the number of hash table buckets.
         *
         *      The number of buckets MUST BE a power of 2, and
         *      the actual value is the next power of 2 greater
         *
         *      The number of buckets MUST BE a power of 2, and
         *      the actual value is the next power of 2 greater
@@ -136,27 +146,20 @@ vm_offset_t vm_page_startup(start, end, vaddr)
         *              This computation can be tweaked if desired.
         */
 
         *              This computation can be tweaked if desired.
         */
 
-       vm_page_buckets = (queue_t) vaddr;
-       bucket = vm_page_buckets;
        if (vm_page_bucket_count == 0) {
                vm_page_bucket_count = 1;
        if (vm_page_bucket_count == 0) {
                vm_page_bucket_count = 1;
-               while (vm_page_bucket_count < atop(end - start))
+               while (vm_page_bucket_count < atop(*end - *start))
                        vm_page_bucket_count <<= 1;
        }
 
        vm_page_hash_mask = vm_page_bucket_count - 1;
 
        /*
                        vm_page_bucket_count <<= 1;
        }
 
        vm_page_hash_mask = vm_page_bucket_count - 1;
 
        /*
-        *      Validate these addresses.
+        *      Allocate (and initialize) the hash table buckets.
         */
         */
-
-       new_start = round_page(((queue_t)start) + vm_page_bucket_count);
-       mapped = vaddr;
-       vaddr = pmap_map(mapped, start, new_start,
-                       VM_PROT_READ|VM_PROT_WRITE);
-       start = new_start;
-       blkclr((caddr_t) mapped, vaddr - mapped);
-       mapped = vaddr;
+       vm_page_buckets = (queue_t) pmap_bootstrap_alloc(vm_page_bucket_count
+               * sizeof(struct queue_entry));
+       bucket = vm_page_buckets;
 
        for (i = vm_page_bucket_count; i--;) {
                queue_init(bucket);
 
        for (i = vm_page_bucket_count; i--;) {
                queue_init(bucket);
@@ -166,10 +169,10 @@ vm_offset_t vm_page_startup(start, end, vaddr)
        simple_lock_init(&bucket_lock);
 
        /*
        simple_lock_init(&bucket_lock);
 
        /*
-        *      round (or truncate) the addresses to our page size.
+        *      Truncate the remainder of physical memory to our page size.
         */
 
         */
 
-       end = trunc_page(end);
+       *end = trunc_page(*end);
 
        /*
         *      Pre-allocate maps and map entries that cannot be dynamically
 
        /*
         *      Pre-allocate maps and map entries that cannot be dynamically
@@ -185,19 +188,7 @@ vm_offset_t vm_page_startup(start, end, vaddr)
 
        kentry_data_size = MAX_KMAP * sizeof(struct vm_map) +
                           MAX_KMAPENT * sizeof(struct vm_map_entry);
 
        kentry_data_size = MAX_KMAP * sizeof(struct vm_map) +
                           MAX_KMAPENT * sizeof(struct vm_map_entry);
-       kentry_data_size = round_page(kentry_data_size);
-       kentry_data = (vm_offset_t) vaddr;
-       vaddr += kentry_data_size;
-
-       /*
-        *      Validate these zone addresses.
-        */
-
-       new_start = start + (vaddr - mapped);
-       pmap_map(mapped, start, new_start, VM_PROT_READ|VM_PROT_WRITE);
-       blkclr((caddr_t) mapped, (vaddr - mapped));
-       mapped = vaddr;
-       start = new_start;
+       kentry_data = (vm_offset_t) pmap_bootstrap_alloc(kentry_data_size);
 
        /*
         *      Compute the number of pages of memory that will be
 
        /*
         *      Compute the number of pages of memory that will be
@@ -205,16 +196,15 @@ vm_offset_t vm_page_startup(start, end, vaddr)
         *      of a page structure per page).
         */
 
         *      of a page structure per page).
         */
 
-       vm_page_free_count = npages =
-               (end - start)/(PAGE_SIZE + sizeof(struct vm_page));
+       cnt.v_free_count = npages =
+               (*end - *start)/(PAGE_SIZE + sizeof(struct vm_page));
 
        /*
 
        /*
-        *      Initialize the mem entry structures now, and
-        *      put them in the free queue.
+        *      Record the extent of physical memory that the
+        *      virtual memory system manages.
         */
 
         */
 
-       m = vm_page_array = (vm_page_t) vaddr;
-       first_page = start;
+       first_page = *start;
        first_page += npages*sizeof(struct vm_page);
        first_page = atop(round_page(first_page));
        last_page  = first_page + npages - 1;
        first_page += npages*sizeof(struct vm_page);
        first_page = atop(round_page(first_page));
        last_page  = first_page + npages - 1;
@@ -222,19 +212,18 @@ vm_offset_t vm_page_startup(start, end, vaddr)
        first_phys_addr = ptoa(first_page);
        last_phys_addr  = ptoa(last_page) + PAGE_MASK;
 
        first_phys_addr = ptoa(first_page);
        last_phys_addr  = ptoa(last_page) + PAGE_MASK;
 
+
        /*
        /*
-        *      Validate these addresses.
+        *      Allocate and clear the mem entry structures.
         */
 
         */
 
-       new_start = start + (round_page(m + npages) - mapped);
-       mapped = pmap_map(mapped, start, new_start,
-                       VM_PROT_READ|VM_PROT_WRITE);
-       start = new_start;
+       m = vm_page_array = (vm_page_t)
+               pmap_bootstrap_alloc(npages * sizeof(struct vm_page));
 
        /*
 
        /*
-        *      Clear all of the page structures
+        *      Initialize the mem entry structures now, and
+        *      put them in the free queue.
         */
         */
-       blkclr((caddr_t)m, npages * sizeof(*m));
 
        pa = first_phys_addr;
        while (npages--) {
 
        pa = first_phys_addr;
        while (npages--) {
@@ -245,7 +234,18 @@ vm_offset_t vm_page_startup(start, end, vaddr)
                m->busy = FALSE;
                m->object = NULL;
                m->phys_addr = pa;
                m->busy = FALSE;
                m->object = NULL;
                m->phys_addr = pa;
+#ifdef i386
+               if (pmap_isvalidphys(m->phys_addr)) {
+                       queue_enter(&vm_page_queue_free, m, vm_page_t, pageq);
+               } else {
+                       /* perhaps iomem needs it's own type, or dev pager? */
+                       m->fictitious = 1;
+                       m->busy = TRUE;
+                       cnt.v_free_count--;
+               }
+#else /* i386 */
                queue_enter(&vm_page_queue_free, m, vm_page_t, pageq);
                queue_enter(&vm_page_queue_free, m, vm_page_t, pageq);
+#endif /* i386 */
                m++;
                pa += PAGE_SIZE;
        }
                m++;
                pa += PAGE_SIZE;
        }
@@ -256,7 +256,8 @@ vm_offset_t vm_page_startup(start, end, vaddr)
         */
        simple_lock_init(&vm_pages_needed_lock);
 
         */
        simple_lock_init(&vm_pages_needed_lock);
 
-       return(mapped);
+       /* from now on, pmap_bootstrap_alloc can't be used */
+       vm_page_startup_initialized = TRUE;
 }
 
 /*
 }
 
 /*
@@ -278,7 +279,7 @@ vm_offset_t vm_page_startup(start, end, vaddr)
  *     The object and page must be locked.
  */
 
  *     The object and page must be locked.
  */
 
-void vm_page_insert(mem, object, offset)
+static void vm_page_insert(mem, object, offset)
        register vm_page_t      mem;
        register vm_object_t    object;
        register vm_offset_t    offset;
        register vm_page_t      mem;
        register vm_object_t    object;
        register vm_offset_t    offset;
@@ -326,6 +327,7 @@ void vm_page_insert(mem, object, offset)
 
 /*
  *     vm_page_remove:         [ internal use only ]
 
 /*
  *     vm_page_remove:         [ internal use only ]
+ *                             NOTE: used by device pager as well -wfj
  *
  *     Removes the given mem entry from the object/offset-page
  *     table and the object page list.
  *
  *     Removes the given mem entry from the object/offset-page
  *     table and the object page list.
@@ -440,6 +442,26 @@ void               vm_page_init(mem, object, offset)
        vm_object_t     object;
        vm_offset_t     offset;
 {
        vm_object_t     object;
        vm_offset_t     offset;
 {
+#ifdef DEBUG
+#define        vm_page_init(mem, object, offset)  {\
+               (mem)->busy = TRUE; \
+               (mem)->tabled = FALSE; \
+               vm_page_insert((mem), (object), (offset)); \
+               (mem)->absent = FALSE; \
+               (mem)->fictitious = FALSE; \
+               (mem)->page_lock = VM_PROT_NONE; \
+               (mem)->unlock_request = VM_PROT_NONE; \
+               (mem)->laundry = FALSE; \
+               (mem)->active = FALSE; \
+               (mem)->inactive = FALSE; \
+               (mem)->wire_count = 0; \
+               (mem)->clean = TRUE; \
+               (mem)->copy_on_write = FALSE; \
+               (mem)->fake = TRUE; \
+               (mem)->pagerowned = FALSE; \
+               (mem)->ptpage = FALSE; \
+       }
+#else
 #define        vm_page_init(mem, object, offset)  {\
                (mem)->busy = TRUE; \
                (mem)->tabled = FALSE; \
 #define        vm_page_init(mem, object, offset)  {\
                (mem)->busy = TRUE; \
                (mem)->tabled = FALSE; \
@@ -456,6 +478,7 @@ void                vm_page_init(mem, object, offset)
                (mem)->copy_on_write = FALSE; \
                (mem)->fake = TRUE; \
        }
                (mem)->copy_on_write = FALSE; \
                (mem)->fake = TRUE; \
        }
+#endif
 
        vm_page_init(mem, object, offset);
 }
 
        vm_page_init(mem, object, offset);
 }
@@ -485,7 +508,7 @@ vm_page_t vm_page_alloc(object, offset)
 
        queue_remove_first(&vm_page_queue_free, mem, vm_page_t, pageq);
 
 
        queue_remove_first(&vm_page_queue_free, mem, vm_page_t, pageq);
 
-       vm_page_free_count--;
+       cnt.v_free_count--;
        simple_unlock(&vm_page_queue_free_lock);
        splx(spl);
 
        simple_unlock(&vm_page_queue_free_lock);
        splx(spl);
 
@@ -502,10 +525,10 @@ vm_page_t vm_page_alloc(object, offset)
         *      it doesn't really matter.
         */
 
         *      it doesn't really matter.
         */
 
-       if ((vm_page_free_count < vm_page_free_min) ||
-                       ((vm_page_free_count < vm_page_free_target) &&
-                       (vm_page_inactive_count < vm_page_inactive_target)))
-               thread_wakeup(&vm_pages_needed);
+       if ((cnt.v_free_count < cnt.v_free_min) ||
+                       ((cnt.v_free_count < cnt.v_free_target) &&
+                       (cnt.v_inactive_count < cnt.v_inactive_target)))
+               thread_wakeup((int)&vm_pages_needed);
        return(mem);
 }
 
        return(mem);
 }
 
@@ -524,13 +547,13 @@ void vm_page_free(mem)
        if (mem->active) {
                queue_remove(&vm_page_queue_active, mem, vm_page_t, pageq);
                mem->active = FALSE;
        if (mem->active) {
                queue_remove(&vm_page_queue_active, mem, vm_page_t, pageq);
                mem->active = FALSE;
-               vm_page_active_count--;
+               cnt.v_active_count--;
        }
 
        if (mem->inactive) {
                queue_remove(&vm_page_queue_inactive, mem, vm_page_t, pageq);
                mem->inactive = FALSE;
        }
 
        if (mem->inactive) {
                queue_remove(&vm_page_queue_inactive, mem, vm_page_t, pageq);
                mem->inactive = FALSE;
-               vm_page_inactive_count--;
+               cnt.v_inactive_count--;
        }
 
        if (!mem->fictitious) {
        }
 
        if (!mem->fictitious) {
@@ -540,7 +563,7 @@ void vm_page_free(mem)
                simple_lock(&vm_page_queue_free_lock);
                queue_enter(&vm_page_queue_free, mem, vm_page_t, pageq);
 
                simple_lock(&vm_page_queue_free_lock);
                queue_enter(&vm_page_queue_free, mem, vm_page_t, pageq);
 
-               vm_page_free_count++;
+               cnt.v_free_count++;
                simple_unlock(&vm_page_queue_free_lock);
                splx(spl);
        }
                simple_unlock(&vm_page_queue_free_lock);
                splx(spl);
        }
@@ -564,16 +587,16 @@ void vm_page_wire(mem)
                if (mem->active) {
                        queue_remove(&vm_page_queue_active, mem, vm_page_t,
                                                pageq);
                if (mem->active) {
                        queue_remove(&vm_page_queue_active, mem, vm_page_t,
                                                pageq);
-                       vm_page_active_count--;
+                       cnt.v_active_count--;
                        mem->active = FALSE;
                }
                if (mem->inactive) {
                        queue_remove(&vm_page_queue_inactive, mem, vm_page_t,
                                                pageq);
                        mem->active = FALSE;
                }
                if (mem->inactive) {
                        queue_remove(&vm_page_queue_inactive, mem, vm_page_t,
                                                pageq);
-                       vm_page_inactive_count--;
+                       cnt.v_inactive_count--;
                        mem->inactive = FALSE;
                }
                        mem->inactive = FALSE;
                }
-               vm_page_wire_count++;
+               cnt.v_wire_count++;
        }
        mem->wire_count++;
 }
        }
        mem->wire_count++;
 }
@@ -594,9 +617,9 @@ void vm_page_unwire(mem)
        mem->wire_count--;
        if (mem->wire_count == 0) {
                queue_enter(&vm_page_queue_active, mem, vm_page_t, pageq);
        mem->wire_count--;
        if (mem->wire_count == 0) {
                queue_enter(&vm_page_queue_active, mem, vm_page_t, pageq);
-               vm_page_active_count++;
+               cnt.v_active_count++;
                mem->active = TRUE;
                mem->active = TRUE;
-               vm_page_wire_count--;
+               cnt.v_wire_count--;
        }
 }
 
        }
 }
 
@@ -625,8 +648,8 @@ void vm_page_deactivate(m)
                queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq);
                m->active = FALSE;
                m->inactive = TRUE;
                queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq);
                m->active = FALSE;
                m->inactive = TRUE;
-               vm_page_active_count--;
-               vm_page_inactive_count++;
+               cnt.v_active_count--;
+               cnt.v_inactive_count++;
                if (pmap_is_modified(VM_PAGE_TO_PHYS(m)))
                        m->clean = FALSE;
                m->laundry = !m->clean;
                if (pmap_is_modified(VM_PAGE_TO_PHYS(m)))
                        m->clean = FALSE;
                m->laundry = !m->clean;
@@ -649,7 +672,7 @@ void vm_page_activate(m)
        if (m->inactive) {
                queue_remove(&vm_page_queue_inactive, m, vm_page_t,
                                                pageq);
        if (m->inactive) {
                queue_remove(&vm_page_queue_inactive, m, vm_page_t,
                                                pageq);
-               vm_page_inactive_count--;
+               cnt.v_inactive_count--;
                m->inactive = FALSE;
        }
        if (m->wire_count == 0) {
                m->inactive = FALSE;
        }
        if (m->wire_count == 0) {
@@ -658,7 +681,7 @@ void vm_page_activate(m)
 
                queue_enter(&vm_page_queue_active, m, vm_page_t, pageq);
                m->active = TRUE;
 
                queue_enter(&vm_page_queue_active, m, vm_page_t, pageq);
                m->active = TRUE;
-               vm_page_active_count++;
+               cnt.v_active_count++;
        }
 }
 
        }
 }