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.


Extensive, Pedantic Error Checking in Linux module, especially for memory
[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) {
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\n");
124             return 0;
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         //DEBUG("Allocating %llu pages from bitmap allocator\n", num_pages);
149         //addr = pool.base_addr;
150         addr = alloc_contig_pgs(num_pages, alignment);
151         if (!addr) { 
152             ERROR("Could not allocate large number of contiguous pages\n");
153         }
154     }
155
156
157     //DEBUG("Returning from alloc addr=%p, vaddr=%p\n", (void *)addr, __va(addr));
158     return addr;
159 }
160
161
162
163 void free_palacios_pgs(uintptr_t pg_addr, int num_pages) {
164     //DEBUG("Freeing Memory page %p\n", (void *)pg_addr);
165
166     if ((pg_addr >= pool.base_addr) && 
167         (pg_addr < pool.base_addr + (PAGE_SIZE * pool.num_pages))) {
168         int pg_idx = (pg_addr - pool.base_addr) / PAGE_SIZE;
169         int i = 0;
170
171
172         if (num_pages<OFFLINE_POOL_THRESHOLD) { 
173             ERROR("ALERT ALERT  small page deallocation from offline pool\n");
174             return;
175         }       
176
177         if ((pg_idx + num_pages) > pool.num_pages) {
178             ERROR("Freeing memory bounds exceeded for offline pool\n");
179             return;
180         }
181
182         for (i = 0; i < num_pages; i++) {
183             if (get_page_bit(pg_idx + i) == 0) { 
184                 ERROR("Trying to free unallocated page from offline pool\n");
185             }
186             clear_page_bit(pg_idx + i);
187         }
188         
189     } else {
190         if (num_pages>=OFFLINE_POOL_THRESHOLD) {
191            ERROR("ALERT ALERT Large page deallocation from linux pool\n");
192         }
193         __free_pages(pfn_to_page(pg_addr >> PAGE_SHIFT), get_order(num_pages * PAGE_SIZE));
194     }
195 }
196
197
198 int add_palacios_memory(uintptr_t base_addr, u64 num_pages) {
199     /* JRL: OK.... so this is horrible, terrible and if anyone else did it I would yell at them.
200      * But... the fact that you can do this in C is so ridiculous that I can't help myself.
201      * Note that we're repurposing "true" to be 1 here
202      */
203
204     int bitmap_size = (num_pages / 8) + ((num_pages % 8) > 0); 
205
206     if (pool.num_pages != 0) {
207         ERROR("ERROR: Memory has already been added\n");
208         return -1;
209     }
210
211     DEBUG("Managing %dMB of memory starting at %llu (%lluMB)\n", 
212            (unsigned int)(num_pages * PAGE_SIZE) / (1024 * 1024), 
213            (unsigned long long)base_addr, 
214            (unsigned long long)(base_addr / (1024 * 1024)));
215
216
217     pool.bitmap = palacios_alloc(bitmap_size);
218     
219     if (IS_ERR(pool.bitmap)) {
220         ERROR("Error allocating Palacios MM bitmap\n");
221         return -1;
222     }
223     
224     memset(pool.bitmap, 0, bitmap_size);
225
226     pool.base_addr = base_addr;
227     pool.num_pages = num_pages;
228
229     return 0;
230 }
231
232
233
234 int palacios_init_mm( void ) {
235
236     pool.base_addr = 0;
237     pool.num_pages = 0;
238     pool.bitmap = NULL;
239
240     return 0;
241 }
242
243 int palacios_deinit_mm( void ) {
244
245     palacios_free(pool.bitmap);
246
247     pool.bitmap=0;
248     pool.base_addr=0;
249     pool.num_pages=0;
250
251     // note that the memory is not onlined here - offlining and onlining
252     // is the resposibility of the caller
253     
254     return 0;
255 }