<kernel v5.15>
부트 메모리 초기화
bootmem_init()
arch/arm64/mm/init.c
void __init bootmem_init(void) { unsigned long min, max; min = PFN_UP(memblock_start_of_DRAM()); max = PFN_DOWN(memblock_end_of_DRAM()); early_memtest(min << PAGE_SHIFT, max << PAGE_SHIFT); max_pfn = max_low_pfn = max; min_low_pfn = min; arm64_numa_init(); /* * must be done after arm64_numa_init() which calls numa_init() to * initialize node_online_map that gets used in hugetlb_cma_reserve() * while allocating required CMA size across online nodes. */ #if defined(CONFIG_HUGETLB_PAGE) && defined(CONFIG_CMA) arm64_hugetlb_cma_reserve(); #endif dma_pernuma_cma_reserve(); kvm_hyp_reserve(); /* * sparse_init() tries to allocate memory from memblock, so must be * done after the fixed reservations */ sparse_init(); zone_sizes_init(min, max); /* * Reserve the CMA area after arm64_dma_phys_limit was initialised. */ dma_contiguous_reserve(arm64_dma_phys_limit); /* * request_standard_resources() depends on crashkernel's memory being * reserved, so do it here. */ reserve_crashkernel(); memblock_dump_all(); }
부트 메모리 초기화 루틴에서는 각 노드의 각 존별 초기화를 수행한다.
- 코드 라인 5~8에서 “memtest=<count>” 커널 파라메터가 주어진 경우 메모리에 대한 패턴 테스트를 <count> 수 만큼 수행한다.
- 코드 라인 10에서 arm64에는 highmem이 없다. 따라서 highmem 경계를 나타내는 max_low_pfn은 max 값과 동일하다.
- 코드 라인 11에서 min_low_pfn에 위에서 산출한 min 값을 대입한다.
- 코드 라인 13에서 NUMA 시스템인 경우 초기화를 수행한다. ACPI 또는 디바이스 트리를 통해 초기화를 수행한다. ACPI 또는 디바이스 트리를 통해 NUMA 초기화를 수행하지 못하는 경우이거나, “numa=off” 커널 파라메터가 주어진 경우 NUMA disable 상태로 초기화를 수행한다.
- 참고: NUMA -1- (ARM64 초기화) | 문c
- 코드 라인 21에서 ‘hugetlb_cma=’ 명령을 사용하여 cma 영역에 hugetlb를 지원하도록 한다.
- 기존에는 4K만 지원하였지만, 커널 v5.7-rc1 부터 16K 및 64K 페이지를 사용하는 시스템에서도 hugetlb_cma를 지원한다.
- 참고: mm: hugetlb: optionally allocate gigantic hugepages using cma (2020, v5.7-rc1)
- 코드 라인 24에서 “cma_pernuma=size” 명령을 사용하여 NUMA 별 cma 영역을 사용할 수 있게 한다.
- 참고: dma-contiguous: provide the ability to reserve per-numa CMA (2020, v5.10-rc1)
- 코드 라인 26에서 kvm 하이퍼 바이저 모듈을 위한 영역을 reserve 한다.
- 코드 라인 32에서 Sparse memory 모델을 사용하는 시스템을 위해 관리 영역을 할당받고 매핑 초기화한다.
- 참고: Sparse Memory | 문c
- 코드 라인 33에서 존별로 메모리 영역을 지정하고 초기화한다.
- 코드 라인 38에서 dma 사용을 위한 cma 영역을 reserve 한다.
- 코드 라인 44에서 크래시 상황에서 크래시 커널을 기동하여 크래시 로그를 출력할 수 있도록 크래시커널용 영역을 reserve 한다.
- 코드 라인 46에서 “memblock=debug” 커널 파라메터가 주어진 경우 memblock 상태를 덤프한다.
다음은 4G RAM을 가진 rock960 보드의 memblock 상태를 덤프하여 보여준다.
$ cat /sys/kernel/debug/memblock/memory 0: 0x0000000000200000..0x00000000f7ffffff $ cat /sys/kernel/debug/memblock/reserved 0: 0x0000000002080000..0x00000000033b5fff 1: 0x00000000ef400000..0x00000000f5dfffff 2: 0x00000000f5eef000..0x00000000f5f01fff 3: 0x00000000f6000000..0x00000000f7bfffff 4: 0x00000000f7df4000..0x00000000f7df4fff 5: 0x00000000f7df5e00..0x00000000f7df5fff 6: 0x00000000f7e74000..0x00000000f7f61fff 7: 0x00000000f7f62600..0x00000000f7f6265f 8: 0x00000000f7f62680..0x00000000f7f626df 9: 0x00000000f7f62700..0x00000000f7f6282f 10: 0x00000000f7f62840..0x00000000f7f62857 11: 0x00000000f7f62880..0x00000000f7f62887 12: 0x00000000f7f648c0..0x00000000f7f6492b 13: 0x00000000f7f64940..0x00000000f7f649ab 14: 0x00000000f7f649c0..0x00000000f7f64a2b 15: 0x00000000f7f64a40..0x00000000f7f64a47 16: 0x00000000f7f64a64..0x00000000f7f64aea 17: 0x00000000f7f64aec..0x00000000f7f64b1a 18: 0x00000000f7f64b1c..0x00000000f7f64b4a 19: 0x00000000f7f64b4c..0x00000000f7f64b7a 20: 0x00000000f7f64b7c..0x00000000f7f64baa 21: 0x00000000f7f64bac..0x00000000f7fcdff7 22: 0x00000000f7fce000..0x00000000f7ffffff
참고
- Memory Model -1- (Basic) | 문c
- Memory Model -2- (mem_map) | 문c
- Memory Model -3- (Sparse Memory) | 문c
- Memory Model -4- (APIs) | 문c
- ZONE 타입 | 문c
- bootmem_init()-ARM64 | 문c – 현재 글
- zone_size_init() | 문c
- NUMA -1- (ARM64 초기화) | 문c
- build_all_zonelists() | 문c