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.


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