|
|
1.1 root 1: /*
2: * Copyright (c) 1991 Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * The Mach Operating System project at Carnegie-Mellon University.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
1.1.1.4 ! root 36: * from: @(#)vm_page.c 7.4 (Berkeley) 5/7/91
! 37: * vm_page.c,v 1.5 1993/06/30 03:48:25 andrew Exp
1.1 root 38: *
39: *
40: * Copyright (c) 1987, 1990 Carnegie-Mellon University.
41: * All rights reserved.
42: *
43: * Authors: Avadis Tevanian, Jr., Michael Wayne Young
44: *
45: * Permission to use, copy, modify and distribute this software and
46: * its documentation is hereby granted, provided that both the copyright
47: * notice and this permission notice appear in all copies of the
48: * software, derivative works or modified versions, and any portions
49: * thereof, and that both notices appear in supporting documentation.
50: *
51: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
52: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
53: * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
54: *
55: * Carnegie Mellon requests users of this software to return to
56: *
57: * Software Distribution Coordinator or [email protected]
58: * School of Computer Science
59: * Carnegie Mellon University
60: * Pittsburgh PA 15213-3890
61: *
62: * any improvements or extensions that they make and grant Carnegie the
63: * rights to redistribute these changes.
64: */
65:
66: /*
67: * Resident memory management module.
68: */
69:
70: #include "param.h"
71:
72: #include "vm.h"
73: #include "vm_map.h"
74: #include "vm_page.h"
75: #include "vm_pageout.h"
76:
77: /*
78: * Associated with page of user-allocatable memory is a
79: * page structure.
80: */
81:
82: queue_head_t *vm_page_buckets; /* Array of buckets */
83: int vm_page_bucket_count = 0; /* How big is array? */
84: int vm_page_hash_mask; /* Mask for hash function */
85: simple_lock_data_t bucket_lock; /* lock for all buckets XXX */
86:
87: vm_size_t page_size = 4096;
88: vm_size_t page_mask = 4095;
89: int page_shift = 12;
90:
91: queue_head_t vm_page_queue_free;
92: queue_head_t vm_page_queue_active;
93: queue_head_t vm_page_queue_inactive;
94: simple_lock_data_t vm_page_queue_lock;
95: simple_lock_data_t vm_page_queue_free_lock;
96:
97: vm_page_t vm_page_array;
98: long first_page;
99: long last_page;
100: vm_offset_t first_phys_addr;
101: vm_offset_t last_phys_addr;
102:
103: int vm_page_free_count;
104: int vm_page_active_count;
105: int vm_page_inactive_count;
106: int vm_page_wire_count;
107: int vm_page_laundry_count;
108:
109: int vm_page_free_target = 0;
110: int vm_page_free_min = 0;
111: int vm_page_inactive_target = 0;
112: int vm_page_free_reserved = 0;
113:
114: /*
115: * vm_set_page_size:
116: *
117: * Sets the page size, perhaps based upon the memory
118: * size. Must be called before any use of page-size
119: * dependent functions.
120: *
121: * Sets page_shift and page_mask from page_size.
122: */
123: void vm_set_page_size()
124: {
125: page_mask = page_size - 1;
126:
127: if ((page_mask & page_size) != 0)
128: panic("vm_set_page_size: page size not a power of two");
129:
130: for (page_shift = 0; ; page_shift++)
131: if ((1 << page_shift) == page_size)
132: break;
133: }
134:
135:
136: /*
137: * vm_page_startup:
138: *
139: * Initializes the resident memory module.
140: *
141: * Allocates memory for the page cells, and
142: * for the object/offset-to-page hash table headers.
143: * Each page cell is initialized and placed on the free list.
144: */
145: vm_offset_t vm_page_startup(start, end, vaddr)
146: register vm_offset_t start;
147: vm_offset_t end;
148: register vm_offset_t vaddr;
149: {
150: register vm_offset_t mapped;
151: register vm_page_t m;
152: register queue_t bucket;
153: vm_size_t npages;
154: register vm_offset_t new_start;
155: int i;
156: vm_offset_t pa;
157:
158: extern vm_offset_t kentry_data;
159: extern vm_size_t kentry_data_size;
160:
161:
162: /*
163: * Initialize the locks
164: */
165:
166: simple_lock_init(&vm_page_queue_free_lock);
167: simple_lock_init(&vm_page_queue_lock);
168:
169: /*
170: * Initialize the queue headers for the free queue,
171: * the active queue and the inactive queue.
172: */
173:
174: queue_init(&vm_page_queue_free);
175: queue_init(&vm_page_queue_active);
176: queue_init(&vm_page_queue_inactive);
177:
178: /*
179: * Allocate (and initialize) the hash table buckets.
180: *
181: * The number of buckets MUST BE a power of 2, and
182: * the actual value is the next power of 2 greater
183: * than the number of physical pages in the system.
184: *
185: * Note:
186: * This computation can be tweaked if desired.
187: */
188:
189: vm_page_buckets = (queue_t) vaddr;
190: bucket = vm_page_buckets;
191: if (vm_page_bucket_count == 0) {
192: vm_page_bucket_count = 1;
193: while (vm_page_bucket_count < atop(end - start))
194: vm_page_bucket_count <<= 1;
195: }
196:
197: vm_page_hash_mask = vm_page_bucket_count - 1;
198:
199: /*
200: * Validate these addresses.
201: */
202:
203: new_start = round_page(((queue_t)start) + vm_page_bucket_count);
204: mapped = vaddr;
205: vaddr = pmap_map(mapped, start, new_start,
206: VM_PROT_READ|VM_PROT_WRITE);
207: start = new_start;
1.1.1.2 root 208: bzero((caddr_t) mapped, vaddr - mapped);
1.1 root 209: mapped = vaddr;
210:
211: for (i = vm_page_bucket_count; i--;) {
212: queue_init(bucket);
213: bucket++;
214: }
215:
216: simple_lock_init(&bucket_lock);
217:
218: /*
219: * round (or truncate) the addresses to our page size.
220: */
221:
222: end = trunc_page(end);
223:
224: /*
225: * Pre-allocate maps and map entries that cannot be dynamically
226: * allocated via malloc(). The maps include the kernel_map and
227: * kmem_map which must be initialized before malloc() will
228: * work (obviously). Also could include pager maps which would
229: * be allocated before kmeminit.
230: *
231: * Allow some kernel map entries... this should be plenty
232: * since people shouldn't be cluttering up the kernel
233: * map (they should use their own maps).
234: */
235:
236: kentry_data_size = MAX_KMAP * sizeof(struct vm_map) +
237: MAX_KMAPENT * sizeof(struct vm_map_entry);
238: kentry_data_size = round_page(kentry_data_size);
239: kentry_data = (vm_offset_t) vaddr;
240: vaddr += kentry_data_size;
241:
242: /*
243: * Validate these zone addresses.
244: */
245:
246: new_start = start + (vaddr - mapped);
247: pmap_map(mapped, start, new_start, VM_PROT_READ|VM_PROT_WRITE);
1.1.1.2 root 248: bzero((caddr_t) mapped, (vaddr - mapped));
1.1 root 249: mapped = vaddr;
250: start = new_start;
251:
252: /*
253: * Compute the number of pages of memory that will be
254: * available for use (taking into account the overhead
255: * of a page structure per page).
256: */
257:
258: vm_page_free_count = npages =
1.1.1.4 ! root 259: (end - start + sizeof(struct vm_page))/(PAGE_SIZE + sizeof(struct vm_page));
1.1 root 260:
261: /*
262: * Initialize the mem entry structures now, and
263: * put them in the free queue.
264: */
265:
266: m = vm_page_array = (vm_page_t) vaddr;
267: first_page = start;
268: first_page += npages*sizeof(struct vm_page);
269: first_page = atop(round_page(first_page));
270: last_page = first_page + npages - 1;
271:
272: first_phys_addr = ptoa(first_page);
273: last_phys_addr = ptoa(last_page) + page_mask;
274:
275: /*
276: * Validate these addresses.
277: */
278:
279: new_start = start + (round_page(m + npages) - mapped);
280: mapped = pmap_map(mapped, start, new_start,
281: VM_PROT_READ|VM_PROT_WRITE);
282: start = new_start;
283:
284: /*
285: * Clear all of the page structures
286: */
1.1.1.2 root 287: bzero((caddr_t)m, npages * sizeof(*m));
1.1 root 288:
289: pa = first_phys_addr;
290: while (npages--) {
291: m->copy_on_write = FALSE;
292: m->wanted = FALSE;
293: m->inactive = FALSE;
294: m->active = FALSE;
295: m->busy = FALSE;
296: m->object = NULL;
297: m->phys_addr = pa;
298: queue_enter(&vm_page_queue_free, m, vm_page_t, pageq);
299: m++;
300: pa += PAGE_SIZE;
301: }
302:
303: /*
304: * Initialize vm_pages_needed lock here - don't wait for pageout
305: * daemon XXX
306: */
307: simple_lock_init(&vm_pages_needed_lock);
308:
309: return(mapped);
310: }
311:
312: /*
313: * vm_page_hash:
314: *
315: * Distributes the object/offset key pair among hash buckets.
316: *
317: * NOTE: This macro depends on vm_page_bucket_count being a power of 2.
318: */
319: #define vm_page_hash(object, offset) \
320: (((unsigned)object+(unsigned)atop(offset))&vm_page_hash_mask)
321:
322: /*
323: * vm_page_insert: [ internal use only ]
324: *
325: * Inserts the given mem entry into the object/object-page
326: * table and object list.
327: *
328: * The object and page must be locked.
329: */
330:
331: void vm_page_insert(mem, object, offset)
332: register vm_page_t mem;
333: register vm_object_t object;
334: register vm_offset_t offset;
335: {
336: register queue_t bucket;
337: int spl;
338:
339: VM_PAGE_CHECK(mem);
340:
341: if (mem->tabled)
342: panic("vm_page_insert: already inserted");
343:
344: /*
345: * Record the object/offset pair in this page
346: */
347:
348: mem->object = object;
349: mem->offset = offset;
350:
351: /*
352: * Insert it into the object_object/offset hash table
353: */
354:
355: bucket = &vm_page_buckets[vm_page_hash(object, offset)];
356: spl = splimp();
357: simple_lock(&bucket_lock);
358: queue_enter(bucket, mem, vm_page_t, hashq);
359: simple_unlock(&bucket_lock);
360: (void) splx(spl);
361:
362: /*
363: * Now link into the object's list of backed pages.
364: */
365:
366: queue_enter(&object->memq, mem, vm_page_t, listq);
367: mem->tabled = TRUE;
368:
369: /*
370: * And show that the object has one more resident
371: * page.
372: */
373:
374: object->resident_page_count++;
375: }
376:
377: /*
378: * vm_page_remove: [ internal use only ]
379: *
380: * Removes the given mem entry from the object/offset-page
381: * table and the object page list.
382: *
383: * The object and page must be locked.
384: */
385:
386: void vm_page_remove(mem)
387: register vm_page_t mem;
388: {
389: register queue_t bucket;
390: int spl;
391:
392: VM_PAGE_CHECK(mem);
393:
394: if (!mem->tabled)
395: return;
396:
397: /*
398: * Remove from the object_object/offset hash table
399: */
400:
401: bucket = &vm_page_buckets[vm_page_hash(mem->object, mem->offset)];
402: spl = splimp();
403: simple_lock(&bucket_lock);
404: queue_remove(bucket, mem, vm_page_t, hashq);
405: simple_unlock(&bucket_lock);
406: (void) splx(spl);
407:
408: /*
409: * Now remove from the object's list of backed pages.
410: */
411:
412: queue_remove(&mem->object->memq, mem, vm_page_t, listq);
413:
414: /*
415: * And show that the object has one fewer resident
416: * page.
417: */
418:
419: mem->object->resident_page_count--;
420:
421: mem->tabled = FALSE;
422: }
423:
424: /*
425: * vm_page_lookup:
426: *
427: * Returns the page associated with the object/offset
428: * pair specified; if none is found, NULL is returned.
429: *
430: * The object must be locked. No side effects.
431: */
432:
433: vm_page_t vm_page_lookup(object, offset)
434: register vm_object_t object;
435: register vm_offset_t offset;
436: {
437: register vm_page_t mem;
438: register queue_t bucket;
439: int spl;
440:
441: /*
442: * Search the hash table for this object/offset pair
443: */
444:
445: bucket = &vm_page_buckets[vm_page_hash(object, offset)];
446:
447: spl = splimp();
448: simple_lock(&bucket_lock);
449: mem = (vm_page_t) queue_first(bucket);
450: while (!queue_end(bucket, (queue_entry_t) mem)) {
451: VM_PAGE_CHECK(mem);
452: if ((mem->object == object) && (mem->offset == offset)) {
453: simple_unlock(&bucket_lock);
454: splx(spl);
455: return(mem);
456: }
457: mem = (vm_page_t) queue_next(&mem->hashq);
458: }
459:
460: simple_unlock(&bucket_lock);
461: splx(spl);
462: return(NULL);
463: }
464:
465: /*
466: * vm_page_rename:
467: *
468: * Move the given memory entry from its
469: * current object to the specified target object/offset.
470: *
471: * The object must be locked.
472: */
473: void vm_page_rename(mem, new_object, new_offset)
474: register vm_page_t mem;
475: register vm_object_t new_object;
476: vm_offset_t new_offset;
477: {
478: if (mem->object == new_object)
479: return;
480:
481: vm_page_lock_queues(); /* keep page from moving out from
482: under pageout daemon */
483: vm_page_remove(mem);
484: vm_page_insert(mem, new_object, new_offset);
485: vm_page_unlock_queues();
486: }
487:
488: void vm_page_init(mem, object, offset)
489: vm_page_t mem;
490: vm_object_t object;
491: vm_offset_t offset;
492: {
493: #ifdef DEBUG
494: #define vm_page_init(mem, object, offset) {\
495: (mem)->busy = TRUE; \
496: (mem)->tabled = FALSE; \
497: vm_page_insert((mem), (object), (offset)); \
498: (mem)->absent = FALSE; \
499: (mem)->fictitious = FALSE; \
500: (mem)->page_lock = VM_PROT_NONE; \
501: (mem)->unlock_request = VM_PROT_NONE; \
502: (mem)->laundry = FALSE; \
503: (mem)->active = FALSE; \
504: (mem)->inactive = FALSE; \
505: (mem)->wire_count = 0; \
506: (mem)->clean = TRUE; \
507: (mem)->copy_on_write = FALSE; \
508: (mem)->fake = TRUE; \
509: (mem)->pagerowned = FALSE; \
510: (mem)->ptpage = FALSE; \
511: }
512: #else
513: #define vm_page_init(mem, object, offset) {\
514: (mem)->busy = TRUE; \
515: (mem)->tabled = FALSE; \
516: vm_page_insert((mem), (object), (offset)); \
517: (mem)->absent = FALSE; \
518: (mem)->fictitious = FALSE; \
519: (mem)->page_lock = VM_PROT_NONE; \
520: (mem)->unlock_request = VM_PROT_NONE; \
521: (mem)->laundry = FALSE; \
522: (mem)->active = FALSE; \
523: (mem)->inactive = FALSE; \
524: (mem)->wire_count = 0; \
525: (mem)->clean = TRUE; \
526: (mem)->copy_on_write = FALSE; \
527: (mem)->fake = TRUE; \
528: }
529: #endif
530:
531: vm_page_init(mem, object, offset);
532: }
533:
534: /*
535: * vm_page_alloc:
536: *
537: * Allocate and return a memory cell associated
538: * with this VM object/offset pair.
539: *
540: * Object must be locked.
541: */
542: vm_page_t vm_page_alloc(object, offset)
543: vm_object_t object;
544: vm_offset_t offset;
545: {
546: register vm_page_t mem;
547: int spl;
548:
549: spl = splimp(); /* XXX */
550: simple_lock(&vm_page_queue_free_lock);
1.1.1.4 ! root 551: if ( object != kernel_object &&
! 552: object != kmem_object &&
! 553: vm_page_free_count <= vm_page_free_reserved) {
! 554:
! 555: simple_unlock(&vm_page_queue_free_lock);
! 556: splx(spl);
! 557: return(NULL);
! 558: }
1.1 root 559: if (queue_empty(&vm_page_queue_free)) {
560: simple_unlock(&vm_page_queue_free_lock);
561: splx(spl);
562: return(NULL);
563: }
564:
565: queue_remove_first(&vm_page_queue_free, mem, vm_page_t, pageq);
566:
567: vm_page_free_count--;
568: simple_unlock(&vm_page_queue_free_lock);
569: splx(spl);
570:
571: vm_page_init(mem, object, offset);
572:
573: /*
574: * Decide if we should poke the pageout daemon.
575: * We do this if the free count is less than the low
576: * water mark, or if the free count is less than the high
577: * water mark (but above the low water mark) and the inactive
578: * count is less than its target.
579: *
580: * We don't have the counts locked ... if they change a little,
581: * it doesn't really matter.
582: */
583:
584: if ((vm_page_free_count < vm_page_free_min) ||
585: ((vm_page_free_count < vm_page_free_target) &&
586: (vm_page_inactive_count < vm_page_inactive_target)))
587: thread_wakeup(&vm_pages_needed);
588: return(mem);
589: }
590:
591: /*
592: * vm_page_free:
593: *
594: * Returns the given page to the free list,
595: * disassociating it with any VM object.
596: *
597: * Object and page must be locked prior to entry.
598: */
599: void vm_page_free(mem)
600: register vm_page_t mem;
601: {
602: vm_page_remove(mem);
603: if (mem->active) {
604: queue_remove(&vm_page_queue_active, mem, vm_page_t, pageq);
605: mem->active = FALSE;
606: vm_page_active_count--;
607: }
608:
609: if (mem->inactive) {
610: queue_remove(&vm_page_queue_inactive, mem, vm_page_t, pageq);
611: mem->inactive = FALSE;
612: vm_page_inactive_count--;
613: }
614:
615: if (!mem->fictitious) {
616: int spl;
617:
618: spl = splimp();
619: simple_lock(&vm_page_queue_free_lock);
620: queue_enter(&vm_page_queue_free, mem, vm_page_t, pageq);
621:
622: vm_page_free_count++;
623: simple_unlock(&vm_page_queue_free_lock);
624: splx(spl);
625: }
626: }
627:
628: /*
629: * vm_page_wire:
630: *
631: * Mark this page as wired down by yet
632: * another map, removing it from paging queues
633: * as necessary.
634: *
635: * The page queues must be locked.
636: */
637: void vm_page_wire(mem)
638: register vm_page_t mem;
639: {
640: VM_PAGE_CHECK(mem);
641:
642: if (mem->wire_count == 0) {
643: if (mem->active) {
644: queue_remove(&vm_page_queue_active, mem, vm_page_t,
645: pageq);
646: vm_page_active_count--;
647: mem->active = FALSE;
648: }
649: if (mem->inactive) {
650: queue_remove(&vm_page_queue_inactive, mem, vm_page_t,
651: pageq);
652: vm_page_inactive_count--;
653: mem->inactive = FALSE;
654: }
655: vm_page_wire_count++;
656: }
657: mem->wire_count++;
658: }
659:
660: /*
661: * vm_page_unwire:
662: *
663: * Release one wiring of this page, potentially
664: * enabling it to be paged again.
665: *
666: * The page queues must be locked.
667: */
668: void vm_page_unwire(mem)
669: register vm_page_t mem;
670: {
671: VM_PAGE_CHECK(mem);
672:
673: mem->wire_count--;
674: if (mem->wire_count == 0) {
675: queue_enter(&vm_page_queue_active, mem, vm_page_t, pageq);
676: vm_page_active_count++;
677: mem->active = TRUE;
678: vm_page_wire_count--;
679: }
680: }
681:
682: /*
683: * vm_page_deactivate:
684: *
685: * Returns the given page to the inactive list,
686: * indicating that no physical maps have access
687: * to this page. [Used by the physical mapping system.]
688: *
689: * The page queues must be locked.
690: */
691: void vm_page_deactivate(m)
692: register vm_page_t m;
693: {
694: VM_PAGE_CHECK(m);
695:
696: /*
697: * Only move active pages -- ignore locked or already
698: * inactive ones.
1.1.1.3 root 699: *
700: * XXX: sometimes we get pages which aren't wired down
701: * or on any queue - we need to put them on the inactive
702: * queue also, otherwise we lose track of them.
703: * Paul Mackerras ([email protected]) 9-Jan-93.
1.1 root 704: */
705:
1.1.1.3 root 706: if (!m->inactive && m->wire_count == 0) {
1.1 root 707: pmap_clear_reference(VM_PAGE_TO_PHYS(m));
1.1.1.3 root 708: if (m->active) {
709: queue_remove(&vm_page_queue_active, m, vm_page_t, pageq);
710: m->active = FALSE;
711: vm_page_active_count--;
712: }
1.1 root 713: queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq);
714: m->inactive = TRUE;
715: vm_page_inactive_count++;
716: if (pmap_is_modified(VM_PAGE_TO_PHYS(m)))
717: m->clean = FALSE;
718: m->laundry = !m->clean;
719: }
720: }
721:
722: /*
723: * vm_page_activate:
724: *
725: * Put the specified page on the active list (if appropriate).
726: *
727: * The page queues must be locked.
728: */
729:
730: void vm_page_activate(m)
731: register vm_page_t m;
732: {
733: VM_PAGE_CHECK(m);
734:
735: if (m->inactive) {
736: queue_remove(&vm_page_queue_inactive, m, vm_page_t,
737: pageq);
738: vm_page_inactive_count--;
739: m->inactive = FALSE;
740: }
741: if (m->wire_count == 0) {
742: if (m->active)
743: panic("vm_page_activate: already active");
744:
745: queue_enter(&vm_page_queue_active, m, vm_page_t, pageq);
746: m->active = TRUE;
747: vm_page_active_count++;
748: }
749: }
750:
751: /*
752: * vm_page_zero_fill:
753: *
754: * Zero-fill the specified page.
755: * Written as a standard pagein routine, to
756: * be used by the zero-fill object.
757: */
758:
759: boolean_t vm_page_zero_fill(m)
760: vm_page_t m;
761: {
762: VM_PAGE_CHECK(m);
763:
764: pmap_zero_page(VM_PAGE_TO_PHYS(m));
765: return(TRUE);
766: }
767:
768: /*
769: * vm_page_copy:
770: *
771: * Copy one page to another
772: */
773:
774: void vm_page_copy(src_m, dest_m)
775: vm_page_t src_m;
776: vm_page_t dest_m;
777: {
778: VM_PAGE_CHECK(src_m);
779: VM_PAGE_CHECK(dest_m);
780:
781: pmap_copy_page(VM_PAGE_TO_PHYS(src_m), VM_PAGE_TO_PHYS(dest_m));
782: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.