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.


Constraints in page allocation, and code changes to use them; shadow paging allocati...
[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 #include "mm.h"
14 #include "buddy.h"
15 #include "numa.h"
16 #include "palacios/vmm.h"
17
18
19 static struct buddy_memzone ** memzones = NULL;
20 static uintptr_t * seed_addrs = NULL;
21
22
23 // alignment is in bytes
24 uintptr_t alloc_palacios_pgs(u64 num_pages, u32 alignment, int node_id, int constraints) {
25     uintptr_t addr = 0; 
26     int any = node_id==-1; // can allocate on any
27     int buddy_constraints=0;
28
29     if (constraints && constraints!=V3_ALLOC_PAGES_CONSTRAINT_4GB) { 
30         ERROR("Unknown constraint mask 0x%x\n",constraints);
31         return 0;
32     }
33     
34     if (constraints & V3_ALLOC_PAGES_CONSTRAINT_4GB) { 
35         buddy_constraints |= LWK_BUDDY_CONSTRAINT_4GB;
36     }
37
38
39     if (node_id == -1) {
40         int cpu_id = get_cpu();
41         put_cpu();
42         
43         node_id = numa_cpu_to_node(cpu_id); // try first preferentially for the calling pcore
44
45     } else if (numa_num_nodes() == 1) {
46         node_id = 0;
47     } else if (node_id >= numa_num_nodes()) {
48         ERROR("Requesting memory from an invalid NUMA node. (Node: %d) (%d nodes on system)\n", 
49               node_id, numa_num_nodes());
50         return 0;
51     }
52
53     addr = buddy_alloc(memzones[node_id], get_order(num_pages * PAGE_SIZE) + PAGE_SHIFT, buddy_constraints);
54
55     if (!addr && any) { 
56         int i;
57         // do a scan to see if we can satisfy request on any node
58         for (i=0; i< numa_num_nodes(); i++) { 
59             if (i!=node_id) { 
60                 addr = buddy_alloc(memzones[i], get_order(num_pages * PAGE_SIZE) + PAGE_SHIFT, buddy_constraints);
61                 if (addr) {
62                     break;
63                 }
64             }
65         }
66     }
67                 
68
69     //DEBUG("Returning from alloc addr=%p, vaddr=%p\n", (void *)addr, __va(addr));
70     return addr;
71 }
72
73
74
75 void free_palacios_pgs(uintptr_t pg_addr, u64 num_pages) {
76     int node_id = numa_addr_to_node(pg_addr);
77
78     //DEBUG("Freeing Memory page %p\n", (void *)pg_addr);
79     buddy_free(memzones[node_id], pg_addr, get_order(num_pages * PAGE_SIZE) + PAGE_SHIFT);
80     
81     return;
82 }
83
84
85 unsigned long long pow2(int i)
86 {
87     unsigned long long x=1;
88     for (;i!=0;i--) { x*=2; } 
89     return x;
90 }
91
92 int add_palacios_memory(struct v3_mem_region *r) {
93     int pool_order = 0;
94     int node_id = 0;
95
96     struct v3_mem_region *keep;
97
98     INFO("Palacios Memory Add Request: type=%d, node=%d, base_addr=0x%llx, num_pages=%llu\n",r->type,r->node,r->base_addr,r->num_pages);
99
100     // fixup request regardless of its type
101     if (r->num_pages*4096 < V3_CONFIG_MEM_BLOCK_SIZE) { 
102         WARNING("Allocating a memory pool smaller than the Palacios block size - may not be useful\n");
103     }
104
105     if (pow2(get_order(r->num_pages*PAGE_SIZE)) != r->num_pages) { 
106         WARNING("Allocating a memory pool that is not a power of two (is %llu) - it will be rounded down!\n", r->num_pages);
107         r->num_pages=pow2(get_order(r->num_pages*PAGE_SIZE));
108         WARNING("Rounded request is for %llu pages\n", r->num_pages);
109     }
110
111
112     if (!(keep=palacios_alloc(sizeof(struct v3_mem_region)))) { 
113         ERROR("Error allocating space for tracking region\n");
114         return -1;
115     }
116
117
118     if (r->type==REQUESTED || r->type==REQUESTED32) { 
119         struct page *pgs;
120
121         INFO("Attempting to allocate %llu pages of %s memory\n", r->num_pages,
122              r->type==REQUESTED ? "64 bit (unrestricted)" : 
123              r->type==REQUESTED32 ? "32 bit (restricted)" : "unknown (assuming 64 bit unrestricted)");
124              
125         pgs = alloc_pages_node(r->node, 
126                                r->type==REQUESTED ? GFP_KERNEL :
127                                r->type==REQUESTED32 ? GFP_DMA32 : GFP_KERNEL, 
128                                get_order(r->num_pages*PAGE_SIZE));
129         if (!pgs) { 
130             ERROR("Unable to satisfy allocation request\n");
131             palacios_free(keep);
132             return -1;
133         }
134         r->base_addr = page_to_pfn(pgs) << PAGE_SHIFT;
135     }
136         
137
138     *keep = *r;
139
140     node_id = numa_addr_to_node(r->base_addr);
141
142     if (node_id == -1) {
143         ERROR("Error locating node for addr %p\n", (void *)(r->base_addr));
144         return -1;
145     }
146
147     if ((node_id != r->node) && (r->node!=-1)) { 
148         INFO("Memory add request is for node %d, but memory is in node %d\n",r->node,node_id);
149     }
150
151     pool_order = get_order(r->num_pages * PAGE_SIZE) + PAGE_SHIFT;
152
153     if (buddy_add_pool(memzones[node_id], r->base_addr, pool_order, keep)) {
154         ERROR("ALERT ALERT ALERT Unable to add pool to buddy allocator...\n");
155         if (r->type==REQUESTED || r->type==REQUESTED32) { 
156             free_pages((uintptr_t)__va(r->base_addr), get_order(r->num_pages));
157         }
158         palacios_free(keep);
159         return -1;
160     }
161
162     return 0;
163 }
164
165
166
167 int palacios_remove_memory(uintptr_t base_addr) {
168     int node_id = numa_addr_to_node(base_addr);
169     struct v3_mem_region *r;
170
171     if (buddy_remove_pool(memzones[node_id], base_addr, 0, (void**)(&r))) { //unforced remove
172         ERROR("Cannot remove memory at base address 0x%p because it is in use\n", (void*)base_addr);
173         return -1;
174     }
175
176     if (r->type==REQUESTED || r->type==REQUESTED32) { 
177         free_pages((uintptr_t)__va(r->base_addr), get_order(r->num_pages));
178     } else {
179         // user space resposible for onlining
180     }
181     
182     palacios_free(r);
183
184     return 0;
185 }
186
187
188
189 int palacios_deinit_mm( void ) {
190
191     int i = 0;
192
193     if (memzones) {
194         for (i = 0; i < numa_num_nodes(); i++) {
195             
196             if (memzones[i]) {
197                 buddy_deinit(memzones[i]);
198             }
199             
200             // note that the memory is not onlined here - offlining and onlining
201             // is the resposibility of the caller
202             
203             if (seed_addrs[i]) {
204                 // free the seed regions
205                 free_pages((uintptr_t)__va(seed_addrs[i]), MAX_ORDER - 1);
206             }
207         }
208         
209         palacios_free(memzones);
210         palacios_free(seed_addrs);
211     }
212
213     return 0;
214 }
215
216 int palacios_init_mm( void ) {
217     int num_nodes = numa_num_nodes();
218     int node_id = 0;
219
220     INFO("memory manager init: MAX_ORDER=%d (%llu bytes)\n",MAX_ORDER, PAGE_SIZE*pow2(MAX_ORDER));
221
222     memzones = palacios_alloc_extended(sizeof(struct buddy_memzone *) * num_nodes, GFP_KERNEL,-1);
223
224     if (!memzones) { 
225         ERROR("Cannot allocate space for memory zones\n");
226         palacios_deinit_mm();
227         return -1;
228     }
229
230     memset(memzones, 0, sizeof(struct buddy_memzone *) * num_nodes);
231
232     seed_addrs = palacios_alloc_extended(sizeof(uintptr_t) * num_nodes, GFP_KERNEL,-1);
233
234     if (!seed_addrs) { 
235         ERROR("Cannot allocate space for seed addrs\n");
236         palacios_deinit_mm();
237         return -1;
238     }
239
240     memset(seed_addrs, 0, sizeof(uintptr_t) * num_nodes);
241
242     for (node_id = 0; node_id < num_nodes; node_id++) {
243         struct buddy_memzone * zone = NULL;
244
245         // Seed the allocator with a small set of pages to allow initialization to complete. 
246         // For now we will just grab some random pages, but in the future we will need to grab NUMA specific regions
247         // See: alloc_pages_node()
248
249         {
250             struct page * pgs;
251
252             // attempt to first allocate below 4 GB for compatibility with
253             // 32 bit shadow paging
254             pgs = alloc_pages_node(node_id, GFP_DMA32, MAX_ORDER - 1);
255
256             if (!pgs) {
257                 INFO("Could not allocate initial memory block for node %d beloew 4GB\n", node_id);
258                 
259                 pgs = alloc_pages_node(node_id, GFP_KERNEL, MAX_ORDER - 1);
260
261                 if (!pgs) {
262                     INFO("Could not allocate initial memory block for node %d beloew 4GB\n", node_id);
263                     if (!pgs) {
264                         ERROR("Could not allocate initial memory block for node %d without restrictions\n", node_id);
265                         BUG_ON(!pgs);
266                         palacios_deinit_mm();
267                         return -1;
268                     }
269                 }
270             }
271
272             seed_addrs[node_id] = page_to_pfn(pgs) << PAGE_SHIFT;
273         }
274
275         zone = buddy_init(get_order(V3_CONFIG_MEM_BLOCK_SIZE) + PAGE_SHIFT, PAGE_SHIFT, node_id);
276
277         if (zone == NULL) {
278             ERROR("Could not initialization memory management for node %d\n", node_id);
279             palacios_deinit_mm();
280             return -1;
281         }
282
283         printk("Zone initialized, Adding seed region (order=%d)\n", 
284                (MAX_ORDER - 1) + PAGE_SHIFT);
285
286         if (buddy_add_pool(zone, seed_addrs[node_id], (MAX_ORDER - 1) + PAGE_SHIFT,0)) { 
287             ERROR("Could not add pool to buddy allocator\n");
288             palacios_deinit_mm();
289             return -1;
290         }
291
292         memzones[node_id] = zone;
293     }
294
295     return 0;
296
297 }
298