2014년 8월 16일 토요일

[Linux Kernel] 66주차(2014.08.16)

ARM Linux Kernel 66주차

일시 : 2014.08.16 (66주차)
모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C
장소 : 토즈 강남 타워점
장소지원: NAVER 개발자 커뮤니티 지원 프로그램
참여인원: 5명

스터디 진도 :

  • mm_init() 복습
  • mm_init()->mem_init();
    • 66차 복습 완료.
  • mm_init()->kmem_cache_init();
    • 66차 일부 복습, 67차에 이어서 복습
  • mm_init()->percpu_init_late();
    • 67차 복습
  • mm_init()->vmalloc_init();
    • 67차 복습

main.c::start_kernel()

asmlinkage void __init start_kernel(void)
{
...
    boot_cpu_init();
    // 현재 cpu(core id)를 얻어서 cpu_XXX_bits[] 의 cpu를 셋한다.

    page_address_init();
    // 128개의 page_address_htable 배열을 초기화
...
    setup_arch(&command_line);
...
    setup_nr_cpu_ids();
    setup_per_cpu_areas();
    // pcpu 구조체를 만들어 줌 (mm/percpu.c)

    smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
    // boot cpu 0의 pcpu 영역의 base주소를 core register에 설정해줌
...
    page_alloc_init();
    // cpu_chain에 page_alloc_cpu_notify를 연결함 (mutex lock/unlock 사용)
...
    vfs_caches_init_early();
    // Dentry cache, Inode-cache용 hash를 위한 메모리 공간을 각각 512kB, 256kB만큼 할당 받고,
    // 131072, 65536개 만큼 hash table을 각각 만듬
...
    mm_init();
    // buddy와 slab 을 활성화 하고 기존 할당 받은 bootmem 은 buddy,
    // pcpu 메모리, vmlist 는 slab으로 이관

// 2014/08/09 종료
  • start_kernel()->mm_init()을 복습합니다. > mm_init();

main.c::mm_init()

static void __init mm_init(void)
{
    page_cgroup_init_flatmem(); // null function
    mem_init();
    // bootmem으로 관리하던 메모리를 buddy로 이관.
    // 각 section 메모리 크기를 출력.

    // mm/Makefile 에서 CONFIG_SLUB 설정으로 slub.c 로 jump
    kmem_cache_init();
    // slub 을 활성화 시킴

    percpu_init_late();
    // dchunk로 할당 받은 pcpu 메모리 값들을 slab으로 카피하여 이관

    pgtable_cache_init(); // null function

    vmalloc_init();
    // vmlist에 등록된 vm struct 들을 slab으로 이관하고 RB Tree로 구성
}
  • mm_init()에서 커널의 메모리 관리자인 buddy와 slab를 활성화 하고 이후 이들로 메모리를 관리니다.
  • 부트 초기에 사용하였던 메모리를 buddy와 slab으로 어떻게 복제하고 활성화하는 지 분석합니다.
  • mem_init();
    • 66차 복습 완료.
  • kmem_cache_init();
    • 66차 일부 복습, 67차에 이어서 복습
  • percpu_init_late();
    • 67차 복습
  • vmalloc_init();
    • 67차 복습

init.c::mem_init()

void __init mem_init(void)
{

    // max_pfn : 0x80000, PHYS_PFN_OFFSET: 0x20000, *mem_map: NULL
    // pfn_to_page(0xA0000): page 10번째 section 주소 + 0xA0000
    max_mapnr   = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
    // max_mapnr: page 10번째 section 주소 + 0xA0000

    /* this will put all unused low memory onto the freelists */
    free_unused_memmap(&meminfo);
    // bank 0, 1에 대해 bank 0, 1 사이에 사용하지 않는 공간이 있거나
    // align이 되어 있지 않으면 free_memmap을 수행

    free_all_bootmem();
    // bootmem으로 관리하던 메모리를 buddy로 이관.

    free_highpages();
    // highmem의 reserved 영역을 제외하고 buddy order 0 에 추가.

    mem_init_print_info(NULL);
    // 각 메모리 섹션의 정보를 구하여 출력.

#define MLK(b, t) b, t, ((t) - (b)) >> 10
#define MLM(b, t) b, t, ((t) - (b)) >> 20
#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)

    printk(KERN_NOTICE "Virtual kernel memory layout:\n"
            "    vector  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
            "    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
            "    vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n"
            "    lowmem  : 0x%08lx - 0x%08lx   (%4ld MB)\n"
#ifdef CONFIG_HIGHMEM // CONFIG_HIGHMEM=y
            "    pkmap   : 0x%08lx - 0x%08lx   (%4ld MB)\n"
#endif
#ifdef CONFIG_MODULES // CONFIG_MODULES=y
            "    modules : 0x%08lx - 0x%08lx   (%4ld MB)\n"
#endif
            "      .text : 0x%p" " - 0x%p" "   (%4d kB)\n"
            "      .init : 0x%p" " - 0x%p" "   (%4d kB)\n"
            "      .data : 0x%p" " - 0x%p" "   (%4d kB)\n"
            "       .bss : 0x%p" " - 0x%p" "   (%4d kB)\n",

            // CONFIG_VECTORS_BASE: 0xffff0000, PAGE_SIZE: 0x1000
            // MLK(0xffff0000UL, 0xffff1000UL): 0xffff0000UL, 0xffff1000UL, 4
            MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
                (PAGE_SIZE)),

            // FIXADDR_START: 0xfff00000, FIXADDR_TOP: 0xfffe0000
            MLK(FIXADDR_START, FIXADDR_TOP),

            // VMALLOC_START: 0xf0000000, VMALLOC_END: 0xff000000
            MLM(VMALLOC_START, VMALLOC_END),
            // PAGE_OFFSET: 0xC0000000
            MLM(PAGE_OFFSET, (unsigned long)high_memory),
#ifdef CONFIG_HIGHMEM // CONFIG_HIGHMEM=y
            // PKMAP_BASE: 0xBFE00000, LAST_PKMAP: 512, PAGE_SIZE: 0x1000
            MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) *
                (PAGE_SIZE)),
