memory memblock으로 부터 lowmem 영역의 경계를 파악하여 각각의 zone으로 경계를 나누어 설정하고 0번 노드의 빈 페이지들을 초기화한다. 또한 Sparse 메모리 모델을 지원하는 경우에는 sparse memory의 초기화도 수행한다.

bootmem_init()
arch/arm/mm/init.c
01 | void __init bootmem_init( void ) |
03 | unsigned long min, max_low, max_high; |
05 | memblock_allow_resize(); |
06 | max_low = max_high = 0; |
08 | find_limits(&min, &max_low, &max_high); |
26 | zone_sizes_init(min, max_low, max_high); |
34 | max_low_pfn = max_low; |
- memblock_allow_resize();
- memblock_can_resize = 1로 만들어 향후 memblock 관리 영역이 모자랄 때 2배 단위로 커질 수 있도록 한다.
- find_limits(&min, &max_low, &max_high);
- memblock 정보로 max_pfn, max_low_pfn, min_low_pfn 값을 얻어온다.
- arm_memory_present();
- Sparsemem의 경우 내부에서 mem_section[] 매핑을 위한 allocation이 수행되기 때문에 반드시 fixed reservation이 끝난 후에 이 함수가 호출되어야 한다.
- 몇 개 32bit ARM 머신을 제외하고 대부분의 32bit ARM에서는 CONFIG_SPARSEMEM 옵션을 사용하지 않는다.
- 참고: Sparse Memory | 문c
- sparse_init();
- Sparse memory 모델을 사용하는 시스템을 위해 관리 영역을 할당받고 매핑 초기화한다.
- 참고: Sparse Memory | 문c
- zone_sizes_init(min, max_low, max_high);
아래와 같이 memblock 설정 값을 읽어 lowmem 영역의 경계를 나눈다. 이 값은 zone을 나누는 경계로도 사용된다.

memblock_allow_resize()
mm/memblock.c
1 | void __init memblock_allow_resize( void ) |
3 | memblock_can_resize = 1; |
- memblock_can_resize 플래그를 enable 시켜 향후 memblock 관리 영역이 모자랄 때 2배 단위로 커질 수 있도록 한다.
find_limits()
arch/arm/mm/init.c
1 | static void __init find_limits(unsigned long *min, unsigned long *max_low, |
2 | unsigned long *max_high) |
4 | *max_low = PFN_DOWN(memblock_get_current_limit()); |
5 | *min = PFN_UP(memblock_start_of_DRAM()); |
6 | *max_high = PFN_DOWN(memblock_end_of_DRAM()); |
- memblock 정보를 읽어 다음을 설정한다.
- max_low
- lowmem/highmem 영역의 경계 pfn
- min
- max_high
zone_sizes_init()
arch/arm/mm/init.c
01 | static void __init zone_sizes_init(unsigned long min, unsigned long max_low, |
02 | unsigned long max_high) |
04 | unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; |
05 | struct memblock_region *reg; |
10 | memset (zone_size, 0, sizeof (zone_size)); |
17 | zone_size[0] = max_low - min; |
19 | zone_size[ZONE_HIGHMEM] = max_high - max_low; |
26 | memcpy (zhole_size, zone_size, sizeof (zhole_size)); |
27 | for_each_memblock(memory, reg) { |
28 | unsigned long start = memblock_region_memory_base_pfn(reg); |
29 | unsigned long end = memblock_region_memory_end_pfn(reg); |
31 | if (start < max_low) { |
32 | unsigned long low_end = min(end, max_low); |
33 | zhole_size[0] -= low_end - start; |
37 | unsigned long high_start = max(start, max_low); |
38 | zhole_size[ZONE_HIGHMEM] -= end - high_start; |
48 | if (arm_dma_zone_size) |
49 | arm_adjust_dma_zone(zone_size, zhole_size, |
50 | arm_dma_zone_size >> PAGE_SHIFT); |
53 | free_area_init_node(0, zone_size, min, zhole_size); |
- zone_size[0] = max_low – min;
- zone_size[ZONE_HIGHMEM] = max_high – max_low;
- highmem이 동작하는 경우 highmem 영역 사이즈 설정
- memcpy(zhole_size, zone_size, sizeof(zhole_size));
- zone_size[]를 zhole_size[]에 복사
- for_each_memblock(memory, reg) {
- memory memblock을 루프를 돌며 하나씩 얻어온다.
- if (start < max_low) {
- memory memblock이 lowmem 영역에 들어있거나 일부 겹치는 경우
- unsigned long low_end = min(end, max_low);
- 끝 주소가 lowmem을 초과하지 않게 한다.
- zhole_size[0] -= low_end – start;
- hole 사이즈를 감소시킨다. 이 값이 0이되면 hole이 없는 것이다.
- highmem 영역에 대해서도 위와 똑같은 방법으로 hole 사이즈를 감소시킨다.
- if (arm_dma_zone_size)
- DMA zone 사이즈가 존재하는 경우 dma zone 사이즈만큼 ZONE_DMA에 사이즈를 구성하고 ZONE_NORMAL 영역에서 그 사이즈만큼 뺀다.
- free_area_init_node(0, zone_size, min, zhole_size);
아래 그림과 같이 highmem 영역을 사용하는 경우 ZONE_HIGHMEM에 대한 사이즈가 지정되고, 아키텍처가 dma 영역을 별도로 지정하여 사용하는 경우 ZONE_NORMAL에 대한 size를 dma 사이즈 만큼 감소시키고 ZONE_DMA에 대한 사이즈를 dma 사이즈로 지정한다.

참고