|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1993-1988 Carnegie Mellon University
4: * All Rights Reserved.
5: *
6: * Permission to use, copy, modify and distribute this software and its
7: * documentation is hereby granted, provided that both the copyright
8: * notice and this permission notice appear in all copies of the
9: * software, derivative works or modified versions, and any portions
10: * thereof, and that both notices appear in supporting documentation.
11: *
12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15: *
16: * Carnegie Mellon requests users of this software to return to
17: *
18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
22: *
23: * any improvements or extensions that they make and grant Carnegie Mellon
24: * the rights to redistribute these changes.
25: */
26: /*
27: * File: vm/vm_page.h
28: * Author: Avadis Tevanian, Jr., Michael Wayne Young
29: * Date: 1985
30: *
31: * Resident memory system definitions.
32: */
33:
34: #ifndef _VM_VM_PAGE_H_
35: #define _VM_VM_PAGE_H_
36:
37: #include <mach/boolean.h>
38: #include <mach/vm_prot.h>
1.1.1.6 ! root 39: #include <machine/vm_param.h>
1.1 root 40: #include <vm/vm_object.h>
1.1.1.3 root 41: #include <vm/vm_types.h>
1.1 root 42: #include <kern/queue.h>
43: #include <kern/lock.h>
1.1.1.6 ! root 44: #include <kern/log2.h>
1.1 root 45:
1.1.1.5 root 46: #include <kern/macros.h>
1.1 root 47: #include <kern/sched_prim.h> /* definitions of wait/wakeup */
48:
49: #if MACH_VM_DEBUG
50: #include <mach_debug/hash_info.h>
51: #endif
52:
53: /*
54: * Management of resident (logical) pages.
55: *
56: * A small structure is kept for each resident
57: * page, indexed by page number. Each structure
58: * is an element of several lists:
59: *
60: * A hash table bucket used to quickly
61: * perform object/offset lookups
62: *
63: * A list of all pages for a given object,
64: * so they can be quickly deactivated at
65: * time of deallocation.
66: *
67: * An ordered list of pages due for pageout.
68: *
69: * In addition, the structure contains the object
70: * and offset to which this page belongs (for pageout),
71: * and sundry status bits.
72: *
73: * Fields in this structure are locked either by the lock on the
74: * object that the page belongs to (O) or by the lock on the page
75: * queues (P). [Some fields require that both locks be held to
76: * change that field; holding either lock is sufficient to read.]
77: */
78:
79: struct vm_page {
1.1.1.6 ! root 80: /* Members used in the vm_page module only */
! 81: struct list node;
! 82: unsigned short type;
! 83: unsigned short seg_index;
! 84: unsigned short order;
! 85: void *priv;
! 86:
! 87: /*
! 88: * This member is used throughout the code and may only change for
! 89: * fictitious pages.
! 90: */
! 91: phys_addr_t phys_addr;
! 92:
! 93: /* We use an empty struct as the delimiter. */
! 94: struct {} vm_page_header;
! 95: #define VM_PAGE_HEADER_SIZE offsetof(struct vm_page, vm_page_header)
! 96:
1.1 root 97: queue_chain_t pageq; /* queue info for FIFO
98: * queue or free list (P) */
99: queue_chain_t listq; /* all pages in same object (O) */
100: struct vm_page *next; /* VP bucket link (O) */
101:
102: vm_object_t object; /* which object am I in (O,P) */
103: vm_offset_t offset; /* offset into that object (O,P) */
104:
1.1.1.4 root 105: unsigned int wire_count:15, /* how many wired down maps use me?
1.1 root 106: (O&P) */
107: /* boolean_t */ inactive:1, /* page is in inactive list (P) */
108: active:1, /* page is in active list (P) */
109: laundry:1, /* page is being cleaned now (P)*/
110: free:1, /* page is on free list (P) */
111: reference:1, /* page has been used (P) */
1.1.1.2 root 112: external:1, /* page considered external (P) */
1.1.1.4 root 113: extcounted:1, /* page counted in ext counts (P) */
114: busy:1, /* page is in transit (O) */
1.1 root 115: wanted:1, /* someone is waiting for page (O) */
116: tabled:1, /* page is in VP table (O) */
117: fictitious:1, /* Physical page doesn't exist (O) */
118: private:1, /* Page should not be returned to
119: * the free list (O) */
120: absent:1, /* Data has been requested, but is
121: * not yet available (O) */
122: error:1, /* Data manager was unable to provide
123: * data due to error (O) */
124: dirty:1, /* Page must be cleaned (O) */
125: precious:1, /* Page is precious; data must be
126: * returned even if clean (O) */
1.1.1.4 root 127: overwriting:1; /* Request to unlock has been made
1.1 root 128: * without having data. (O)
129: * [See vm_object_overwrite] */
130:
131: vm_prot_t page_lock; /* Uses prohibited by data manager (O) */
132: vm_prot_t unlock_request; /* Outstanding unlock request (O) */
133: };
134:
135: /*
136: * For debugging, this macro can be defined to perform
137: * some useful check on a page structure.
138: */
139:
140: #define VM_PAGE_CHECK(mem)
141:
142: /*
143: * Each pageable resident page falls into one of three lists:
144: *
145: * free
146: * Available for allocation now.
147: * inactive
148: * Not referenced in any map, but still has an
149: * object/offset-page mapping, and may be dirty.
150: * This is the list of pages that should be
151: * paged out next.
152: * active
153: * A list of pages which have been placed in
154: * at least one physical map. This list is
155: * ordered, in LRU-like fashion.
156: */
157:
158: extern
159: vm_page_t vm_page_queue_fictitious; /* fictitious free queue */
160: extern
161: queue_head_t vm_page_queue_active; /* active memory queue */
162: extern
163: queue_head_t vm_page_queue_inactive; /* inactive memory queue */
164:
165: extern
166: int vm_page_fictitious_count;/* How many fictitious pages are free? */
167: extern
168: int vm_page_active_count; /* How many pages are active? */
169: extern
170: int vm_page_inactive_count; /* How many pages are inactive? */
171: extern
172: int vm_page_wire_count; /* How many pages are wired? */
173: extern
174: int vm_page_free_target; /* How many do we want free? */
175: extern
176: int vm_page_free_min; /* When to wakeup pageout */
177: extern
178: int vm_page_inactive_target;/* How many do we want inactive? */
179: extern
180: int vm_page_free_reserved; /* How many pages reserved to do pageout */
181: extern
182: int vm_page_laundry_count; /* How many pages being laundered? */
1.1.1.2 root 183: extern
184: int vm_page_external_limit; /* Max number of pages for external objects */
185:
186: /* Only objects marked with the extcounted bit are included in this total.
187: Pages which we scan for possible pageout, but which are not actually
188: dirty, don't get considered against the external page limits any more
189: in this way. */
190: extern
191: int vm_page_external_count; /* How many pages for external objects? */
192:
193:
1.1 root 194:
195: decl_simple_lock_data(extern,vm_page_queue_lock)/* lock on active and inactive
196: page queues */
197: decl_simple_lock_data(extern,vm_page_queue_free_lock)
198: /* lock on free page queue */
199:
200: extern unsigned int vm_page_free_wanted;
201: /* how many threads are waiting for memory */
202:
203: extern vm_offset_t vm_page_fictitious_addr;
204: /* (fake) phys_addr of fictitious pages */
205:
206: extern void vm_page_bootstrap(
207: vm_offset_t *startp,
208: vm_offset_t *endp);
209: extern void vm_page_module_init(void);
210:
211: extern vm_page_t vm_page_lookup(
212: vm_object_t object,
213: vm_offset_t offset);
214: extern vm_page_t vm_page_grab_fictitious(void);
1.1.1.6 ! root 215: extern boolean_t vm_page_convert(vm_page_t *, boolean_t);
1.1 root 216: extern void vm_page_more_fictitious(void);
1.1.1.2 root 217: extern vm_page_t vm_page_grab(boolean_t);
1.1.1.6 ! root 218: extern vm_page_t vm_page_grab_contig(vm_size_t, unsigned int);
! 219: extern void vm_page_free_contig(vm_page_t, vm_size_t);
1.1 root 220: extern void vm_page_wait(void (*)(void));
221: extern vm_page_t vm_page_alloc(
222: vm_object_t object,
223: vm_offset_t offset);
224: extern void vm_page_init(
1.1.1.6 ! root 225: vm_page_t mem);
1.1 root 226: extern void vm_page_free(vm_page_t);
227: extern void vm_page_activate(vm_page_t);
228: extern void vm_page_deactivate(vm_page_t);
229: extern void vm_page_rename(
230: vm_page_t mem,
231: vm_object_t new_object,
232: vm_offset_t new_offset);
233: extern void vm_page_insert(
234: vm_page_t mem,
235: vm_object_t object,
236: vm_offset_t offset);
237: extern void vm_page_remove(
238: vm_page_t mem);
239:
240: extern void vm_page_zero_fill(vm_page_t);
241: extern void vm_page_copy(vm_page_t src_m, vm_page_t dest_m);
242:
243: extern void vm_page_wire(vm_page_t);
244: extern void vm_page_unwire(vm_page_t);
245:
246: #if MACH_VM_DEBUG
247: extern unsigned int vm_page_info(
248: hash_info_bucket_t *info,
249: unsigned int count);
250: #endif
251:
252: /*
253: * Functions implemented as macros
254: */
255:
256: #define PAGE_ASSERT_WAIT(m, interruptible) \
257: MACRO_BEGIN \
258: (m)->wanted = TRUE; \
259: assert_wait((event_t) (m), (interruptible)); \
260: MACRO_END
261:
262: #define PAGE_WAKEUP_DONE(m) \
263: MACRO_BEGIN \
264: (m)->busy = FALSE; \
265: if ((m)->wanted) { \
266: (m)->wanted = FALSE; \
267: thread_wakeup(((event_t) m)); \
268: } \
269: MACRO_END
270:
271: #define PAGE_WAKEUP(m) \
272: MACRO_BEGIN \
273: if ((m)->wanted) { \
274: (m)->wanted = FALSE; \
275: thread_wakeup((event_t) (m)); \
276: } \
277: MACRO_END
278:
279: #define VM_PAGE_FREE(p) \
280: MACRO_BEGIN \
281: vm_page_lock_queues(); \
282: vm_page_free(p); \
283: vm_page_unlock_queues(); \
284: MACRO_END
285:
286: /*
287: * Macro to be used in place of pmap_enter()
288: */
289:
290: #define PMAP_ENTER(pmap, virtual_address, page, protection, wired) \
291: MACRO_BEGIN \
292: pmap_enter( \
293: (pmap), \
294: (virtual_address), \
295: (page)->phys_addr, \
296: (protection) & ~(page)->page_lock, \
297: (wired) \
298: ); \
299: MACRO_END
300:
301: #define VM_PAGE_WAIT(continuation) vm_page_wait(continuation)
302:
303: #define vm_page_lock_queues() simple_lock(&vm_page_queue_lock)
304: #define vm_page_unlock_queues() simple_unlock(&vm_page_queue_lock)
305:
306: #define VM_PAGE_QUEUES_REMOVE(mem) \
307: MACRO_BEGIN \
308: if (mem->active) { \
309: queue_remove(&vm_page_queue_active, \
310: mem, vm_page_t, pageq); \
311: mem->active = FALSE; \
312: vm_page_active_count--; \
313: } \
314: \
315: if (mem->inactive) { \
316: queue_remove(&vm_page_queue_inactive, \
317: mem, vm_page_t, pageq); \
318: mem->inactive = FALSE; \
319: vm_page_inactive_count--; \
320: } \
321: MACRO_END
322:
1.1.1.6 ! root 323: /*
! 324: * Copyright (c) 2010-2014 Richard Braun.
! 325: *
! 326: * This program is free software: you can redistribute it and/or modify
! 327: * it under the terms of the GNU General Public License as published by
! 328: * the Free Software Foundation, either version 2 of the License, or
! 329: * (at your option) any later version.
! 330: *
! 331: * This program is distributed in the hope that it will be useful,
! 332: * but WITHOUT ANY WARRANTY; without even the implied warranty of
! 333: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 334: * GNU General Public License for more details.
! 335: *
! 336: * You should have received a copy of the GNU General Public License
! 337: * along with this program. If not, see <http://www.gnu.org/licenses/>.
! 338: *
! 339: *
! 340: * Physical page management.
! 341: */
! 342:
! 343: /*
! 344: * Address/page conversion and rounding macros (not inline functions to
! 345: * be easily usable on both virtual and physical addresses, which may not
! 346: * have the same type size).
! 347: */
! 348: #define vm_page_atop(addr) ((addr) >> PAGE_SHIFT)
! 349: #define vm_page_ptoa(page) ((page) << PAGE_SHIFT)
! 350: #define vm_page_trunc(addr) P2ALIGN(addr, PAGE_SIZE)
! 351: #define vm_page_round(addr) P2ROUND(addr, PAGE_SIZE)
! 352: #define vm_page_aligned(addr) P2ALIGNED(addr, PAGE_SIZE)
! 353:
! 354: /*
! 355: * Segment selectors.
! 356: *
! 357: * Selector-to-segment-list translation table :
! 358: * DMA DMA
! 359: * DMA32 DMA32 DMA
! 360: * DIRECTMAP DIRECTMAP DMA32 DMA
! 361: * HIGHMEM HIGHMEM DIRECTMAP DMA32 DMA
! 362: */
! 363: #define VM_PAGE_SEL_DMA 0
! 364: #define VM_PAGE_SEL_DMA32 1
! 365: #define VM_PAGE_SEL_DIRECTMAP 2
! 366: #define VM_PAGE_SEL_HIGHMEM 3
! 367:
! 368: /*
! 369: * Page usage types.
! 370: *
! 371: * Failing to allocate pmap pages will cause a kernel panic.
! 372: * TODO Obviously, this needs to be addressed, e.g. with a reserved pool of
! 373: * pages.
! 374: */
! 375: #define VM_PT_FREE 0 /* Page unused */
! 376: #define VM_PT_RESERVED 1 /* Page reserved at boot time */
! 377: #define VM_PT_TABLE 2 /* Page is part of the page table */
! 378: #define VM_PT_PMAP 3 /* Page stores pmap-specific data */
! 379: #define VM_PT_KMEM 4 /* Page is part of a kmem slab */
! 380: #define VM_PT_STACK 5 /* Type for generic kernel allocations */
! 381: #define VM_PT_KERNEL 6 /* Type for generic kernel allocations */
! 382:
! 383: static inline unsigned short
! 384: vm_page_type(const struct vm_page *page)
! 385: {
! 386: return page->type;
! 387: }
! 388:
! 389: void vm_page_set_type(struct vm_page *page, unsigned int order,
! 390: unsigned short type);
! 391:
! 392: static inline unsigned int
! 393: vm_page_order(size_t size)
! 394: {
! 395: return iorder2(vm_page_atop(vm_page_round(size)));
! 396: }
! 397:
! 398: static inline phys_addr_t
! 399: vm_page_to_pa(const struct vm_page *page)
! 400: {
! 401: return page->phys_addr;
! 402: }
! 403:
! 404: #if 0
! 405: static inline unsigned long
! 406: vm_page_direct_va(phys_addr_t pa)
! 407: {
! 408: assert(pa < VM_PAGE_DIRECTMAP_LIMIT);
! 409: return ((unsigned long)pa + VM_MIN_DIRECTMAP_ADDRESS);
! 410: }
! 411:
! 412: static inline phys_addr_t
! 413: vm_page_direct_pa(unsigned long va)
! 414: {
! 415: assert(va >= VM_MIN_DIRECTMAP_ADDRESS);
! 416: assert(va < VM_MAX_DIRECTMAP_ADDRESS);
! 417: return (va - VM_MIN_DIRECTMAP_ADDRESS);
! 418: }
! 419:
! 420: static inline void *
! 421: vm_page_direct_ptr(const struct vm_page *page)
! 422: {
! 423: return (void *)vm_page_direct_va(vm_page_to_pa(page));
! 424: }
! 425: #endif
! 426:
! 427: /*
! 428: * Associate private data with a page.
! 429: */
! 430: static inline void
! 431: vm_page_set_priv(struct vm_page *page, void *priv)
! 432: {
! 433: page->priv = priv;
! 434: }
! 435:
! 436: static inline void *
! 437: vm_page_get_priv(const struct vm_page *page)
! 438: {
! 439: return page->priv;
! 440: }
! 441:
! 442: /*
! 443: * Load physical memory into the vm_page module at boot time.
! 444: *
! 445: * The avail_start and avail_end parameters are used to maintain a simple
! 446: * heap for bootstrap allocations.
! 447: *
! 448: * All addresses must be page-aligned. Segments can be loaded in any order.
! 449: */
! 450: void vm_page_load(unsigned int seg_index, phys_addr_t start, phys_addr_t end,
! 451: phys_addr_t avail_start, phys_addr_t avail_end);
! 452:
! 453: /*
! 454: * Return true if the vm_page module is completely initialized, false
! 455: * otherwise, in which case only vm_page_bootalloc() can be used for
! 456: * allocations.
! 457: */
! 458: int vm_page_ready(void);
! 459:
! 460: /*
! 461: * Early allocation function.
! 462: *
! 463: * This function is used by the vm_resident module to implement
! 464: * pmap_steal_memory. It can be used after physical segments have been loaded
! 465: * and before the vm_page module is initialized.
! 466: */
! 467: unsigned long vm_page_bootalloc(size_t size);
! 468:
! 469: /*
! 470: * Set up the vm_page module.
! 471: *
! 472: * Architecture-specific code must have loaded segments before calling this
! 473: * function. Segments must comply with the selector-to-segment-list table,
! 474: * e.g. HIGHMEM is loaded if and only if DIRECTMAP, DMA32 and DMA are loaded,
! 475: * notwithstanding segment aliasing.
! 476: *
! 477: * Once this function returns, the vm_page module is ready, and normal
! 478: * allocation functions can be used.
! 479: */
! 480: void vm_page_setup(void);
! 481:
! 482: /*
! 483: * Make the given page managed by the vm_page module.
! 484: *
! 485: * If additional memory can be made usable after the VM system is initialized,
! 486: * it should be reported through this function.
! 487: */
! 488: void vm_page_manage(struct vm_page *page);
! 489:
! 490: /*
! 491: * Return the page descriptor for the given physical address.
! 492: */
! 493: struct vm_page * vm_page_lookup_pa(phys_addr_t pa);
! 494:
! 495: /*
! 496: * Allocate a block of 2^order physical pages.
! 497: *
! 498: * The selector is used to determine the segments from which allocation can
! 499: * be attempted.
! 500: *
! 501: * This function should only be used by the vm_resident module.
! 502: */
! 503: struct vm_page * vm_page_alloc_pa(unsigned int order, unsigned int selector,
! 504: unsigned short type);
! 505:
! 506: /*
! 507: * Release a block of 2^order physical pages.
! 508: *
! 509: * This function should only be used by the vm_resident module.
! 510: */
! 511: void vm_page_free_pa(struct vm_page *page, unsigned int order);
! 512:
! 513: /*
! 514: * Return the name of the given segment.
! 515: */
! 516: const char * vm_page_seg_name(unsigned int seg_index);
! 517:
! 518: /*
! 519: * Display internal information about the module.
! 520: */
! 521: void vm_page_info_all(void);
! 522:
! 523: /*
! 524: * Return the total amount of physical memory.
! 525: */
! 526: phys_addr_t vm_page_mem_size(void);
! 527:
! 528: /*
! 529: * Return the amount of free (unused) pages.
! 530: *
! 531: * XXX This currently relies on the kernel being non preemptible and
! 532: * uniprocessor.
! 533: */
! 534: unsigned long vm_page_mem_free(void);
! 535:
1.1 root 536: #endif /* _VM_VM_PAGE_H_ */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.