#endif
#ifdef CONFIG_MODULES // CONFIG_MODULES=y
            // MODULES_VADDR: 0xBF000000, MODULES_END: 0xBFE00000
            MLM(MODULES_VADDR, MODULES_END),
#endif

            MLK_ROUNDUP(_text, _etext),
            MLK_ROUNDUP(__init_begin, __init_end),
            MLK_ROUNDUP(_sdata, _edata),
            MLK_ROUNDUP(__bss_start, __bss_stop));

#undef MLK
#undef MLM
#undef MLK_ROUNDUP

    /*
     * Check boundaries twice: Some fundamental inconsistencies can
     * be detected at build time already.
     */
#ifdef CONFIG_MMU // CONFIG_MMU=y
    // TASK_SIZE: 0xBF000000, MODULES_VADDR: 0xBF000000
    BUILD_BUG_ON(TASK_SIZE              > MODULES_VADDR);
    BUG_ON(TASK_SIZE                > MODULES_VADDR);
#endif

#ifdef CONFIG_HIGHMEM // CONFIG_HIGHMEM=y
    // PKMAP_BASE: 0xBFE00000, LAST_PKMAP: 512, PAGE_SIZE: 0x1000, PAGE_OFFSET: 0xC0000000
    BUILD_BUG_ON(PKMAP_BASE + LAST_PKMAP * PAGE_SIZE > PAGE_OFFSET);
    BUG_ON(PKMAP_BASE + LAST_PKMAP * PAGE_SIZE  > PAGE_OFFSET);
#endif
    // PAGE_SIZE: 0x1000 (4096), get_num_physpages(): 0x80000
    if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) {
        // PAGE_SIZE 가 16K 보다 크고 물리 메모리가 512K 이하면 수행.
        extern int sysctl_overcommit_memory;
        /*
         * On a machine this small we won't get
         * anywhere without overcommit, so turn
         * it on by default.
         */
        sysctl_overcommit_memory = OVERCOMMIT_ALWAYS;
    }
}

init.c::free_unuses_memmap()

  • free_unused_memmap(&meminfo);
