/* * Mach Operating System * Copyright (c) 1993-1988 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 Mellon * the rights to redistribute these changes. */ /* * File: vm/vm_page.h * Author: Avadis Tevanian, Jr., Michael Wayne Young * Date: 1985 * * Resident memory system definitions. */ #ifndef _VM_VM_PAGE_H_ #define _VM_VM_PAGE_H_ #include #include #include #include #include #include #include #include #include #include #include /* definitions of wait/wakeup */ #if MACH_VM_DEBUG #include #endif /* * Management of resident (logical) pages. * * A small structure is kept for each resident * page, indexed by page number. Each structure * is an element of several lists: * * A hash table bucket used to quickly * perform object/offset lookups * * A list of all pages for a given object, * so they can be quickly deactivated at * time of deallocation. * * An ordered list of pages due for pageout. * * In addition, the structure contains the object * and offset to which this page belongs (for pageout), * and sundry status bits. * * Fields in this structure are locked either by the lock on the * object that the page belongs to (O) or by the lock on the page * queues (P). [Some fields require that both locks be held to * change that field; holding either lock is sufficient to read.] */ struct vm_page { struct list node; /* page queues or free list (P) */ unsigned short type; unsigned short seg_index; unsigned short order; void *priv; /* * This member is used throughout the code and may only change for * fictitious pages. */ phys_addr_t phys_addr; queue_chain_t listq; /* all pages in same object (O) */ struct vm_page *next; /* VP bucket link (O) */ /* We use an empty struct as the delimiter. */ struct {} vm_page_header; #define VM_PAGE_HEADER_SIZE offsetof(struct vm_page, vm_page_header) vm_object_t object; /* which object am I in (O,P) */ vm_offset_t offset; /* offset into that object (O,P) */ unsigned int wire_count:15, /* how many wired down maps use me? (O&P) */ /* boolean_t */ inactive:1, /* page is in inactive list (P) */ active:1, /* page is in active list (P) */ laundry:1, /* page is being cleaned now (P)*/ external_laundry:1, /* same as laundry for external pagers (P)*/ free:1, /* page is on free list (P) */ reference:1, /* page has been used (P) */ external:1, /* page in external object (P) */ busy:1, /* page is in transit (O) */ wanted:1, /* someone is waiting for page (O) */ tabled:1, /* page is in VP table (O) */ fictitious:1, /* Physical page doesn't exist (O) */ private:1, /* Page should not be returned to * the free list (O) */ absent:1, /* Data has been requested, but is * not yet available (O) */ error:1, /* Data manager was unable to provide * data due to error (O) */ dirty:1, /* Page must be cleaned (O) */ precious:1, /* Page is precious; data must be * returned even if clean (O) */ overwriting:1; /* Request to unlock has been made * without having data. (O) * [See vm_object_overwrite] */ vm_prot_t page_lock; /* Uses prohibited by data manager (O) */ vm_prot_t unlock_request; /* Outstanding unlock request (O) */ }; /* * For debugging, this macro can be defined to perform * some useful check on a page structure. */ #define VM_PAGE_CHECK(mem) vm_page_check(mem) void vm_page_check(const struct vm_page *page); /* * Each pageable resident page falls into one of three lists: * * free * Available for allocation now. * inactive * Not referenced in any map, but still has an * object/offset-page mapping, and may be dirty. * This is the list of pages that should be * paged out next. * active * A list of pages which have been placed in * at least one physical map. This list is * ordered, in LRU-like fashion. */ extern int vm_page_fictitious_count;/* How many fictitious pages are free? */ extern int vm_page_active_count; /* How many pages are active? */ extern int vm_page_inactive_count; /* How many pages are inactive? */ extern int vm_page_wire_count; /* How many pages are wired? */ extern int vm_page_laundry_count; /* How many pages being laundered? */ extern int vm_page_external_laundry_count; /* How many external pages being paged out? */ decl_simple_lock_data(extern,vm_page_queue_lock)/* lock on active and inactive page queues */ decl_simple_lock_data(extern,vm_page_queue_free_lock) /* lock on free page queue */ extern phys_addr_t vm_page_fictitious_addr; /* (fake) phys_addr of fictitious pages */ extern void vm_page_bootstrap( vm_offset_t *startp, vm_offset_t *endp); extern void vm_page_module_init(void); extern vm_page_t vm_page_lookup( vm_object_t object, vm_offset_t offset); extern vm_page_t vm_page_grab_fictitious(void); extern boolean_t vm_page_convert(vm_page_t *); extern void vm_page_more_fictitious(void); extern vm_page_t vm_page_grab(void); extern void vm_page_release(vm_page_t, boolean_t, boolean_t); extern phys_addr_t vm_page_grab_phys_addr(void); extern vm_page_t vm_page_grab_contig(vm_size_t, unsigned int); extern void vm_page_free_contig(vm_page_t, vm_size_t); extern void vm_page_wait(void (*)(void)); extern vm_page_t vm_page_alloc( vm_object_t object, vm_offset_t offset); extern void vm_page_init( vm_page_t mem); extern void vm_page_free(vm_page_t); extern void vm_page_activate(vm_page_t); extern void vm_page_deactivate(vm_page_t); extern void vm_page_rename( vm_page_t mem, vm_object_t new_object, vm_offset_t new_offset); extern void vm_page_insert( vm_page_t mem, vm_object_t object, vm_offset_t offset); extern void vm_page_remove( vm_page_t mem); extern void vm_page_zero_fill(vm_page_t); extern void vm_page_copy(vm_page_t src_m, vm_page_t dest_m); extern void vm_page_wire(vm_page_t); extern void vm_page_unwire(vm_page_t); #if MACH_VM_DEBUG extern unsigned int vm_page_info( hash_info_bucket_t *info, unsigned int count); #endif /* * Functions implemented as macros */ #define PAGE_ASSERT_WAIT(m, interruptible) \ MACRO_BEGIN \ (m)->wanted = TRUE; \ assert_wait((event_t) (m), (interruptible)); \ MACRO_END #define PAGE_WAKEUP_DONE(m) \ MACRO_BEGIN \ (m)->busy = FALSE; \ if ((m)->wanted) { \ (m)->wanted = FALSE; \ thread_wakeup(((event_t) m)); \ } \ MACRO_END #define PAGE_WAKEUP(m) \ MACRO_BEGIN \ if ((m)->wanted) { \ (m)->wanted = FALSE; \ thread_wakeup((event_t) (m)); \ } \ MACRO_END #define VM_PAGE_FREE(p) \ MACRO_BEGIN \ vm_page_lock_queues(); \ vm_page_free(p); \ vm_page_unlock_queues(); \ MACRO_END /* * Macro to be used in place of pmap_enter() */ #define PMAP_ENTER(pmap, virtual_address, page, protection, wired) \ MACRO_BEGIN \ pmap_enter( \ (pmap), \ (virtual_address), \ (page)->phys_addr, \ (protection) & ~(page)->page_lock, \ (wired) \ ); \ MACRO_END #define VM_PAGE_WAIT(continuation) vm_page_wait(continuation) #define vm_page_lock_queues() simple_lock(&vm_page_queue_lock) #define vm_page_unlock_queues() simple_unlock(&vm_page_queue_lock) #define VM_PAGE_QUEUES_REMOVE(mem) vm_page_queues_remove(mem) /* * Copyright (c) 2010-2014 Richard Braun. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * * Physical page management. */ /* * Address/page conversion and rounding macros (not inline functions to * be easily usable on both virtual and physical addresses, which may not * have the same type size). */ #define vm_page_atop(addr) ((addr) >> PAGE_SHIFT) #define vm_page_ptoa(page) ((page) << PAGE_SHIFT) #define vm_page_trunc(addr) P2ALIGN(addr, PAGE_SIZE) #define vm_page_round(addr) P2ROUND(addr, PAGE_SIZE) #define vm_page_aligned(addr) P2ALIGNED(addr, PAGE_SIZE) /* * Segment selectors. * * Selector-to-segment-list translation table : * DMA DMA * DMA32 DMA32 DMA * DIRECTMAP DIRECTMAP DMA32 DMA * HIGHMEM HIGHMEM DIRECTMAP DMA32 DMA */ #define VM_PAGE_SEL_DMA 0 #define VM_PAGE_SEL_DMA32 1 #define VM_PAGE_SEL_DIRECTMAP 2 #define VM_PAGE_SEL_HIGHMEM 3 /* * Page usage types. */ #define VM_PT_FREE 0 /* Page unused */ #define VM_PT_RESERVED 1 /* Page reserved at boot time */ #define VM_PT_TABLE 2 /* Page is part of the page table */ #define VM_PT_KERNEL 3 /* Type for generic kernel allocations */ static inline unsigned short vm_page_type(const struct vm_page *page) { return page->type; } void vm_page_set_type(struct vm_page *page, unsigned int order, unsigned short type); static inline unsigned int vm_page_order(size_t size) { return iorder2(vm_page_atop(vm_page_round(size))); } static inline phys_addr_t vm_page_to_pa(const struct vm_page *page) { return page->phys_addr; } /* * Associate private data with a page. */ static inline void vm_page_set_priv(struct vm_page *page, void *priv) { page->priv = priv; } static inline void * vm_page_get_priv(const struct vm_page *page) { return page->priv; } /* * Load physical memory into the vm_page module at boot time. * * All addresses must be page-aligned. Segments can be loaded in any order. */ void vm_page_load(unsigned int seg_index, phys_addr_t start, phys_addr_t end); /* * Load available physical memory into the vm_page module at boot time. * * The segment referred to must have been loaded with vm_page_load * before loading its heap. */ void vm_page_load_heap(unsigned int seg_index, phys_addr_t start, phys_addr_t end); /* * Return true if the vm_page module is completely initialized, false * otherwise, in which case only vm_page_bootalloc() can be used for * allocations. */ int vm_page_ready(void); /* * Early allocation function. * * This function is used by the vm_resident module to implement * pmap_steal_memory. It can be used after physical segments have been loaded * and before the vm_page module is initialized. */ unsigned long vm_page_bootalloc(size_t size); /* * Set up the vm_page module. * * Architecture-specific code must have loaded segments before calling this * function. Segments must comply with the selector-to-segment-list table, * e.g. HIGHMEM is loaded if and only if DIRECTMAP, DMA32 and DMA are loaded, * notwithstanding segment aliasing. * * Once this function returns, the vm_page module is ready, and normal * allocation functions can be used. */ void vm_page_setup(void); /* * Make the given page managed by the vm_page module. * * If additional memory can be made usable after the VM system is initialized, * it should be reported through this function. */ void vm_page_manage(struct vm_page *page); /* * Return the page descriptor for the given physical address. */ struct vm_page * vm_page_lookup_pa(phys_addr_t pa); /* * Allocate a block of 2^order physical pages. * * The selector is used to determine the segments from which allocation can * be attempted. * * This function should only be used by the vm_resident module. */ struct vm_page * vm_page_alloc_pa(unsigned int order, unsigned int selector, unsigned short type); /* * Release a block of 2^order physical pages. * * This function should only be used by the vm_resident module. */ void vm_page_free_pa(struct vm_page *page, unsigned int order); /* * Return the name of the given segment. */ const char * vm_page_seg_name(unsigned int seg_index); /* * Display internal information about the module. */ void vm_page_info_all(void); /* * Return the maximum physical address for a given segment selector. */ phys_addr_t vm_page_seg_end(unsigned int selector); /* * Return the total number of physical pages. */ unsigned long vm_page_table_size(void); /* * Return the index of a page in the page table. */ unsigned long vm_page_table_index(phys_addr_t pa); /* * Return the total amount of physical memory. */ phys_addr_t vm_page_mem_size(void); /* * Return the amount of free (unused) pages. * * XXX This currently relies on the kernel being non preemptible and * uniprocessor. */ unsigned long vm_page_mem_free(void); /* * Remove the given page from any page queue it might be in. */ void vm_page_queues_remove(struct vm_page *page); /* * Balance physical pages among segments. * * This function should be called first by the pageout daemon * on memory pressure, since it may be unnecessary to perform any * other operation, let alone shrink caches, if balancing is * enough to make enough free pages. * * Return TRUE if balancing made enough free pages for unprivileged * allocations to succeed, in which case pending allocations are resumed. * * This function acquires vm_page_queue_free_lock, which is held on return. */ boolean_t vm_page_balance(void); /* * Evict physical pages. * * This function should be called by the pageout daemon after balancing * the segments and shrinking kernel caches. * * Return TRUE if eviction made enough free pages for unprivileged * allocations to succeed, in which case pending allocations are resumed. * * Otherwise, report whether the pageout daemon should wait (some pages * have been paged out) or not (only clean pages have been released). * * This function acquires vm_page_queue_free_lock, which is held on return. */ boolean_t vm_page_evict(boolean_t *should_wait); /* * Turn active pages into inactive ones for second-chance LRU * approximation. * * This function should be called by the pageout daemon on memory pressure, * i.e. right before evicting pages. * * XXX This is probably not the best strategy, compared to keeping the * active/inactive ratio in check at all times, but this means less * frequent refills. */ void vm_page_refill_inactive(void); #endif /* _VM_VM_PAGE_H_ */