arm64内存-zone_sizes_init-free_area_init
上一篇: https://www.cnblogs.com/zhangzhiwei122/p/16097591.html
setup_arch -> bootmem_init -> zone_sizes_init
arch/arm64/mm/init.c
188static void __init zone_sizes_init(unsigned long min, unsigned long max) 189{ 190 unsigned long max_zone_pfns[MAX_NR_ZONES] = {0}; 191 193 max_zone_pfns[ZONE_DMA] = PFN_DOWN(arm64_dma_phys_limit); 198 max_zone_pfns[ZONE_NORMAL] = max; 199 200 free_area_init(max_zone_pfns); 201}
将各个zone的 max pfn 数组丢给 free_area_init 函数
free_area_init
mm/page_alloc.c
369static unsigned long arch_zone_lowest_possible_pfn[MAX_NR_ZONES] __initdata; 370static unsigned long arch_zone_highest_possible_pfn[MAX_NR_ZONES] __initdata; 375static unsigned long zone_movable_pfn[MAX_NUMNODES] __initdata; 7427void __init free_area_init(unsigned long *max_zone_pfn) 7428{ 7429 unsigned long start_pfn, end_pfn; 7430 int i, nid, zone; 7431 bool descending; 7432 7433 /* Record where the zone boundaries are */ 7434 memset(arch_zone_lowest_possible_pfn, 0, 7435 sizeof(arch_zone_lowest_possible_pfn)); 7436 memset(arch_zone_highest_possible_pfn, 0, 7437 sizeof(arch_zone_highest_possible_pfn)); 7438 7439 start_pfn = find_min_pfn_with_active_regions(); 7440 descending = arch_has_descending_max_zone_pfns(); 7441 7442 for (i = 0; i < MAX_NR_ZONES; i++) { 7443 if (descending) 7444 zone = MAX_NR_ZONES - i - 1; 7445 else 7446 zone = i; 7447 7448 if (zone == ZONE_MOVABLE) 7449 continue; 7450 7451 end_pfn = max(max_zone_pfn[zone], start_pfn); 7452 arch_zone_lowest_possible_pfn[zone] = start_pfn; 7453 arch_zone_highest_possible_pfn[zone] = end_pfn; 7454 7455 start_pfn = end_pfn; 7456 } 7457 7458 /* Find the PFNs that ZONE_MOVABLE begins at in each node */ 7459 memset(zone_movable_pfn, 0, sizeof(zone_movable_pfn)); 7460 find_zone_movable_pfns_for_nodes(); 7500 /* Initialise every node */ 7501 mminit_verify_pageflags_layout(); 7502 setup_nr_node_ids(); 7503 init_unavailable_mem(); 7504 for_each_online_node(nid) { 7505 pg_data_t *pgdat = NODE_DATA(nid); 7506 free_area_init_node(nid); 7507 7508 /* Any memory on that node */ 7509 if (pgdat->node_present_pages) 7510 node_set_state(nid, N_MEMORY); 7511 check_for_memory(pgdat, nid); 7512 } 7513}
369 ~ 375 定义文件中使用的 全局变量 arch_zone_lowest_possible_pfn arch_zone_highest_possible_pfn zone_movable_pfn
arch_zone_lowest_possible_pfn arch_zone_highest_possible_pfn 分别记录 zone idx 对应的 lowest pfn 和 hignest pfn
zone_movable_pfn 记录各个 node 中的 movable zone 的start pfn .
7434 ~ 7456 先将 arch_zone_lowest_possible_pfn arch_zone_highest_possible_pfn 清零,然后 for 循环,填充里面的值。
7439 - 从memblock 得到当前 node 的最小 pfn , 给 start_pfn 。
for 循环中,默认 前一个 zone 的 end pfn 是下一个zone 的 start pfn .
7459 ~ 7460 ~ 先将 zone_movable_pfn 清零, 然后调用 find zone movable pfn for nodes ,给各个node的 zone_movable_pfn 进行赋值。即 zone_movable_pfn 被初始化了。
7501 verify flag
7502 setup_nr_node_ids 设置系统的 node 数目。 UMA 上面为空函数。
7503 init unavailable memory
7504 开始for 循环遍历 每一个 node , UMA 上面 就是 1 个 node 。 for 循环 1 次。
7505 取得 node 的 pglist_data 指针, UMA 上面只有全局唯一的一个 palist_data 对象 ,见 上一篇: https://www.cnblogs.com/zhangzhiwei122/p/16097591.html 。
7506 free_area_init_node (nid) 对指定的 node idx 作 free area 的初始化。
free_area_init_node
mm/page_alloc.c
6967static void __init free_area_init_node(int nid) 6968{ 6969 pg_data_t *pgdat = NODE_DATA(nid); 6970 unsigned long start_pfn = 0; 6971 unsigned long end_pfn = 0; 6976 get_pfn_range_for_nid(nid, &start_pfn, &end_pfn); 6978 pgdat->node_id = nid; 6979 pgdat->node_start_pfn = start_pfn; 6980 pgdat->per_cpu_nodestats = NULL; 6985 calculate_node_totalpages(pgdat, start_pfn, end_pfn); 6987 alloc_node_mem_map(pgdat); 6988 pgdat_set_deferred_range(pgdat); 6990 free_area_init_core(pgdat); 6991}
6976 - 遍历 memblock 中的 node idx 下面的 mem region 信息,得到 这个node 的start pfn 和 end pfn
6978 ~ 6980 - 赋值初始化 node 的 pg_data_t 对象 的 node_id , start pfn, per_cpu_nodestats
6985 - 计算 node 上面的 node_spanned_pages node_present_pages ,
计算 node 内各个 zone 的 start pfn , spanned pages ; present pages - 后面的 free area init core 里面会使用这儿设置的值。
使用 arch_zone_lowest_possible_pfn arch_zone_highest_possible_pfn zone_movable_pfn 和 memblock 信息得到,然后给 pgdat 里面的成员 赋值 。
6987 alloc node mem map - 在 FLAG 内存模型下面, 给 pgdat 的 node_mem_map 指针分配内存。在 sparse内存模型下面,为空。
6988 deferred range 不用关心。
6990 free area init core - free area init 的核心代码
free_area_init_core
mm/page_alloc.c
6843static void __init free_area_init_core(struct pglist_data *pgdat) 6844{ 6845 enum zone_type j; 6846 int nid = pgdat->node_id; 6847 6848 pgdat_init_internals(pgdat); 6849 pgdat->per_cpu_nodestats = &boot_nodestats; 6850 6851 for (j = 0; j < MAX_NR_ZONES; j++) { 6852 struct zone *zone = pgdat->node_zones + j; 6853 unsigned long size, freesize, memmap_pages; 6854 unsigned long zone_start_pfn = zone->zone_start_pfn; 6855 6856 size = zone->spanned_pages; 6857 freesize = zone->present_pages; 6858 6859 /* 6860 * Adjust freesize so that it accounts for how much memory 6861 * is used by this zone for memmap. This affects the watermark 6862 * and per-cpu initialisations 6863 */ 6864 memmap_pages = calc_memmap_size(size, freesize); 6865 if (!is_highmem_idx(j)) { 6866 if (freesize >= memmap_pages) { 6867 freesize -= memmap_pages; 6868 if (memmap_pages) 6869 printk(KERN_DEBUG 6870 " %s zone: %lu pages used for memmap\n", 6871 zone_names[j], memmap_pages); 6872 } else 6873 pr_warn(" %s zone: %lu pages exceeds freesize %lu\n", 6874 zone_names[j], memmap_pages, freesize); 6875 } 6876 6877 /* Account for reserved pages */ 6878 if (j == 0 && freesize > dma_reserve) { 6879 freesize -= dma_reserve; 6880 printk(KERN_DEBUG " %s zone: %lu pages reserved\n", 6881 zone_names[0], dma_reserve); 6882 } 6883 6884 if (!is_highmem_idx(j)) 6885 nr_kernel_pages += freesize; 6886 /* Charge for highmem memmap if there are enough kernel pages */ 6887 else if (nr_kernel_pages > memmap_pages * 2) 6888 nr_kernel_pages -= memmap_pages; 6889 nr_all_pages += freesize; 6890 6891 /* 6892 * Set an approximate value for lowmem here, it will be adjusted 6893 * when the bootmem allocator frees pages into the buddy system. 6894 * And all highmem pages will be managed by the buddy system. 6895 */ 6896 zone_init_internals(zone, j, nid, freesize); 6897 6898 if (!size) 6899 continue; 6900 6901 set_pageblock_order(); 6902 setup_usemap(pgdat, zone, zone_start_pfn, size); 6903 init_currently_empty_zone(zone, zone_start_pfn, size); 6904 memmap_init(size, nid, j, zone_start_pfn); 6905 } 6906}
请参考: https://www.cnblogs.com/LoyenWang/p/11568481.html 里面有示例图,便于理解。
6848 ~ 6849 设置 pgdat 里面的一些成员变量的初始值 。 per_cpu_nodestats 设置为 boot_nodestats 的地址。
boot_nodestats 是一个 per cpu 对象,在 mm/page_alloc.c 中。
5908static DEFINE_PER_CPU(struct per_cpu_pageset, boot_pageset); 5909static DEFINE_PER_CPU(struct per_cpu_nodestat, boot_nodestats);
6851 开始 for 循环 处理 每个 zone
6856 ~ 6889 通过zone 的 spanned pages 和 present pages 计算得到 freesize ,然后更新 全局变量 nr_all_pages nr_kernel_pages
6896 zone 对象内,各种成员的初始值设定。比如各种锁的初始值。
6901 set pageblock order 设置 pageblock_order 这个变量,表示 页块 由 多少个 页 组成 (2 ^ order 为 页 数)。 ARM64 上面,这个函数为空, pageblock_order 为常量 - PMD_SHIFT - PAGE_SHIFT = 9
include/linux/pageblock-flags.h
40/* Huge pages are a constant size */ 41#define pageblock_order HUGETLB_PAGE_ORDER 42
arch/arm64/include/asm/pgtable.h
332#define HPAGE_SHIFT PMD_SHIFT 335#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
6902 在 FLAT 内存模型,给 zone->pageblock_flags 指针 分配内存。 在SPARSE 内存模型上面,为空函数。
6903 init_currently_empty_zone 在,同文件中,设置zone 的 zone_start_pfn ; initialized ; free_area[MAX_ORDER] ( free_list[xx] ) 。 nr_free 都设置的为 0 。
6396void __meminit init_currently_empty_zone(struct zone *zone, 6397 unsigned long zone_start_pfn, 6398 unsigned long size) 6399{ 6400 struct pglist_data *pgdat = zone->zone_pgdat; 6401 int zone_idx = zone_idx(zone) + 1; 6403 if (zone_idx > pgdat->nr_zones) 6404 pgdat->nr_zones = zone_idx; 6405 6406 zone->zone_start_pfn = zone_start_pfn; 6414 zone_init_free_lists(zone); 6415 zone->initialized = 1; 6416}
6179static void __meminit zone_init_free_lists(struct zone *zone) 6180{ 6181 unsigned int order, t; 6182 for_each_migratetype_order(order, t) { 6183 INIT_LIST_HEAD(&zone->free_area[order].free_list[t]); 6184 zone->free_area[order].nr_free = 0; 6185 } 6186}
6904 memmap_init ,同文件中
根据PFN
,通过pfn_to_page
找到对应的struct page
结构,并将该结构进行初始化处理,并设置MIGRATE_MOVABLE
标志
6188void __meminit __weak memmap_init(unsigned long size, int nid, 6189 unsigned long zone, 6190 unsigned long range_start_pfn) 6191{ 6192 unsigned long start_pfn, end_pfn; 6193 unsigned long range_end_pfn = range_start_pfn + size; 6194 int i; 6195 6196 for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) { 6197 start_pfn = clamp(start_pfn, range_start_pfn, range_end_pfn); 6198 end_pfn = clamp(end_pfn, range_start_pfn, range_end_pfn); 6199 6200 if (end_pfn > start_pfn) { 6201 size = end_pfn - start_pfn; 6202 memmap_init_zone(size, nid, zone, start_pfn, 6203 MEMINIT_EARLY, NULL, MIGRATE_MOVABLE); 6204 } 6205 } 6206}
pfn_to_page include/asm-generic/memory_model.h 中,各种 内存模型下面,有不同实现 。 下面是 sparse 的实现
57#elif defined(CONFIG_SPARSEMEM) 68#define __pfn_to_page(pfn) \ 69({ unsigned long __pfn = (pfn); \ 70 struct mem_section *__sec = __pfn_to_section(__pfn); \ 71 __section_mem_map_addr(__sec) + __pfn; \ 72}) 73#endif /* CONFIG_FLATMEM/DISCONTIGMEM/SPARSEMEM */ 81#define page_to_pfn __page_to_pfn 82#define pfn_to_page __pfn_to_page
__section_mem_map_addr() 在 include/linux/mmzone.h 中。mem_section 结构体中, section_mem_map 记录了struct page 对象的地址。 sparse 相关信息,
见 1 https://www.cnblogs.com/zhangzhiwei122/p/16096272.html ; 2. https://www.cnblogs.com/zhangzhiwei122/p/16096641.html
1298static inline struct page *__section_mem_map_addr(struct mem_section *section) 1299{ 1300 unsigned long map = section->section_mem_map; 1301 map &= SECTION_MAP_MASK; 1302 return (struct page *)map; 1303}
下一篇: build all zonelists
https://www.cnblogs.com/zhangzhiwei122/p/16099490.html