static void __init free_unused_memmap(struct meminfo *mi)
{
    unsigned long bank_start, prev_bank_end = 0;
    unsigned int i;

    // mi: &meminfo, (&meminfo)->nr_banks: 2
    for_each_bank(i, mi) {
    // for (i = 0; i < (&meminfo)->nr_banks; i++)

        struct membank *bank = &mi->bank[i];
        // [1st] bank: &(&meminfo)->bank[0]
        // [2nd] bank: &(&meminfo)->bank[1]

        // [1st] bank_pfn_start(&(&meminfo)->bank[0]): 0x20000
        // [2nd] bank_pfn_start(&(&meminfo)->bank[1]): 0x4f800
        bank_start = bank_pfn_start(bank);
        // [1st] bank_start: 0x20000
        // [2nd] bank_start: 0x4f800

#ifdef CONFIG_SPARSEMEM // CONFIG_SPARSEMEM=y
        // [1st] bank_start: 0x20000, prev_bank_end: 0, PAGES_PER_SECTION: 0x10000
        // [1st] ALIGN(0x0, 0x10000): 0x0
        // [2nd] bank_start: 0x4f800, prev_bank_end: 0x4f800, PAGES_PER_SECTION: 0x10000
        // [2nd] ALIGN(0x4f800, 0x10000): 0x50000
        bank_start = min(bank_start,
                 ALIGN(prev_bank_end, PAGES_PER_SECTION));
        // [1st] bank_start: 0
        // [2nd] bank_start: 0x4f800
#else
        bank_start = round_down(bank_start, MAX_ORDER_NR_PAGES);
#endif
        // [1st] prev_bank_end: 0, bank_start: 0
        // [2nd] prev_bank_end: 0x4f800, bank_start: 0x4f800
        if (prev_bank_end && prev_bank_end < bank_start)
            free_memmap(prev_bank_end, bank_start);

        // [1st] bank: &(&meminfo)->bank[0], MAX_ORDER_NR_PAGES: 0x400
        // [1st] bank_pfn_end(&(&meminfo)->bank[0]): 0x4f800
        // [2nd] bank: &(&meminfo)->bank[1], MAX_ORDER_NR_PAGES: 0x400
        // [2nd] bank_pfn_end(&(&meminfo)->bank[1]): 0xa0000
        prev_bank_end = ALIGN(bank_pfn_end(bank), MAX_ORDER_NR_PAGES);
        // [1st] prev_bank_end: 0x4f800
        // [2nd] prev_bank_end: 0xa0000
    }

#ifdef CONFIG_SPARSEMEM // CONFIG_SPARSEMEM=y
    // prev_bank_end: 0xa0000, PAGES_PER_SECTION: 0x10000
    if (!IS_ALIGNED(prev_bank_end, PAGES_PER_SECTION))
        free_memmap(prev_bank_end,
                ALIGN(prev_bank_end, PAGES_PER_SECTION));
#endif
}
  • bank 0, 1에 대해 bank 0, 1 사이에 사용하지 않는 공간이 있거나
  • align이 되어 있지 않으면 free_memmap을 수행

bootmem.c::free_all_bootmem()

  • free_all_bootmem();
unsigned long __init free_all_bootmem(void)
{
    unsigned long total_pages = 0;
    bootmem_data_t *bdata;

    reset_all_zones_managed_pages();

    list_for_each_entry(bdata, &bdata_list, list)
    // for (bdata = list_entry((&bdata_list)->next, typeof(*bdata), list);
    //     &bdata->list != (&bdata_list);
    //     bdata = list_entry(bdata->list.next, typeof(*bdata), list))
        // bdata: &bdata_list, &bdata->list: (&bdata_list)->list
        total_pages += free_all_bootmem_core(bdata);
        // total_page: 총 free된 page 수 + 0x6

    // totalram_pages: 0
    totalram_pages += total_pages;
    // totalram_pages: 총 free된 page 수 + 0x6

    // total_page: 총 free된 page 수 + 0x6
    return total_pages;
}

bootmem.c::reset_all_zones_managed_pages()

  • reset_all_zones_managed_pages();
void __init reset_all_zones_managed_pages(void)
{
    struct pglist_data *pgdat;

    for_each_online_pgdat(pgdat)
    // for (pgdat = first_online_pgdat(); pgdat; pgdat = next_online_pgdat(pgdat))
        // first_online_pgdat(): &contig_page_data, pgdat: &contig_page_data
        reset_node_managed_pages(pgdat);

    // reset_managed_pages_done: 0
    reset_managed_pages_done = 1;
    // reset_managed_pages_done: 1
}

bootmem.c::free_all_bootmem_core()

  • list_for_each_entry(bdata, &bdata_list, list)
    • // for (bdata = list_entry((&bdata_list)->next, typeof(*bdata), list);
    • // &bdata->list != (&bdata_list);
    • // bdata = list_entry(bdata->list.next, typeof(*bdata), list))
      • // bdata: &bdata_list, &bdata->list: (&bdata_list)->list
      • total_pages += free_all_bootmem_core(bdata);
      • // total_page: 총 free된 page 수 + 0x6
