반응형
[분석 기준]
kernel version : linux kernel 4.16
architecture : aarch64 (arm64)
memblock_init() 에서 zone_sizes_init() 함수를 분석한다. 분석 기준은 CONFIG_NUMA가 설정되어 있다는 가정하에 설정한다.
zone_sizes_init() 함수에 전달되는 min, max는 DRAM의 memblock 시작과 끝 주소를 전달한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #ifdef CONFIG_NUMA // IMRT >> yes! static void __init zone_sizes_init(unsigned long min, unsigned long max) { unsigned long max_zone_pfns[MAX_NR_ZONES] = {0}; if (IS_ENABLED(CONFIG_ZONE_DMA32)) max_zone_pfns[ZONE_DMA32] = PFN_DOWN(max_zone_dma_phys()); // IMRT >> DMA32 빼고 나머지 전부 NORMAL max_zone_pfns[ZONE_NORMAL] = max; free_area_init_nodes(max_zone_pfns); } | cs |
line 12 :
NUMA 시스템인 경우 전체 노드에 대해 초기화를 해야하므로 free_area_init_nodes() 함수를 호출한다. CONFIG_NUMA가 설정되지 않은 경우에는 free_area_init_node() 함수가 호출되서 하나의 노드만을 초기화한다.
memblock_init()
-> zone_sizes_init()
-> free_area_init_nodes()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | /** * free_area_init_nodes - Initialise all pg_data_t and zone data * @max_zone_pfn: an array of max PFNs for each zone * * This will call free_area_init_node() for each active node in the system. * Using the page ranges provided by memblock_set_node(), the size of each * zone in each node and their holes is calculated. If the maximum PFN * between two adjacent zones match, it is assumed that the zone is empty. * For example, if arch_max_dma_pfn == arch_max_dma32_pfn, it is assumed * that arch_max_dma32_pfn has no pages. It is also assumed that a zone * starts where the previous one ended. For example, ZONE_DMA32 starts * at arch_max_dma_pfn. */ void __init free_area_init_nodes(unsigned long *max_zone_pfn) { unsigned long start_pfn, end_pfn; int i, nid; /* Record where the zone boundaries are */ memset(arch_zone_lowest_possible_pfn, 0, sizeof(arch_zone_lowest_possible_pfn)); memset(arch_zone_highest_possible_pfn, 0, sizeof(arch_zone_highest_possible_pfn)); start_pfn = find_min_pfn_with_active_regions(); for (i = 0; i < MAX_NR_ZONES; i++) { if (i == ZONE_MOVABLE) continue; end_pfn = max(max_zone_pfn[i], start_pfn); arch_zone_lowest_possible_pfn[i] = start_pfn; arch_zone_highest_possible_pfn[i] = end_pfn; start_pfn = end_pfn; } /* Find the PFNs that ZONE_MOVABLE begins at in each node */ memset(zone_movable_pfn, 0, sizeof(zone_movable_pfn)); find_zone_movable_pfns_for_nodes(); /* Print out the zone ranges */ pr_info("Zone ranges:\n"); for (i = 0; i < MAX_NR_ZONES; i++) { if (i == ZONE_MOVABLE) continue; pr_info(" %-8s ", zone_names[i]); if (arch_zone_lowest_possible_pfn[i] == arch_zone_highest_possible_pfn[i]) pr_cont("empty\n"); else pr_cont("[mem %#018Lx-%#018Lx]\n", (u64)arch_zone_lowest_possible_pfn[i] << PAGE_SHIFT, ((u64)arch_zone_highest_possible_pfn[i] << PAGE_SHIFT) - 1); } /* Print out the PFNs ZONE_MOVABLE begins at in each node */ pr_info("Movable zone start for each node\n"); for (i = 0; i < MAX_NUMNODES; i++) { if (zone_movable_pfn[i]) pr_info(" Node %d: %#018Lx\n", i, (u64)zone_movable_pfn[i] << PAGE_SHIFT); } /* Print out the early node map */ pr_info("Early memory node ranges\n"); for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, &nid) pr_info(" node %3d: [mem %#018Lx-%#018Lx]\n", nid, (u64)start_pfn << PAGE_SHIFT, ((u64)end_pfn << PAGE_SHIFT) - 1); /* Initialise every node */ mminit_verify_pageflags_layout(); setup_nr_node_ids(); for_each_online_node(nid) { pg_data_t *pgdat = NODE_DATA(nid); free_area_init_node(nid, NULL, find_min_pfn_for_node(nid), NULL); /* Any memory on that node */ if (pgdat->node_present_pages) node_set_state(nid, N_MEMORY); check_for_memory(pgdat, nid); } zero_resv_unavail(); } | cs |
반응형
'Linux > Kernel Analysis' 카테고리의 다른 글
NUMA BALANCING (0) | 2018.11.10 |
---|---|
메모리 모델 (FLATMEM, DISCONTIGMEM, SPARSEMEM) (0) | 2018.10.06 |
bootmem_init() 부트 메모리 초기화 (0) | 2018.10.06 |
void __init paging_init() - 커널 페이지 초기화 하기 (2) | 2018.09.29 |
[커널분석] arm64_memblock_init() (1) | 2018.09.15 |