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.


Use GFP_DMA32 for small page allocations
[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     /* printk("PALACIOS BAD: LARGE PAGE ALLOCATION FAILED\n"); */
95
96     return 0;
97 }
98
99
100 // alignment is in bytes
101 uintptr_t alloc_palacios_pgs(u64 num_pages, u32 alignment) {
102     uintptr_t addr = 0; 
103
104     if ((num_pages < 12)) {
105         struct page * pgs = NULL;
106         int order = get_order(num_pages * PAGE_SIZE);
107          
108         pgs = alloc_pages(GFP_DMA32, order);
109     
110         WARN(!pgs, "Could not allocate pages\n");
111  
112         /* if (!pgs) { printk("PALACIOS BAD: SMALL PAGE ALLOCATION FAILED\n"); A */}
113        
114         /* printk("%llu pages (order=%d) aquired from alloc_pages\n", 
115                num_pages, order); */
116
117         addr = page_to_pfn(pgs) << PAGE_SHIFT; 
118     } else {
119         //printk("Allocating %llu pages from bitmap allocator\n", num_pages);
120         //addr = pool.base_addr;
121         addr = alloc_contig_pgs(num_pages, alignment);
122     }
123
124
125     //printk("Returning from alloc addr=%p, vaddr=%p\n", (void *)addr, __va(addr));
126     return addr;
127 }
128
129
130
131 void free_palacios_pgs(uintptr_t pg_addr, int num_pages) {
132     //printk("Freeing Memory page %p\n", (void *)pg_addr);
133
134     if ((pg_addr >= pool.base_addr) && 
135         (pg_addr < pool.base_addr + (4096 * pool.num_pages))) {
136         int pg_idx = (pg_addr - pool.base_addr) / 4096;
137         int i = 0;
138
139         if ((pg_idx + num_pages) > pool.num_pages) {
140             printk("Freeing memory bounds exceeded\n");
141             return;
142         }
143
144         for (i = 0; i < num_pages; i++) {
145             WARN(get_page_bit(pg_idx + i) == 0, "Trying to free unallocated page\n");
146
147             clear_page_bit(pg_idx + i);
148         }
149     } else {
150         __free_pages(pfn_to_page(pg_addr >> PAGE_SHIFT), get_order(num_pages * PAGE_SIZE));
151     }
152 }
153
154
155 int add_palacios_memory(uintptr_t base_addr, u64 num_pages) {
156     /* JRL: OK.... so this is horrible, terrible and if anyone else did it I would yell at them.
157      * But... the fact that you can do this in C is so ridiculous that I can't help myself.
158      * Note that we're repurposing "true" to be 1 here
159      */
160
161     int bitmap_size = (num_pages / 8) + ((num_pages % 8) > 0); 
162
163     if (pool.num_pages != 0) {
164         printk("ERROR: Memory has already been added\n");
165         return -1;
166     }
167
168     printk("Managing %dMB of memory starting at %llu (%lluMB)\n", 
169            (unsigned int)(num_pages * 4096) / (1024 * 1024), 
170            (unsigned long long)base_addr, 
171            (unsigned long long)(base_addr / (1024 * 1024)));
172
173
174     pool.bitmap = kmalloc(bitmap_size, GFP_KERNEL);
175     
176     if (IS_ERR(pool.bitmap)) {
177         printk("Error allocating Palacios MM bitmap\n");
178         return -1;
179     }
180     
181     memset(pool.bitmap, 0, bitmap_size);
182
183     pool.base_addr = base_addr;
184     pool.num_pages = num_pages;
185
186     return 0;
187 }
188
189
190
191 int palacios_init_mm( void ) {
192     //    INIT_LIST_HEAD(&(pools));
193     pool.base_addr = 0;
194     pool.num_pages = 0;
195     pool.bitmap = NULL;
196
197     return 0;
198 }
199
200 int palacios_deinit_mm( void ) {
201     kfree(pool.bitmap);
202     
203     return 0;
204 }