리눅스/커널2014. 4. 7. 19:22

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
Posted by code cat