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

 

posted @ 2022-04-04 18:36  张志伟122  阅读(274)  评论(0编辑  收藏  举报