1999-09-12 05:16:55 +04:00
|
|
|
/* $NetBSD: uvm_page_i.h,v 1.11 1999/09/12 01:17:38 chs Exp $ */
|
1998-02-05 09:25:08 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 1997 Charles D. Cranor and Washington University.
|
|
|
|
* Copyright (c) 1991, 1993, The Regents of the University of California.
|
|
|
|
*
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to Berkeley by
|
|
|
|
* The Mach Operating System project at Carnegie-Mellon University.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by Charles D. Cranor,
|
|
|
|
* Washington University, the University of California, Berkeley and
|
|
|
|
* its contributors.
|
|
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* @(#)vm_page.c 8.3 (Berkeley) 3/21/94
|
1998-02-07 14:07:38 +03:00
|
|
|
* from: Id: uvm_page_i.h,v 1.1.2.7 1998/01/05 00:26:02 chuck Exp
|
1998-02-05 09:25:08 +03:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* Copyright (c) 1987, 1990 Carnegie-Mellon University.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify and distribute this software and
|
|
|
|
* its documentation is hereby granted, provided that both the copyright
|
|
|
|
* notice and this permission notice appear in all copies of the
|
|
|
|
* software, derivative works or modified versions, and any portions
|
|
|
|
* thereof, and that both notices appear in supporting documentation.
|
|
|
|
*
|
|
|
|
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
|
|
|
|
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
|
|
|
|
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
|
|
|
*
|
|
|
|
* Carnegie Mellon requests users of this software to return to
|
|
|
|
*
|
|
|
|
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
|
|
|
|
* School of Computer Science
|
|
|
|
* Carnegie Mellon University
|
|
|
|
* Pittsburgh PA 15213-3890
|
|
|
|
*
|
|
|
|
* any improvements or extensions that they make and grant Carnegie the
|
|
|
|
* rights to redistribute these changes.
|
|
|
|
*/
|
|
|
|
|
1998-02-10 05:34:17 +03:00
|
|
|
#ifndef _UVM_UVM_PAGE_I_H_
|
|
|
|
#define _UVM_UVM_PAGE_I_H_
|
|
|
|
|
1998-02-05 09:25:08 +03:00
|
|
|
/*
|
|
|
|
* uvm_page_i.h
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* inline functions [maybe]
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if defined(UVM_PAGE_INLINE) || defined(UVM_PAGE)
|
|
|
|
|
1999-05-24 23:10:57 +04:00
|
|
|
/*
|
|
|
|
* uvm_lock_fpageq: lock the free page queue
|
|
|
|
*
|
|
|
|
* => free page queue can be accessed in interrupt context, so this
|
|
|
|
* blocks all interrupts that can cause memory allocation, and
|
|
|
|
* returns the previous interrupt level.
|
|
|
|
*/
|
|
|
|
|
|
|
|
PAGE_INLINE int
|
|
|
|
uvm_lock_fpageq()
|
|
|
|
{
|
|
|
|
int s;
|
|
|
|
|
|
|
|
s = splimp();
|
|
|
|
simple_lock(&uvm.fpageqlock);
|
|
|
|
return (s);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* uvm_unlock_fpageq: unlock the free page queue
|
|
|
|
*
|
|
|
|
* => caller must supply interrupt level returned by uvm_lock_fpageq()
|
|
|
|
* so that it may be restored.
|
|
|
|
*/
|
|
|
|
|
|
|
|
PAGE_INLINE void
|
|
|
|
uvm_unlock_fpageq(s)
|
|
|
|
int s;
|
|
|
|
{
|
|
|
|
|
|
|
|
simple_unlock(&uvm.fpageqlock);
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
1998-02-05 09:25:08 +03:00
|
|
|
/*
|
|
|
|
* uvm_pagelookup: look up a page
|
|
|
|
*
|
|
|
|
* => caller should lock object to keep someone from pulling the page
|
|
|
|
* out from under it
|
|
|
|
*/
|
|
|
|
|
1998-03-09 03:58:55 +03:00
|
|
|
struct vm_page *
|
|
|
|
uvm_pagelookup(obj, off)
|
|
|
|
struct uvm_object *obj;
|
1998-08-13 06:10:37 +04:00
|
|
|
vaddr_t off;
|
1998-02-05 09:25:08 +03:00
|
|
|
{
|
1998-03-09 03:58:55 +03:00
|
|
|
struct vm_page *pg;
|
|
|
|
struct pglist *buck;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
buck = &uvm.page_hash[uvm_pagehash(obj,off)];
|
|
|
|
|
|
|
|
s = splimp();
|
|
|
|
simple_lock(&uvm.hashlock);
|
|
|
|
for (pg = buck->tqh_first ; pg != NULL ; pg = pg->hashq.tqe_next) {
|
|
|
|
if (pg->uobject == obj && pg->offset == off) {
|
|
|
|
simple_unlock(&uvm.hashlock);
|
|
|
|
splx(s);
|
|
|
|
return(pg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
simple_unlock(&uvm.hashlock);
|
|
|
|
splx(s);
|
|
|
|
return(NULL);
|
1998-02-05 09:25:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1998-03-23 00:29:30 +03:00
|
|
|
* uvm_pagewire: wire the page, thus removing it from the daemon's grasp
|
1998-02-05 09:25:08 +03:00
|
|
|
*
|
|
|
|
* => caller must lock page queues
|
|
|
|
*/
|
|
|
|
|
1998-03-09 03:58:55 +03:00
|
|
|
PAGE_INLINE void
|
1998-03-23 00:29:30 +03:00
|
|
|
uvm_pagewire(pg)
|
1998-03-09 03:58:55 +03:00
|
|
|
struct vm_page *pg;
|
1998-02-05 09:25:08 +03:00
|
|
|
{
|
1998-03-09 03:58:55 +03:00
|
|
|
|
|
|
|
if (pg->wire_count == 0) {
|
|
|
|
if (pg->pqflags & PQ_ACTIVE) {
|
|
|
|
TAILQ_REMOVE(&uvm.page_active, pg, pageq);
|
|
|
|
pg->pqflags &= ~PQ_ACTIVE;
|
|
|
|
uvmexp.active--;
|
|
|
|
}
|
|
|
|
if (pg->pqflags & PQ_INACTIVE) {
|
|
|
|
if (pg->pqflags & PQ_SWAPBACKED)
|
|
|
|
TAILQ_REMOVE(&uvm.page_inactive_swp, pg, pageq);
|
|
|
|
else
|
|
|
|
TAILQ_REMOVE(&uvm.page_inactive_obj, pg, pageq);
|
|
|
|
pg->pqflags &= ~PQ_INACTIVE;
|
|
|
|
uvmexp.inactive--;
|
|
|
|
}
|
|
|
|
uvmexp.wired++;
|
|
|
|
}
|
1998-03-23 00:29:30 +03:00
|
|
|
pg->wire_count++;
|
1998-02-05 09:25:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* uvm_pageunwire: unwire the page.
|
|
|
|
*
|
|
|
|
* => activate if wire count goes to zero.
|
|
|
|
* => caller must lock page queues
|
|
|
|
*/
|
|
|
|
|
1998-03-09 03:58:55 +03:00
|
|
|
PAGE_INLINE void
|
|
|
|
uvm_pageunwire(pg)
|
|
|
|
struct vm_page *pg;
|
1998-02-05 09:25:08 +03:00
|
|
|
{
|
1998-03-09 03:58:55 +03:00
|
|
|
|
|
|
|
pg->wire_count--;
|
|
|
|
if (pg->wire_count == 0) {
|
|
|
|
TAILQ_INSERT_TAIL(&uvm.page_active, pg, pageq);
|
|
|
|
uvmexp.active++;
|
|
|
|
pg->pqflags |= PQ_ACTIVE;
|
|
|
|
uvmexp.wired--;
|
|
|
|
}
|
1998-02-05 09:25:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* uvm_pagedeactivate: deactivate page -- no pmaps have access to page
|
|
|
|
*
|
|
|
|
* => caller must lock page queues
|
|
|
|
* => caller must check to make sure page is not wired
|
|
|
|
* => object that page belongs to must be locked (so we can adjust pg->flags)
|
|
|
|
*/
|
|
|
|
|
1998-03-09 03:58:55 +03:00
|
|
|
PAGE_INLINE void
|
|
|
|
uvm_pagedeactivate(pg)
|
|
|
|
struct vm_page *pg;
|
1998-02-05 09:25:08 +03:00
|
|
|
{
|
1998-03-09 03:58:55 +03:00
|
|
|
if (pg->pqflags & PQ_ACTIVE) {
|
|
|
|
TAILQ_REMOVE(&uvm.page_active, pg, pageq);
|
|
|
|
pg->pqflags &= ~PQ_ACTIVE;
|
|
|
|
uvmexp.active--;
|
|
|
|
}
|
|
|
|
if ((pg->pqflags & PQ_INACTIVE) == 0) {
|
1998-02-05 09:25:08 +03:00
|
|
|
#ifdef DIAGNOSTIC
|
1998-03-09 03:58:55 +03:00
|
|
|
if (pg->wire_count)
|
|
|
|
panic("uvm_pagedeactivate: caller did not check "
|
|
|
|
"wire count");
|
1998-02-05 09:25:08 +03:00
|
|
|
#endif
|
1998-03-09 03:58:55 +03:00
|
|
|
if (pg->pqflags & PQ_SWAPBACKED)
|
|
|
|
TAILQ_INSERT_TAIL(&uvm.page_inactive_swp, pg, pageq);
|
|
|
|
else
|
|
|
|
TAILQ_INSERT_TAIL(&uvm.page_inactive_obj, pg, pageq);
|
|
|
|
pg->pqflags |= PQ_INACTIVE;
|
|
|
|
uvmexp.inactive++;
|
1999-09-12 05:16:55 +04:00
|
|
|
pmap_clear_reference(pg);
|
|
|
|
if (pmap_is_modified(pg))
|
1998-03-09 03:58:55 +03:00
|
|
|
pg->flags &= ~PG_CLEAN;
|
|
|
|
}
|
1998-02-05 09:25:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* uvm_pageactivate: activate page
|
|
|
|
*
|
|
|
|
* => caller must lock page queues
|
|
|
|
*/
|
|
|
|
|
1998-03-09 03:58:55 +03:00
|
|
|
PAGE_INLINE void
|
|
|
|
uvm_pageactivate(pg)
|
|
|
|
struct vm_page *pg;
|
1998-02-05 09:25:08 +03:00
|
|
|
{
|
1998-03-09 03:58:55 +03:00
|
|
|
if (pg->pqflags & PQ_INACTIVE) {
|
|
|
|
if (pg->pqflags & PQ_SWAPBACKED)
|
|
|
|
TAILQ_REMOVE(&uvm.page_inactive_swp, pg, pageq);
|
|
|
|
else
|
|
|
|
TAILQ_REMOVE(&uvm.page_inactive_obj, pg, pageq);
|
|
|
|
pg->pqflags &= ~PQ_INACTIVE;
|
|
|
|
uvmexp.inactive--;
|
|
|
|
}
|
|
|
|
if (pg->wire_count == 0) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if page is already active, remove it from list so we
|
|
|
|
* can put it at tail. if it wasn't active, then mark
|
|
|
|
* it active and bump active count
|
|
|
|
*/
|
|
|
|
if (pg->pqflags & PQ_ACTIVE)
|
|
|
|
TAILQ_REMOVE(&uvm.page_active, pg, pageq);
|
|
|
|
else {
|
|
|
|
pg->pqflags |= PQ_ACTIVE;
|
|
|
|
uvmexp.active++;
|
|
|
|
}
|
|
|
|
|
|
|
|
TAILQ_INSERT_TAIL(&uvm.page_active, pg, pageq);
|
|
|
|
}
|
1998-02-05 09:25:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* uvm_pagezero: zero fill a page
|
|
|
|
*
|
|
|
|
* => if page is part of an object then the object should be locked
|
|
|
|
* to protect pg->flags.
|
|
|
|
*/
|
|
|
|
|
1998-03-09 03:58:55 +03:00
|
|
|
PAGE_INLINE void
|
|
|
|
uvm_pagezero(pg)
|
|
|
|
struct vm_page *pg;
|
1998-02-05 09:25:08 +03:00
|
|
|
{
|
1998-03-09 03:58:55 +03:00
|
|
|
|
|
|
|
pg->flags &= ~PG_CLEAN;
|
|
|
|
pmap_zero_page(VM_PAGE_TO_PHYS(pg));
|
1998-02-05 09:25:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* uvm_pagecopy: copy a page
|
|
|
|
*
|
|
|
|
* => if page is part of an object then the object should be locked
|
|
|
|
* to protect pg->flags.
|
|
|
|
*/
|
|
|
|
|
1998-03-09 03:58:55 +03:00
|
|
|
PAGE_INLINE void
|
|
|
|
uvm_pagecopy(src, dst)
|
|
|
|
struct vm_page *src, *dst;
|
1998-02-05 09:25:08 +03:00
|
|
|
{
|
1998-03-09 03:58:55 +03:00
|
|
|
|
|
|
|
dst->flags &= ~PG_CLEAN;
|
|
|
|
pmap_copy_page(VM_PAGE_TO_PHYS(src), VM_PAGE_TO_PHYS(dst));
|
1998-02-05 09:25:08 +03:00
|
|
|
}
|
|
|
|
|
Add support for multiple memory free lists. There is at least one
default free list, and 0 - N additional free list, in order of descending
priority.
A new page allocation function, uvm_pagealloc_strat(), has been added,
providing three page allocation strategies:
- normal: high -> low priority free list walk, taking the
page off the first free list that has one.
- only: attempt to allocate a page only from the specified free
list, failing if that free list has none available.
- fallback: if `only' fails, fall back on `normal'.
uvm_pagealloc(...) is provided for normal use (and is a synonym for
uvm_pagealloc_strat(..., UVM_PGA_STRAT_NORMAL, 0); the free list argument
is ignored for the `normal' case).
uvm_page_physload() now specified which free list the pages will be
loaded onto. This means that some platforms which have multiple physical
memory segments may define additional vm_physsegs if they wish to break
individual physical segments into differing priorities.
Machine-dependent code must define _at least_ the following constants
in <machine/vmparam.h>:
VM_NFREELIST: the number of free lists the system will have
VM_FREELIST_DEFAULT: the default freelist (should always be 0,
but is defined in machdep code so that it's with all of the
other free list-related constants).
Additional free list names may be defined by machine-dependent code, but
they will only be used by machine-dependent code (e.g. for loading the
vm_physsegs).
1998-07-08 08:28:27 +04:00
|
|
|
/*
|
|
|
|
* uvm_page_lookup_freelist: look up the free list for the specified page
|
|
|
|
*/
|
|
|
|
|
|
|
|
PAGE_INLINE int
|
|
|
|
uvm_page_lookup_freelist(pg)
|
|
|
|
struct vm_page *pg;
|
|
|
|
{
|
|
|
|
int lcv;
|
|
|
|
|
|
|
|
lcv = vm_physseg_find(atop(VM_PAGE_TO_PHYS(pg)), NULL);
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (lcv == -1)
|
|
|
|
panic("uvm_page_lookup_freelist: unable to locate physseg");
|
|
|
|
#endif
|
|
|
|
return (vm_physmem[lcv].free_list);
|
|
|
|
}
|
|
|
|
|
1998-02-05 09:25:08 +03:00
|
|
|
#endif /* defined(UVM_PAGE_INLINE) || defined(UVM_PAGE) */
|
1998-02-10 05:34:17 +03:00
|
|
|
|
|
|
|
#endif /* _UVM_UVM_PAGE_I_H_ */
|