Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Added non-contiguous memory region support.
[palacios.git] / linux_module / mm.c
1 /* Palacios memory manager 
2  * (c) Jack Lange, 2010
3  */
4
5 #include <asm/page_64_types.h>
6 #include <linux/kernel.h>
7 #include <linux/list.h>
8 #include <linux/slab.h>
9 #include <linux/mm.h>
10 //static struct list_head pools;
11
12 #include "palacios.h"
13
14 #define OFFLINE_POOL_THRESHOLD 12
15
16 struct mempool {
17     uintptr_t base_addr;
18     u64 num_pages;
19
20     u8 * bitmap;
21 };
22
23
24 static struct mempool pool;
25
26 static inline int get_page_bit(int index) {
27     int major = index / 8;
28     int minor = index % 8;
29
30     return (pool.bitmap[major] & (0x1 << minor));
31 }
32
33 static inline void set_page_bit(int index) {
34     int major = index / 8;
35     int minor = index % 8;
36
37     pool.bitmap[major] |= (0x1 << minor);
38 }
39
40 static inline void clear_page_bit(int index) {
41     int major = index / 8;
42     int minor = index % 8;
43
44     pool.bitmap[major] &= ~(0x1 << minor);
45 }
46
47
48 uintptr_t get_palacios_base_addr(void) {
49     return pool.base_addr;
50 }
51
52 u64 get_palacios_num_pages(void) {
53     return pool.num_pages;
54 }
55
56
57 static uintptr_t alloc_contig_pgs(u64 num_pages, u32 alignment) {
58     int step = 1;
59     int i = 0;
60     int start = 0;
61
62     DEBUG("Allocating %llu pages (align=%lu)\n", 
63            num_pages, (unsigned long)alignment);
64
65     if (pool.bitmap == NULL) {
66         ERROR("ERROR: Attempting to allocate from non initialized memory\n");
67         return 0;
68     }
69
70     if (alignment > 0) {
71         step = alignment / PAGE_SIZE;
72     }
73
74     // Start the search at the correct alignment 
75     if (pool.base_addr % alignment) {
76         start = ((alignment - (pool.base_addr % alignment)) >> 12);
77     }
78
79     DEBUG("\t Start idx %d (base_addr=%p)\n", start, (void *)(u64)pool.base_addr);
80
81     for (i = start; i < (pool.num_pages - num_pages); i += step) {
82         if (get_page_bit(i) == 0) {
83             int j = 0;
84             int collision = 0;
85
86             for (j = i; (j - i) < num_pages; j++) {
87                 if (get_page_bit(j) == 1) {
88                     collision = 1;
89                     break;
90                 }
91             }
92
93             if (collision == 1) {
94                 break;
95             }
96
97             for (j = i; (j - i) < num_pages; j++) {
98                 set_page_bit(j);
99             }
100
101             return pool.base_addr + (i * PAGE_SIZE);
102         }
103     }
104
105     ERROR("ALERT ALERT Allocation of Large Number of Contiguous Pages FAILED\n"); 
106
107     return 0;
108 }
109
110
111 // alignment is in bytes
112 uintptr_t alloc_palacios_pgs(u64 num_pages, u32 alignment, int node) {
113     uintptr_t addr = 0; 
114
115     if (num_pages < OFFLINE_POOL_THRESHOLD) {
116         struct page * pgs = NULL;
117         void *temp;
118         int order = get_order(num_pages * PAGE_SIZE);
119          
120         pgs = alloc_pages(GFP_DMA32, order);
121     
122         if (!pgs) { 
123             ERROR("Could not allocate small number of contigious pages - retrying with internal allocation\n");
124             goto trybig;
125         }
126  
127         /* DEBUG("%llu pages (order=%d) aquired from alloc_pages\n", 
128                num_pages, order); */
129
130         addr = page_to_pfn(pgs) << PAGE_SHIFT; 
131
132         temp = (void*)addr;
133
134         if ( (temp>=(void*)(pool.base_addr) && 
135               (temp<((void*)(pool.base_addr)+pool.num_pages*PAGE_SIZE))) 
136              || ((temp+num_pages*PAGE_SIZE)>=(void*)(pool.base_addr) && 
137                  ((temp+num_pages*PAGE_SIZE)<((void*)(pool.base_addr)+pool.num_pages*PAGE_SIZE))) ) {
138
139             ERROR("ALERT ALERT Allocation of small number of contiguous pages returned block that "
140                   "OVERLAPS with the offline page pool addr=%p, addr+numpages=%p, "
141                   "pool.base_addr=%p, pool.base_addr+pool.numpages=%p\n", 
142                   temp, temp+num_pages*PAGE_SIZE, (void*)(pool.base_addr), 
143                   (void*)(pool.base_addr)+pool.num_pages*PAGE_SIZE);
144         }
145
146         
147     } else {
148     trybig:
149         //DEBUG("Allocating %llu pages from bitmap allocator\n", num_pages);
150         //addr = pool.base_addr;
151         addr = alloc_contig_pgs(num_pages, alignment);
152         if (!addr) { 
153             ERROR("Could not allocate large number of contiguous pages\n");
154         }
155     }
156
157
158     //DEBUG("Returning from alloc addr=%p, vaddr=%p\n", (void *)addr, __va(addr));
159     return addr;
160 }
161
162
163
164 void free_palacios_pgs(uintptr_t pg_addr, int num_pages) {
165     //DEBUG("Freeing Memory page %p\n", (void *)pg_addr);
166
167     if ((pg_addr >= pool.base_addr) && 
168         (pg_addr < pool.base_addr + (PAGE_SIZE * pool.num_pages))) {
169         int pg_idx = (pg_addr - pool.base_addr) / PAGE_SIZE;
170         int i = 0;
171
172
173         if (num_pages<OFFLINE_POOL_THRESHOLD) { 
174             ERROR("ALERT ALERT  small page deallocation from offline pool\n");
175             return;
176         }       
177
178         if ((pg_idx + num_pages) > pool.num_pages) {
179             ERROR("Freeing memory bounds exceeded for offline pool\n");
180             return;
181         }
182
183         for (i = 0; i < num_pages; i++) {
184             if (get_page_bit(pg_idx + i) == 0) { 
185                 ERROR("Trying to free unallocated page from offline pool\n");
186             }
187             clear_page_bit(pg_idx + i);
188         }
189         
190     } else {
191         if (num_pages>=OFFLINE_POOL_THRESHOLD) {
192            ERROR("ALERT ALERT Large page deallocation from linux pool\n");
193         }
194         __free_pages(pfn_to_page(pg_addr >> PAGE_SHIFT), get_order(num_pages * PAGE_SIZE));
195     }
196 }
197
198
199 int add_palacios_memory(uintptr_t base_addr, u64 num_pages) {
200     /* JRL: OK.... so this is horrible, terrible and if anyone else did it I would yell at them.
201      * But... the fact that you can do this in C is so ridiculous that I can't help myself.
202      * Note that we're repurposing "true" to be 1 here
203      */
204
205     int bitmap_size = (num_pages / 8) + ((num_pages % 8) > 0); 
206
207     if (pool.num_pages != 0) {
208         ERROR("ERROR: Memory has already been added\n");
209         return -1;
210     }
211
212     DEBUG("Managing %dMB of memory starting at %llu (%lluMB)\n", 
213            (unsigned int)(num_pages * PAGE_SIZE) / (1024 * 1024), 
214            (unsigned long long)base_addr, 
215            (unsigned long long)(base_addr / (1024 * 1024)));
216
217
218     pool.bitmap = palacios_alloc(bitmap_size);
219     
220     if (IS_ERR(pool.bitmap)) {
221         ERROR("Error allocating Palacios MM bitmap\n");
222         return -1;
223     }
224     
225     memset(pool.bitmap, 0, bitmap_size);
226
227     pool.base_addr = base_addr;
228     pool.num_pages = num_pages;
229
230     return 0;
231 }
232
233
234
235 int palacios_init_mm( void ) {
236
237     pool.base_addr = 0;
238     pool.num_pages = 0;
239     pool.bitmap = NULL;
240
241     return 0;
242 }
243
244 int palacios_deinit_mm( void ) {
245
246     palacios_free(pool.bitmap);
247
248     pool.bitmap=0;
249     pool.base_addr=0;
250     pool.num_pages=0;
251
252     // note that the memory is not onlined here - offlining and onlining
253     // is the resposibility of the caller
254     
255     return 0;
256 }