arch/arm/mm/init.c : mem_init(void)
586 unsigned long reserved_pages, free_pages; 587 struct memblock_region *reg;
/* 633 * Since our memory may not be contiguous, calculate the 634 * real number of pages we have in this system 635 */ 636 printk(KERN_INFO "Memory:"); 637 num_physpages = 0; 638 for_each_memblock(memory, reg) { 639 unsigned long pages = memblock_region_memory_end_pfn(reg) - 640 memblock_region_memory_base_pfn(reg); 641 num_physpages += pages; 642 printk(" %ldMB", pages >> (20 - PAGE_SHIFT)); 643 } 644 printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT)); 645 646 printk(KERN_NOTICE "Memory: %luk/%luk available, %luk reserved, %luK highmem\n", 647 nr_free_pages() << (PAGE_SHIFT-10), 648 free_pages << (PAGE_SHIFT-10), 649 reserved_pages << (PAGE_SHIFT-10), 650 totalhigh_pages << (PAGE_SHIFT-10));
include/linux/memblock.h
150#define for_each_memblock(memblock_type, region) \ 151 for (region = memblock.memblock_type.regions; \ 152 region < (memblock.memblock_type.regions + memblock.memblock_type.cnt); \ 153 region++) 154
include/linux/memblock.h
123/** 124 * memblock_region_memory_end_pfn - Return the end_pfn this region 125 * @reg: memblock_region structure 126 */ 127static inline unsigned long memblock_region_memory_end_pfn(const struct memblock_region *reg) 128{ 129 return PFN_DOWN(reg->base + reg->size); 130}
include/linux/memblock.h
132/** 133 * memblock_region_reserved_base_pfn - Return the lowest pfn intersecting with the reserved region 134 * @reg: memblock_region structure 135 */ 136static inline unsigned long memblock_region_reserved_base_pfn(const struct memblock_region *reg) 137{ 138 return PFN_DOWN(reg->base); 139}
include/linux/memblock.h
37struct memblock { 38 phys_addr_t current_limit; 39 phys_addr_t memory_size; /* Updated by memblock_analyze() */ 40 struct memblock_type memory; 41 struct memblock_type reserved; 42};
meminfo 라는 구조체에 nr_banks 와 membank라는 구조체가 멤버로 있다. 이들은 부팅 과정에서 이미 arm_add_memory라는 함수를 통해서 bank에 대한 start 및 size가 정해졌있다.(
early_init_dt_add_memory()나 parse_tag_mem32()등의 함수를 통해서 세팅된다(확인필요)
29struct membank { 30 phys_addr_t start; 31 phys_addr_t size; 32 unsigned int highmem; 33}; 34 35struct meminfo { 36 int nr_banks; 37 struct membank bank[NR_BANKS]; 38};
그리고 arch/arm/mm/init.c:find_limits()라는 함수를 통해서, 각 메모리 뱅크를 돌면서 (참고로 이건 3.1.10소스다. 최신은 좀 틀리다)
135static void __init find_limits(unsigned long *min, unsigned long *max_low, 136 unsigned long *max_high) 137{ 138 struct meminfo *mi = &meminfo; 139 int i; 140 141 *min = -1UL; 142 *max_low = *max_high = 0; 143 144 for_each_bank (i, mi) { 145 struct membank *bank = &mi->bank[i]; 146 unsigned long start, end; 147 148 start = bank_pfn_start(bank); 149 end = bank_pfn_end(bank); 150 151 if (*min > start) 152 *min = start; 153 if (*max_high < end) 154 *max_high = end; 155 if (bank->highmem) 156 continue; 157 if (*max_low < end) 158 *max_low = end; 159 } 160}
밑의 매크로를 통해서 페이지프레임넘버를 가져온다.
45#define bank_pfn_start(bank) __phys_to_pfn((bank)->start) 46#define bank_pfn_end(bank) __phys_to_pfn((bank)->start + (bank)->size)
139#define __phys_to_pfn(paddr) ((unsigned long)((paddr) >> PAGE_SHIFT))
가져온 pfn을 start, end에 assign하고 전달받은 min, max_low, max_high를 그에 맞게 설정해 준다.
그 후, bootmem_init()에서 arm_bootmem_init(min, max_low)를 통해 bootmem bitmap page 할당, bootmem allocator 초기화, lowmem 해재, lowmem memblock reservation 등을 한다.
위의 할당된 bootmem 은 나중에 init/main.c 에서 mem_init()를 호출하면,
453static void __init mm_init(void) 454{ 455 /* 456 * page_cgroup requires countinous pages as memmap 457 * and it's bigger than MAX_ORDER unless SPARSEMEM. 458 */ 459 page_cgroup_init_flatmem(); 460 mem_init(); 461 kmem_cache_init(); 462 percpu_init_late(); 463 pgtable_cache_init(); 464 vmalloc_init(); 465}
mem_init()에서 bootmem에 할당되었던 메모리를 해제한다.
600 totalram_pages += free_all_bootmem();
mm/bootmem.c
250unsigned long __init free_all_bootmem(void) 251{ 252 unsigned long total_pages = 0; 253 bootmem_data_t *bdata; 254 255 list_for_each_entry(bdata, &bdata_list, list) 256 total_pages += free_all_bootmem_core(bdata); 257 258 return total_pages; 259}
자 그러면 이제 우리가 원하던 부분이다.
610 reserved_pages = free_pages = 0; 611 612 for_each_bank(i, &meminfo) { 613 struct membank *bank = &meminfo.bank[i]; 614 unsigned int pfn1, pfn2; 615 struct page *page, *end; 616 617 pfn1 = bank_pfn_start(bank); 618 pfn2 = bank_pfn_end(bank); 619 620 page = pfn_to_page(pfn1); 621 end = pfn_to_page(pfn2 - 1) + 1; 622 623 do { 624 if (PageReserved(page)) 625 reserved_pages++; 626 else if (!page_count(page)) 627 free_pages++; 628 page++; 629 } while (page < end); 630 } 631 632 /* 633 * Since our memory may not be contiguous, calculate the 634 * real number of pages we have in this system 635 */ 636 printk(KERN_INFO "Memory:"); 637 num_physpages = 0; 638 for_each_memblock(memory, reg) { 639 unsigned long pages = memblock_region_memory_end_pfn(reg) - 640 memblock_region_memory_base_pfn(reg); 641 num_physpages += pages; 642 printk(" %ldMB", pages >> (20 - PAGE_SHIFT)); 643 } 644 printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT)); 645 646 printk(KERN_NOTICE "Memory: %luk/%luk available, %luk reserved, %luK highmem\n", 647 nr_free_pages() << (PAGE_SHIFT-10), 648 free_pages << (PAGE_SHIFT-10), 649 reserved_pages << (PAGE_SHIFT-10), 650 totalhigh_pages << (PAGE_SHIFT-10)); 651 652#define MLK(b, t) b, t, ((t) - (b)) >> 10 653#define MLM(b, t) b, t, ((t) - (b)) >> 20 654#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K) 655 656 printk(KERN_NOTICE "Virtual kernel memory layout:\n" 657 " vector : 0x%08lx - 0x%08lx (%4ld kB)\n" 658#ifdef CONFIG_HAVE_TCM 659 " DTCM : 0x%08lx - 0x%08lx (%4ld kB)\n" 660 " ITCM : 0x%08lx - 0x%08lx (%4ld kB)\n" 661#endif 662 " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n" 663#ifdef CONFIG_MMU 664 " DMA : 0x%08lx - 0x%08lx (%4ld MB)\n" 665#endif 666 " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n" 667 " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n" 668#ifdef CONFIG_HIGHMEM 669 " pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n" 670#endif 671 " modules : 0x%08lx - 0x%08lx (%4ld MB)\n" 672 " .text : 0x%p" " - 0x%p" " (%4d kB)\n" 673 " .init : 0x%p" " - 0x%p" " (%4d kB)\n" 674 " .data : 0x%p" " - 0x%p" " (%4d kB)\n" 675 " .bss : 0x%p" " - 0x%p" " (%4d kB)\n",
meminfo의 nr_bank숫자 만큼 루핑을 하면서, bank의 start주소와 end주소의 pfn을 가져와, 각각 page, end에 저장시키고, page에서부터 end까지 안에서 루핑하면서, page가 reserved일 경우, reserved_pages++ 하고, !page_count(page)일 경우 free_pages++하고, 마지막으로 page를 increment시킨다.
for_each_memblock(memory, reg) 는
150#define for_each_memblock(memblock_type, region) \ 151 for (region = memblock.memblock_type.regions; \ 152 region < (memblock.memblock_type.regions + memblock.memblock_type.cnt); \ 153 region++)
memblock_type의 memory안의 memblock_region의 regions을 돌면서(memory의 cnt숫자만큼),
26struct memblock_region { 27 phys_addr_t base; 28 phys_addr_t size; 29}; 30 31struct memblock_type { 32 unsigned long cnt; /* number of regions */ 33 unsigned long max; /* size of the allocated array */ 34 struct memblock_region *regions; 35}; 36 37struct memblock { 38 phys_addr_t current_limit; 39 phys_addr_t memory_size; /* Updated by memblock_analyze() */ 40 struct memblock_type memory; 41 struct memblock_type reserved; 42};
pages에 region의 base + size의 PFN 값에서 base의 PFN값을 뺀 값을 설정한다.
639 unsigned long pages = memblock_region_memory_end_pfn(reg) - 640 memblock_region_memory_base_pfn(reg);
그리고 이렇게 얻어진 pages를 num_phypages에 증가시켜준다.
그러면 드디오 이 num_phypages >> (20 - PAGE_SHIFT)가
Memory: = xxx MB total
에 나오는 xxx가 된다.
'리눅스 > 커널' 카테고리의 다른 글
syslog LOCAL7 (0) | 2014.08.28 |
---|---|
Dentry cache hash table 사이즈 (0) | 2014.04.08 |
driver 초기화 시에 쓰이는 module_init (0) | 2014.04.04 |
Machine 이름 바꾸기 (0) | 2014.04.03 |
Machine 이름 알아내기 (0) | 2014.04.03 |