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.


Updates to linux module to use linux print macros
[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 struct mempool {
15     uintptr_t base_addr;
16     u64 num_pages;
17
18     u8 * bitmap;
19 };
20
21
22 static struct mempool pool;
23
24 static inline int get_page_bit(int index) {
25     int major = index / 8;
26     int minor = index % 8;
27
28     return (pool.bitmap[major] & (0x1 << minor));
29 }
30
31 static inline void set_page_bit(int index) {
32     int major = index / 8;
33     int minor = index % 8;
34
35     pool.bitmap[major] |= (0x1 << minor);
36 }
37
38 static inline void clear_page_bit(int index) {
39     int major = index / 8;
40     int minor = index % 8;
41
42     pool.bitmap[major] &= ~(0x1 << minor);
43 }
44
45
46
47 static uintptr_t alloc_contig_pgs(u64 num_pages, u32 alignment) {
48     int step = 1;
49     int i = 0;
50     int start = 0;
51
52     DEBUG("Allocating %llu pages (align=%lu)\n", 
53            num_pages, (unsigned long)alignment);
54
55     if (pool.bitmap == NULL) {
56         ERROR("ERROR: Attempting to allocate from non initialized memory\n");
57         return 0;
58     }
59
60     if (alignment > 0) {
61         step = alignment / 4096;
62     }
63
64     // Start the search at the correct alignment 
65     if (pool.base_addr % alignment) {
66         start = ((alignment - (pool.base_addr % alignment)) >> 12);
67     }
68
69     ERROR("\t Start idx %d (base_addr=%p)\n", start, (void *)(u64)pool.base_addr);
70
71     for (i = start; i < (pool.num_pages - num_pages); i += step) {
72         if (get_page_bit(i) == 0) {
73             int j = 0;
74             int collision = 0;
75
76             for (j = i; (j - i) < num_pages; j++) {
77                 if (get_page_bit(j) == 1) {
78                     collision = 1;
79                     break;
80                 }
81             }
82
83             if (collision == 1) {
84                 break;
85             }
86
87             for (j = i; (j - i) < num_pages; j++) {
88                 set_page_bit(j);
89             }
90
91             return pool.base_addr + (i * 4096);
92         }
93     }
94
95     /* ERROR("PALACIOS BAD: LARGE PAGE ALLOCATION FAILED\n"); */
96
97     return 0;
98 }
99
100
101 // alignment is in bytes
102 uintptr_t alloc_palacios_pgs(u64 num_pages, u32 alignment) {
103     uintptr_t addr = 0; 
104
105     if ((num_pages < 12)) {
106         struct page * pgs = NULL;
107         int order = get_order(num_pages * PAGE_SIZE);
108          
109         pgs = alloc_pages(GFP_DMA32, order);
110     
111         WARN(!pgs, "Could not allocate pages\n");
112  
113         /* if (!pgs) { ERROR("PALACIOS BAD: SMALL PAGE ALLOCATION FAILED\n");  } */
114        
115         /* DEBUG("%llu pages (order=%d) aquired from alloc_pages\n", 
116                num_pages, order); */
117
118         addr = page_to_pfn(pgs) << PAGE_SHIFT; 
119     } else {
120         //DEBUG("Allocating %llu pages from bitmap allocator\n", num_pages);
121         //addr = pool.base_addr;
122         addr = alloc_contig_pgs(num_pages, alignment);
123     }
124
125
126     //DEBUG("Returning from alloc addr=%p, vaddr=%p\n", (void *)addr, __va(addr));
127     return addr;
128 }
129
130
131
132 void free_palacios_pgs(uintptr_t pg_addr, int num_pages) {
133     //DEBUG("Freeing Memory page %p\n", (void *)pg_addr);
134
135     if ((pg_addr >= pool.base_addr) && 
136         (pg_addr < pool.base_addr + (4096 * pool.num_pages))) {
137         int pg_idx = (pg_addr - pool.base_addr) / 4096;
138         int i = 0;
139
140         if ((pg_idx + num_pages) > pool.num_pages) {
141             ERROR("Freeing memory bounds exceeded\n");
142             return;
143         }
144
145         for (i = 0; i < num_pages; i++) {
146             WARN(get_page_bit(pg_idx + i) == 0, "Trying to free unallocated page\n");
147
148             clear_page_bit(pg_idx + i);
149         }
150     } else {
151         __free_pages(pfn_to_page(pg_addr >> PAGE_SHIFT), get_order(num_pages * PAGE_SIZE));
152     }
153 }
154
155
156 int add_palacios_memory(uintptr_t base_addr, u64 num_pages) {
157     /* JRL: OK.... so this is horrible, terrible and if anyone else did it I would yell at them.
158      * But... the fact that you can do this in C is so ridiculous that I can't help myself.
159      * Note that we're repurposing "true" to be 1 here
160      */
161
162     int bitmap_size = (num_pages / 8) + ((num_pages % 8) > 0); 
163
164     if (pool.num_pages != 0) {
165         ERROR("ERROR: Memory has already been added\n");
166         return -1;
167     }
168
169     DEBUG("Managing %dMB of memory starting at %llu (%lluMB)\n", 
170            (unsigned int)(num_pages * 4096) / (1024 * 1024), 
171            (unsigned long long)base_addr, 
172            (unsigned long long)(base_addr / (1024 * 1024)));
173
174
175     pool.bitmap = kmalloc(bitmap_size, GFP_KERNEL);
176     
177     if (IS_ERR(pool.bitmap)) {
178         WARNING("Error allocating Palacios MM bitmap\n");
179         return -1;
180     }
181     
182     memset(pool.bitmap, 0, bitmap_size);
183
184     pool.base_addr = base_addr;
185     pool.num_pages = num_pages;
186
187     return 0;
188 }
189
190
191
192 int palacios_init_mm( void ) {
193     //    INIT_LIST_HEAD(&(pools));
194     pool.base_addr = 0;
195     pool.num_pages = 0;
196     pool.bitmap = NULL;
197
198     return 0;
199 }
200
201 int palacios_deinit_mm( void ) {
202     kfree(pool.bitmap);
203     
204     return 0;
205 }