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