diff options
Diffstat (limited to 'vm/vm_page.h')
-rw-r--r-- | vm/vm_page.h | 275 |
1 files changed, 241 insertions, 34 deletions
diff --git a/vm/vm_page.h b/vm/vm_page.h index 4536d1c5..f2e20a78 100644 --- a/vm/vm_page.h +++ b/vm/vm_page.h @@ -36,13 +36,14 @@ #include <mach/boolean.h> #include <mach/vm_prot.h> -#include <mach/vm_param.h> +#include <machine/vm_param.h> #include <vm/vm_object.h> #include <vm/vm_types.h> #include <kern/queue.h> #include <kern/lock.h> +#include <kern/log2.h> -#include <kern/macro_help.h> +#include <kern/macros.h> #include <kern/sched_prim.h> /* definitions of wait/wakeup */ #if MACH_VM_DEBUG @@ -76,6 +77,23 @@ */ struct vm_page { + /* Members used in the vm_page module only */ + struct list node; + 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; + + /* We use an empty struct as the delimiter. */ + struct {} vm_page_header; +#define VM_PAGE_HEADER_SIZE offsetof(struct vm_page, vm_page_header) + queue_chain_t pageq; /* queue info for FIFO * queue or free list (P) */ queue_chain_t listq; /* all pages in same object (O) */ @@ -84,7 +102,7 @@ struct vm_page { 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:16, /* how many wired down maps use me? + 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) */ @@ -92,14 +110,8 @@ struct vm_page { free:1, /* page is on free list (P) */ reference:1, /* page has been used (P) */ external:1, /* page considered external (P) */ - extcounted:1, /* page counted in ext counts (P) */ - :0; /* (force to 'long' boundary) */ -#ifdef ns32000 - int pad; /* extra space for ns32000 bit ops */ -#endif /* ns32000 */ - - unsigned int - /* boolean_t */ busy:1, /* page is in transit (O) */ + extcounted:1, /* page counted in ext counts (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) */ @@ -112,13 +124,10 @@ struct vm_page { 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 + overwriting:1; /* Request to unlock has been made * without having data. (O) * [See vm_object_overwrite] */ - :0; - vm_offset_t phys_addr; /* Physical address of page, passed - * to pmap_enter (read-only) */ vm_prot_t page_lock; /* Uses prohibited by data manager (O) */ vm_prot_t unlock_request; /* Outstanding unlock request (O) */ }; @@ -147,8 +156,6 @@ struct vm_page { */ extern -vm_page_t vm_page_queue_free; /* memory free queue */ -extern vm_page_t vm_page_queue_fictitious; /* fictitious free queue */ extern queue_head_t vm_page_queue_active; /* active memory queue */ @@ -156,13 +163,6 @@ extern queue_head_t vm_page_queue_inactive; /* inactive memory queue */ extern -vm_offset_t first_phys_addr; /* physical address for first_page */ -extern -vm_offset_t last_phys_addr; /* physical address for last_page */ - -extern -int vm_page_free_count; /* How many pages are free? */ -extern int vm_page_fictitious_count;/* How many fictitious pages are free? */ extern int vm_page_active_count; /* How many pages are active? */ @@ -208,25 +208,21 @@ extern void vm_page_bootstrap( vm_offset_t *endp); extern void vm_page_module_init(void); -extern void vm_page_create( - vm_offset_t start, - vm_offset_t end); 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 void vm_page_release_fictitious(vm_page_t); -extern boolean_t vm_page_convert(vm_page_t, boolean_t); +extern boolean_t vm_page_convert(vm_page_t *, boolean_t); extern void vm_page_more_fictitious(void); extern vm_page_t vm_page_grab(boolean_t); -extern void vm_page_release(vm_page_t, boolean_t); +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, - vm_offset_t phys_addr); + 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); @@ -247,8 +243,6 @@ 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); -extern void vm_set_page_size(void); - #if MACH_VM_DEBUG extern unsigned int vm_page_info( hash_info_bucket_t *info, @@ -326,4 +320,217 @@ extern unsigned int vm_page_info( } \ MACRO_END +/* + * 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 <http://www.gnu.org/licenses/>. + * + * + * 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. + * + * Failing to allocate pmap pages will cause a kernel panic. + * TODO Obviously, this needs to be addressed, e.g. with a reserved pool of + * pages. + */ +#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_PMAP 3 /* Page stores pmap-specific data */ +#define VM_PT_KMEM 4 /* Page is part of a kmem slab */ +#define VM_PT_STACK 5 /* Type for generic kernel allocations */ +#define VM_PT_KERNEL 6 /* 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; +} + +#if 0 +static inline unsigned long +vm_page_direct_va(phys_addr_t pa) +{ + assert(pa < VM_PAGE_DIRECTMAP_LIMIT); + return ((unsigned long)pa + VM_MIN_DIRECTMAP_ADDRESS); +} + +static inline phys_addr_t +vm_page_direct_pa(unsigned long va) +{ + assert(va >= VM_MIN_DIRECTMAP_ADDRESS); + assert(va < VM_MAX_DIRECTMAP_ADDRESS); + return (va - VM_MIN_DIRECTMAP_ADDRESS); +} + +static inline void * +vm_page_direct_ptr(const struct vm_page *page) +{ + return (void *)vm_page_direct_va(vm_page_to_pa(page)); +} +#endif + +/* + * 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. + * + * The avail_start and avail_end parameters are used to maintain a simple + * heap for bootstrap allocations. + * + * 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, + phys_addr_t avail_start, phys_addr_t avail_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 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); + #endif /* _VM_VM_PAGE_H_ */ |