static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
{
    struct page *page;
    unsigned long *map, start, end, pages, count = 0;

    // bdata->node_bootmem_map: (&bdata_list)->node_bootmem_map: NULL 아닌 값
    if (!bdata->node_bootmem_map)
        return 0;

    // bdata->node_bootmem_map: (&bdata_list)->node_bootmem_map
    map = bdata->node_bootmem_map;
    // map: (&bdata_list)->node_bootmem_map

    // bdata->node_min_pfn: (&bdata_list)->node_min_pfn: 0x20000
    start = bdata->node_min_pfn;
    // start: 0x20000

    // bdata->node_low_pfn: (&bdata_list)->node_low_pfn: 0x4f800
    end = bdata->node_low_pfn;
    // end: 0x4f800

    bdebug("nid=%td start=%lx end=%lx\n",
        bdata - bootmem_node_data, start, end);
    // "nid=0 start=0x20000 end=0x4f800"

    // start: 0x20000, end: 0x4f800
    while (start < end) {
        unsigned long idx, vec;
        unsigned shift;

        // start: 0x20000
        // bdata->node_min_pfn: (&bdata_list)->node_min_pfn: 0x20000
        idx = start - bdata->node_min_pfn;
        // idx: 0

        // BITS_PER_LONG: 32
        shift = idx & (BITS_PER_LONG - 1);
        // shift: 0

        /*
         * vec holds at most BITS_PER_LONG map bits,
         * bit 0 corresponds to start.
         */
        // idx: 0, BITS_PER_LONG: 32
        // map: (&bdata_list)->node_bootmem_map
        vec = ~map[idx / BITS_PER_LONG];
        // vec: ~((&bdata_list)->node_bootmem_map[0])

        // shift: 0
        if (shift) {
            vec >>= shift;
            if (end - start >= BITS_PER_LONG)
                vec |= ~map[idx / BITS_PER_LONG + 1] <<
                    (BITS_PER_LONG - shift);
        }
        /*
         * If we have a properly aligned and fully unreserved
         * BITS_PER_LONG block of pages in front of us, free
         * it in one go.
         */
        // start: 0x20000, BITS_PER_LONG: 32, ~0: 0xFFFFFFFF
        // vec: ~((&bdata_list)->node_bootmem_map[0])
        if (IS_ALIGNED(start, BITS_PER_LONG) && vec == ~0UL) {
            // node_bootmem_map[0]의 값이 0일 경우로 가정

            // BITS_PER_LONG: 32, ilog2(BITS_PER_LONG): 5
            int order = ilog2(BITS_PER_LONG);
            // order: 5

            // start: 0x20000, pfn_to_page(0x20000): 0x20000의 해당하는 struct page의 주소
            __free_pages_bootmem(pfn_to_page(start), order);
            // CPU0의 vm_event_states.event[PGFREE] 를 32로 설정함
            // page에 해당하는 pageblock의 migrate flag를 반환함
            // struct page의 index 멤버에 migratetype을 저장함
            // struct page의 _count 멥버의 값을 0 으로 초기화함
            // order 5 buddy를 contig_page_data에 추가함
            // (&contig_page_data)->node_zones[ZONE_NORMAL].vm_stat[NR_FREE_PAGES]: 32 로 설정
            // vmstat.c의 vm_stat[NR_FREE_PAGES] 전역 변수에도 32로 설정

            // count: 0, BITS_PER_LONG: 32
            count += BITS_PER_LONG;
            // count: 32

            // start: 0x20000 (pfn), BITS_PER_LONG: 32
            start += BITS_PER_LONG;
            // start: 0x20020
        } else {
            // node_bootmem_map[0]의 값이 0아닐 경우로 가정
            // node_bootmem_map[0]의 값이 0x000000F0 로 가정하고 분석

            // start: 0x20000
            unsigned long cur = start;
            // cur: 0x20000

            // start: 0x20000, BITS_PER_LONG: 32
            start = ALIGN(start + 1, BITS_PER_LONG);
            // start: 0x20020

            // vec: ~((&bdata_list)->node_bootmem_map[0]): 0xffffff0f,
            // start: 0x20020, cur: 0x20000
            while (vec && cur != start) {
                // vec: 0xffffff0f
                if (vec & 1) {
                    // cur: 0x20000
                    page = pfn_to_page(cur);
                    // page: 0x20000 (pfn)

                    // page: 0x20000 (pfn), 0
                    __free_pages_bootmem(page, 0);
                    // CPU0의 vm_event_states.event[PGFREE] 를 1로 설정함
                    // page에 해당하는 pageblock의 migrate flag를 반환함
                    // struct page의 index 멤버에 migratetype을 저장함
                    // struct page의 _count 멥버의 값을 0 으로 초기화함
                    // order 0 buddy를 contig_page_data에 추가함
                    // (&contig_page_data)->node_zones[ZONE_NORMAL].vm_stat[NR_FREE_PAGES]: 1 로 설정
                    // vmstat.c의 vm_stat[NR_FREE_PAGES] 전역 변수에도 1로 설정

                    // count: 0
                    count++;
                    // count: 1
                }
                // vec: 0xffffff0f
                vec >>= 1;
                // vec: 0x7fffff87

                // cur: 0x20000
                ++cur;
                // cur: 0x20001
            }
            // cur이 0x20000 ~ 0x20020까지 수행됨
        }
    }

    // CPU0의 vm_event_states.event[PGFREE] 를 order로 설정함
    // page에 해당하는 pageblock의 migrate flag를 반환함
    // struct page의 index 멤버에 migratetype을 저장함
    // order 값의 buddy를 contig_page_data에 추가함
    // (&contig_page_data)->node_zones[ZONE_NORMAL].vm_stat[NR_FREE_PAGES]: 2^order 값으로 설정
    // vmstat.c의 vm_stat[NR_FREE_PAGES] 전역 변수에도 2^order 로 설정
    // 현재 page의 page->private값과 buddy의 page->private값이 같으면 page order를 합치는 작업 수행

    // bdata->node_bootmem_map: (&bdata_list)->node_bootmem_map: NULL 아닌 값
    page = virt_to_page(bdata->node_bootmem_map);
    // page: bdata->node_bootmem_map (pfn)

    // bdata->node_low_pfn: (&bdata_list)->node_low_pfn: 0x4f800
    // bdata->node_min_pfn: (&bdata_list)->node_min_pfn: 0x20000
    pages = bdata->node_low_pfn - bdata->node_min_pfn;
    // pages: 0x2f800

    // bootmem_bootmap_pages(0x2f800): 0x6
    pages = bootmem_bootmap_pages(pages);
    // pages: 0x6

    // count: 총 free된 page 수
    count += pages;
    // count: 총 free된 page 수 + 0x6

    // pages: 0x6
    while (pages--)
        __free_pages_bootmem(page++, 0);
        // bdata->node_bootmem_map에서 사용하던 page를 free시킴
        // 이제부터는 buddy로 관리

    // count: 총 free된 page 수 + 0x6
    bdebug("nid=%td released=%lx\n", bdata - bootmem_node_data, count);
    // "nid=0 released=????"

    // count: 총 free된 page 수 + 0x6
    return count;
}

