Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.18-rc2 463 lines 12 kB view raw
1/* 2 * linux/mm/bootmem.c 3 * 4 * Copyright (C) 1999 Ingo Molnar 5 * Discontiguous memory support, Kanoj Sarcar, SGI, Nov 1999 6 * 7 * simple boot-time physical memory area allocator and 8 * free memory collector. It's used to deal with reserved 9 * system memory and memory holes as well. 10 */ 11 12#include <linux/mm.h> 13#include <linux/kernel_stat.h> 14#include <linux/swap.h> 15#include <linux/interrupt.h> 16#include <linux/init.h> 17#include <linux/bootmem.h> 18#include <linux/mmzone.h> 19#include <linux/module.h> 20#include <asm/dma.h> 21#include <asm/io.h> 22#include "internal.h" 23 24/* 25 * Access to this subsystem has to be serialized externally. (this is 26 * true for the boot process anyway) 27 */ 28unsigned long max_low_pfn; 29unsigned long min_low_pfn; 30unsigned long max_pfn; 31 32EXPORT_UNUSED_SYMBOL(max_pfn); /* June 2006 */ 33 34static LIST_HEAD(bdata_list); 35#ifdef CONFIG_CRASH_DUMP 36/* 37 * If we have booted due to a crash, max_pfn will be a very low value. We need 38 * to know the amount of memory that the previous kernel used. 39 */ 40unsigned long saved_max_pfn; 41#endif 42 43/* return the number of _pages_ that will be allocated for the boot bitmap */ 44unsigned long __init bootmem_bootmap_pages (unsigned long pages) 45{ 46 unsigned long mapsize; 47 48 mapsize = (pages+7)/8; 49 mapsize = (mapsize + ~PAGE_MASK) & PAGE_MASK; 50 mapsize >>= PAGE_SHIFT; 51 52 return mapsize; 53} 54/* 55 * link bdata in order 56 */ 57static void link_bootmem(bootmem_data_t *bdata) 58{ 59 bootmem_data_t *ent; 60 if (list_empty(&bdata_list)) { 61 list_add(&bdata->list, &bdata_list); 62 return; 63 } 64 /* insert in order */ 65 list_for_each_entry(ent, &bdata_list, list) { 66 if (bdata->node_boot_start < ent->node_boot_start) { 67 list_add_tail(&bdata->list, &ent->list); 68 return; 69 } 70 } 71 list_add_tail(&bdata->list, &bdata_list); 72 return; 73} 74 75 76/* 77 * Called once to set up the allocator itself. 78 */ 79static unsigned long __init init_bootmem_core (pg_data_t *pgdat, 80 unsigned long mapstart, unsigned long start, unsigned long end) 81{ 82 bootmem_data_t *bdata = pgdat->bdata; 83 unsigned long mapsize = ((end - start)+7)/8; 84 85 mapsize = ALIGN(mapsize, sizeof(long)); 86 bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT); 87 bdata->node_boot_start = (start << PAGE_SHIFT); 88 bdata->node_low_pfn = end; 89 link_bootmem(bdata); 90 91 /* 92 * Initially all pages are reserved - setup_arch() has to 93 * register free RAM areas explicitly. 94 */ 95 memset(bdata->node_bootmem_map, 0xff, mapsize); 96 97 return mapsize; 98} 99 100/* 101 * Marks a particular physical memory range as unallocatable. Usable RAM 102 * might be used for boot-time allocations - or it might get added 103 * to the free page pool later on. 104 */ 105static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size) 106{ 107 unsigned long i; 108 /* 109 * round up, partially reserved pages are considered 110 * fully reserved. 111 */ 112 unsigned long sidx = (addr - bdata->node_boot_start)/PAGE_SIZE; 113 unsigned long eidx = (addr + size - bdata->node_boot_start + 114 PAGE_SIZE-1)/PAGE_SIZE; 115 unsigned long end = (addr + size + PAGE_SIZE-1)/PAGE_SIZE; 116 117 BUG_ON(!size); 118 BUG_ON(sidx >= eidx); 119 BUG_ON((addr >> PAGE_SHIFT) >= bdata->node_low_pfn); 120 BUG_ON(end > bdata->node_low_pfn); 121 122 for (i = sidx; i < eidx; i++) 123 if (test_and_set_bit(i, bdata->node_bootmem_map)) { 124#ifdef CONFIG_DEBUG_BOOTMEM 125 printk("hm, page %08lx reserved twice.\n", i*PAGE_SIZE); 126#endif 127 } 128} 129 130static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size) 131{ 132 unsigned long i; 133 unsigned long start; 134 /* 135 * round down end of usable mem, partially free pages are 136 * considered reserved. 137 */ 138 unsigned long sidx; 139 unsigned long eidx = (addr + size - bdata->node_boot_start)/PAGE_SIZE; 140 unsigned long end = (addr + size)/PAGE_SIZE; 141 142 BUG_ON(!size); 143 BUG_ON(end > bdata->node_low_pfn); 144 145 if (addr < bdata->last_success) 146 bdata->last_success = addr; 147 148 /* 149 * Round up the beginning of the address. 150 */ 151 start = (addr + PAGE_SIZE-1) / PAGE_SIZE; 152 sidx = start - (bdata->node_boot_start/PAGE_SIZE); 153 154 for (i = sidx; i < eidx; i++) { 155 if (unlikely(!test_and_clear_bit(i, bdata->node_bootmem_map))) 156 BUG(); 157 } 158} 159 160/* 161 * We 'merge' subsequent allocations to save space. We might 'lose' 162 * some fraction of a page if allocations cannot be satisfied due to 163 * size constraints on boxes where there is physical RAM space 164 * fragmentation - in these cases (mostly large memory boxes) this 165 * is not a problem. 166 * 167 * On low memory boxes we get it right in 100% of the cases. 168 * 169 * alignment has to be a power of 2 value. 170 * 171 * NOTE: This function is _not_ reentrant. 172 */ 173void * __init 174__alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size, 175 unsigned long align, unsigned long goal, unsigned long limit) 176{ 177 unsigned long offset, remaining_size, areasize, preferred; 178 unsigned long i, start = 0, incr, eidx, end_pfn = bdata->node_low_pfn; 179 void *ret; 180 181 if(!size) { 182 printk("__alloc_bootmem_core(): zero-sized request\n"); 183 BUG(); 184 } 185 BUG_ON(align & (align-1)); 186 187 if (limit && bdata->node_boot_start >= limit) 188 return NULL; 189 190 limit >>=PAGE_SHIFT; 191 if (limit && end_pfn > limit) 192 end_pfn = limit; 193 194 eidx = end_pfn - (bdata->node_boot_start >> PAGE_SHIFT); 195 offset = 0; 196 if (align && 197 (bdata->node_boot_start & (align - 1UL)) != 0) 198 offset = (align - (bdata->node_boot_start & (align - 1UL))); 199 offset >>= PAGE_SHIFT; 200 201 /* 202 * We try to allocate bootmem pages above 'goal' 203 * first, then we try to allocate lower pages. 204 */ 205 if (goal && (goal >= bdata->node_boot_start) && 206 ((goal >> PAGE_SHIFT) < end_pfn)) { 207 preferred = goal - bdata->node_boot_start; 208 209 if (bdata->last_success >= preferred) 210 if (!limit || (limit && limit > bdata->last_success)) 211 preferred = bdata->last_success; 212 } else 213 preferred = 0; 214 215 preferred = ALIGN(preferred, align) >> PAGE_SHIFT; 216 preferred += offset; 217 areasize = (size+PAGE_SIZE-1)/PAGE_SIZE; 218 incr = align >> PAGE_SHIFT ? : 1; 219 220restart_scan: 221 for (i = preferred; i < eidx; i += incr) { 222 unsigned long j; 223 i = find_next_zero_bit(bdata->node_bootmem_map, eidx, i); 224 i = ALIGN(i, incr); 225 if (i >= eidx) 226 break; 227 if (test_bit(i, bdata->node_bootmem_map)) 228 continue; 229 for (j = i + 1; j < i + areasize; ++j) { 230 if (j >= eidx) 231 goto fail_block; 232 if (test_bit (j, bdata->node_bootmem_map)) 233 goto fail_block; 234 } 235 start = i; 236 goto found; 237 fail_block: 238 i = ALIGN(j, incr); 239 } 240 241 if (preferred > offset) { 242 preferred = offset; 243 goto restart_scan; 244 } 245 return NULL; 246 247found: 248 bdata->last_success = start << PAGE_SHIFT; 249 BUG_ON(start >= eidx); 250 251 /* 252 * Is the next page of the previous allocation-end the start 253 * of this allocation's buffer? If yes then we can 'merge' 254 * the previous partial page with this allocation. 255 */ 256 if (align < PAGE_SIZE && 257 bdata->last_offset && bdata->last_pos+1 == start) { 258 offset = ALIGN(bdata->last_offset, align); 259 BUG_ON(offset > PAGE_SIZE); 260 remaining_size = PAGE_SIZE-offset; 261 if (size < remaining_size) { 262 areasize = 0; 263 /* last_pos unchanged */ 264 bdata->last_offset = offset+size; 265 ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset + 266 bdata->node_boot_start); 267 } else { 268 remaining_size = size - remaining_size; 269 areasize = (remaining_size+PAGE_SIZE-1)/PAGE_SIZE; 270 ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset + 271 bdata->node_boot_start); 272 bdata->last_pos = start+areasize-1; 273 bdata->last_offset = remaining_size; 274 } 275 bdata->last_offset &= ~PAGE_MASK; 276 } else { 277 bdata->last_pos = start + areasize - 1; 278 bdata->last_offset = size & ~PAGE_MASK; 279 ret = phys_to_virt(start * PAGE_SIZE + bdata->node_boot_start); 280 } 281 282 /* 283 * Reserve the area now: 284 */ 285 for (i = start; i < start+areasize; i++) 286 if (unlikely(test_and_set_bit(i, bdata->node_bootmem_map))) 287 BUG(); 288 memset(ret, 0, size); 289 return ret; 290} 291 292static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat) 293{ 294 struct page *page; 295 unsigned long pfn; 296 bootmem_data_t *bdata = pgdat->bdata; 297 unsigned long i, count, total = 0; 298 unsigned long idx; 299 unsigned long *map; 300 int gofast = 0; 301 302 BUG_ON(!bdata->node_bootmem_map); 303 304 count = 0; 305 /* first extant page of the node */ 306 pfn = bdata->node_boot_start >> PAGE_SHIFT; 307 idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT); 308 map = bdata->node_bootmem_map; 309 /* Check physaddr is O(LOG2(BITS_PER_LONG)) page aligned */ 310 if (bdata->node_boot_start == 0 || 311 ffs(bdata->node_boot_start) - PAGE_SHIFT > ffs(BITS_PER_LONG)) 312 gofast = 1; 313 for (i = 0; i < idx; ) { 314 unsigned long v = ~map[i / BITS_PER_LONG]; 315 316 if (gofast && v == ~0UL) { 317 int order; 318 319 page = pfn_to_page(pfn); 320 count += BITS_PER_LONG; 321 order = ffs(BITS_PER_LONG) - 1; 322 __free_pages_bootmem(page, order); 323 i += BITS_PER_LONG; 324 page += BITS_PER_LONG; 325 } else if (v) { 326 unsigned long m; 327 328 page = pfn_to_page(pfn); 329 for (m = 1; m && i < idx; m<<=1, page++, i++) { 330 if (v & m) { 331 count++; 332 __free_pages_bootmem(page, 0); 333 } 334 } 335 } else { 336 i+=BITS_PER_LONG; 337 } 338 pfn += BITS_PER_LONG; 339 } 340 total += count; 341 342 /* 343 * Now free the allocator bitmap itself, it's not 344 * needed anymore: 345 */ 346 page = virt_to_page(bdata->node_bootmem_map); 347 count = 0; 348 for (i = 0; i < ((bdata->node_low_pfn-(bdata->node_boot_start >> PAGE_SHIFT))/8 + PAGE_SIZE-1)/PAGE_SIZE; i++,page++) { 349 count++; 350 __free_pages_bootmem(page, 0); 351 } 352 total += count; 353 bdata->node_bootmem_map = NULL; 354 355 return total; 356} 357 358unsigned long __init init_bootmem_node (pg_data_t *pgdat, unsigned long freepfn, unsigned long startpfn, unsigned long endpfn) 359{ 360 return(init_bootmem_core(pgdat, freepfn, startpfn, endpfn)); 361} 362 363void __init reserve_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size) 364{ 365 reserve_bootmem_core(pgdat->bdata, physaddr, size); 366} 367 368void __init free_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size) 369{ 370 free_bootmem_core(pgdat->bdata, physaddr, size); 371} 372 373unsigned long __init free_all_bootmem_node (pg_data_t *pgdat) 374{ 375 return(free_all_bootmem_core(pgdat)); 376} 377 378unsigned long __init init_bootmem (unsigned long start, unsigned long pages) 379{ 380 max_low_pfn = pages; 381 min_low_pfn = start; 382 return(init_bootmem_core(NODE_DATA(0), start, 0, pages)); 383} 384 385#ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE 386void __init reserve_bootmem (unsigned long addr, unsigned long size) 387{ 388 reserve_bootmem_core(NODE_DATA(0)->bdata, addr, size); 389} 390#endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */ 391 392void __init free_bootmem (unsigned long addr, unsigned long size) 393{ 394 free_bootmem_core(NODE_DATA(0)->bdata, addr, size); 395} 396 397unsigned long __init free_all_bootmem (void) 398{ 399 return(free_all_bootmem_core(NODE_DATA(0))); 400} 401 402void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align, unsigned long goal) 403{ 404 bootmem_data_t *bdata; 405 void *ptr; 406 407 list_for_each_entry(bdata, &bdata_list, list) 408 if ((ptr = __alloc_bootmem_core(bdata, size, align, goal, 0))) 409 return(ptr); 410 return NULL; 411} 412 413void * __init __alloc_bootmem(unsigned long size, unsigned long align, unsigned long goal) 414{ 415 void *mem = __alloc_bootmem_nopanic(size,align,goal); 416 if (mem) 417 return mem; 418 /* 419 * Whoops, we cannot satisfy the allocation request. 420 */ 421 printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size); 422 panic("Out of memory"); 423 return NULL; 424} 425 426 427void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size, unsigned long align, 428 unsigned long goal) 429{ 430 void *ptr; 431 432 ptr = __alloc_bootmem_core(pgdat->bdata, size, align, goal, 0); 433 if (ptr) 434 return (ptr); 435 436 return __alloc_bootmem(size, align, goal); 437} 438 439#define LOW32LIMIT 0xffffffff 440 441void * __init __alloc_bootmem_low(unsigned long size, unsigned long align, unsigned long goal) 442{ 443 bootmem_data_t *bdata; 444 void *ptr; 445 446 list_for_each_entry(bdata, &bdata_list, list) 447 if ((ptr = __alloc_bootmem_core(bdata, size, 448 align, goal, LOW32LIMIT))) 449 return(ptr); 450 451 /* 452 * Whoops, we cannot satisfy the allocation request. 453 */ 454 printk(KERN_ALERT "low bootmem alloc of %lu bytes failed!\n", size); 455 panic("Out of low memory"); 456 return NULL; 457} 458 459void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size, 460 unsigned long align, unsigned long goal) 461{ 462 return __alloc_bootmem_core(pgdat->bdata, size, align, goal, LOW32LIMIT); 463}