ac4831bd6238914337b4b4102b8ca84f6de64aec
[akaros.git] / kern / src / page_alloc.c
1 /* Copyright (c) 2009 The Regents of the University  of California. 
2  * See the COPYRIGHT files at the top of this source tree for full 
3  * license information.
4  * 
5  * Kevin Klues <klueska@cs.berkeley.edu>    
6  */
7
8 #ifdef __SHARC__
9 #pragma nosharc
10 #endif
11
12 #include <sys/queue.h>
13 #include <page_alloc.h>
14 #include <pmap.h>
15 #include <string.h>
16
17 /**
18  * @brief Clear a Page structure.
19  *
20  * The result has null links and 0 refcount.
21  * Note that the corresponding physical page is NOT initialized!
22  */
23 static void page_clear(page_t *SAFE page)
24 {
25         memset(page, 0, sizeof(page_t));
26 }
27
28 /**
29  * @brief Allocates a physical page from a pool of unused physical memory
30  *
31  * Does NOT set the contents of the physical page to zero -
32  * the caller must do that if necessary.
33  *
34  * @param[out] page  set to point to the Page struct
35  *                   of the newly allocated page
36  *
37  * @return ESUCCESS on success
38  * @return -ENOMEM  otherwise
39  */
40 error_t page_alloc(page_t** page) 
41 {
42         //TODO: Put a lock around this
43         if(!LIST_EMPTY(&page_free_list)) {
44                 *page = LIST_FIRST(&page_free_list);
45                 LIST_REMOVE(*page, global_link);
46                 REMOVE_CACHE_COLORING_PAGE_FROM_FREE_LISTS(page);
47                 page_clear(*page);
48                 return ESUCCESS;
49         }
50         return -ENOMEM;
51 }
52
53 /*
54  * This macro defines multiple functions of the form:
55  * error_t _cache##_page_alloc(page_t** page, size_t color)
56  *
57  * Each of these functions operates on a different level of 
58  * of the cache heirarchy, and allocates a physical page
59  * from the list of pages corresponding to the supplied 
60  * color for the given cache.  
61  * 
62  * Does NOT set the contents of the physical page to zero -
63  * the caller must do that if necessary.
64  *
65  * color       -- the color from which to allocate a page
66  * *page       -- is set to point to the Page struct 
67  *                of the newly allocated page
68  *
69  * RETURNS 
70  *   ESUCCESS  -- on success
71  *   -ENOMEM   -- otherwise 
72  *
73  * error_t _cache##_page_alloc(page_t** page, size_t color)
74  * {
75  *       if(!LIST_EMPTY(&(_cache##_cache_colored_page_list)[(color)])) {
76  *        *(page) = LIST_FIRST(&(_cache##_cache_colored_page_list)[(color)]);
77  *               LIST_REMOVE(*page, global_link);
78  *               REMOVE_CACHE_COLORING_PAGE_FROM_FREE_LISTS(page);
79  *               page_clear(*page);
80  *               return ESUCCESS;
81  *       }
82  *       return -ENOMEM;
83  * }
84  */
85 DECLARE_CACHE_COLORED_PAGE_ALLOC_FUNCTIONS();
86
87 /*
88  * Allocates a specific physical page.
89  * Does NOT set the contents of the physical page to zero -
90  * the caller must do that if necessary.
91  *
92  * ppn         -- the page number to allocate
93  * *page       -- is set to point to the Page struct 
94  *                of the newly allocated page
95  *
96  * RETURNS 
97  *   ESUCCESS  -- on success
98  *   -ENOMEM   -- otherwise 
99  */
100 error_t page_alloc_specific(page_t** page, size_t ppn)
101 {
102         //TODO: Put a lock around this
103         page_t* sp_page = ppn2page(ppn);
104         if( sp_page->page_ref != 0 )
105                 return -ENOMEM;
106         *page = sp_page;
107         LIST_REMOVE(*page, global_link);
108         REMOVE_CACHE_COLORING_PAGE_FROM_FREE_LISTS(page);
109         page_clear(*page);
110         return 0;
111 }
112
113 /*
114  * Return a page to the free list.
115  * (This function should only be called when pp->page_ref reaches 0.)
116  */
117 error_t page_free(page_t* page) 
118 {
119         //TODO: Put a lock around this
120         page_clear(page);
121         LIST_INSERT_HEAD(&page_free_list, page, global_link);
122         INSERT_CACHE_COLORING_PAGE_ONTO_FREE_LISTS(page);       
123         return ESUCCESS;
124 }
125
126 /*
127  * Check if a page with the given pyhysical page # is free
128  */
129 int page_is_free(size_t ppn) {
130         //TODO: Put a lock around this
131         page_t* page = ppn2page(ppn);
132         if( page->page_ref == 0 )
133                 return TRUE;
134         return FALSE;
135 }
136
137 /*
138  * Increment the reference count on a page
139  */
140 void page_incref(page_t *page)
141 {
142         page->page_ref++;
143 }
144
145 /*
146  * Decrement the reference count on a page,
147  * freeing it if there are no more refs.
148  */
149 void page_decref(page_t *page)
150 {
151         if (--page->page_ref == 0)
152                 page_free(page);
153 }
154
155 /*
156  * Set the reference count on a page to a specific value
157  */
158 void page_setref(page_t *page, size_t val)
159 {
160         page->page_ref = val;
161 }
162
163 /*
164  * Get the reference count on a page
165  */
166 size_t page_getref(page_t *page)
167 {
168         return page->page_ref;
169 }
170