init.c::free_highpages()

static void __init free_highpages(void)
{
#ifdef CONFIG_HIGHMEM // CONFIG_HIGHMEM=y
    // max_low_pfn: 0x4F800
    unsigned long max_low = max_low_pfn;
    // max_low: 0x4F800
    struct memblock_region *mem, *res;

    /* set highmem page free */
    // memblock.memory.cnt : 1
    for_each_memblock(memory, mem) {
    // for (mem = memblock.memory.regions;
    //      mem < (memblock.memory.regions + memblock.memory.cnt); mem++)

        // mem: memblock.memory.regions
        unsigned long start = memblock_region_memory_base_pfn(mem);
        // start: 0x20000
        // mem: memblock.memory.regions
        unsigned long end = memblock_region_memory_end_pfn(mem);
        // end: 0xA0000

        /* Ignore complete lowmem entries */
        // end: 0xA0000, max_low: 0x4F800
        if (end <= max_low)
            continue;

        /* Truncate partial highmem entries */
        // start: 0x20000, max_low: 0x4F800
        if (start < max_low)
            start = max_low;
            // start: 0x4F800

        /* Find and exclude any reserved regions */
        // res: memblock.reserved.regions, memblock.reserved.cnt: ??(4개 이상)
        for_each_memblock(reserved, res) {
        // for (res = memblock.reserved.regions;
        //      res < (memblock.reserved.regions + memblock.reserved.cnt); res++)

            // 현재 highmem은 매핑되지 않았다.
            // 가정: 0x50000 (pfn) ~ 0x50100 (pfn) highmem 영역이 reserved 되어있다.

            unsigned long res_start, res_end;

            // res: memblock.reserved.regions
            res_start = memblock_region_reserved_base_pfn(res);

            // res: memblock.reserved.regions
            res_end = memblock_region_reserved_end_pfn(res);

            // 가정값:
            // res_start: 0x50000 (pfn), res_end: 0x50100 (pfn)

            // res_end: 0x50100, start: 0x4F800
            if (res_end < start)
                continue;
                // lowmem의 reserved 영역은 skip

            // highmem의 reserved 영역만 체크

            // res_start: 0x50000, start: 0x4F800
            if (res_start < start)
                res_start = start;

            // res_start: 0x50000, end: 0xA0000
            if (res_start > end)
                res_start = end;

            // res_end: 0x50100, end: 0xA0000
            if (res_end > end)
                res_end = end;

            // res_start: 0x50000, start: 0x4F800
            if (res_start != start)
                // start: 0x4F800, res_start: 0x50000
                free_area_high(start, res_start);
                // page를 order 0 으로 buddy에 추가.
                // totalram_pages, (&(&contig_page_data)->node_zones[1])->managed_pages, totalhigh_pages
                // 변수를 free된 page 만큼 증가

            // start: 0x4F800, res_end: 0x50100
            start = res_end;
            // start: 0x50100

            // start: 0x50100, end: 0xA0000
            if (start == end)
                break;
        }

        /* And now free anything which remains */
        if (start < end)
            free_area_high(start, end);
            // highmem에 reserved 영역이 없을땐 highmem 영역 전체를 한번에 buddy order 0 에 추가.
    }
#endif
}

