该阶段完成了
1. 根据 memblock 的 reserved 成员 reserve 不需要填充的页表 // reserve_bootmem_region
2. 通过 在 全物理内存内 互补 memblock 的 reserved,得到未使用的物理内存,填充需要填充的页表 // __free_memory_core
3. 至此 , buddy 初始化完成
4. 用(内存地址,内存大小,申请块大小)填充 kmalloc_caches[type([0-1])][idx([6-d])]
5. 至此 , slab 初始化完成
6. 将 在vmalloc区间的 已经使用的虚拟内存地址A(主要是io设备) 注册到 vmap_area_root
7. 通过 在 全虚拟内存(非vmalloc区间)内 互补 A , 得到虚拟地址空间,注册到 free_vmap_area_root
8. 至此 , vmalloc 初始化完成
// 现在已经不打印 虚拟内存布局 了
// 请查看 1c31d4e96b8c205fe3aa8e73e930a0ccbf4b9a2b
其实 setup_arch 中也有 关于 mem 的部分
setup_arch 中 与mem 相关的部分
2. 匹配 板级 mdesc , 并解析 atags(包括core cmdline mem)
5. 初始化 各种类型的 描述符表
6. 添加 各种(kernel/initrd/设备树/atags/设备树中预留的/)预留的内存到 memblock
7. 对 即将存储页表的地址 清0
8. 针对 多项内容(lowmem/设备树/vectors/各项设备)填充页表
10. 申请内存,用于存储 很多个struct page
11. 初始化所有的 struct page
可以这么说 , setup_arch 中完成了
1. 虚拟页表的创建(lowmem/设备树/vectors/各项设备)
2. memblock 的初始化 // 在 setup_arch 的末尾,已经可以 通过 memblock_alloc 来 申请内存了
3. buddy初始化的第一部分 // 所有低端内存的 struct page 已经准备好了
在这篇文章中,主要关注下面的函数
page_address_init
// null
setup_arch
// 之前已经讨论过
build_all_zonelists
// 打印信息
// Built 1 zonelists, mobility grouping on. Total pages: 65024
mm_init
// 打印信息
// mem auto-init: stack:off, heap alloc:off, heap free:off
// Memory: 243936K/262144K available (5120K kernel code, 6569K rwdata, 732K rodata, 1024K init, 2134K bss, 18208K reserved, 0K cma-reserved)
// SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
- build_all_zonelists
build_all_zonelists
build_all_zonelists_init
__build_all_zonelists
for_each_online_node(nid) build_zonelists(pgdat);
zonerefs = pgdat->node_zonelists[ZONELIST_FALLBACK]._zonerefs;
nr_zones = build_zonerefs_node(pgdat, zonerefs);
zone = pgdat->node_zones + zone_type;
zoneref_set_zone(zone, &zonerefs[nr_zones++]);
zoneref->zone = zone;
zoneref->zone_idx = zone_idx(zone);
zonerefs += nr_zones;
for_each_possible_cpu(cpu) pageset_init(&per_cpu(boot_pageset, cpu));
mminit_verify_zonelist
cpuset_init_current_mems_allowed
vm_total_pages = nr_free_zone_pages(gfp_zone(GFP_HIGHUSER_MOVABLE)); // fe00
page_group_by_mobility_disabled = 0;
- mm_init
mm_init
page_ext_init_flatmem
// null
init_mem_debugging_and_hardening
// TODO
report_meminit
// pr_info
mem_init
set_max_mapnr(pfn_to_page(max_pfn) - mem_map);
max_mapnr = pfn_to_page(max_pfn) - mem_map;
/* this will put all unused low memory onto the freelists */
memblock_free_all
free_unused_memmap // 稀疏内存相关,释放不存在的地址
free_memmap
reset_all_zones_managed_pages
pages = free_low_memory_core_early
// reserve all the struct page
for_each_reserved_mem_range(i, &start, &end) reserve_bootmem_region(start, end); // reserve_bootmem_region 执行了 16次
for (; start_pfn < end_pfn; start_pfn++)
init_reserved_page(start_pfn);
INIT_LIST_HEAD(&page->lru);
__SetPageReserved(page);
/*
// 这 16 个 是 memblock 中的 reserved 成员
为 kernel/页表/struct page/vectors 预留的
还有 io map/request_standard_resources 过程中申请的内存
reserve_bootmem_region // 16次,之所以是16次,是因为之前调用了 memblock_alloc 16次
start_pfn:50004,end_pfn:50008 // 标记这段地址已经被使用,用作页表
page:cfdf5080
page:cfdf50a0
page:cfdf50c0
page:cfdf50e0
start_pfn:50100,end_pfn:51081 // 标记这段地址已经被使用,用作 kernel中的 (__pa(KERNEL_START), KERNEL_END - KERNEL_START)
page:cfdf7000
...
page:cfe16000
start_pfn:5fdbc,end_pfn:5fdf4
page:cfff0780
...
page:cfff0e60
start_pfn:5fdf5,end_pfn:5fffc // 标记这段地址已经被使用,用作 struct page
page:cfff0ea0
...
page:cfff4f60
start_pfn:5fffc,end_pfn:5fffd
page:cfff4f80
start_pfn:5fffc,end_pfn:5fffd
page:cfff4f80
start_pfn:5fffc,end_pfn:5fffd
page:cfff4f80
start_pfn:5fffc,end_pfn:5fffd
page:cfff4f80
start_pfn:5fffc,end_pfn:5fffd
page:cfff4f80
start_pfn:5fffc,end_pfn:5fffd
page:cfff4f80
start_pfn:5fffc,end_pfn:5fffd
page:cfff4f80
start_pfn:5fffc,end_pfn:5fffd
page:cfff4f80
start_pfn:5fffc,end_pfn:5fffd
page:cfff4f80
start_pfn:5fffc,end_pfn:5fffd
page:cfff4f80
start_pfn:5fffc,end_pfn:5fffd
page:cfff4f80
start_pfn:5fffc,end_pfn:60000 // 标记这段被 vectors 和 其他等 占用
page:cfff4f80
...
page:cfff4fe0
*/
// free mem
for_each_free_mem_range __free_memory_core(start, end);
__free_pages_memory(start_pfn, end_pfn); // __free_pages_memory 执行了 4次
memblock_free_pages(pfn_to_page(start), start, order);
__free_pages_core
__free_pages_ok
free_one_page
__free_one_page
add_to_free_list(page, zone, order, migratetype);
/*
__free_pages_memory 执行了4次
// 之所以是4次,是因为 总的内存 减去 memblock_alloc 的内存 ,只剩下4块连续的 free 内存
start_pfn:50000,end_pfn:50004 // 标记这段内存没被使用
pfn_to_page(start):cfdf5000, start:50000, order:2
start_pfn:50008,end_pfn:50100 // 标记这段内存没被使用,虽然这段是属于kernel的,但是不属于 kernel 的 (__pa(KERNEL_START), KERNEL_END - KERNEL_START)
pfn_to_page(start):cfdf5100, start:50008, order:3
pfn_to_page(start):cfdf5200, start:50010, order:4
pfn_to_page(start):cfdf5400, start:50020, order:5
pfn_to_page(start):cfdf5800, start:50040, order:6
pfn_to_page(start):cfdf6000, start:50080, order:7
start_pfn:51081,end_pfn:5fdbc
pfn_to_page(start):cfe16020, start:51081, order:0
pfn_to_page(start):cfe16040, start:51082, order:1
pfn_to_page(start):cfe16080, start:51084, order:2
pfn_to_page(start):cfe16100, start:51088, order:3
pfn_to_page(start):cfe16200, start:51090, order:4
pfn_to_page(start):cfe16400, start:510a0, order:5
pfn_to_page(start):cfe16800, start:510c0, order:6
pfn_to_page(start):cfe17000, start:51100, order:8
pfn_to_page(start):cfe19000, start:51200, order:9
pfn_to_page(start):cfe1d000, start:51400, order:a
pfn_to_page(start):cfe25000, start:51800, order:a
pfn_to_page(start):cfe2d000, start:51c00, order:a
pfn_to_page(start):cfe35000, start:52000, order:a
pfn_to_page(start):cfe3d000, start:52400, order:a
pfn_to_page(start):cfe45000, start:52800, order:a
pfn_to_page(start):cfe4d000, start:52c00, order:a
pfn_to_page(start):cfe55000, start:53000, order:a
pfn_to_page(start):cfe5d000, start:53400, order:a
pfn_to_page(start):cfe65000, start:53800, order:a
pfn_to_page(start):cfe6d000, start:53c00, order:a
pfn_to_page(start):cfe75000, start:54000, order:a
pfn_to_page(start):cfe7d000, start:54400, order:a
pfn_to_page(start):cfe85000, start:54800, order:a
pfn_to_page(start):cfe8d000, start:54c00, order:a
pfn_to_page(start):cfe95000, start:55000, order:a
pfn_to_page(start):cfe9d000, start:55400, order:a
pfn_to_page(start):cfea5000, start:55800, order:a
pfn_to_page(start):cfead000, start:55c00, order:a
pfn_to_page(start):cfeb5000, start:56000, order:a
pfn_to_page(start):cfebd000, start:56400, order:a
pfn_to_page(start):cfec5000, start:56800, order:a
pfn_to_page(start):cfecd000, start:56c00, order:a
pfn_to_page(start):cfed5000, start:57000, order:a
pfn_to_page(start):cfedd000, start:57400, order:a
pfn_to_page(start):cfee5000, start:57800, order:a
pfn_to_page(start):cfeed000, start:57c00, order:a
pfn_to_page(start):cfef5000, start:58000, order:a
pfn_to_page(start):cfefd000, start:58400, order:a
pfn_to_page(start):cff05000, start:58800, order:a
pfn_to_page(start):cff0d000, start:58c00, order:a
pfn_to_page(start):cff15000, start:59000, order:a
pfn_to_page(start):cff1d000, start:59400, order:a
pfn_to_page(start):cff25000, start:59800, order:a
pfn_to_page(start):cff2d000, start:59c00, order:a
pfn_to_page(start):cff35000, start:5a000, order:a
pfn_to_page(start):cff3d000, start:5a400, order:a
pfn_to_page(start):cff45000, start:5a800, order:a
pfn_to_page(start):cff4d000, start:5ac00, order:a
pfn_to_page(start):cff55000, start:5b000, order:a
pfn_to_page(start):cff5d000, start:5b400, order:a
pfn_to_page(start):cff65000, start:5b800, order:a
pfn_to_page(start):cff6d000, start:5bc00, order:a
pfn_to_page(start):cff75000, start:5c000, order:a
pfn_to_page(start):cff7d000, start:5c400, order:a
pfn_to_page(start):cff85000, start:5c800, order:a
pfn_to_page(start):cff8d000, start:5cc00, order:a
pfn_to_page(start):cff95000, start:5d000, order:a
pfn_to_page(start):cff9d000, start:5d400, order:a
pfn_to_page(start):cffa5000, start:5d800, order:a
pfn_to_page(start):cffad000, start:5dc00, order:a
pfn_to_page(start):cffb5000, start:5e000, order:a
pfn_to_page(start):cffbd000, start:5e400, order:a
pfn_to_page(start):cffc5000, start:5e800, order:a
pfn_to_page(start):cffcd000, start:5ec00, order:a
pfn_to_page(start):cffd5000, start:5f000, order:a
pfn_to_page(start):cffdd000, start:5f400, order:a
pfn_to_page(start):cffe5000, start:5f800, order:a
pfn_to_page(start):cffed000, start:5fc00, order:8
pfn_to_page(start):cffef000, start:5fd00, order:7
pfn_to_page(start):cfff0000, start:5fd80, order:5
pfn_to_page(start):cfff0400, start:5fda0, order:4
pfn_to_page(start):cfff0600, start:5fdb0, order:3
pfn_to_page(start):cfff0700, start:5fdb8, order:2
start_pfn:5fdf4,end_pfn:5fdf5 // 标记这段内存没被使用
pfn_to_page(start):cfff0e80, start:5fdf4, order:0
*/
/*
至此,50000000 - 60000000 已经被 struct page 记录完毕
50000 000 - 50004 000 : free // 0x5000 0100 应该有 atags ,但是memblock 没预留这段内存,因为 atags 已经解析完了,没用了
50004 000 - 50008 000 : reserved // 页表/段表
50008 000 - 50100 000 : free
50100 000 - 51081 000 : reserved // kernel 的 (__pa(KERNEL_START), KERNEL_END - KERNEL_START)
51081 000 - 5fdbc 000 : free
5fdbc 000 - 5fdf4 000 : reserved // 过程中 memblock_alloc 过的内存
5fdf4 000 - 5fdf5 000 : free
5fdf5 000 - 5fffc 000 : reserved // struct page
5fffc 000 - 60000 000 : reserved // vectors等
*/
totalram_pages_add(pages);
_totalram_pages = _totalram_pages + pages ; // _totalram_pages 初始化为0
free_highpages
// null
mem_init_print_info
pr_info("Memory: %luK/%luK available (%luK kernel code
// 这个过程初始化 好的 内存管理器 是 buddy
// 怎么向 buddy 申请内存
// alloc_pages/alloc_page
page_ext_init_flatmem_late
// null
kmem_cache_init
// 打印信息
// SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
// A1. 初始化局部变量 boot_kmem_cache 的成员
// A2. bootstrap(&boot_kmem_cache) , 并以返回值 作为 全局变量 struct kmem_cache *kmem_cache; 的 值
// B1. 初始化局部变量 boot_kmem_cache_node 的成员
// B2. bootstrap(&boot_kmem_cache_node) , 并以返回值 作为 全局变量 struct kmem_cache *kmem_cache_node; 的 值
// C . 用 create_kmalloc_caches 填充 kmalloc_caches[type([0-1])][idx([6-d])]
// create_kmalloc_caches-> new_kmalloc_cache -> create_kmalloc_cache
// 填充的值 为 create_kmalloc_cache 的返回值,该值为struct kmem_cache
// struct kmem_cache 中有内存仓库的 内存大小,内存仓库的地址,可申请内存块的大小
// 内存仓库用来存储 多个 内存块 , 每个块为 X ,且该 内存仓库的 可申请块大小 就为 X
// X 与 idx 相关 , 具体去看 kmalloc_info 数组(mm/slab_common.c)
// idx : 6 , X : 0x40
// idx : 7 , X : 0x80
// idx : 8 , X : 0xc0
// idx : 9 , X : 0x10
// idx : a , X : 0x200
// idx : b , X : 0x400
// idx : c , X : 0x1000
// idx : d , X : 0x2000
// 消费者 如何 向 kmem_cache 申请内存
// kmalloc
// 这个过程初始化完成的内存管理器叫 slab
kmemleak_init
// null
pgtable_init
ptlock_cache_init
// null
pgtable_cache_init
// null
debug_objects_mem_init
// null
vmalloc_init
// 针对所有的虚拟内存 1 - ffffffff
// vmap_area_cachep = 0xc1401600;
// /* Import existing vmlist entries. */
/*
insert_vmap_area
A : start_kernel-> setup_arch-> paging_init-> smdk6410_map_io-> s3c64xx_init_io-> iotable_init-> add_static_vm_early
// A 设置了11个
B : start_kernel-> setup_arch-> paging_init-> tcm_init-> iotable_init-> add_static_vm_early
// B 设置了2个
start:f6000000,end:f6004000 // A 设置的
start:f6010000,end:f6014000 // A 设置的
start:f6100000,end:f6101000 // A 设置的
start:f6200000,end:f6201000 // A 设置的
start:f6300000,end:f6304000 // A 设置的
start:f6400000,end:f6401000 // A 设置的
start:f6500000,end:f6501000 // A 设置的
start:f6600000,end:f6601000 // A 设置的
start:f6700000,end:f6701000 // A 设置的
start:f7005000,end:f7006000 // A 设置的
start:f7100000,end:f7104000 // A 设置的
start:fffe0000,end:fffe4000 // B 设置的
start:fffe8000,end:fffec000 // B 设置的
*/
// vmap_init_free_space
// The KVA space
/*
insert_vmap_area_augment
start:1,end:f6000000
start:f6004000,end:f6010000
start:f6014000,end:f6100000
start:f6101000,end:f6200000
start:f6201000,end:f6300000
start:f6304000,end:f6400000
start:f6401000,end:f6500000
start:f6501000,end:f6600000
start:f6601000,end:f6700000
start:f6701000,end:f7005000
start:f7006000,end:f7100000
start:f7104000,end:fffe0000
start:fffe4000,end:fffe8000
*/
//
/*
start:fffec000,end:ffffffff
*/
// 消费者调用的是什么 API
// vmalloc
ioremap_huge_init
// null
init_espfix_bsp
// null
pti_init
// null
其他
create_kmalloc_cache
kmem_cache_zalloc
kmem_cache_alloc
slab_alloc
slab_alloc_node
__slab_alloc
___slab_alloc
get_freelist
freelist = page->freelist;
create_boot_cache
__kmem_cache_create
kmem_cache_open
sysfs_slab_add
insert_vmap_area
find_va_links
link_va
kmalloc 和 vmalloc 的区别
vmalloc 返回值 在 vmalloc区间内