在uboot 传递给kernel memory bank相关信息后,kernel这边会以memblcok的方式保存这些信息,当buddy system 没有起来之前,在kernel中也是要有一套机制来管理memory的申请和释放.
source/mm/Makefile
44 ifdef CONFIG_NO_BOOTMEM
45 obj-y += nobootmem.o
46 else
47 obj-y += bootmem.o
48 endif
如上所示kernel 可以选择nobootmem 或者bootmem 来在buddy system起来之前管理memory.
这两种机制对提供的API是一致的,因此对用户是透明的。我们以alloc_bootmem 为例来分析一下这两种机制的差别.
可以看到alloc_bootmem 在下面两个文件中都有实现。
mm/nobootmem.c, line 309
mm/bootmem.c, line 700
700 void * __init __alloc_bootmem(unsigned long size, unsigned long align,
701 unsigned long goal)
702 {
703 unsigned long limit = 0;
704
705 return ___alloc_bootmem(size, align, goal, limit);
706 }
两种机制继续调用___alloc_bootmem
672 static void * __init ___alloc_bootmem(unsigned long size, unsigned long align,
673 unsigned long goal, unsigned long limit)
674 {
675 void *mem = ___alloc_bootmem_nopanic(size, align, goal, limit);
676
677 if (mem)
678 return mem;
679 /*
680 * Whoops, we cannot satisfy the allocation request.
681 */
682 pr_alert("bootmem alloc of %lu bytes failed!\n", size);
683 panic("Out of memory");
684 return NULL;
685 }
两种机制继续调用___alloc_bootmem_nopanic
632 static void * __init ___alloc_bootmem_nopanic(unsigned long size,
633 unsigned long align,
634 unsigned long goal,
635 unsigned long limit)
636 {
637 void *ptr;
638
639 restart:
640 ptr = alloc_bootmem_core(size, align, goal, limit);
641 if (ptr)
642 return ptr;
643 if (goal) {
644 goal = 0;
645 goto restart;
646 }
647
648 return NULL;
649 }
从___alloc_bootmem_nopanic 两种机制走的flow就不一样了我们先看bootmem 调用alloc_bootmem_core
static void * __init alloc_bootmem_core(unsigned long size,
608 unsigned long align,
609 unsigned long goal,
610 unsigned long limit)
611 {
612 bootmem_data_t *bdata;
613 void *region;
614
615 if (WARN_ON_ONCE(slab_is_available()))
616 return kzalloc(size, GFP_NOWAIT);
617
618 list_for_each_entry(bdata, &bdata_list, list) {
619 if (goal && bdata->node_low_pfn <= PFN_DOWN(goal))
620 continue;
621 if (limit && bdata->node_min_pfn >= PFN_DOWN(limit))
622 break;
623
624 region = alloc_bootmem_bdata(bdata, size, align, goal, limit);
625 if (region)
626 return region;
627 }
628
629 return NULL;
630 }
这个时候就去bdata 中的bitmap中找是否有足够的memory 进行,是page来计算的。
而noboomem的___alloc_bootmem_nopanic的实现如下:
235 static void * __init ___alloc_bootmem_nopanic(unsigned long size,
236 unsigned long align,
237 unsigned long goal,
238 unsigned long limit)
239 {
240 void *ptr;
241
242 if (WARN_ON_ONCE(slab_is_available()))
243 return kzalloc(size, GFP_NOWAIT);
244
245 restart:
246
247 ptr = __alloc_memory_core_early(NUMA_NO_NODE, size, align, goal, limit);
248
249 if (ptr)
250 return ptr;
251
252 if (goal != 0) {
253 goal = 0;
254 goto restart;
255 }
256
257 return NULL;
258 }
调用__alloc_memory_core_early 来分配memory
static void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
37 u64 goal, u64 limit)
38 {
39 void *ptr;
40 u64 addr;
41 ulong flags = choose_memblock_flags();
42
43 if (limit > memblock.current_limit)
44 limit = memblock.current_limit;
45
46 again:
47 addr = memblock_find_in_range_node(size, align, goal, limit, nid,
48 flags);
49 if (!addr && (flags & MEMBLOCK_MIRROR)) {
50 flags &= ~MEMBLOCK_MIRROR;
51 pr_warn("Could not allocate %pap bytes of mirrored memory\n",
52 &size);
53 goto again;
54 }
55 if (!addr)
56 return NULL;
57
58 if (memblock_reserve(addr, size))
59 return NULL;
60
61 ptr = phys_to_virt(addr);
62 memset(ptr, 0, size);
63 /*
64 * The min_count is set to 0 so that bootmem allocated blocks
65 * are never reported as leaks.
66 */
67 kmemleak_alloc(ptr, size, 0, 0);
68 return ptr;
69 }
最终的是47行直接调用memblcok 来分配.
可见两种机制提供的API是一致的。但是实现的细节不同。bootmem是通过bitmap,按page来申请的。而nobootmem 直接通过memblock来实现。个人还是比较喜欢nobootmem 去繁就简的实现。
source/mm/Makefile
44 ifdef CONFIG_NO_BOOTMEM
45 obj-y += nobootmem.o
46 else
47 obj-y += bootmem.o
48 endif
如上所示kernel 可以选择nobootmem 或者bootmem 来在buddy system起来之前管理memory.
这两种机制对提供的API是一致的,因此对用户是透明的。我们以alloc_bootmem 为例来分析一下这两种机制的差别.
可以看到alloc_bootmem 在下面两个文件中都有实现。
mm/nobootmem.c, line 309
mm/bootmem.c, line 700
700 void * __init __alloc_bootmem(unsigned long size, unsigned long align,
701 unsigned long goal)
702 {
703 unsigned long limit = 0;
704
705 return ___alloc_bootmem(size, align, goal, limit);
706 }
两种机制继续调用___alloc_bootmem
672 static void * __init ___alloc_bootmem(unsigned long size, unsigned long align,
673 unsigned long goal, unsigned long limit)
674 {
675 void *mem = ___alloc_bootmem_nopanic(size, align, goal, limit);
676
677 if (mem)
678 return mem;
679 /*
680 * Whoops, we cannot satisfy the allocation request.
681 */
682 pr_alert("bootmem alloc of %lu bytes failed!\n", size);
683 panic("Out of memory");
684 return NULL;
685 }
两种机制继续调用___alloc_bootmem_nopanic
632 static void * __init ___alloc_bootmem_nopanic(unsigned long size,
633 unsigned long align,
634 unsigned long goal,
635 unsigned long limit)
636 {
637 void *ptr;
638
639 restart:
640 ptr = alloc_bootmem_core(size, align, goal, limit);
641 if (ptr)
642 return ptr;
643 if (goal) {
644 goal = 0;
645 goto restart;
646 }
647
648 return NULL;
649 }
从___alloc_bootmem_nopanic 两种机制走的flow就不一样了我们先看bootmem 调用alloc_bootmem_core
static void * __init alloc_bootmem_core(unsigned long size,
608 unsigned long align,
609 unsigned long goal,
610 unsigned long limit)
611 {
612 bootmem_data_t *bdata;
613 void *region;
614
615 if (WARN_ON_ONCE(slab_is_available()))
616 return kzalloc(size, GFP_NOWAIT);
617
618 list_for_each_entry(bdata, &bdata_list, list) {
619 if (goal && bdata->node_low_pfn <= PFN_DOWN(goal))
620 continue;
621 if (limit && bdata->node_min_pfn >= PFN_DOWN(limit))
622 break;
623
624 region = alloc_bootmem_bdata(bdata, size, align, goal, limit);
625 if (region)
626 return region;
627 }
628
629 return NULL;
630 }
这个时候就去bdata 中的bitmap中找是否有足够的memory 进行,是page来计算的。
而noboomem的___alloc_bootmem_nopanic的实现如下:
235 static void * __init ___alloc_bootmem_nopanic(unsigned long size,
236 unsigned long align,
237 unsigned long goal,
238 unsigned long limit)
239 {
240 void *ptr;
241
242 if (WARN_ON_ONCE(slab_is_available()))
243 return kzalloc(size, GFP_NOWAIT);
244
245 restart:
246
247 ptr = __alloc_memory_core_early(NUMA_NO_NODE, size, align, goal, limit);
248
249 if (ptr)
250 return ptr;
251
252 if (goal != 0) {
253 goal = 0;
254 goto restart;
255 }
256
257 return NULL;
258 }
调用__alloc_memory_core_early 来分配memory
static void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
37 u64 goal, u64 limit)
38 {
39 void *ptr;
40 u64 addr;
41 ulong flags = choose_memblock_flags();
42
43 if (limit > memblock.current_limit)
44 limit = memblock.current_limit;
45
46 again:
47 addr = memblock_find_in_range_node(size, align, goal, limit, nid,
48 flags);
49 if (!addr && (flags & MEMBLOCK_MIRROR)) {
50 flags &= ~MEMBLOCK_MIRROR;
51 pr_warn("Could not allocate %pap bytes of mirrored memory\n",
52 &size);
53 goto again;
54 }
55 if (!addr)
56 return NULL;
57
58 if (memblock_reserve(addr, size))
59 return NULL;
60
61 ptr = phys_to_virt(addr);
62 memset(ptr, 0, size);
63 /*
64 * The min_count is set to 0 so that bootmem allocated blocks
65 * are never reported as leaks.
66 */
67 kmemleak_alloc(ptr, size, 0, 0);
68 return ptr;
69 }
最终的是47行直接调用memblcok 来分配.
可见两种机制提供的API是一致的。但是实现的细节不同。bootmem是通过bitmap,按page来申请的。而nobootmem 直接通过memblock来实现。个人还是比较喜欢nobootmem 去繁就简的实现。