page_alloc.c::mem_init_print_info()

void __init mem_init_print_info(const char *str)
{
    unsigned long physpages, codesize, datasize, rosize, bss_size;
    unsigned long init_code_size, init_data_size;

    // get_num_physpages(): 0x80000
    physpages = get_num_physpages();
        // physpages: 0x80000

    // System.map 에서 영역 계산 가능 (이하 적용)
    codesize = _etext - _stext;
    datasize = _edata - _sdata;
    rosize = __end_rodata - __start_rodata;
    bss_size = __bss_stop - __bss_start;
    init_data_size = __init_end - __init_begin;
    init_code_size = _einittext - _sinittext;

    /*
     * Detect special cases and adjust section sizes accordingly:
     * 1) .init.* may be embedded into .data sections
     * 2) .init.text.* may be out of [__init_begin, __init_end],
     *    please refer to arch/tile/kernel/vmlinux.lds.S.
     * 3) .rodata.* may be embedded into .text or .data sections.
     */

    // .init.* , .init.text.* , .rodata.* 섹션은 이후 다른 섹션으로 변경되기
    // 때문에 현재 section의 size를 미리 계산하여 로그용으로 사용.

#define adj_init_size(start, end, size, pos, adj) \
    do { \
        if (start <= pos && pos < end && size > adj) \
            size -= adj; \
    } while (0)

    adj_init_size(__init_begin, __init_end, init_data_size,
             _sinittext, init_code_size);
    adj_init_size(_stext, _etext, codesize, _sinittext, init_code_size);
    adj_init_size(_sdata, _edata, datasize, __init_begin, init_data_size);
    adj_init_size(_stext, _etext, codesize, __start_rodata, rosize);
    adj_init_size(_sdata, _edata, datasize, __start_rodata, rosize);

#undef  adj_init_size

    printk("Memory: %luK/%luK available "
           "(%luK kernel code, %luK rwdata, %luK rodata, "
           "%luK init, %luK bss, %luK reserved"
#ifdef  CONFIG_HIGHMEM // CONFIG_HIGHMEM=y
           ", %luK highmem"
#endif
           "%s%s)\n",
           // PAGE_SHIFT: 12
           nr_free_pages() << (PAGE_SHIFT-10), physpages << (PAGE_SHIFT-10),
           codesize >> 10, datasize >> 10, rosize >> 10,
           (init_data_size + init_code_size) >> 10, bss_size >> 10,
           (physpages - totalram_pages) << (PAGE_SHIFT-10),
#ifdef  CONFIG_HIGHMEM // CONFIG_HIGHMEM=y
           totalhigh_pages << (PAGE_SHIFT-10),
#endif
           str ? ", " : "", str ? str : "");
}

댓글 없음:

댓글 쓰기