bootmem.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  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. #include <linux/mm.h>
  12. #include <linux/kernel_stat.h>
  13. #include <linux/swap.h>
  14. #include <linux/swapctl.h>
  15. #include <linux/interrupt.h>
  16. #include <linux/init.h>
  17. #include <linux/bootmem.h>
  18. #include <linux/mmzone.h>
  19. #include <asm/dma.h>
  20. #include <asm/io.h>
  21. /*
  22.  * Access to this subsystem has to be serialized externally. (this is
  23.  * true for the boot process anyway)
  24.  */
  25. unsigned long max_low_pfn;
  26. unsigned long min_low_pfn;
  27. unsigned long max_pfn;
  28. /* return the number of _pages_ that will be allocated for the boot bitmap */
  29. unsigned long __init bootmem_bootmap_pages (unsigned long pages)
  30. {
  31. unsigned long mapsize;
  32. mapsize = (pages+7)/8;
  33. mapsize = (mapsize + ~PAGE_MASK) & PAGE_MASK;
  34. mapsize >>= PAGE_SHIFT;
  35. return mapsize;
  36. }
  37. /*
  38.  * Called once to set up the allocator itself.
  39.  */
  40. static unsigned long __init init_bootmem_core (pg_data_t *pgdat,
  41. unsigned long mapstart, unsigned long start, unsigned long end)
  42. {
  43. bootmem_data_t *bdata = pgdat->bdata;
  44. unsigned long mapsize = ((end - start)+7)/8;
  45. pgdat->node_next = pgdat_list;
  46. pgdat_list = pgdat;
  47. mapsize = (mapsize + (sizeof(long) - 1UL)) & ~(sizeof(long) - 1UL);
  48. bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT);
  49. bdata->node_boot_start = (start << PAGE_SHIFT);
  50. bdata->node_low_pfn = end;
  51. /*
  52.  * Initially all pages are reserved - setup_arch() has to
  53.  * register free RAM areas explicitly.
  54.  */
  55. memset(bdata->node_bootmem_map, 0xff, mapsize);
  56. return mapsize;
  57. }
  58. /*
  59.  * Marks a particular physical memory range as unallocatable. Usable RAM
  60.  * might be used for boot-time allocations - or it might get added
  61.  * to the free page pool later on.
  62.  */
  63. static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size)
  64. {
  65. unsigned long i;
  66. /*
  67.  * round up, partially reserved pages are considered
  68.  * fully reserved.
  69.  */
  70. unsigned long sidx = (addr - bdata->node_boot_start)/PAGE_SIZE;
  71. unsigned long eidx = (addr + size - bdata->node_boot_start + 
  72. PAGE_SIZE-1)/PAGE_SIZE;
  73. unsigned long end = (addr + size + PAGE_SIZE-1)/PAGE_SIZE;
  74. if (!size) BUG();
  75. if (sidx < 0)
  76. BUG();
  77. if (eidx < 0)
  78. BUG();
  79. if (sidx >= eidx)
  80. BUG();
  81. if ((addr >> PAGE_SHIFT) >= bdata->node_low_pfn)
  82. BUG();
  83. if (end > bdata->node_low_pfn)
  84. BUG();
  85. for (i = sidx; i < eidx; i++)
  86. if (test_and_set_bit(i, bdata->node_bootmem_map))
  87. printk("hm, page %08lx reserved twice.n", i*PAGE_SIZE);
  88. }
  89. static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size)
  90. {
  91. unsigned long i;
  92. unsigned long start;
  93. /*
  94.  * round down end of usable mem, partially free pages are
  95.  * considered reserved.
  96.  */
  97. unsigned long sidx;
  98. unsigned long eidx = (addr + size - bdata->node_boot_start)/PAGE_SIZE;
  99. unsigned long end = (addr + size)/PAGE_SIZE;
  100. if (!size) BUG();
  101. if (end > bdata->node_low_pfn)
  102. BUG();
  103. /*
  104.  * Round up the beginning of the address.
  105.  */
  106. start = (addr + PAGE_SIZE-1) / PAGE_SIZE;
  107. sidx = start - (bdata->node_boot_start/PAGE_SIZE);
  108. for (i = sidx; i < eidx; i++) {
  109. if (!test_and_clear_bit(i, bdata->node_bootmem_map))
  110. BUG();
  111. }
  112. }
  113. /*
  114.  * We 'merge' subsequent allocations to save space. We might 'lose'
  115.  * some fraction of a page if allocations cannot be satisfied due to
  116.  * size constraints on boxes where there is physical RAM space
  117.  * fragmentation - in these cases * (mostly large memory boxes) this
  118.  * is not a problem.
  119.  *
  120.  * On low memory boxes we get it right in 100% of the cases.
  121.  */
  122. /*
  123.  * alignment has to be a power of 2 value.
  124.  */
  125. static void * __init __alloc_bootmem_core (bootmem_data_t *bdata, 
  126. unsigned long size, unsigned long align, unsigned long goal)
  127. {
  128. unsigned long i, start = 0;
  129. void *ret;
  130. unsigned long offset, remaining_size;
  131. unsigned long areasize, preferred, incr;
  132. unsigned long eidx = bdata->node_low_pfn - (bdata->node_boot_start >>
  133. PAGE_SHIFT);
  134. if (!size) BUG();
  135. if (align & (align-1))
  136. BUG();
  137. offset = 0;
  138. if (align &&
  139.     (bdata->node_boot_start & (align - 1UL)) != 0)
  140. offset = (align - (bdata->node_boot_start & (align - 1UL)));
  141. offset >>= PAGE_SHIFT;
  142. /*
  143.  * We try to allocate bootmem pages above 'goal'
  144.  * first, then we try to allocate lower pages.
  145.  */
  146. if (goal && (goal >= bdata->node_boot_start) && 
  147. ((goal >> PAGE_SHIFT) < bdata->node_low_pfn)) {
  148. preferred = goal - bdata->node_boot_start;
  149. } else
  150. preferred = 0;
  151. preferred = ((preferred + align - 1) & ~(align - 1)) >> PAGE_SHIFT;
  152. preferred += offset;
  153. areasize = (size+PAGE_SIZE-1)/PAGE_SIZE;
  154. incr = align >> PAGE_SHIFT ? : 1;
  155. restart_scan:
  156. for (i = preferred; i < eidx; i += incr) {
  157. unsigned long j;
  158. if (test_bit(i, bdata->node_bootmem_map))
  159. continue;
  160. for (j = i + 1; j < i + areasize; ++j) {
  161. if (j >= eidx)
  162. goto fail_block;
  163. if (test_bit (j, bdata->node_bootmem_map))
  164. goto fail_block;
  165. }
  166. start = i;
  167. goto found;
  168. fail_block:;
  169. }
  170. if (preferred) {
  171. preferred = offset;
  172. goto restart_scan;
  173. }
  174. return NULL;
  175. found:
  176. if (start >= eidx)
  177. BUG();
  178. /*
  179.  * Is the next page of the previous allocation-end the start
  180.  * of this allocation's buffer? If yes then we can 'merge'
  181.  * the previous partial page with this allocation.
  182.  */
  183. if (align <= PAGE_SIZE
  184.     && bdata->last_offset && bdata->last_pos+1 == start) {
  185. offset = (bdata->last_offset+align-1) & ~(align-1);
  186. if (offset > PAGE_SIZE)
  187. BUG();
  188. remaining_size = PAGE_SIZE-offset;
  189. if (size < remaining_size) {
  190. areasize = 0;
  191. // last_pos unchanged
  192. bdata->last_offset = offset+size;
  193. ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset +
  194. bdata->node_boot_start);
  195. } else {
  196. remaining_size = size - remaining_size;
  197. areasize = (remaining_size+PAGE_SIZE-1)/PAGE_SIZE;
  198. ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset +
  199. bdata->node_boot_start);
  200. bdata->last_pos = start+areasize-1;
  201. bdata->last_offset = remaining_size;
  202. }
  203. bdata->last_offset &= ~PAGE_MASK;
  204. } else {
  205. bdata->last_pos = start + areasize - 1;
  206. bdata->last_offset = size & ~PAGE_MASK;
  207. ret = phys_to_virt(start * PAGE_SIZE + bdata->node_boot_start);
  208. }
  209. /*
  210.  * Reserve the area now:
  211.  */
  212. for (i = start; i < start+areasize; i++)
  213. if (test_and_set_bit(i, bdata->node_bootmem_map))
  214. BUG();
  215. memset(ret, 0, size);
  216. return ret;
  217. }
  218. static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat)
  219. {
  220. struct page *page = pgdat->node_mem_map;
  221. bootmem_data_t *bdata = pgdat->bdata;
  222. unsigned long i, count, total = 0;
  223. unsigned long idx;
  224. if (!bdata->node_bootmem_map) BUG();
  225. count = 0;
  226. idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT);
  227. for (i = 0; i < idx; i++, page++) {
  228. if (!test_bit(i, bdata->node_bootmem_map)) {
  229. count++;
  230. ClearPageReserved(page);
  231. set_page_count(page, 1);
  232. __free_page(page);
  233. }
  234. }
  235. total += count;
  236. /*
  237.  * Now free the allocator bitmap itself, it's not
  238.  * needed anymore:
  239.  */
  240. page = virt_to_page(bdata->node_bootmem_map);
  241. count = 0;
  242. for (i = 0; i < ((bdata->node_low_pfn-(bdata->node_boot_start >> PAGE_SHIFT))/8 + PAGE_SIZE-1)/PAGE_SIZE; i++,page++) {
  243. count++;
  244. ClearPageReserved(page);
  245. set_page_count(page, 1);
  246. __free_page(page);
  247. }
  248. total += count;
  249. bdata->node_bootmem_map = NULL;
  250. return total;
  251. }
  252. unsigned long __init init_bootmem_node (pg_data_t *pgdat, unsigned long freepfn, unsigned long startpfn, unsigned long endpfn)
  253. {
  254. return(init_bootmem_core(pgdat, freepfn, startpfn, endpfn));
  255. }
  256. void __init reserve_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size)
  257. {
  258. reserve_bootmem_core(pgdat->bdata, physaddr, size);
  259. }
  260. void __init free_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size)
  261. {
  262. return(free_bootmem_core(pgdat->bdata, physaddr, size));
  263. }
  264. unsigned long __init free_all_bootmem_node (pg_data_t *pgdat)
  265. {
  266. return(free_all_bootmem_core(pgdat));
  267. }
  268. unsigned long __init init_bootmem (unsigned long start, unsigned long pages)
  269. {
  270. max_low_pfn = pages;
  271. min_low_pfn = start;
  272. return(init_bootmem_core(&contig_page_data, start, 0, pages));
  273. }
  274. void __init reserve_bootmem (unsigned long addr, unsigned long size)
  275. {
  276. reserve_bootmem_core(contig_page_data.bdata, addr, size);
  277. }
  278. void __init free_bootmem (unsigned long addr, unsigned long size)
  279. {
  280. return(free_bootmem_core(contig_page_data.bdata, addr, size));
  281. }
  282. unsigned long __init free_all_bootmem (void)
  283. {
  284. return(free_all_bootmem_core(&contig_page_data));
  285. }
  286. void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal)
  287. {
  288. pg_data_t *pgdat;
  289. void *ptr;
  290. for_each_pgdat(pgdat)
  291. if ((ptr = __alloc_bootmem_core(pgdat->bdata, size,
  292. align, goal)))
  293. return(ptr);
  294. /*
  295.  * Whoops, we cannot satisfy the allocation request.
  296.  */
  297. printk(KERN_ALERT "bootmem alloc of %lu bytes failed!n", size);
  298. panic("Out of memory");
  299. return NULL;
  300. }
  301. void * __init __alloc_bootmem_node (pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal)
  302. {
  303. void *ptr;
  304. ptr = __alloc_bootmem_core(pgdat->bdata, size, align, goal);
  305. if (ptr)
  306. return (ptr);
  307. /*
  308.  * Whoops, we cannot satisfy the allocation request.
  309.  */
  310. printk(KERN_ALERT "bootmem alloc of %lu bytes failed!n", size);
  311. panic("Out of memory");
  312. return NULL;
  313. }