Annotation of XNU/osfmk/vm/vm_resident.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  * @OSF_COPYRIGHT@
        !            24:  */
        !            25: /* 
        !            26:  * Mach Operating System
        !            27:  * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
        !            28:  * All Rights Reserved.
        !            29:  * 
        !            30:  * Permission to use, copy, modify and distribute this software and its
        !            31:  * documentation is hereby granted, provided that both the copyright
        !            32:  * notice and this permission notice appear in all copies of the
        !            33:  * software, derivative works or modified versions, and any portions
        !            34:  * thereof, and that both notices appear in supporting documentation.
        !            35:  * 
        !            36:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            37:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !            38:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            39:  * 
        !            40:  * Carnegie Mellon requests users of this software to return to
        !            41:  * 
        !            42:  *  Software Distribution Coordinator  or  [email protected]
        !            43:  *  School of Computer Science
        !            44:  *  Carnegie Mellon University
        !            45:  *  Pittsburgh PA 15213-3890
        !            46:  * 
        !            47:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            48:  * the rights to redistribute these changes.
        !            49:  */
        !            50: /*
        !            51:  */
        !            52: /*
        !            53:  *     File:   vm/vm_page.c
        !            54:  *     Author: Avadis Tevanian, Jr., Michael Wayne Young
        !            55:  *
        !            56:  *     Resident memory management module.
        !            57:  */
        !            58: 
        !            59: #include <mach/vm_prot.h>
        !            60: #include <mach/vm_statistics.h>
        !            61: #include <kern/counters.h>
        !            62: #include <kern/sched_prim.h>
        !            63: #include <kern/task.h>
        !            64: #include <kern/thread.h>
        !            65: #include <kern/zalloc.h>
        !            66: #include <kern/xpr.h>
        !            67: #include <vm/pmap.h>
        !            68: #include <vm/vm_init.h>
        !            69: #include <vm/vm_map.h>
        !            70: #include <vm/vm_page.h>
        !            71: #include <vm/vm_pageout.h>
        !            72: #include <vm/vm_kern.h>                        /* kernel_memory_allocate() */
        !            73: #include <kern/misc_protos.h>
        !            74: #include <zone_debug.h>
        !            75: #include <vm/cpm.h>
        !            76: 
        !            77: /*
        !            78:  *     Associated with page of user-allocatable memory is a
        !            79:  *     page structure.
        !            80:  */
        !            81: 
        !            82: /*
        !            83:  *     These variables record the values returned by vm_page_bootstrap,
        !            84:  *     for debugging purposes.  The implementation of pmap_steal_memory
        !            85:  *     and pmap_startup here also uses them internally.
        !            86:  */
        !            87: 
        !            88: vm_offset_t virtual_space_start;
        !            89: vm_offset_t virtual_space_end;
        !            90: int    vm_page_pages;
        !            91: 
        !            92: /*
        !            93:  *     The vm_page_lookup() routine, which provides for fast
        !            94:  *     (virtual memory object, offset) to page lookup, employs
        !            95:  *     the following hash table.  The vm_page_{insert,remove}
        !            96:  *     routines install and remove associations in the table.
        !            97:  *     [This table is often called the virtual-to-physical,
        !            98:  *     or VP, table.]
        !            99:  */
        !           100: typedef struct {
        !           101:        vm_page_t       pages;
        !           102: #if    MACH_PAGE_HASH_STATS
        !           103:        int             cur_count;              /* current count */
        !           104:        int             hi_count;               /* high water mark */
        !           105: #endif /* MACH_PAGE_HASH_STATS */
        !           106: } vm_page_bucket_t;
        !           107: 
        !           108: vm_page_bucket_t *vm_page_buckets;             /* Array of buckets */
        !           109: unsigned int   vm_page_bucket_count = 0;       /* How big is array? */
        !           110: unsigned int   vm_page_hash_mask;              /* Mask for hash function */
        !           111: unsigned int   vm_page_hash_shift;             /* Shift for hash function */
        !           112: decl_simple_lock_data(,vm_page_bucket_lock)
        !           113: 
        !           114: #if    MACH_PAGE_HASH_STATS
        !           115: /* This routine is only for debug.  It is intended to be called by
        !           116:  * hand by a developer using a kernel debugger.  This routine prints
        !           117:  * out vm_page_hash table statistics to the kernel debug console.
        !           118:  */
        !           119: void
        !           120: hash_debug(void)
        !           121: {
        !           122:        int     i;
        !           123:        int     numbuckets = 0;
        !           124:        int     highsum = 0;
        !           125:        int     maxdepth = 0;
        !           126: 
        !           127:        for (i = 0; i < vm_page_bucket_count; i++) {
        !           128:                if (vm_page_buckets[i].hi_count) {
        !           129:                        numbuckets++;
        !           130:                        highsum += vm_page_buckets[i].hi_count;
        !           131:                        if (vm_page_buckets[i].hi_count > maxdepth)
        !           132:                                maxdepth = vm_page_buckets[i].hi_count;
        !           133:                }
        !           134:        }
        !           135:        printf("Total number of buckets: %d\n", vm_page_bucket_count);
        !           136:        printf("Number used buckets:     %d = %d%%\n",
        !           137:                numbuckets, 100*numbuckets/vm_page_bucket_count);
        !           138:        printf("Number unused buckets:   %d = %d%%\n",
        !           139:                vm_page_bucket_count - numbuckets,
        !           140:                100*(vm_page_bucket_count-numbuckets)/vm_page_bucket_count);
        !           141:        printf("Sum of bucket max depth: %d\n", highsum);
        !           142:        printf("Average bucket depth:    %d.%2d\n",
        !           143:                highsum/vm_page_bucket_count,
        !           144:                highsum%vm_page_bucket_count);
        !           145:        printf("Maximum bucket depth:    %d\n", maxdepth);
        !           146: }
        !           147: #endif /* MACH_PAGE_HASH_STATS */
        !           148: 
        !           149: /*
        !           150:  *     The virtual page size is currently implemented as a runtime
        !           151:  *     variable, but is constant once initialized using vm_set_page_size.
        !           152:  *     This initialization must be done in the machine-dependent
        !           153:  *     bootstrap sequence, before calling other machine-independent
        !           154:  *     initializations.
        !           155:  *
        !           156:  *     All references to the virtual page size outside this
        !           157:  *     module must use the PAGE_SIZE, PAGE_MASK and PAGE_SHIFT
        !           158:  *     constants.
        !           159:  */
        !           160: #ifndef PAGE_SIZE_FIXED
        !           161: vm_size_t      page_size  = 4096;
        !           162: vm_size_t      page_mask  = 4095;
        !           163: int            page_shift = 12;
        !           164: #endif /* PAGE_SIZE_FIXED */
        !           165: 
        !           166: /*
        !           167:  *     Resident page structures are initialized from
        !           168:  *     a template (see vm_page_alloc).
        !           169:  *
        !           170:  *     When adding a new field to the virtual memory
        !           171:  *     object structure, be sure to add initialization
        !           172:  *     (see vm_page_bootstrap).
        !           173:  */
        !           174: struct vm_page vm_page_template;
        !           175: 
        !           176: /*
        !           177:  *     Resident pages that represent real memory
        !           178:  *     are allocated from a free list.
        !           179:  */
        !           180: vm_page_t      vm_page_queue_free;
        !           181: vm_page_t       vm_page_queue_fictitious;
        !           182: decl_mutex_data(,vm_page_queue_free_lock)
        !           183: unsigned int   vm_page_free_wanted;
        !           184: int            vm_page_free_count;
        !           185: int            vm_page_fictitious_count;
        !           186: 
        !           187: unsigned int   vm_page_free_count_minimum;     /* debugging */
        !           188: 
        !           189: /*
        !           190:  *     Occasionally, the virtual memory system uses
        !           191:  *     resident page structures that do not refer to
        !           192:  *     real pages, for example to leave a page with
        !           193:  *     important state information in the VP table.
        !           194:  *
        !           195:  *     These page structures are allocated the way
        !           196:  *     most other kernel structures are.
        !           197:  */
        !           198: zone_t vm_page_zone;
        !           199: decl_mutex_data(,vm_page_alloc_lock)
        !           200: 
        !           201: /*
        !           202:  *     Fictitious pages don't have a physical address,
        !           203:  *     but we must initialize phys_addr to something.
        !           204:  *     For debugging, this should be a strange value
        !           205:  *     that the pmap module can recognize in assertions.
        !           206:  */
        !           207: vm_offset_t vm_page_fictitious_addr = (vm_offset_t) -1;
        !           208: 
        !           209: /*
        !           210:  *     Resident page structures are also chained on
        !           211:  *     queues that are used by the page replacement
        !           212:  *     system (pageout daemon).  These queues are
        !           213:  *     defined here, but are shared by the pageout
        !           214:  *     module.
        !           215:  */
        !           216: queue_head_t   vm_page_queue_active;
        !           217: queue_head_t   vm_page_queue_inactive;
        !           218: decl_mutex_data(,vm_page_queue_lock)
        !           219: int            vm_page_active_count;
        !           220: int            vm_page_inactive_count;
        !           221: int            vm_page_wire_count;
        !           222: int            vm_page_gobble_count = 0;
        !           223: int            vm_page_wire_count_warning = 0;
        !           224: int            vm_page_gobble_count_warning = 0;
        !           225: 
        !           226: /* the following fields are protected by the vm_page_queue_lock */
        !           227: queue_head_t   vm_page_queue_limbo;
        !           228: int    vm_page_limbo_count = 0;                /* total pages in limbo */
        !           229: int    vm_page_limbo_real_count = 0;           /* real pages in limbo */
        !           230: int    vm_page_pin_count = 0;                  /* number of pinned pages */
        !           231: 
        !           232: decl_simple_lock_data(,vm_page_preppin_lock)
        !           233: 
        !           234: /*
        !           235:  *     Several page replacement parameters are also
        !           236:  *     shared with this module, so that page allocation
        !           237:  *     (done here in vm_page_alloc) can trigger the
        !           238:  *     pageout daemon.
        !           239:  */
        !           240: int    vm_page_free_target = 0;
        !           241: int    vm_page_free_min = 0;
        !           242: int    vm_page_inactive_target = 0;
        !           243: int    vm_page_free_reserved = 0;
        !           244: int    vm_page_laundry_count = 0;
        !           245: 
        !           246: /*
        !           247:  *     The VM system has a couple of heuristics for deciding
        !           248:  *     that pages are "uninteresting" and should be placed
        !           249:  *     on the inactive queue as likely candidates for replacement.
        !           250:  *     These variables let the heuristics be controlled at run-time
        !           251:  *     to make experimentation easier.
        !           252:  */
        !           253: 
        !           254: boolean_t vm_page_deactivate_hint = TRUE;
        !           255: 
        !           256: /* 
        !           257:  * Definition for automatic physical memory reservation.  Declared in
        !           258:  * vm_page.h, defined here.  See vm_page.h for details.  There's an
        !           259:  * extra zero entry to allow the code to compile if there are no requests
        !           260:  * for physical memory allocation; pmem_reserve_ctl_size is decremented
        !           261:  * by one to compensate.
        !           262:  */
        !           263: #include <flipc.h>
        !           264: #if FLIPC
        !           265: #include <flipc/flipc_usermsg.h>
        !           266: #endif
        !           267: 
        !           268: struct pmem_reserve pmem_reserve_ctl_array[] = {
        !           269: #if FLIPC
        !           270:     { &flipc_cb_length, (vm_offset_t *) &flipc_cb_base },
        !           271: #endif
        !           272:     { 0, (vm_offset_t *) 0 }
        !           273: };
        !           274: 
        !           275: struct pmem_reserve *pmem_reserve_ctl = &pmem_reserve_ctl_array[0];
        !           276: 
        !           277: int pmem_reserve_ctl_size =
        !           278:   (sizeof(pmem_reserve_ctl_array) / sizeof(struct pmem_reserve)) - 1;
        !           279: 
        !           280: /*
        !           281:  *     vm_set_page_size:
        !           282:  *
        !           283:  *     Sets the page size, perhaps based upon the memory
        !           284:  *     size.  Must be called before any use of page-size
        !           285:  *     dependent functions.
        !           286:  *
        !           287:  *     Sets page_shift and page_mask from page_size.
        !           288:  */
        !           289: void
        !           290: vm_set_page_size(void)
        !           291: {
        !           292: #ifndef PAGE_SIZE_FIXED
        !           293:        page_mask = page_size - 1;
        !           294: 
        !           295:        if ((page_mask & page_size) != 0)
        !           296:                panic("vm_set_page_size: page size not a power of two");
        !           297: 
        !           298:        for (page_shift = 0; ; page_shift++)
        !           299:                if ((1 << page_shift) == page_size)
        !           300:                        break;
        !           301: #endif /* PAGE_SIZE_FIXED */
        !           302: }
        !           303: 
        !           304: /*
        !           305:  *     vm_page_bootstrap:
        !           306:  *
        !           307:  *     Initializes the resident memory module.
        !           308:  *
        !           309:  *     Allocates memory for the page cells, and
        !           310:  *     for the object/offset-to-page hash table headers.
        !           311:  *     Each page cell is initialized and placed on the free list.
        !           312:  *     Returns the range of available kernel virtual memory.
        !           313:  */
        !           314: 
        !           315: void
        !           316: vm_page_bootstrap(
        !           317:        vm_offset_t             *startp,
        !           318:        vm_offset_t             *endp)
        !           319: {
        !           320:        register vm_page_t      m;
        !           321:        int                     i;
        !           322:        unsigned int            log1;
        !           323:        unsigned int            log2;
        !           324:        unsigned int            size;
        !           325: 
        !           326:        /*
        !           327:         *      Initialize the vm_page template.
        !           328:         */
        !           329: 
        !           330:        m = &vm_page_template;
        !           331:        m->object = VM_OBJECT_NULL;     /* reset later */
        !           332:        m->offset = 0;                  /* reset later */
        !           333:        m->wire_count = 0;
        !           334: 
        !           335:        m->inactive = FALSE;
        !           336:        m->active = FALSE;
        !           337:        m->laundry = FALSE;
        !           338:        m->free = FALSE;
        !           339:        m->reference = FALSE;
        !           340:        m->pageout = FALSE;
        !           341:        m->list_req_pending = FALSE;
        !           342: 
        !           343:        m->busy = TRUE;
        !           344:        m->wanted = FALSE;
        !           345:        m->tabled = FALSE;
        !           346:        m->fictitious = FALSE;
        !           347:        m->private = FALSE;
        !           348:        m->absent = FALSE;
        !           349:        m->error = FALSE;
        !           350:        m->dirty = FALSE;
        !           351:        m->cleaning = FALSE;
        !           352:        m->precious = FALSE;
        !           353:        m->clustered = FALSE;
        !           354:        m->lock_supplied = FALSE;
        !           355:        m->unusual = FALSE;
        !           356:        m->restart = FALSE;
        !           357:        m->limbo = FALSE;
        !           358: 
        !           359:        m->phys_addr = 0;               /* reset later */
        !           360: 
        !           361:        m->page_lock = VM_PROT_NONE;
        !           362:        m->unlock_request = VM_PROT_NONE;
        !           363:        m->page_error = KERN_SUCCESS;
        !           364: 
        !           365:        /*
        !           366:         *      Initialize the page queues.
        !           367:         */
        !           368: 
        !           369:        mutex_init(&vm_page_queue_free_lock, ETAP_VM_PAGEQ_FREE);
        !           370:        mutex_init(&vm_page_queue_lock, ETAP_VM_PAGEQ);
        !           371:        simple_lock_init(&vm_page_preppin_lock, ETAP_VM_PREPPIN);
        !           372: 
        !           373:        vm_page_queue_free = VM_PAGE_NULL;
        !           374:        vm_page_queue_fictitious = VM_PAGE_NULL;
        !           375:        queue_init(&vm_page_queue_active);
        !           376:        queue_init(&vm_page_queue_inactive);
        !           377:        queue_init(&vm_page_queue_limbo);
        !           378: 
        !           379:        vm_page_free_wanted = 0;
        !           380: 
        !           381:        /*
        !           382:         *      Steal memory for the map and zone subsystems.
        !           383:         */
        !           384: 
        !           385:        vm_map_steal_memory();
        !           386:        zone_steal_memory();
        !           387: 
        !           388:        /*
        !           389:         *      Allocate (and initialize) the virtual-to-physical
        !           390:         *      table hash buckets.
        !           391:         *
        !           392:         *      The number of buckets should be a power of two to
        !           393:         *      get a good hash function.  The following computation
        !           394:         *      chooses the first power of two that is greater
        !           395:         *      than the number of physical pages in the system.
        !           396:         */
        !           397: 
        !           398:        simple_lock_init(&vm_page_bucket_lock, ETAP_VM_BUCKET);
        !           399:        
        !           400:        if (vm_page_bucket_count == 0) {
        !           401:                unsigned int npages = pmap_free_pages();
        !           402: 
        !           403:                vm_page_bucket_count = 1;
        !           404:                while (vm_page_bucket_count < npages)
        !           405:                        vm_page_bucket_count <<= 1;
        !           406:        }
        !           407: 
        !           408:        vm_page_hash_mask = vm_page_bucket_count - 1;
        !           409: 
        !           410:        /*
        !           411:         *      Calculate object shift value for hashing algorithm:
        !           412:         *              O = log2(sizeof(struct vm_object))
        !           413:         *              B = log2(vm_page_bucket_count)
        !           414:         *              hash shifts the object left by
        !           415:         *              B/2 - O
        !           416:         */
        !           417:        size = vm_page_bucket_count;
        !           418:        for (log1 = 0; size > 1; log1++) 
        !           419:                size /= 2;
        !           420:        size = sizeof(struct vm_object);
        !           421:        for (log2 = 0; size > 1; log2++) 
        !           422:                size /= 2;
        !           423:        vm_page_hash_shift = log1/2 - log2 + 1;
        !           424: 
        !           425:        if (vm_page_hash_mask & vm_page_bucket_count)
        !           426:                printf("vm_page_bootstrap: WARNING -- strange page hash\n");
        !           427: 
        !           428:        vm_page_buckets = (vm_page_bucket_t *)
        !           429:                pmap_steal_memory(vm_page_bucket_count *
        !           430:                                  sizeof(vm_page_bucket_t));
        !           431: 
        !           432:        for (i = 0; i < vm_page_bucket_count; i++) {
        !           433:                register vm_page_bucket_t *bucket = &vm_page_buckets[i];
        !           434: 
        !           435:                bucket->pages = VM_PAGE_NULL;
        !           436: #if     MACH_PAGE_HASH_STATS
        !           437:                bucket->cur_count = 0;
        !           438:                bucket->hi_count = 0;
        !           439: #endif /* MACH_PAGE_HASH_STATS */
        !           440:        }
        !           441: 
        !           442:        /*
        !           443:         *      Machine-dependent code allocates the resident page table.
        !           444:         *      It uses vm_page_init to initialize the page frames.
        !           445:         *      The code also returns to us the virtual space available
        !           446:         *      to the kernel.  We don't trust the pmap module
        !           447:         *      to get the alignment right.
        !           448:         */
        !           449: 
        !           450:        pmap_startup(&virtual_space_start, &virtual_space_end);
        !           451:        virtual_space_start = round_page(virtual_space_start);
        !           452:        virtual_space_end = trunc_page(virtual_space_end);
        !           453: 
        !           454:        *startp = virtual_space_start;
        !           455:        *endp = virtual_space_end;
        !           456: 
        !           457:        /*
        !           458:         *      Compute the initial "wire" count.
        !           459:         *      Up until now, the pages which have been set aside are not under 
        !           460:         *      the VM system's control, so although they aren't explicitly
        !           461:         *      wired, they nonetheless can't be moved. At this moment,
        !           462:         *      all VM managed pages are "free", courtesy of pmap_startup.
        !           463:         */
        !           464:        vm_page_wire_count = atop(mem_size) - vm_page_free_count;       /* initial value */
        !           465: 
        !           466:        printf("vm_page_bootstrap: %d free pages\n", vm_page_free_count);
        !           467:        vm_page_free_count_minimum = vm_page_free_count;
        !           468: }
        !           469: 
        !           470: #ifndef        MACHINE_PAGES
        !           471: /*
        !           472:  *     We implement pmap_steal_memory and pmap_startup with the help
        !           473:  *     of two simpler functions, pmap_virtual_space and pmap_next_page.
        !           474:  */
        !           475: 
        !           476: vm_offset_t
        !           477: pmap_steal_memory(
        !           478:        vm_size_t size)
        !           479: {
        !           480:        vm_offset_t addr, vaddr, paddr;
        !           481: 
        !           482:        /*
        !           483:         *      We round the size to a round multiple.
        !           484:         */
        !           485: 
        !           486:        size = (size + sizeof (void *) - 1) &~ (sizeof (void *) - 1);
        !           487: 
        !           488:        /*
        !           489:         *      If this is the first call to pmap_steal_memory,
        !           490:         *      we have to initialize ourself.
        !           491:         */
        !           492: 
        !           493:        if (virtual_space_start == virtual_space_end) {
        !           494:                pmap_virtual_space(&virtual_space_start, &virtual_space_end);
        !           495: 
        !           496:                /*
        !           497:                 *      The initial values must be aligned properly, and
        !           498:                 *      we don't trust the pmap module to do it right.
        !           499:                 */
        !           500: 
        !           501:                virtual_space_start = round_page(virtual_space_start);
        !           502:                virtual_space_end = trunc_page(virtual_space_end);
        !           503:        }
        !           504: 
        !           505:        /*
        !           506:         *      Allocate virtual memory for this request.
        !           507:         */
        !           508: 
        !           509:        addr = virtual_space_start;
        !           510:        virtual_space_start += size;
        !           511: 
        !           512:        kprintf("pmap_steal_memory: %08X - %08X; size=%08X\n", addr, virtual_space_start, size);        /* (TEST/DEBUG) */
        !           513: 
        !           514:        /*
        !           515:         *      Allocate and map physical pages to back new virtual pages.
        !           516:         */
        !           517: 
        !           518:        for (vaddr = round_page(addr);
        !           519:             vaddr < addr + size;
        !           520:             vaddr += PAGE_SIZE) {
        !           521:                if (!pmap_next_page(&paddr))
        !           522:                        panic("pmap_steal_memory");
        !           523: 
        !           524:                /*
        !           525:                 *      XXX Logically, these mappings should be wired,
        !           526:                 *      but some pmap modules barf if they are.
        !           527:                 */
        !           528: 
        !           529:                pmap_enter(kernel_pmap, vaddr, paddr,
        !           530:                           VM_PROT_READ|VM_PROT_WRITE, FALSE);
        !           531:                /*
        !           532:                 * Account for newly stolen memory
        !           533:                 */
        !           534:                vm_page_wire_count++;
        !           535: 
        !           536:        }
        !           537: 
        !           538:        return addr;
        !           539: }
        !           540: 
        !           541: void
        !           542: pmap_startup(
        !           543:        vm_offset_t *startp,
        !           544:        vm_offset_t *endp)
        !           545: {
        !           546:        unsigned int i, npages, pages_initialized;
        !           547:        vm_page_t pages;
        !           548:        vm_offset_t paddr;
        !           549: 
        !           550:        /*
        !           551:         *      We calculate how many page frames we will have
        !           552:         *      and then allocate the page structures in one chunk.
        !           553:         */
        !           554: 
        !           555:        npages = ((PAGE_SIZE * pmap_free_pages() +
        !           556:                   (round_page(virtual_space_start) - virtual_space_start)) /
        !           557:                  (PAGE_SIZE + sizeof *pages));
        !           558: 
        !           559:        pages = (vm_page_t) pmap_steal_memory(npages * sizeof *pages);
        !           560: 
        !           561:        /*
        !           562:         *      Initialize the page frames.
        !           563:         */
        !           564: 
        !           565:        for (i = 0, pages_initialized = 0; i < npages; i++) {
        !           566:                if (!pmap_next_page(&paddr))
        !           567:                        break;
        !           568: 
        !           569:                vm_page_init(&pages[i], paddr);
        !           570:                vm_page_pages++;
        !           571:                pages_initialized++;
        !           572:        }
        !           573: 
        !           574:        /*
        !           575:         * Release pages in reverse order so that physical pages
        !           576:         * initially get allocated in ascending addresses. This keeps
        !           577:         * the devices (which must address physical memory) happy if
        !           578:         * they require several consecutive pages.
        !           579:         */
        !           580: 
        !           581:        for (i = pages_initialized; i > 0; i--) {
        !           582:                vm_page_release(&pages[i - 1]);
        !           583:        }
        !           584: 
        !           585:        /*
        !           586:         *      We have to re-align virtual_space_start,
        !           587:         *      because pmap_steal_memory has been using it.
        !           588:         */
        !           589: 
        !           590:        virtual_space_start = round_page(virtual_space_start);
        !           591: 
        !           592:        *startp = virtual_space_start;
        !           593:        *endp = virtual_space_end;
        !           594: }
        !           595: #endif /* MACHINE_PAGES */
        !           596: 
        !           597: /*
        !           598:  *     Routine:        vm_page_module_init
        !           599:  *     Purpose:
        !           600:  *             Second initialization pass, to be done after
        !           601:  *             the basic VM system is ready.
        !           602:  */
        !           603: void
        !           604: vm_page_module_init(void)
        !           605: {
        !           606:        vm_page_zone = zinit((vm_size_t) sizeof(struct vm_page),
        !           607:                             0, PAGE_SIZE, "vm pages");
        !           608: 
        !           609: #if    ZONE_DEBUG
        !           610:        zone_debug_disable(vm_page_zone);
        !           611: #endif /* ZONE_DEBUG */
        !           612: 
        !           613:        zone_change(vm_page_zone, Z_EXPAND, FALSE);
        !           614:        zone_change(vm_page_zone, Z_EXHAUST, TRUE);
        !           615:        zone_change(vm_page_zone, Z_FOREIGN, TRUE);
        !           616: 
        !           617:         /*
        !           618:          * Adjust zone statistics to account for the real pages allocated
        !           619:          * in vm_page_create(). [Q: is this really what we want?]
        !           620:          */
        !           621:         vm_page_zone->count += vm_page_pages;
        !           622:         vm_page_zone->cur_size += vm_page_pages * vm_page_zone->elem_size;
        !           623: 
        !           624:        mutex_init(&vm_page_alloc_lock, ETAP_VM_PAGE_ALLOC);
        !           625: }
        !           626: 
        !           627: /*
        !           628:  *     Routine:        vm_page_create
        !           629:  *     Purpose:
        !           630:  *             After the VM system is up, machine-dependent code
        !           631:  *             may stumble across more physical memory.  For example,
        !           632:  *             memory that it was reserving for a frame buffer.
        !           633:  *             vm_page_create turns this memory into available pages.
        !           634:  */
        !           635: 
        !           636: void
        !           637: vm_page_create(
        !           638:        vm_offset_t start,
        !           639:        vm_offset_t end)
        !           640: {
        !           641:        vm_offset_t paddr;
        !           642:        vm_page_t m;
        !           643: 
        !           644:        for (paddr = round_page(start);
        !           645:             paddr < trunc_page(end);
        !           646:             paddr += PAGE_SIZE) {
        !           647:                while ((m = (vm_page_t) vm_page_grab_fictitious())
        !           648:                        == VM_PAGE_NULL)
        !           649:                        vm_page_more_fictitious();
        !           650: 
        !           651:                vm_page_init(m, paddr);
        !           652:                vm_page_pages++;
        !           653:                vm_page_release(m);
        !           654:        }
        !           655: }
        !           656: 
        !           657: /*
        !           658:  *     vm_page_hash:
        !           659:  *
        !           660:  *     Distributes the object/offset key pair among hash buckets.
        !           661:  *
        !           662:  *     NOTE:   To get a good hash function, the bucket count should
        !           663:  *             be a power of two.
        !           664:  */
        !           665: #define vm_page_hash(object, offset) (\
        !           666:        ( ((natural_t)(vm_offset_t)object<<vm_page_hash_shift) + (natural_t)atop(offset))\
        !           667:         & vm_page_hash_mask)
        !           668: 
        !           669: /*
        !           670:  *     vm_page_insert:         [ internal use only ]
        !           671:  *
        !           672:  *     Inserts the given mem entry into the object/object-page
        !           673:  *     table and object list.
        !           674:  *
        !           675:  *     The object must be locked.
        !           676:  */
        !           677: 
        !           678: void
        !           679: vm_page_insert(
        !           680:        register vm_page_t      mem,
        !           681:        register vm_object_t    object,
        !           682:        register vm_offset_t    offset)
        !           683: {
        !           684:        register vm_page_bucket_t *bucket;
        !           685: 
        !           686:         XPR(XPR_VM_PAGE,
        !           687:                 "vm_page_insert, object 0x%X offset 0x%X page 0x%X\n",
        !           688:                 (integer_t)object, (integer_t)offset, (integer_t)mem, 0,0);
        !           689: 
        !           690:        VM_PAGE_CHECK(mem);
        !           691: 
        !           692:        if (mem->tabled)
        !           693:                panic("vm_page_insert");
        !           694: 
        !           695:        assert(!object->internal || offset < object->size);
        !           696: 
        !           697:        /* only insert "pageout" pages into "pageout" objects,
        !           698:         * and normal pages into normal objects */
        !           699:        assert(object->pageout == mem->pageout);
        !           700: 
        !           701:        /*
        !           702:         *      Record the object/offset pair in this page
        !           703:         */
        !           704: 
        !           705:        mem->object = object;
        !           706:        mem->offset = offset;
        !           707: 
        !           708:        /*
        !           709:         *      Insert it into the object_object/offset hash table
        !           710:         */
        !           711: 
        !           712:        bucket = &vm_page_buckets[vm_page_hash(object, offset)];
        !           713:        simple_lock(&vm_page_bucket_lock);
        !           714:        mem->next = bucket->pages;
        !           715:        bucket->pages = mem;
        !           716: #if     MACH_PAGE_HASH_STATS
        !           717:        if (++bucket->cur_count > bucket->hi_count)
        !           718:                bucket->hi_count = bucket->cur_count;
        !           719: #endif /* MACH_PAGE_HASH_STATS */
        !           720:        simple_unlock(&vm_page_bucket_lock);
        !           721: 
        !           722:        /*
        !           723:         *      Now link into the object's list of backed pages.
        !           724:         */
        !           725: 
        !           726:        queue_enter(&object->memq, mem, vm_page_t, listq);
        !           727:        mem->tabled = TRUE;
        !           728: 
        !           729:        /*
        !           730:         *      Show that the object has one more resident page.
        !           731:         */
        !           732: 
        !           733:        object->resident_page_count++;
        !           734: }
        !           735: 
        !           736: /*
        !           737:  *     vm_page_replace:
        !           738:  *
        !           739:  *     Exactly like vm_page_insert, except that we first
        !           740:  *     remove any existing page at the given offset in object.
        !           741:  *
        !           742:  *     The object and page queues must be locked.
        !           743:  */
        !           744: 
        !           745: void
        !           746: vm_page_replace(
        !           747:        register vm_page_t      mem,
        !           748:        register vm_object_t    object,
        !           749:        register vm_offset_t    offset)
        !           750: {
        !           751:        register vm_page_bucket_t *bucket;
        !           752: 
        !           753:        VM_PAGE_CHECK(mem);
        !           754: 
        !           755:        if (mem->tabled)
        !           756:                panic("vm_page_replace");
        !           757: 
        !           758:        /*
        !           759:         *      Record the object/offset pair in this page
        !           760:         */
        !           761: 
        !           762:        mem->object = object;
        !           763:        mem->offset = offset;
        !           764: 
        !           765:        /*
        !           766:         *      Insert it into the object_object/offset hash table,
        !           767:         *      replacing any page that might have been there.
        !           768:         */
        !           769: 
        !           770:        bucket = &vm_page_buckets[vm_page_hash(object, offset)];
        !           771:        simple_lock(&vm_page_bucket_lock);
        !           772:        if (bucket->pages) {
        !           773:                vm_page_t *mp = &bucket->pages;
        !           774:                register vm_page_t m = *mp;
        !           775:                do {
        !           776:                        if (m->object == object && m->offset == offset) {
        !           777:                                /*
        !           778:                                 * Remove page from bucket and from object,
        !           779:                                 * and return it to the free list.
        !           780:                                 */
        !           781:                                *mp = m->next;
        !           782:                                queue_remove(&object->memq, m, vm_page_t,
        !           783:                                             listq);
        !           784:                                m->tabled = FALSE;
        !           785:                                object->resident_page_count--;
        !           786: 
        !           787:                                /*
        !           788:                                 * Return page to the free list.
        !           789:                                 * Note the page is not tabled now, so this
        !           790:                                 * won't self-deadlock on the bucket lock.
        !           791:                                 */
        !           792: 
        !           793:                                vm_page_free(m);
        !           794:                                break;
        !           795:                        }
        !           796:                        mp = &m->next;
        !           797:                } while (m = *mp);
        !           798:                mem->next = bucket->pages;
        !           799:        } else {
        !           800:                mem->next = VM_PAGE_NULL;
        !           801:        }
        !           802:        bucket->pages = mem;
        !           803:        simple_unlock(&vm_page_bucket_lock);
        !           804: 
        !           805:        /*
        !           806:         *      Now link into the object's list of backed pages.
        !           807:         */
        !           808: 
        !           809:        queue_enter(&object->memq, mem, vm_page_t, listq);
        !           810:        mem->tabled = TRUE;
        !           811: 
        !           812:        /*
        !           813:         *      And show that the object has one more resident
        !           814:         *      page.
        !           815:         */
        !           816: 
        !           817:        object->resident_page_count++;
        !           818: }
        !           819: 
        !           820: /*
        !           821:  *     vm_page_remove:         [ internal use only ]
        !           822:  *
        !           823:  *     Removes the given mem entry from the object/offset-page
        !           824:  *     table and the object page list.
        !           825:  *
        !           826:  *     The object and page must be locked.
        !           827:  */
        !           828: 
        !           829: void
        !           830: vm_page_remove(
        !           831:        register vm_page_t      mem)
        !           832: {
        !           833:        register vm_page_bucket_t       *bucket;
        !           834:        register vm_page_t      this;
        !           835: 
        !           836:         XPR(XPR_VM_PAGE,
        !           837:                 "vm_page_remove, object 0x%X offset 0x%X page 0x%X\n",
        !           838:                 (integer_t)mem->object, (integer_t)mem->offset, 
        !           839:                (integer_t)mem, 0,0);
        !           840: 
        !           841:        assert(mem->tabled);
        !           842:        assert(!mem->cleaning);
        !           843:        VM_PAGE_CHECK(mem);
        !           844: 
        !           845:        /*
        !           846:         *      Remove from the object_object/offset hash table
        !           847:         */
        !           848: 
        !           849:        bucket = &vm_page_buckets[vm_page_hash(mem->object, mem->offset)];
        !           850:        simple_lock(&vm_page_bucket_lock);
        !           851:        if ((this = bucket->pages) == mem) {
        !           852:                /* optimize for common case */
        !           853: 
        !           854:                bucket->pages = mem->next;
        !           855:        } else {
        !           856:                register vm_page_t      *prev;
        !           857: 
        !           858:                for (prev = &this->next;
        !           859:                     (this = *prev) != mem;
        !           860:                     prev = &this->next)
        !           861:                        continue;
        !           862:                *prev = this->next;
        !           863:        }
        !           864: #if     MACH_PAGE_HASH_STATS
        !           865:        bucket->cur_count--;
        !           866: #endif /* MACH_PAGE_HASH_STATS */
        !           867:        simple_unlock(&vm_page_bucket_lock);
        !           868: 
        !           869:        /*
        !           870:         *      Now remove from the object's list of backed pages.
        !           871:         */
        !           872: 
        !           873:        queue_remove(&mem->object->memq, mem, vm_page_t, listq);
        !           874: 
        !           875:        /*
        !           876:         *      And show that the object has one fewer resident
        !           877:         *      page.
        !           878:         */
        !           879: 
        !           880:        mem->object->resident_page_count--;
        !           881: 
        !           882:        mem->tabled = FALSE;
        !           883:        mem->object = VM_OBJECT_NULL;
        !           884:        mem->offset = 0;
        !           885: }
        !           886: 
        !           887: /*
        !           888:  *     vm_page_lookup:
        !           889:  *
        !           890:  *     Returns the page associated with the object/offset
        !           891:  *     pair specified; if none is found, VM_PAGE_NULL is returned.
        !           892:  *
        !           893:  *     The object must be locked.  No side effects.
        !           894:  */
        !           895: 
        !           896: vm_page_t
        !           897: vm_page_lookup(
        !           898:        register vm_object_t    object,
        !           899:        register vm_offset_t    offset)
        !           900: {
        !           901:        register vm_page_t      mem;
        !           902:        register vm_page_bucket_t *bucket;
        !           903: 
        !           904:        /*
        !           905:         *      Search the hash table for this object/offset pair
        !           906:         */
        !           907: 
        !           908:        bucket = &vm_page_buckets[vm_page_hash(object, offset)];
        !           909: 
        !           910:        simple_lock(&vm_page_bucket_lock);
        !           911:        for (mem = bucket->pages; mem != VM_PAGE_NULL; mem = mem->next) {
        !           912:                VM_PAGE_CHECK(mem);
        !           913:                if ((mem->object == object) && (mem->offset == offset))
        !           914:                        break;
        !           915:        }
        !           916:        simple_unlock(&vm_page_bucket_lock);
        !           917:        return(mem);
        !           918: }
        !           919: 
        !           920: /*
        !           921:  *     vm_page_rename:
        !           922:  *
        !           923:  *     Move the given memory entry from its
        !           924:  *     current object to the specified target object/offset.
        !           925:  *
        !           926:  *     The object must be locked.
        !           927:  */
        !           928: void
        !           929: vm_page_rename(
        !           930:        register vm_page_t      mem,
        !           931:        register vm_object_t    new_object,
        !           932:        vm_offset_t             new_offset)
        !           933: {
        !           934:        assert(mem->object != new_object);
        !           935:        /*
        !           936:         *      Changes to mem->object require the page lock because
        !           937:         *      the pageout daemon uses that lock to get the object.
        !           938:         */
        !           939: 
        !           940:         XPR(XPR_VM_PAGE,
        !           941:                 "vm_page_rename, new object 0x%X, offset 0x%X page 0x%X\n",
        !           942:                 (integer_t)new_object, (integer_t)new_offset, 
        !           943:                (integer_t)mem, 0,0);
        !           944: 
        !           945:        vm_page_lock_queues();
        !           946:        vm_page_remove(mem);
        !           947:        vm_page_insert(mem, new_object, new_offset);
        !           948:        vm_page_unlock_queues();
        !           949: }
        !           950: 
        !           951: /*
        !           952:  *     vm_page_init:
        !           953:  *
        !           954:  *     Initialize the fields in a new page.
        !           955:  *     This takes a structure with random values and initializes it
        !           956:  *     so that it can be given to vm_page_release or vm_page_insert.
        !           957:  */
        !           958: void
        !           959: vm_page_init(
        !           960:        vm_page_t       mem,
        !           961:        vm_offset_t     phys_addr)
        !           962: {
        !           963:        *mem = vm_page_template;
        !           964:        mem->phys_addr = phys_addr;
        !           965: }
        !           966: 
        !           967: /*
        !           968:  *     vm_page_grab_fictitious:
        !           969:  *
        !           970:  *     Remove a fictitious page from the free list.
        !           971:  *     Returns VM_PAGE_NULL if there are no free pages.
        !           972:  */
        !           973: int    c_vm_page_grab_fictitious = 0;
        !           974: int    c_vm_page_release_fictitious = 0;
        !           975: int    c_vm_page_more_fictitious = 0;
        !           976: 
        !           977: vm_page_t
        !           978: vm_page_grab_fictitious(void)
        !           979: {
        !           980:        register vm_page_t m;
        !           981: 
        !           982:        m = (vm_page_t)zget(vm_page_zone);
        !           983:        if (m) {
        !           984:                m->free = FALSE;
        !           985: #if    MACH_ASSERT || ZONE_DEBUG
        !           986:                vm_page_init(m, vm_page_fictitious_addr);
        !           987:                m->fictitious = TRUE;
        !           988: #endif /* MACH_ASSERT || ZONE_DEBUG */
        !           989:        }
        !           990: 
        !           991:        c_vm_page_grab_fictitious++;
        !           992:        return m;
        !           993: }
        !           994: 
        !           995: /*
        !           996:  *     vm_page_release_fictitious:
        !           997:  *
        !           998:  *     Release a fictitious page to the free list.
        !           999:  */
        !          1000: 
        !          1001: void
        !          1002: vm_page_release_fictitious(
        !          1003:        register vm_page_t m)
        !          1004: {
        !          1005:        assert(!m->free);
        !          1006:        assert(m->busy);
        !          1007:        assert(m->fictitious);
        !          1008:        assert(m->phys_addr == vm_page_fictitious_addr);
        !          1009: 
        !          1010:        c_vm_page_release_fictitious++;
        !          1011: 
        !          1012:        if (m->free)
        !          1013:                panic("vm_page_release_fictitious");
        !          1014:        m->free = TRUE;
        !          1015:        zfree(vm_page_zone, (vm_offset_t)m);
        !          1016: }
        !          1017: 
        !          1018: /*
        !          1019:  *     vm_page_more_fictitious:
        !          1020:  *
        !          1021:  *     Add more fictitious pages to the free list.
        !          1022:  *     Allowed to block. This routine is way intimate
        !          1023:  *     with the zones code, for several reasons:
        !          1024:  *     1. we need to carve some page structures out of physical
        !          1025:  *        memory before zones work, so they _cannot_ come from
        !          1026:  *        the zone_map.
        !          1027:  *     2. the zone needs to be collectable in order to prevent
        !          1028:  *        growth without bound. These structures are used by
        !          1029:  *        the device pager (by the hundreds and thousands), as
        !          1030:  *        private pages for pageout, and as blocking pages for
        !          1031:  *        pagein. Temporary bursts in demand should not result in
        !          1032:  *        permanent allocation of a resource.
        !          1033:  *     3. To smooth allocation humps, we allocate single pages
        !          1034:  *        with kernel_memory_allocate(), and cram them into the
        !          1035:  *        zone. This also allows us to initialize the vm_page_t's
        !          1036:  *        on the way into the zone, so that zget() always returns
        !          1037:  *        an initialized structure. The zone free element pointer
        !          1038:  *        and the free page pointer are both the first item in the
        !          1039:  *        vm_page_t.
        !          1040:  *     4. By having the pages in the zone pre-initialized, we need
        !          1041:  *        not keep 2 levels of lists. The garbage collector simply
        !          1042:  *        scans our list, and reduces physical memory usage as it
        !          1043:  *        sees fit.
        !          1044:  */
        !          1045: 
        !          1046: void vm_page_more_fictitious(void)
        !          1047: {
        !          1048:        extern vm_map_t zone_map;
        !          1049:        register vm_page_t m;
        !          1050:        vm_offset_t addr;
        !          1051:        kern_return_t retval;
        !          1052:        int i;
        !          1053: 
        !          1054:        c_vm_page_more_fictitious++;
        !          1055: 
        !          1056:        /* this may free up some fictitious pages */
        !          1057:        cleanup_limbo_queue();
        !          1058: 
        !          1059:        /*
        !          1060:         * Allocate a single page from the zone_map. Do not wait if no physical
        !          1061:         * pages are immediately available, and do not zero the space. We need
        !          1062:         * our own blocking lock here to prevent having multiple,
        !          1063:         * simultaneous requests from piling up on the zone_map lock. Exactly
        !          1064:         * one (of our) threads should be potentially waiting on the map lock.
        !          1065:         * If winner is not vm-privileged, then the page allocation will fail,
        !          1066:         * and it will temporarily block here in the vm_page_wait().
        !          1067:         */
        !          1068:        mutex_lock(&vm_page_alloc_lock);
        !          1069:        /*
        !          1070:         * If another thread allocated space, just bail out now.
        !          1071:         */
        !          1072:        if (zone_free_count(vm_page_zone) > 5) {
        !          1073:                /*
        !          1074:                 * The number "5" is a small number that is larger than the
        !          1075:                 * number of fictitious pages that any single caller will
        !          1076:                 * attempt to allocate. Otherwise, a thread will attempt to
        !          1077:                 * acquire a fictitious page (vm_page_grab_fictitious), fail,
        !          1078:                 * release all of the resources and locks already acquired,
        !          1079:                 * and then call this routine. This routine finds the pages
        !          1080:                 * that the caller released, so fails to allocate new space.
        !          1081:                 * The process repeats infinitely. The largest known number
        !          1082:                 * of fictitious pages required in this manner is 2. 5 is
        !          1083:                 * simply a somewhat larger number.
        !          1084:                 */
        !          1085:                mutex_unlock(&vm_page_alloc_lock);
        !          1086:                return;
        !          1087:        }
        !          1088: 
        !          1089:        if ((retval = kernel_memory_allocate(zone_map,
        !          1090:                        &addr, PAGE_SIZE, VM_PROT_ALL,
        !          1091:                        KMA_KOBJECT|KMA_NOPAGEWAIT)) != KERN_SUCCESS) { 
        !          1092:                /*
        !          1093:                 * No page was available. Tell the pageout daemon, drop the
        !          1094:                 * lock to give another thread a chance at it, and
        !          1095:                 * wait for the pageout daemon to make progress.
        !          1096:                 */
        !          1097:                mutex_unlock(&vm_page_alloc_lock);
        !          1098:                vm_page_wait();
        !          1099:                return;
        !          1100:        }
        !          1101:        /*
        !          1102:         * Initialize as many vm_page_t's as will fit on this page. This
        !          1103:         * depends on the zone code disturbing ONLY the first item of
        !          1104:         * each zone element.
        !          1105:         */
        !          1106:        m = (vm_page_t)addr;
        !          1107:        for (i = PAGE_SIZE/sizeof(struct vm_page); i > 0; i--) {
        !          1108:                vm_page_init(m, vm_page_fictitious_addr);
        !          1109:                m->fictitious = TRUE;
        !          1110:                m++;
        !          1111:        }
        !          1112:        zcram(vm_page_zone, addr, PAGE_SIZE);
        !          1113:        mutex_unlock(&vm_page_alloc_lock);
        !          1114: }
        !          1115: 
        !          1116: /*
        !          1117:  *     vm_page_convert:
        !          1118:  *
        !          1119:  *     Attempt to convert a fictitious page into a real page.
        !          1120:  */
        !          1121: 
        !          1122: boolean_t
        !          1123: vm_page_convert(
        !          1124:        register vm_page_t m)
        !          1125: {
        !          1126:        register vm_page_t real_m;
        !          1127: 
        !          1128:        assert(m->busy);
        !          1129:        assert(m->fictitious);
        !          1130:        assert(!m->dirty);
        !          1131: 
        !          1132:        real_m = vm_page_grab();
        !          1133:        if (real_m == VM_PAGE_NULL)
        !          1134:                return FALSE;
        !          1135: 
        !          1136:        m->phys_addr = real_m->phys_addr;
        !          1137:        m->fictitious = FALSE;
        !          1138: 
        !          1139:        vm_page_lock_queues();
        !          1140:        if (m->active)
        !          1141:                vm_page_active_count++;
        !          1142:        else if (m->inactive)
        !          1143:                vm_page_inactive_count++;
        !          1144:        vm_page_unlock_queues();
        !          1145: 
        !          1146:        real_m->phys_addr = vm_page_fictitious_addr;
        !          1147:        real_m->fictitious = TRUE;
        !          1148: 
        !          1149:        vm_page_release_fictitious(real_m);
        !          1150:        return TRUE;
        !          1151: }
        !          1152: 
        !          1153: /*
        !          1154:  *     vm_pool_low():
        !          1155:  *
        !          1156:  *     Return true if it is not likely that a non-vm_privileged thread
        !          1157:  *     can get memory without blocking.  Advisory only, since the
        !          1158:  *     situation may change under us.
        !          1159:  */
        !          1160: int
        !          1161: vm_pool_low(void)
        !          1162: {
        !          1163:        /* No locking, at worst we will fib. */
        !          1164:        return( vm_page_free_count < vm_page_free_reserved );
        !          1165: }
        !          1166: 
        !          1167: /*
        !          1168:  *     vm_page_grab:
        !          1169:  *
        !          1170:  *     Remove a page from the free list.
        !          1171:  *     Returns VM_PAGE_NULL if the free list is too small.
        !          1172:  */
        !          1173: 
        !          1174: unsigned long  vm_page_grab_count = 0; /* measure demand */
        !          1175: 
        !          1176: vm_page_t
        !          1177: vm_page_grab(void)
        !          1178: {
        !          1179:        register vm_page_t      mem;
        !          1180: 
        !          1181:        mutex_lock(&vm_page_queue_free_lock);
        !          1182:        vm_page_grab_count++;
        !          1183: 
        !          1184:        /*
        !          1185:         *      Optionally produce warnings if the wire or gobble
        !          1186:         *      counts exceed some threshold.
        !          1187:         */
        !          1188:        if (vm_page_wire_count_warning > 0
        !          1189:            && vm_page_wire_count >= vm_page_wire_count_warning) {
        !          1190:                printf("mk: vm_page_grab(): high wired page count of %d\n",
        !          1191:                        vm_page_wire_count);
        !          1192:                assert(vm_page_wire_count < vm_page_wire_count_warning);
        !          1193:        }
        !          1194:        if (vm_page_gobble_count_warning > 0
        !          1195:            && vm_page_gobble_count >= vm_page_gobble_count_warning) {
        !          1196:                printf("mk: vm_page_grab(): high gobbled page count of %d\n",
        !          1197:                        vm_page_gobble_count);
        !          1198:                assert(vm_page_gobble_count < vm_page_gobble_count_warning);
        !          1199:        }
        !          1200: 
        !          1201:        /*
        !          1202:         *      Only let privileged threads (involved in pageout)
        !          1203:         *      dip into the reserved pool.
        !          1204:         */
        !          1205: 
        !          1206:        if ((vm_page_free_count < vm_page_free_reserved) &&
        !          1207:            !current_thread()->vm_privilege) {
        !          1208:                mutex_unlock(&vm_page_queue_free_lock);
        !          1209:                mem = VM_PAGE_NULL;
        !          1210:                goto wakeup_pageout;
        !          1211:        }
        !          1212: 
        !          1213:        while (vm_page_queue_free == VM_PAGE_NULL) {
        !          1214:                printf("vm_page_grab: no free pages, trouble expected...\n");
        !          1215:                mutex_unlock(&vm_page_queue_free_lock);
        !          1216:                VM_PAGE_WAIT();
        !          1217:                mutex_lock(&vm_page_queue_free_lock);
        !          1218:        }
        !          1219: 
        !          1220:        if (--vm_page_free_count < vm_page_free_count_minimum)
        !          1221:                vm_page_free_count_minimum = vm_page_free_count;
        !          1222:        mem = vm_page_queue_free;
        !          1223:        vm_page_queue_free = (vm_page_t) mem->pageq.next;
        !          1224:        mem->free = FALSE;
        !          1225:        mutex_unlock(&vm_page_queue_free_lock);
        !          1226: 
        !          1227:        /*
        !          1228:         *      Decide if we should poke the pageout daemon.
        !          1229:         *      We do this if the free count is less than the low
        !          1230:         *      water mark, or if the free count is less than the high
        !          1231:         *      water mark (but above the low water mark) and the inactive
        !          1232:         *      count is less than its target.
        !          1233:         *
        !          1234:         *      We don't have the counts locked ... if they change a little,
        !          1235:         *      it doesn't really matter.
        !          1236:         */
        !          1237: 
        !          1238: wakeup_pageout:
        !          1239:        if ((vm_page_free_count < vm_page_free_min) ||
        !          1240:            ((vm_page_free_count < vm_page_free_target) &&
        !          1241:             (vm_page_inactive_count < vm_page_inactive_target)))
        !          1242:                thread_wakeup((event_t) &vm_page_free_wanted);
        !          1243: 
        !          1244: //     dbgLog(mem->phys_addr, vm_page_free_count, vm_page_wire_count, 4);      /* (TEST/DEBUG) */
        !          1245: 
        !          1246:        return mem;
        !          1247: }
        !          1248: 
        !          1249: /*
        !          1250:  *     vm_page_release:
        !          1251:  *
        !          1252:  *     Return a page to the free list.
        !          1253:  */
        !          1254: 
        !          1255: void
        !          1256: vm_page_release(
        !          1257:        register vm_page_t      mem)
        !          1258: {
        !          1259:        assert(!mem->private && !mem->fictitious);
        !          1260: 
        !          1261: //     dbgLog(mem->phys_addr, vm_page_free_count, vm_page_wire_count, 5);      /* (TEST/DEBUG) */
        !          1262: 
        !          1263:        mutex_lock(&vm_page_queue_free_lock);
        !          1264:        if (mem->free)
        !          1265:                panic("vm_page_release");
        !          1266:        mem->free = TRUE;
        !          1267:        mem->pageq.next = (queue_entry_t) vm_page_queue_free;
        !          1268:        vm_page_queue_free = mem;
        !          1269:        vm_page_free_count++;
        !          1270: 
        !          1271:        /*
        !          1272:         *      Check if we should wake up someone waiting for page.
        !          1273:         *      But don't bother waking them unless they can allocate.
        !          1274:         *
        !          1275:         *      We wakeup only one thread, to prevent starvation.
        !          1276:         *      Because the scheduling system handles wait queues FIFO,
        !          1277:         *      if we wakeup all waiting threads, one greedy thread
        !          1278:         *      can starve multiple niceguy threads.  When the threads
        !          1279:         *      all wakeup, the greedy threads runs first, grabs the page,
        !          1280:         *      and waits for another page.  It will be the first to run
        !          1281:         *      when the next page is freed.
        !          1282:         *
        !          1283:         *      However, there is a slight danger here.
        !          1284:         *      The thread we wake might not use the free page.
        !          1285:         *      Then the other threads could wait indefinitely
        !          1286:         *      while the page goes unused.  To forestall this,
        !          1287:         *      the pageout daemon will keep making free pages
        !          1288:         *      as long as vm_page_free_wanted is non-zero.
        !          1289:         */
        !          1290: 
        !          1291:        if ((vm_page_free_wanted > 0) &&
        !          1292:            (vm_page_free_count >= vm_page_free_reserved)) {
        !          1293:                vm_page_free_wanted--;
        !          1294:                thread_wakeup_one((event_t) &vm_page_free_count);
        !          1295:        }
        !          1296: 
        !          1297:        mutex_unlock(&vm_page_queue_free_lock);
        !          1298: }
        !          1299: 
        !          1300: /*
        !          1301:  * Release a page to the limbo list.
        !          1302:  * Put real pages at the head of the queue, fictitious at the tail.
        !          1303:  * Page queues must be locked.
        !          1304:  */
        !          1305: void
        !          1306: vm_page_release_limbo(
        !          1307:        register vm_page_t      m)
        !          1308: {
        !          1309:        assert(m->limbo);
        !          1310:        vm_page_limbo_count++;
        !          1311:        if (m->fictitious) {
        !          1312:                queue_enter(&vm_page_queue_limbo, m, vm_page_t, pageq);
        !          1313:        } else {
        !          1314:                vm_page_limbo_real_count++;
        !          1315:                queue_enter_first(&vm_page_queue_limbo, m, vm_page_t, pageq);
        !          1316:        }
        !          1317: }
        !          1318: 
        !          1319: /*
        !          1320:  * Exchange a real page in limbo (limbo_m) with a fictitious page (new_m).
        !          1321:  * The end result is that limbo_m is fictitious and still in limbo, and new_m
        !          1322:  * is the real page.  The prep and pin counts remain with the page in limbo
        !          1323:  * although they will be briefly cleared by vm_page_init.  This is OK since
        !          1324:  * there will be no interrupt-level interactions (the page is in limbo) and
        !          1325:  * vm_page_unprep must lock the page queues before changing the prep count.
        !          1326:  *
        !          1327:  * Page queues must be locked, and limbo_m must have been removed from its
        !          1328:  * object.
        !          1329:  */
        !          1330: void
        !          1331: vm_page_limbo_exchange(
        !          1332:        register vm_page_t      limbo_m,
        !          1333:        register vm_page_t      new_m)
        !          1334: {
        !          1335:        assert(limbo_m->limbo && !limbo_m->fictitious);
        !          1336:        assert(!limbo_m->tabled);
        !          1337:        assert(new_m->fictitious);
        !          1338: 
        !          1339:        *new_m = *limbo_m;
        !          1340:        vm_page_init(limbo_m, vm_page_fictitious_addr);
        !          1341: 
        !          1342:        limbo_m->fictitious = TRUE;
        !          1343:        limbo_m->limbo = TRUE;
        !          1344:        new_m->limbo = FALSE;
        !          1345: 
        !          1346:        limbo_m->prep_pin_count = new_m->prep_pin_count;
        !          1347:        new_m->prep_pin_count = 0;
        !          1348: }
        !          1349: 
        !          1350: /*
        !          1351:  *     vm_page_wait:
        !          1352:  *
        !          1353:  *     Wait for a page to become available.
        !          1354:  *     If there are plenty of free pages, then we don't sleep.
        !          1355:  */
        !          1356: 
        !          1357: void
        !          1358: vm_page_wait( void )
        !          1359: {
        !          1360:        /*
        !          1361:         *      We can't use vm_page_free_reserved to make this
        !          1362:         *      determination.  Consider: some thread might
        !          1363:         *      need to allocate two pages.  The first allocation
        !          1364:         *      succeeds, the second fails.  After the first page is freed,
        !          1365:         *      a call to vm_page_wait must really block.
        !          1366:         */
        !          1367: 
        !          1368:        mutex_lock(&vm_page_queue_free_lock);
        !          1369:        if (vm_page_free_count < vm_page_free_target) {
        !          1370:                if (vm_page_free_wanted++ == 0)
        !          1371:                        thread_wakeup((event_t)&vm_page_free_wanted);
        !          1372:                assert_wait((event_t)&vm_page_free_count, THREAD_UNINT);
        !          1373:                mutex_unlock(&vm_page_queue_free_lock);
        !          1374:                counter(c_vm_page_wait_block++);
        !          1375:                thread_block((void (*)(void))0);
        !          1376:        } else
        !          1377:                mutex_unlock(&vm_page_queue_free_lock);
        !          1378: }
        !          1379: 
        !          1380: /*
        !          1381:  *     vm_page_alloc:
        !          1382:  *
        !          1383:  *     Allocate and return a memory cell associated
        !          1384:  *     with this VM object/offset pair.
        !          1385:  *
        !          1386:  *     Object must be locked.
        !          1387:  */
        !          1388: 
        !          1389: vm_page_t
        !          1390: vm_page_alloc(
        !          1391:        vm_object_t     object,
        !          1392:        vm_offset_t     offset)
        !          1393: {
        !          1394:        register vm_page_t      mem;
        !          1395: 
        !          1396:        mem = vm_page_grab();
        !          1397:        if (mem == VM_PAGE_NULL)
        !          1398:                return VM_PAGE_NULL;
        !          1399: 
        !          1400:        vm_page_insert(mem, object, offset);
        !          1401: 
        !          1402:        return(mem);
        !          1403: }
        !          1404: 
        !          1405: int c_limbo_page_free = 0;     /* debugging */
        !          1406: int c_limbo_convert = 0;       /* debugging */
        !          1407: counter(unsigned int c_laundry_pages_freed = 0;)
        !          1408: 
        !          1409: int vm_pagein_cluster_unused = 0;
        !          1410: boolean_t      vm_page_free_verify = FALSE;
        !          1411: /*
        !          1412:  *     vm_page_free:
        !          1413:  *
        !          1414:  *     Returns the given page to the free list,
        !          1415:  *     disassociating it with any VM object.
        !          1416:  *
        !          1417:  *     Object and page queues must be locked prior to entry.
        !          1418:  */
        !          1419: void
        !          1420: vm_page_free(
        !          1421:        register vm_page_t      mem)
        !          1422: {
        !          1423:        vm_object_t     object = mem->object;
        !          1424: 
        !          1425:        assert(!mem->free);
        !          1426:        assert(!mem->cleaning);
        !          1427:        assert(!mem->pageout);
        !          1428:        assert(!vm_page_free_verify || pmap_verify_free(mem->phys_addr));
        !          1429: 
        !          1430:        if (mem->tabled)
        !          1431:                vm_page_remove(mem);    /* clears tabled, object, offset */
        !          1432:        VM_PAGE_QUEUES_REMOVE(mem);     /* clears active or inactive */
        !          1433: 
        !          1434:        if (mem->clustered) {
        !          1435:                mem->clustered = FALSE;
        !          1436:                vm_pagein_cluster_unused++;
        !          1437:        }
        !          1438: 
        !          1439:        if (mem->wire_count) {
        !          1440:                if (!mem->private && !mem->fictitious)
        !          1441:                        vm_page_wire_count--;
        !          1442:                mem->wire_count = 0;
        !          1443:                assert(!mem->gobbled);
        !          1444:        } else if (mem->gobbled) {
        !          1445:                if (!mem->private && !mem->fictitious)
        !          1446:                        vm_page_wire_count--;
        !          1447:                vm_page_gobble_count--;
        !          1448:        }
        !          1449:        mem->gobbled = FALSE;
        !          1450: 
        !          1451:        if (mem->laundry) {
        !          1452:                extern int vm_page_laundry_min;
        !          1453:                vm_page_laundry_count--;
        !          1454:                mem->laundry = FALSE;   /* laundry is now clear */
        !          1455:                counter(++c_laundry_pages_freed);
        !          1456:                if (vm_page_laundry_count < vm_page_laundry_min) {
        !          1457:                        vm_page_laundry_min = 0;
        !          1458:                        thread_wakeup((event_t) &vm_page_laundry_count);
        !          1459:                }
        !          1460:        }
        !          1461: 
        !          1462:        mem->discard_request = FALSE;
        !          1463: 
        !          1464:        PAGE_WAKEUP(mem);       /* clears wanted */
        !          1465: 
        !          1466:        if (mem->absent)
        !          1467:                vm_object_absent_release(object);
        !          1468: 
        !          1469:        if (mem->limbo) {
        !          1470:                /*
        !          1471:                 * The pageout daemon put this page into limbo and then freed
        !          1472:                 * it.  The page has already been removed from the object and
        !          1473:                 * queues, so any attempt to look it up will fail.  Put it
        !          1474:                 * on the limbo queue; the pageout daemon will convert it to a
        !          1475:                 * fictitious page and/or free the real one later.
        !          1476:                 */
        !          1477:                /* assert that it came from pageout daemon (how?) */
        !          1478:                assert(!mem->fictitious && !mem->absent);
        !          1479:                c_limbo_page_free++;
        !          1480:                vm_page_release_limbo(mem);
        !          1481:                return;
        !          1482:        }
        !          1483:        assert(mem->prep_pin_count == 0);
        !          1484: 
        !          1485:                /* Some of these may be unnecessary */
        !          1486:        mem->page_lock = 0;
        !          1487:        mem->unlock_request = 0;
        !          1488:        mem->busy = TRUE;
        !          1489:        mem->absent = FALSE;
        !          1490:        mem->error = FALSE;
        !          1491:        mem->dirty = FALSE;
        !          1492:        mem->precious = FALSE;
        !          1493:        mem->reference = FALSE;
        !          1494: 
        !          1495:        mem->page_error = KERN_SUCCESS;
        !          1496: 
        !          1497:        if (mem->private) {
        !          1498:                mem->private = FALSE;
        !          1499:                mem->fictitious = TRUE;
        !          1500:                mem->phys_addr = vm_page_fictitious_addr;
        !          1501:        }
        !          1502:        if (mem->fictitious) {
        !          1503:                vm_page_release_fictitious(mem);
        !          1504:        } else {
        !          1505:                vm_page_init(mem, mem->phys_addr);
        !          1506:                vm_page_release(mem);
        !          1507:        }
        !          1508: }
        !          1509: 
        !          1510: /*
        !          1511:  *     vm_page_wire:
        !          1512:  *
        !          1513:  *     Mark this page as wired down by yet
        !          1514:  *     another map, removing it from paging queues
        !          1515:  *     as necessary.
        !          1516:  *
        !          1517:  *     The page's object and the page queues must be locked.
        !          1518:  */
        !          1519: void
        !          1520: vm_page_wire(
        !          1521:        register vm_page_t      mem)
        !          1522: {
        !          1523: 
        !          1524: //     dbgLog(current_act(), mem->offset, mem->object, 1);     /* (TEST/DEBUG) */
        !          1525: 
        !          1526:        VM_PAGE_CHECK(mem);
        !          1527: 
        !          1528:        if (mem->wire_count == 0) {
        !          1529:                VM_PAGE_QUEUES_REMOVE(mem);
        !          1530:                if (!mem->private && !mem->fictitious && !mem->gobbled)
        !          1531:                        vm_page_wire_count++;
        !          1532:                if (mem->gobbled)
        !          1533:                        vm_page_gobble_count--;
        !          1534:                mem->gobbled = FALSE;
        !          1535:        }
        !          1536:        assert(!mem->gobbled);
        !          1537:        mem->wire_count++;
        !          1538: }
        !          1539: 
        !          1540: /*
        !          1541:  *      vm_page_gobble:
        !          1542:  *
        !          1543:  *      Mark this page as consumed by the vm/ipc/xmm subsystems.
        !          1544:  *
        !          1545:  *      Called only for freshly vm_page_grab()ed pages - w/ nothing locked.
        !          1546:  */
        !          1547: void
        !          1548: vm_page_gobble(
        !          1549:         register vm_page_t      mem)
        !          1550: {
        !          1551:         vm_page_lock_queues();
        !          1552:         VM_PAGE_CHECK(mem);
        !          1553: 
        !          1554:        assert(!mem->gobbled);
        !          1555:        assert(mem->wire_count == 0);
        !          1556: 
        !          1557:         if (!mem->gobbled && mem->wire_count == 0) {
        !          1558:                 if (!mem->private && !mem->fictitious)
        !          1559:                         vm_page_wire_count++;
        !          1560:         }
        !          1561:        vm_page_gobble_count++;
        !          1562:         mem->gobbled = TRUE;
        !          1563:         vm_page_unlock_queues();
        !          1564: }
        !          1565: 
        !          1566: /*
        !          1567:  *     vm_page_unwire:
        !          1568:  *
        !          1569:  *     Release one wiring of this page, potentially
        !          1570:  *     enabling it to be paged again.
        !          1571:  *
        !          1572:  *     The page's object and the page queues must be locked.
        !          1573:  */
        !          1574: void
        !          1575: vm_page_unwire(
        !          1576:        register vm_page_t      mem)
        !          1577: {
        !          1578: 
        !          1579: //     dbgLog(current_act(), mem->offset, mem->object, 0);     /* (TEST/DEBUG) */
        !          1580: 
        !          1581:        VM_PAGE_CHECK(mem);
        !          1582:        assert(mem->wire_count > 0);
        !          1583: 
        !          1584:        if (--mem->wire_count == 0) {
        !          1585:                assert(!mem->private && !mem->fictitious);
        !          1586:                vm_page_wire_count--;
        !          1587:                queue_enter(&vm_page_queue_active, mem, vm_page_t, pageq);
        !          1588:                vm_page_active_count++;
        !          1589:                mem->active = TRUE;
        !          1590:                mem->reference = TRUE;
        !          1591:        }
        !          1592: }
        !          1593: 
        !          1594: /*
        !          1595:  *     vm_page_deactivate:
        !          1596:  *
        !          1597:  *     Returns the given page to the inactive list,
        !          1598:  *     indicating that no physical maps have access
        !          1599:  *     to this page.  [Used by the physical mapping system.]
        !          1600:  *
        !          1601:  *     The page queues must be locked.
        !          1602:  */
        !          1603: void
        !          1604: vm_page_deactivate(
        !          1605:        register vm_page_t      m)
        !          1606: {
        !          1607:        VM_PAGE_CHECK(m);
        !          1608: 
        !          1609: //     dbgLog(m->phys_addr, vm_page_free_count, vm_page_wire_count, 6);        /* (TEST/DEBUG) */
        !          1610: 
        !          1611:        /*
        !          1612:         *      This page is no longer very interesting.  If it was
        !          1613:         *      interesting (active or inactive/referenced), then we
        !          1614:         *      clear the reference bit and (re)enter it in the
        !          1615:         *      inactive queue.  Note wired pages should not have
        !          1616:         *      their reference bit cleared.
        !          1617:         */
        !          1618:        if (m->gobbled) {               /* can this happen? */
        !          1619:                assert(m->wire_count == 0);
        !          1620:                if (!m->private && !m->fictitious)
        !          1621:                        vm_page_wire_count--;
        !          1622:                vm_page_gobble_count--;
        !          1623:                m->gobbled = FALSE;
        !          1624:        }
        !          1625:        if (m->private || (m->wire_count != 0))
        !          1626:                return;
        !          1627:        if (m->active || (m->inactive && m->reference)) {
        !          1628:                if (!m->fictitious && !m->absent)
        !          1629:                        pmap_clear_reference(m->phys_addr);
        !          1630:                m->reference = FALSE;
        !          1631:                VM_PAGE_QUEUES_REMOVE(m);
        !          1632:        }
        !          1633:        if (m->wire_count == 0 && !m->inactive) {
        !          1634:                queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq);
        !          1635:                m->inactive = TRUE;
        !          1636:                if (!m->fictitious)
        !          1637:                        vm_page_inactive_count++;
        !          1638:        }
        !          1639: }
        !          1640: 
        !          1641: /*
        !          1642:  *     vm_page_activate:
        !          1643:  *
        !          1644:  *     Put the specified page on the active list (if appropriate).
        !          1645:  *
        !          1646:  *     The page queues must be locked.
        !          1647:  */
        !          1648: 
        !          1649: void
        !          1650: vm_page_activate(
        !          1651:        register vm_page_t      m)
        !          1652: {
        !          1653:        VM_PAGE_CHECK(m);
        !          1654: 
        !          1655:        if (m->gobbled) {
        !          1656:                assert(m->wire_count == 0);
        !          1657:                if (!m->private && !m->fictitious)
        !          1658:                        vm_page_wire_count--;
        !          1659:                vm_page_gobble_count--;
        !          1660:                m->gobbled = FALSE;
        !          1661:        }
        !          1662:        if (m->private)
        !          1663:                return;
        !          1664: 
        !          1665:        if (m->inactive) {
        !          1666:                queue_remove(&vm_page_queue_inactive, m, vm_page_t, pageq);
        !          1667:                if (!m->fictitious)
        !          1668:                        vm_page_inactive_count--;
        !          1669:                m->inactive = FALSE;
        !          1670:        }
        !          1671:        if (m->wire_count == 0) {
        !          1672:                if (m->active)
        !          1673:                        panic("vm_page_activate: already active");
        !          1674: 
        !          1675:                queue_enter(&vm_page_queue_active, m, vm_page_t, pageq);
        !          1676:                m->active = TRUE;
        !          1677:                m->reference = TRUE;
        !          1678:                if (!m->fictitious)
        !          1679:                        vm_page_active_count++;
        !          1680:        }
        !          1681: }
        !          1682: 
        !          1683: /*
        !          1684:  *     vm_page_part_zero_fill:
        !          1685:  *
        !          1686:  *     Zero-fill a part of the page.
        !          1687:  */
        !          1688: void
        !          1689: vm_page_part_zero_fill(
        !          1690:        vm_page_t       m,
        !          1691:        vm_offset_t     m_pa,
        !          1692:        vm_size_t       len)
        !          1693: {
        !          1694:        VM_PAGE_CHECK(m);
        !          1695: 
        !          1696:        pmap_zero_part_page(m->phys_addr, m_pa, len);
        !          1697: }
        !          1698: 
        !          1699: /*
        !          1700:  *     vm_page_zero_fill:
        !          1701:  *
        !          1702:  *     Zero-fill the specified page.
        !          1703:  */
        !          1704: void
        !          1705: vm_page_zero_fill(
        !          1706:        vm_page_t       m)
        !          1707: {
        !          1708:         XPR(XPR_VM_PAGE,
        !          1709:                 "vm_page_zero_fill, object 0x%X offset 0x%X page 0x%X\n",
        !          1710:                 (integer_t)m->object, (integer_t)m->offset, (integer_t)m, 0,0);
        !          1711: 
        !          1712:        VM_PAGE_CHECK(m);
        !          1713: 
        !          1714:        pmap_zero_page(m->phys_addr);
        !          1715: }
        !          1716: 
        !          1717: /*
        !          1718:  *     vm_page_part_copy:
        !          1719:  *
        !          1720:  *     copy part of one page to another
        !          1721:  */
        !          1722: 
        !          1723: void
        !          1724: vm_page_part_copy(
        !          1725:        vm_page_t       src_m,
        !          1726:        vm_offset_t     src_pa,
        !          1727:        vm_page_t       dst_m,
        !          1728:        vm_offset_t     dst_pa,
        !          1729:        vm_size_t       len)
        !          1730: {
        !          1731:        VM_PAGE_CHECK(src_m);
        !          1732:        VM_PAGE_CHECK(dst_m);
        !          1733: 
        !          1734:        pmap_copy_part_page(src_m->phys_addr, src_pa,
        !          1735:                        dst_m->phys_addr, dst_pa, len);
        !          1736: }
        !          1737: 
        !          1738: /*
        !          1739:  *     vm_page_copy:
        !          1740:  *
        !          1741:  *     Copy one page to another
        !          1742:  */
        !          1743: 
        !          1744: void
        !          1745: vm_page_copy(
        !          1746:        vm_page_t       src_m,
        !          1747:        vm_page_t       dest_m)
        !          1748: {
        !          1749:         XPR(XPR_VM_PAGE,
        !          1750:         "vm_page_copy, object 0x%X offset 0x%X to object 0x%X offset 0x%X\n",
        !          1751:         (integer_t)src_m->object, src_m->offset, 
        !          1752:        (integer_t)dest_m->object, dest_m->offset,
        !          1753:        0);
        !          1754: 
        !          1755:        VM_PAGE_CHECK(src_m);
        !          1756:        VM_PAGE_CHECK(dest_m);
        !          1757: 
        !          1758:        pmap_copy_page(src_m->phys_addr, dest_m->phys_addr);
        !          1759: }
        !          1760: 
        !          1761: /*
        !          1762:  * Limbo pages are placed on the limbo queue to await their prep count
        !          1763:  * going to zero.  A page is put into limbo by the pageout daemon.  If the
        !          1764:  * page is real, then the pageout daemon did not need to page out the page,
        !          1765:  * it just freed it.  When the prep_pin_count is zero the page can be freed.
        !          1766:  * Real pages with a non-zero prep count are converted to fictitious pages
        !          1767:  * so that the memory can be reclaimed; the fictitious page will remain on
        !          1768:  * the limbo queue until its prep count reaches zero.
        !          1769:  *
        !          1770:  * cleanup_limbo_queue is called by vm_page_more_fictitious and the pageout
        !          1771:  * daemon since it can free both real and fictitious pages.
        !          1772:  * It returns the number of fictitious pages freed.
        !          1773:  */
        !          1774: void
        !          1775: cleanup_limbo_queue(void)
        !          1776: {
        !          1777:        register vm_page_t free_m, m;
        !          1778:        vm_offset_t phys_addr;
        !          1779: 
        !          1780:        vm_page_lock_queues();
        !          1781:        assert(vm_page_limbo_count >= vm_page_limbo_real_count);
        !          1782: 
        !          1783:        /*
        !          1784:         * first free up all pages with prep/pin counts of zero.  This
        !          1785:         * may free both real and fictitious pages, which may be needed
        !          1786:         * later to convert real ones.
        !          1787:         */
        !          1788:        m = (vm_page_t)queue_first(&vm_page_queue_limbo);
        !          1789:        while (!queue_end(&vm_page_queue_limbo, (queue_entry_t)m)) {
        !          1790:                if (m->prep_pin_count == 0) {
        !          1791:                        free_m = m;
        !          1792:                        m = (vm_page_t)queue_next(&m->pageq);
        !          1793:                        queue_remove(&vm_page_queue_limbo, free_m, vm_page_t,
        !          1794:                                                                        pageq);
        !          1795:                        vm_page_limbo_count--;
        !          1796:                        if (!free_m->fictitious)
        !          1797:                                vm_page_limbo_real_count--;
        !          1798:                        free_m->limbo = FALSE;
        !          1799:                        vm_page_free(free_m);
        !          1800:                        assert(vm_page_limbo_count >= 0);
        !          1801:                        assert(vm_page_limbo_real_count >= 0);
        !          1802:                } else {
        !          1803:                        m = (vm_page_t)queue_next(&m->pageq);
        !          1804:                }
        !          1805:        }
        !          1806: 
        !          1807:        /*
        !          1808:         * now convert any remaining real pages to fictitious and free the
        !          1809:         * real ones.
        !          1810:         */
        !          1811:        while (vm_page_limbo_real_count > 0) {
        !          1812:                queue_remove_first(&vm_page_queue_limbo, m, vm_page_t, pageq);
        !          1813:                assert(!m->fictitious);
        !          1814:                assert(m->limbo);
        !          1815: 
        !          1816:                /*
        !          1817:                 * Try to get a fictitious page.  If impossible,
        !          1818:                 * requeue the real one and give up.
        !          1819:                 */
        !          1820:                free_m = vm_page_grab_fictitious();
        !          1821:                if (free_m == VM_PAGE_NULL) {
        !          1822:                        queue_enter_first(&vm_page_queue_limbo, m, vm_page_t,
        !          1823:                                                                        pageq);
        !          1824:                        break;
        !          1825:                }
        !          1826:                c_limbo_convert++;
        !          1827:                vm_page_limbo_exchange(m, free_m);
        !          1828:                assert(m->limbo && m->fictitious);
        !          1829:                assert(!free_m->limbo && !free_m->fictitious);
        !          1830:                queue_enter(&vm_page_queue_limbo, m, vm_page_t, pageq);
        !          1831:                vm_page_free(free_m);
        !          1832:                vm_page_limbo_real_count--;
        !          1833:        }
        !          1834: 
        !          1835:        vm_page_unlock_queues();
        !          1836: }
        !          1837: 
        !          1838: /*
        !          1839:  * Increment prep_count on a page.
        !          1840:  * Must be called in thread context.  Page must not disappear: object
        !          1841:  * must be locked.
        !          1842:  */
        !          1843: kern_return_t
        !          1844: vm_page_prep(
        !          1845:        register vm_page_t      m)
        !          1846: {
        !          1847:        kern_return_t retval = KERN_SUCCESS;
        !          1848: 
        !          1849:        assert(m != VM_PAGE_NULL);
        !          1850:        vm_page_lock_queues();
        !          1851:        if (!m->busy && !m->error && !m->fictitious && !m->absent) {
        !          1852:                if (m->prep_pin_count != 0) {
        !          1853:                        vm_page_pin_lock();
        !          1854:                        m->prep_count++;
        !          1855:                        vm_page_pin_unlock();
        !          1856:                } else {
        !          1857:                        m->prep_count++;
        !          1858:                }
        !          1859:                assert(m->prep_count != 0);     /* check for wraparound */
        !          1860:        } else {
        !          1861:                retval = KERN_FAILURE;
        !          1862:        }
        !          1863:        vm_page_unlock_queues();
        !          1864:        return retval;
        !          1865: }
        !          1866: 
        !          1867: 
        !          1868: /*
        !          1869:  * Pin a page (increment pin count).
        !          1870:  * Must have been previously prepped.
        !          1871:  *
        !          1872:  * MUST BE CALLED AT SPLVM.
        !          1873:  *
        !          1874:  * May be called from thread or interrupt context.
        !          1875:  * If page is in "limbo" it cannot be pinned.
        !          1876:  */
        !          1877: kern_return_t
        !          1878: vm_page_pin(
        !          1879:        register vm_page_t      m)
        !          1880: {
        !          1881:        kern_return_t retval = KERN_SUCCESS;
        !          1882: 
        !          1883:        assert(m != VM_PAGE_NULL);
        !          1884:        vm_page_pin_lock();
        !          1885:        if (m->limbo || m->prep_count == 0) {
        !          1886:                retval = KERN_FAILURE;
        !          1887:        } else {
        !          1888:                assert(!m->fictitious);
        !          1889:                if (m->pin_count == 0)
        !          1890:                        vm_page_pin_count++;
        !          1891:                m->pin_count++;
        !          1892:        }
        !          1893:        vm_page_pin_unlock();
        !          1894:        return retval;
        !          1895: }
        !          1896: 
        !          1897: 
        !          1898: /*
        !          1899:  * Unprep a page (decrement prep count).
        !          1900:  * Must have been previously prepped.
        !          1901:  * Called to decrement prep count after an attempt to pin failed.
        !          1902:  * Must be called from thread context.
        !          1903:  */
        !          1904: kern_return_t
        !          1905: vm_page_unprep(
        !          1906:        register vm_page_t      m)
        !          1907: {
        !          1908:        kern_return_t retval = KERN_SUCCESS;
        !          1909: 
        !          1910:        assert(m != VM_PAGE_NULL);
        !          1911:        vm_page_lock_queues();
        !          1912:        vm_page_pin_lock();
        !          1913:        assert(m->prep_count != 0);
        !          1914:        if (m->prep_count == 0)
        !          1915:                retval = KERN_FAILURE;          /* shouldn't happen */
        !          1916:        else
        !          1917:                m->prep_count--;
        !          1918:        vm_page_pin_unlock();
        !          1919:        vm_page_unlock_queues();
        !          1920:        return retval;
        !          1921: }
        !          1922: 
        !          1923: 
        !          1924: /*
        !          1925:  * Unpin a page: decrement pin AND prep counts.
        !          1926:  * Must have been previously prepped AND pinned.
        !          1927:  *
        !          1928:  * MUST BE CALLED AT SPLVM.
        !          1929:  *
        !          1930:  * May be called from thread or interrupt context.
        !          1931:  */
        !          1932: kern_return_t
        !          1933: vm_page_unpin(
        !          1934:        register vm_page_t      m)
        !          1935: {
        !          1936:        kern_return_t retval = KERN_SUCCESS;
        !          1937: 
        !          1938:        assert(m != VM_PAGE_NULL);
        !          1939:        vm_page_pin_lock();
        !          1940:        assert(m->prep_count != 0 && m->pin_count != 0);
        !          1941:        assert(m->prep_count >= m->pin_count);
        !          1942:        assert(!m->limbo && !m->fictitious);
        !          1943:        if (m->prep_count != 0 && m->pin_count != 0) {
        !          1944:                m->prep_count--;
        !          1945:                m->pin_count--;
        !          1946:                if (m->pin_count == 0)
        !          1947:                        vm_page_pin_count--;
        !          1948:        } else {
        !          1949:                retval = KERN_FAILURE;          /* shouldn't happen */
        !          1950:        }
        !          1951:        vm_page_pin_unlock();
        !          1952:        return retval;
        !          1953: }
        !          1954: 
        !          1955: /*
        !          1956:  *     Currently, this is a primitive allocator that grabs
        !          1957:  *     free pages from the system, sorts them by physical
        !          1958:  *     address, then searches for a region large enough to
        !          1959:  *     satisfy the user's request.
        !          1960:  *
        !          1961:  *     Additional levels of effort:
        !          1962:  *             + steal clean active/inactive pages
        !          1963:  *             + force pageouts of dirty pages
        !          1964:  *             + maintain a map of available physical
        !          1965:  *             memory
        !          1966:  */
        !          1967: 
        !          1968: #define        SET_NEXT_PAGE(m,n)      ((m)->pageq.next = (struct queue_entry *) (n))
        !          1969: 
        !          1970: #if    MACH_ASSERT
        !          1971: int    vm_page_verify_contiguous(
        !          1972:                vm_page_t       pages,
        !          1973:                unsigned int    npages);
        !          1974: #endif /* MACH_ASSERT */
        !          1975: 
        !          1976: cpm_counter(unsigned int       vpfls_pages_handled = 0;)
        !          1977: cpm_counter(unsigned int       vpfls_head_insertions = 0;)
        !          1978: cpm_counter(unsigned int       vpfls_tail_insertions = 0;)
        !          1979: cpm_counter(unsigned int       vpfls_general_insertions = 0;)
        !          1980: cpm_counter(unsigned int       vpfc_failed = 0;)
        !          1981: cpm_counter(unsigned int       vpfc_satisfied = 0;)
        !          1982: 
        !          1983: /*
        !          1984:  *     Sort free list by ascending physical address,
        !          1985:  *     using a not-particularly-bright sort algorithm.
        !          1986:  *     Caller holds vm_page_queue_free_lock.
        !          1987:  */
        !          1988: static void
        !          1989: vm_page_free_list_sort(void)
        !          1990: {
        !          1991:        vm_page_t       sort_list;
        !          1992:        vm_page_t       sort_list_end;
        !          1993:        vm_page_t       m, m1, *prev, next_m;
        !          1994:        vm_offset_t     addr;
        !          1995: #if    MACH_ASSERT
        !          1996:        unsigned int    npages;
        !          1997:        int             old_free_count;
        !          1998: #endif /* MACH_ASSERT */
        !          1999: 
        !          2000: #if    MACH_ASSERT
        !          2001:        /*
        !          2002:         *      Verify pages in the free list..
        !          2003:         */
        !          2004:        npages = 0;
        !          2005:        for (m = vm_page_queue_free; m != VM_PAGE_NULL; m = NEXT_PAGE(m))
        !          2006:                ++npages;
        !          2007:        if (npages != vm_page_free_count)
        !          2008:                panic("vm_sort_free_list:  prelim:  npages %d free_count %d",
        !          2009:                      npages, vm_page_free_count);
        !          2010:        old_free_count = vm_page_free_count;
        !          2011: #endif /* MACH_ASSERT */
        !          2012: 
        !          2013:        sort_list = sort_list_end = vm_page_queue_free;
        !          2014:        m = NEXT_PAGE(vm_page_queue_free);
        !          2015:        SET_NEXT_PAGE(vm_page_queue_free, VM_PAGE_NULL);
        !          2016:        cpm_counter(vpfls_pages_handled = 0);
        !          2017:        while (m != VM_PAGE_NULL) {
        !          2018:                cpm_counter(++vpfls_pages_handled);
        !          2019:                next_m = NEXT_PAGE(m);
        !          2020:                if (m->phys_addr < sort_list->phys_addr) {
        !          2021:                        cpm_counter(++vpfls_head_insertions);
        !          2022:                        SET_NEXT_PAGE(m, sort_list);
        !          2023:                        sort_list = m;
        !          2024:                } else if (m->phys_addr > sort_list_end->phys_addr) {
        !          2025:                        cpm_counter(++vpfls_tail_insertions);
        !          2026:                        SET_NEXT_PAGE(sort_list_end, m);
        !          2027:                        SET_NEXT_PAGE(m, VM_PAGE_NULL);
        !          2028:                        sort_list_end = m;
        !          2029:                } else {
        !          2030:                        cpm_counter(++vpfls_general_insertions);
        !          2031:                        /* general sorted list insertion */
        !          2032:                        prev = &sort_list;
        !          2033:                        for (m1=sort_list; m1!=VM_PAGE_NULL; m1=NEXT_PAGE(m1)) {
        !          2034:                                if (m1->phys_addr > m->phys_addr) {
        !          2035:                                        if (*prev != m1)
        !          2036:                                                panic("vm_sort_free_list: ugh");
        !          2037:                                        SET_NEXT_PAGE(m, *prev);
        !          2038:                                        *prev = m;
        !          2039:                                        break;
        !          2040:                                }
        !          2041:                                prev = (vm_page_t *) &m1->pageq.next;
        !          2042:                        }
        !          2043:                }
        !          2044:                m = next_m;
        !          2045:        }
        !          2046: 
        !          2047: #if    MACH_ASSERT
        !          2048:        /*
        !          2049:         *      Verify that pages are sorted into ascending order.
        !          2050:         */
        !          2051:        for (m = sort_list, npages = 0; m != VM_PAGE_NULL; m = NEXT_PAGE(m)) {
        !          2052:                if (m != sort_list &&
        !          2053:                    m->phys_addr <= addr) {
        !          2054:                        printf("m 0x%x addr 0x%x\n", m, addr);
        !          2055:                        panic("vm_sort_free_list");
        !          2056:                }
        !          2057:                addr = m->phys_addr;
        !          2058:                ++npages;
        !          2059:        }
        !          2060:        if (old_free_count != vm_page_free_count)
        !          2061:                panic("vm_sort_free_list:  old_free %d free_count %d",
        !          2062:                      old_free_count, vm_page_free_count);
        !          2063:        if (npages != vm_page_free_count)
        !          2064:                panic("vm_sort_free_list:  npages %d free_count %d",
        !          2065:                      npages, vm_page_free_count);
        !          2066: #endif /* MACH_ASSERT */
        !          2067: 
        !          2068:        vm_page_queue_free = sort_list;
        !          2069: }
        !          2070: 
        !          2071: 
        !          2072: #if    MACH_ASSERT
        !          2073: /*
        !          2074:  *     Check that the list of pages is ordered by
        !          2075:  *     ascending physical address and has no holes.
        !          2076:  */
        !          2077: int
        !          2078: vm_page_verify_contiguous(
        !          2079:        vm_page_t       pages,
        !          2080:        unsigned int    npages)
        !          2081: {
        !          2082:        register vm_page_t      m;
        !          2083:        unsigned int            page_count;
        !          2084:        vm_offset_t             prev_addr;
        !          2085: 
        !          2086:        prev_addr = pages->phys_addr;
        !          2087:        page_count = 1;
        !          2088:        for (m = NEXT_PAGE(pages); m != VM_PAGE_NULL; m = NEXT_PAGE(m)) {
        !          2089:                if (m->phys_addr != prev_addr + page_size) {
        !          2090:                        printf("m 0x%x prev_addr 0x%x, current addr 0x%x\n",
        !          2091:                               m, prev_addr, m->phys_addr);
        !          2092:                        printf("pages 0x%x page_count %d\n", pages, page_count);
        !          2093:                        panic("vm_page_verify_contiguous:  not contiguous!");
        !          2094:                }
        !          2095:                prev_addr = m->phys_addr;
        !          2096:                ++page_count;
        !          2097:        }
        !          2098:        if (page_count != npages) {
        !          2099:                printf("pages 0x%x actual count 0x%x but requested 0x%x\n",
        !          2100:                       pages, page_count, npages);
        !          2101:                panic("vm_page_verify_contiguous:  count error");
        !          2102:        }
        !          2103:        return 1;
        !          2104: }
        !          2105: #endif /* MACH_ASSERT */
        !          2106: 
        !          2107: 
        !          2108: /*
        !          2109:  *     Find a region large enough to contain at least npages
        !          2110:  *     of contiguous physical memory.
        !          2111:  *
        !          2112:  *     Requirements:
        !          2113:  *             - Called while holding vm_page_queue_free_lock.
        !          2114:  *             - Doesn't respect vm_page_free_reserved; caller
        !          2115:  *             must not ask for more pages than are legal to grab.
        !          2116:  *
        !          2117:  *     Returns a pointer to a list of gobbled pages or VM_PAGE_NULL.
        !          2118:  *
        !          2119:  */
        !          2120: static vm_page_t
        !          2121: vm_page_find_contiguous(
        !          2122:        int             npages)
        !          2123: {
        !          2124:        vm_page_t       m, *contig_prev, *prev_ptr;
        !          2125:        vm_offset_t     prev_addr;
        !          2126:        unsigned int    contig_npages;
        !          2127:        vm_page_t       list;
        !          2128: 
        !          2129:        if (npages < 1)
        !          2130:                return VM_PAGE_NULL;
        !          2131: 
        !          2132:        prev_addr = vm_page_queue_free->phys_addr - (page_size + 1);
        !          2133:        prev_ptr = &vm_page_queue_free;
        !          2134:        for (m = vm_page_queue_free; m != VM_PAGE_NULL; m = NEXT_PAGE(m)) {
        !          2135: 
        !          2136:                if (m->phys_addr != prev_addr + page_size) {
        !          2137:                        /*
        !          2138:                         *      Whoops!  Pages aren't contiguous.  Start over.
        !          2139:                         */
        !          2140:                        contig_npages = 0;
        !          2141:                        contig_prev = prev_ptr;
        !          2142:                }
        !          2143: 
        !          2144:                if (++contig_npages == npages) {
        !          2145:                        /*
        !          2146:                         *      Chop these pages out of the free list.
        !          2147:                         *      Mark them all as gobbled.
        !          2148:                         */
        !          2149:                        list = *contig_prev;
        !          2150:                        *contig_prev = NEXT_PAGE(m);
        !          2151:                        SET_NEXT_PAGE(m, VM_PAGE_NULL);
        !          2152:                        for (m = list; m != VM_PAGE_NULL; m = NEXT_PAGE(m)) {
        !          2153:                                assert(m->free);
        !          2154:                                assert(!m->wanted);
        !          2155:                                m->free = FALSE;
        !          2156:                                m->gobbled = TRUE;
        !          2157:                        }
        !          2158:                        vm_page_free_count -= npages;
        !          2159:                        if (vm_page_free_count < vm_page_free_count_minimum)
        !          2160:                                vm_page_free_count_minimum = vm_page_free_count;
        !          2161:                        vm_page_gobble_count += npages;
        !          2162:                        cpm_counter(++vpfc_satisfied);
        !          2163:                        assert(vm_page_verify_contiguous(list, contig_npages));
        !          2164:                        return list;
        !          2165:                }
        !          2166: 
        !          2167:                assert(contig_npages < npages);
        !          2168:                prev_ptr = (vm_page_t *) &m->pageq.next;
        !          2169:                prev_addr = m->phys_addr;
        !          2170:        }
        !          2171:        cpm_counter(++vpfc_failed);
        !          2172:        return VM_PAGE_NULL;
        !          2173: }
        !          2174: 
        !          2175: /*
        !          2176:  *     Allocate a list of contiguous, wired pages.
        !          2177:  */
        !          2178: kern_return_t
        !          2179: cpm_allocate(
        !          2180:        vm_size_t       size,
        !          2181:        vm_page_t       *list,
        !          2182:        boolean_t       wire)
        !          2183: {
        !          2184:        register vm_page_t      m;
        !          2185:        vm_page_t               *first_contig;
        !          2186:        vm_page_t               free_list, pages;
        !          2187:        unsigned int            npages, n1pages;
        !          2188:        int                     vm_pages_available;
        !          2189: 
        !          2190:        if (size % page_size != 0)
        !          2191:                return KERN_INVALID_ARGUMENT;
        !          2192: 
        !          2193:        vm_page_lock_queues();
        !          2194:        mutex_lock(&vm_page_queue_free_lock);
        !          2195: 
        !          2196:        /*
        !          2197:         *      Should also take active and inactive pages
        !          2198:         *      into account...  One day...
        !          2199:         */
        !          2200:        vm_pages_available = vm_page_free_count - vm_page_free_reserved;
        !          2201: 
        !          2202:        if (size > vm_pages_available * page_size) {
        !          2203:                mutex_unlock(&vm_page_queue_free_lock);
        !          2204:                return KERN_RESOURCE_SHORTAGE;
        !          2205:        }
        !          2206: 
        !          2207:        vm_page_free_list_sort();
        !          2208: 
        !          2209:        npages = size / page_size;
        !          2210: 
        !          2211:        /*
        !          2212:         *      Obtain a pointer to a subset of the free
        !          2213:         *      list large enough to satisfy the request;
        !          2214:         *      the region will be physically contiguous.
        !          2215:         */
        !          2216:        pages = vm_page_find_contiguous(npages);
        !          2217:        if (pages == VM_PAGE_NULL) {
        !          2218:                mutex_unlock(&vm_page_queue_free_lock);
        !          2219:                return KERN_NO_SPACE;
        !          2220:        }
        !          2221: 
        !          2222:        mutex_unlock(&vm_page_queue_free_lock);
        !          2223: 
        !          2224:        /*
        !          2225:         *      Walk the returned list, wiring the pages.
        !          2226:         */
        !          2227:        if (wire == TRUE)
        !          2228:                for (m = pages; m != VM_PAGE_NULL; m = NEXT_PAGE(m)) {
        !          2229:                        /*
        !          2230:                         *      Essentially inlined vm_page_wire.
        !          2231:                         */
        !          2232:                        assert(!m->active);
        !          2233:                        assert(!m->inactive);
        !          2234:                        assert(!m->private);
        !          2235:                        assert(!m->fictitious);
        !          2236:                        assert(m->wire_count == 0);
        !          2237:                        assert(m->gobbled);
        !          2238:                        m->gobbled = FALSE;
        !          2239:                        m->wire_count++;
        !          2240:                        ++vm_page_wire_count;
        !          2241:                        --vm_page_gobble_count;
        !          2242:                }
        !          2243:        vm_page_unlock_queues();
        !          2244: 
        !          2245:        /*
        !          2246:         *      The CPM pages should now be available and
        !          2247:         *      ordered by ascending physical address.
        !          2248:         */
        !          2249:        assert(vm_page_verify_contiguous(pages, npages));
        !          2250: 
        !          2251:        *list = pages;
        !          2252:        return KERN_SUCCESS;
        !          2253: }
        !          2254: 
        !          2255: 
        !          2256: #include <mach_vm_debug.h>
        !          2257: #if    MACH_VM_DEBUG
        !          2258: 
        !          2259: #include <mach_debug/hash_info.h>
        !          2260: #include <vm/vm_debug.h>
        !          2261: 
        !          2262: /*
        !          2263:  *     Routine:        vm_page_info
        !          2264:  *     Purpose:
        !          2265:  *             Return information about the global VP table.
        !          2266:  *             Fills the buffer with as much information as possible
        !          2267:  *             and returns the desired size of the buffer.
        !          2268:  *     Conditions:
        !          2269:  *             Nothing locked.  The caller should provide
        !          2270:  *             possibly-pageable memory.
        !          2271:  */
        !          2272: 
        !          2273: unsigned int
        !          2274: vm_page_info(
        !          2275:        hash_info_bucket_t *info,
        !          2276:        unsigned int count)
        !          2277: {
        !          2278:        int i;
        !          2279: 
        !          2280:        if (vm_page_bucket_count < count)
        !          2281:                count = vm_page_bucket_count;
        !          2282: 
        !          2283:        for (i = 0; i < count; i++) {
        !          2284:                vm_page_bucket_t *bucket = &vm_page_buckets[i];
        !          2285:                unsigned int bucket_count = 0;
        !          2286:                vm_page_t m;
        !          2287: 
        !          2288:                simple_lock(&vm_page_bucket_lock);
        !          2289:                for (m = bucket->pages; m != VM_PAGE_NULL; m = m->next)
        !          2290:                        bucket_count++;
        !          2291:                simple_unlock(&vm_page_bucket_lock);
        !          2292: 
        !          2293:                /* don't touch pageable memory while holding locks */
        !          2294:                info[i].hib_count = bucket_count;
        !          2295:        }
        !          2296: 
        !          2297:        return vm_page_bucket_count;
        !          2298: }
        !          2299: #endif /* MACH_VM_DEBUG */
        !          2300: 
        !          2301: #include <mach_kdb.h>
        !          2302: #if    MACH_KDB
        !          2303: 
        !          2304: #include <ddb/db_output.h>
        !          2305: #include <vm/vm_print.h>
        !          2306: #define        printf  kdbprintf
        !          2307: 
        !          2308: /*
        !          2309:  *     Routine:        vm_page_print [exported]
        !          2310:  */
        !          2311: void
        !          2312: vm_page_print(
        !          2313:        vm_page_t       p)
        !          2314: {
        !          2315:        extern db_indent;
        !          2316: 
        !          2317:        iprintf("page 0x%x\n", p);
        !          2318: 
        !          2319:        db_indent += 2;
        !          2320: 
        !          2321:        iprintf("object=0x%x", p->object);
        !          2322:        printf(", offset=0x%x", p->offset);
        !          2323:        printf(", wire_count=%d", p->wire_count);
        !          2324:        printf(", prep_count=%d", p->prep_count);
        !          2325:        printf(", pin_count=%d\n", p->pin_count);
        !          2326: 
        !          2327:        iprintf("%sinactive, %sactive, %sgobbled, %slaundry, %sfree, %sref, %sdiscard\n",
        !          2328:                (p->inactive ? "" : "!"),
        !          2329:                (p->active ? "" : "!"),
        !          2330:                (p->gobbled ? "" : "!"),
        !          2331:                (p->laundry ? "" : "!"),
        !          2332:                (p->free ? "" : "!"),
        !          2333:                (p->reference ? "" : "!"),
        !          2334:                (p->discard_request ? "" : "!"));
        !          2335:        iprintf("%sbusy, %swanted, %stabled, %sfictitious, %sprivate, %sprecious\n",
        !          2336:                (p->busy ? "" : "!"),
        !          2337:                (p->wanted ? "" : "!"),
        !          2338:                (p->tabled ? "" : "!"),
        !          2339:                (p->fictitious ? "" : "!"),
        !          2340:                (p->private ? "" : "!"),
        !          2341:                (p->precious ? "" : "!"));
        !          2342:        iprintf("%sabsent, %serror, %sdirty, %scleaning, %spageout, %sclustered\n",
        !          2343:                (p->absent ? "" : "!"),
        !          2344:                (p->error ? "" : "!"),
        !          2345:                (p->dirty ? "" : "!"),
        !          2346:                (p->cleaning ? "" : "!"),
        !          2347:                (p->pageout ? "" : "!"),
        !          2348:                (p->clustered ? "" : "!"));
        !          2349:        iprintf("%slock_supplied, %soverwriting, %srestart, %sunusual, %slimbo\n",
        !          2350:                (p->lock_supplied ? "" : "!"),
        !          2351:                (p->overwriting ? "" : "!"),
        !          2352:                (p->restart ? "" : "!"),
        !          2353:                (p->unusual ? "" : "!"),
        !          2354:                (p->limbo ? "" : "!"));
        !          2355: 
        !          2356:        iprintf("phys_addr=0x%x", p->phys_addr);
        !          2357:        printf(", page_error=0x%x", p->page_error);
        !          2358:        printf(", page_lock=0x%x", p->page_lock);
        !          2359:        printf(", unlock_request=%d\n", p->unlock_request);
        !          2360: 
        !          2361:        db_indent -= 2;
        !          2362: }
        !          2363: #endif /* MACH_KDB */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.