| /* Copyright (c) 2009, 2010 The Regents of the University  of California. | 
 |  * See the COPYRIGHT files at the top of this source tree for full | 
 |  * license information. | 
 |  * | 
 |  * Kevin Klues <klueska@cs.berkeley.edu> | 
 |  * Barret Rhoden <brho@cs.berkeley.edu> */ | 
 |  | 
 | #pragma once | 
 |  | 
 | #include <atomic.h> | 
 | #include <sys/queue.h> | 
 | #include <error.h> | 
 | #include <arch/mmu.h> | 
 | #include <process.h> | 
 | #include <kref.h> | 
 | #include <kthread.h> | 
 | #include <multiboot.h> | 
 |  | 
 | struct page_map;		/* preprocessor games */ | 
 |  | 
 | /****************** Page Structures *********************/ | 
 | struct page; | 
 | typedef size_t ppn_t; | 
 | typedef struct page page_t; | 
 | typedef BSD_LIST_HEAD(PageList, page) page_list_t; | 
 | typedef BSD_LIST_ENTRY(page) page_list_entry_t; | 
 |  | 
 | /* Per-page flag bits related to their state in the page cache */ | 
 | #define PG_LOCKED		0x001	/* involved in an IO op */ | 
 | #define PG_UPTODATE		0x002	/* page map, filled with file data */ | 
 | #define PG_DIRTY		0x004	/* page map, data is dirty */ | 
 | #define PG_BUFFER		0x008	/* is a buffer page, has BHs */ | 
 | #define PG_PAGEMAP		0x010	/* belongs to a page map */ | 
 | #define PG_REMOVAL		0x020	/* Working flag for page map removal */ | 
 |  | 
 | /* TODO: this struct is not protected from concurrent operations in some | 
 |  * functions.  If you want to lock on it, use the spinlock in the semaphore. | 
 |  * This structure is getting pretty big (and we're wasting RAM).  If it becomes | 
 |  * an issue, we can dynamically allocate some of these things when we're a | 
 |  * buffer page (in a page mapping) */ | 
 | struct page { | 
 | 	BSD_LIST_ENTRY(page)		pg_link; | 
 | 	atomic_t			pg_flags; | 
 | 	struct page_map			*pg_mapping;	/* for debugging... */ | 
 | 	unsigned long			pg_index; | 
 | 	void				**pg_tree_slot; | 
 | 	void				*pg_private; | 
 | 	struct semaphore 		pg_sem;	 | 
 | 	uint64_t			gpa;	/* physical address in guest */ | 
 |  | 
 | 	bool				pg_is_free;	/* TODO: will remove */ | 
 | }; | 
 |  | 
 | /******** Externally visible global variables ************/ | 
 | extern spinlock_t page_list_lock; | 
 | extern page_list_t page_free_list; | 
 |  | 
 | /*************** Functional Interface *******************/ | 
 | void base_arena_init(struct multiboot_info *mbi); | 
 |  | 
 | error_t upage_alloc(struct proc *p, page_t **page, bool zero); | 
 | error_t kpage_alloc(page_t **page); | 
 | void *kpage_alloc_addr(void); | 
 | void *kpage_zalloc_addr(void); | 
 |  | 
 | /* Direct allocation from the kpages arena (instead of kmalloc).  These will | 
 |  * give you PGSIZE quantum. */ | 
 | void *kpages_alloc(size_t size, int flags); | 
 | void *kpages_zalloc(size_t size, int flags); | 
 | void kpages_free(void *addr, size_t size); | 
 |  | 
 | void *get_cont_pages(size_t order, int flags); | 
 | void free_cont_pages(void *buf, size_t order); | 
 |  | 
 | void page_decref(page_t *page); | 
 |  | 
 | int page_is_free(size_t ppn); | 
 | void lock_page(struct page *page); | 
 | void unlock_page(struct page *page); | 
 | void print_pageinfo(struct page *page); | 
 | static inline bool page_is_pagemap(struct page *page); | 
 |  | 
 | static inline bool page_is_pagemap(struct page *page) | 
 | { | 
 | 	return atomic_read(&page->pg_flags) & PG_PAGEMAP ? true : false; | 
 | } |