1 /* Palacios memory manager
5 #include <asm/page_64_types.h>
6 #include <linux/kernel.h>
7 #include <linux/list.h>
8 #include <linux/slab.h>
10 //static struct list_head pools;
14 #define OFFLINE_POOL_THRESHOLD 12
24 static struct mempool pool;
26 static inline int get_page_bit(int index) {
27 int major = index / 8;
28 int minor = index % 8;
30 return (pool.bitmap[major] & (0x1 << minor));
33 static inline void set_page_bit(int index) {
34 int major = index / 8;
35 int minor = index % 8;
37 pool.bitmap[major] |= (0x1 << minor);
40 static inline void clear_page_bit(int index) {
41 int major = index / 8;
42 int minor = index % 8;
44 pool.bitmap[major] &= ~(0x1 << minor);
48 uintptr_t get_palacios_base_addr(void) {
49 return pool.base_addr;
52 u64 get_palacios_num_pages(void) {
53 return pool.num_pages;
57 static uintptr_t alloc_contig_pgs(u64 num_pages, u32 alignment) {
62 DEBUG("Allocating %llu pages (align=%lu)\n",
63 num_pages, (unsigned long)alignment);
65 if (pool.bitmap == NULL) {
66 ERROR("ERROR: Attempting to allocate from non initialized memory\n");
71 step = alignment / PAGE_SIZE;
74 // Start the search at the correct alignment
75 if (pool.base_addr % alignment) {
76 start = ((alignment - (pool.base_addr % alignment)) >> 12);
79 DEBUG("\t Start idx %d (base_addr=%p)\n", start, (void *)(u64)pool.base_addr);
81 for (i = start; i < (pool.num_pages - num_pages); i += step) {
82 if (get_page_bit(i) == 0) {
86 for (j = i; (j - i) < num_pages; j++) {
87 if (get_page_bit(j) == 1) {
97 for (j = i; (j - i) < num_pages; j++) {
101 return pool.base_addr + (i * PAGE_SIZE);
105 ERROR("ALERT ALERT Allocation of Large Number of Contiguous Pages FAILED\n");
111 // alignment is in bytes
112 uintptr_t alloc_palacios_pgs(u64 num_pages, u32 alignment) {
115 if (num_pages < OFFLINE_POOL_THRESHOLD) {
116 struct page * pgs = NULL;
118 int order = get_order(num_pages * PAGE_SIZE);
120 pgs = alloc_pages(GFP_DMA32, order);
123 ERROR("Could not allocate small number of contigious pages\n");
127 /* DEBUG("%llu pages (order=%d) aquired from alloc_pages\n",
128 num_pages, order); */
130 addr = page_to_pfn(pgs) << PAGE_SHIFT;
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))) ) {
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);
148 //DEBUG("Allocating %llu pages from bitmap allocator\n", num_pages);
149 //addr = pool.base_addr;
150 addr = alloc_contig_pgs(num_pages, alignment);
152 ERROR("Could not allocate large number of contiguous pages\n");
157 //DEBUG("Returning from alloc addr=%p, vaddr=%p\n", (void *)addr, __va(addr));
163 void free_palacios_pgs(uintptr_t pg_addr, int num_pages) {
164 //DEBUG("Freeing Memory page %p\n", (void *)pg_addr);
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;
172 if (num_pages<OFFLINE_POOL_THRESHOLD) {
173 ERROR("ALERT ALERT small page deallocation from offline pool\n");
177 if ((pg_idx + num_pages) > pool.num_pages) {
178 ERROR("Freeing memory bounds exceeded for offline pool\n");
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");
186 clear_page_bit(pg_idx + i);
190 if (num_pages>=OFFLINE_POOL_THRESHOLD) {
191 ERROR("ALERT ALERT Large page deallocation from linux pool\n");
193 __free_pages(pfn_to_page(pg_addr >> PAGE_SHIFT), get_order(num_pages * PAGE_SIZE));
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
204 int bitmap_size = (num_pages / 8) + ((num_pages % 8) > 0);
206 if (pool.num_pages != 0) {
207 ERROR("ERROR: Memory has already been added\n");
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)));
217 pool.bitmap = palacios_alloc(bitmap_size);
219 if (IS_ERR(pool.bitmap)) {
220 ERROR("Error allocating Palacios MM bitmap\n");
224 memset(pool.bitmap, 0, bitmap_size);
226 pool.base_addr = base_addr;
227 pool.num_pages = num_pages;
234 int palacios_init_mm( void ) {
243 int palacios_deinit_mm( void ) {
245 palacios_free(pool.bitmap);
251 // note that the memory is not onlined here - offlining and onlining
252 // is the resposibility of the caller