arm64内存-memblock交接内存给zoned frame allocator (buddy system)
上一篇:page alloc init
https://www.cnblogs.com/zhangzhiwei122/p/16099528.html
start_kernel -> mm_init -> mem_init
818/* 819 * Set up kernel memory allocators 820 */ 821static void __init mm_init(void) 822{ 823 /* 824 * page_ext requires contiguous pages, 825 * bigger than MAX_ORDER unless SPARSEMEM. 826 */ 827 page_ext_init_flatmem(); 828 init_debug_pagealloc(); 829 report_meminit(); 830 mem_init(); 831 kmem_cache_init(); 848asmlinkage __visible void __init __no_sanitize_address start_kernel(void) 849{ 896 /* 897 * These use large bootmem allocations and must precede 898 * kmem_cache_init() 899 */ 900 setup_log_buf(0); 901 vfs_caches_init_early(); 902 sort_main_extable(); 903 trap_init(); 904 mm_init();
897 ~ 898 注释 - 在 kmem_cache_init 函数之前,调用 这些 使用 大块内存的 函数。使用大块内存的函数,就包括: setup_log_buf ; vfs_caches_init_early ; sort_main_extable ; trap_init ;
904 - 调用 同文件中, 821 行的 static mm_init 函数。
824 ~ 827 注释 - page_ext 功能,需要用到连续物理页(大于 4M 的),buddy system 中,MAX_ORDER 通常为 11,
struct zone 里面 free_area 数组 11个对象,free_area[10] 分配最大的连续页, ( 2 ^10 = 1024 个页,即4M )
需要在将 空闲内存 转交 给 buddy system 之前,初始化它。
我们没有启动 page ext 功能, page_ext_init_flatmem 函数为空 。
828 init_debug_pagealloc , 没有 启用 debug page alloc 功能,这个为空函数 。
829 report mem init , 同文件内 static report_meminit 函数, 打印 mem auto-init: stack: off , heap alloc: on, heap free: on 这样的 信息。
830 mem_init , 各个arch 自己实现, 在 arch/arm64/mm/init.c 中。就是在这个函数里面,将 memblock 管理的空间,交给 zoned frame allocator 的。
mem_init
arch/arm64/mm/init.c
503void __init mem_init(void) 504{ 511 set_max_mapnr(max_pfn - PHYS_PFN_OFFSET); 512 513#ifndef CONFIG_SPARSEMEM_VMEMMAP 514 free_unused_memmap(); 515#endif 516 /* this will put all unused low memory onto the freelists */ 517 memblock_free_all(); 518 519 mem_init_print_info(NULL); 537} 538
511 set_max_mapnr 设置 最大的 map idx 。 max_pfn 是 DRAM 最大 物理地址 对应的 pfn, phys_pfn_offset 是 DRAM 起始 物理地址 对应的pfn 。 减法 后,就是 DRAM 对应的 pfn 的个数了。
max_mapnr 这样一个变量,在 mm/memory.c 中,被设置。
513 ~ 515 ,如果 sparse ,没有使用 VMEMMAP 映射,则调用 free_unused_memmap , 释放 struct page 对象占用的物理内存。 arm64 上面,通常使用 VMEMMAP 映射 struct page 对象。
517 memblock_free_all 这个函数,将 memblock 中 unused memory 交给 buddy system 的 free_list 管理。 (下面详述)
519 打印信息,示例: Memory: 2852320k/2852320k available, 129568k reserved , 在 mm/page_alloc.c 中实现。
memblock_free_all
mm/memblock.c
2011unsigned long __init memblock_free_all(void) 2012{ 2013 unsigned long pages; 2014 2015 reset_all_zones_managed_pages(); 2016 2017 pages = free_low_memory_core_early(); 2018 totalram_pages_add(pages); 2019 2020 return pages; 2021}
2015 - reset all zones managed pages , 将所有 node 的所有 zone 里面的 managed_pages 这个变量设置为 0 。表示 这个zone 里面,管理的 pages 为 0 。
2017 free low memory core early - 释放 memblock 内存到 buddy system 和核心函数, 返回 送给 buddy system 的 free pages 的个数。
2018 将 pages 增加到 _totalram_pages 上面. _tatalram_pages 是 mm/page_alloc.c 里面的变量, include/linux/mm.h 中声明的 操作这个变量的接口, tatalram_pages_add .
free_low_memory_core_early
1960static unsigned long __init free_low_memory_core_early(void) 1961{ 1968 for_each_reserved_mem_range(i, &start, &end) 1969 reserve_bootmem_region(start, end); 1970 1976 for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &start, &end, 1977 NULL) 1978 count += __free_memory_core(start, end); 1979 1980 return count; 1981}
1968 ~ 1970 处理 memblock 中 reserved mem regions , 调用 reserve_bootmem_region 函数,mm/page_alloc.c 中,将对应的 pages 设置为 reserved .
1976 ~ 1978 处理 memblock 中 的 free regions 【在 memory type,但是不在 reserved type 的 regions 】,对每一个 region 调用 __free_memory_core 处理, 得到这个region 对应的 pages 个数 count .
__free_memory_core
1929static void __init __free_pages_memory(unsigned long start, unsigned long end) 1930{ 1931 int order; 1932 1933 while (start < end) { 1934 order = min(MAX_ORDER - 1UL, __ffs(start)); 1935 1936 while (start + (1UL << order) > end) 1937 order--; 1938 1939 memblock_free_pages(pfn_to_page(start), start, order); 1940 1941 start += (1UL << order); 1942 } 1943} 1944 1945static unsigned long __init __free_memory_core(phys_addr_t start, 1946 phys_addr_t end) 1947{ 1948 unsigned long start_pfn = PFN_UP(start); 1949 unsigned long end_pfn = min_t(unsigned long, 1950 PFN_DOWN(end), max_low_pfn); 1951 1952 if (start_pfn >= end_pfn) 1953 return 0; 1954 1955 __free_pages_memory(start_pfn, end_pfn); 1956 1957 return end_pfn - start_pfn; 1958}
1945 行的 __free_memory_core 调用 1929 行的 __free_pages_memory .
1957 行, 返回 end_pfn - start_pfn ,即表示这个 region 内的 pages 个数。
1929 行 __free_pages_memory
1934 ~ 1937 计算,order , order 由首地址 和 长度 决定, order 计算后, 即表示 这段内存,会放的 struct zone 的 free_area[order] 中。
1929 调用 memblock_free_pages , 在 mm/page_alloc.c 中
memblock_free_pages
1603void __init memblock_free_pages(struct page *page, unsigned long pfn, 1604 unsigned int order) 1605{ 1606 if (early_page_uninitialised(pfn)) 1607 return; 1608 __free_pages_core(page, order); 1609} 1610
1606 ~ 1607 - 和deferred page 功能(延迟创建对应 struct page 对象)相关。通常没有这个功能。 所以,不会return .
1529 1530void __free_pages_core(struct page *page, unsigned int order) 1531{ 1532 unsigned int nr_pages = 1 << order; 1533 struct page *p = page; 1534 unsigned int loop; 1541 prefetchw(p); 1542 for (loop = 0; loop < (nr_pages - 1); loop++, p++) { 1543 prefetchw(p + 1); 1544 __ClearPageReserved(p); 1545 set_page_count(p, 0); 1546 } 1547 __ClearPageReserved(p); 1548 set_page_count(p, 0); 1549 1550 atomic_long_add(nr_pages, &page_zone(page)->managed_pages); 1556 __free_pages_ok(page, order, FPI_TO_TAIL); 1557}
1541 ~ 1548 - 循环设置 page 为 非 reserved (清除页描述flag中的PG_Reserved标志位). _refcount 为 0 。
1550 - 更新 page 所属的 zone 的 managed_pages
1556 - 对应的struc page 都清理好了,就进入 buddy system 算法,处理 free page 后事情(比如:合并 pages 等) 。
__free_pages_ok 是一个 static 函数, 就不再深究了 ……
下一篇: kmem cache init - slub 结构体和框架
https://www.cnblogs.com/zhangzhiwei122/p/16101959.html