static unsigned long __init bootmem_init_node(int node, struct meminfo *mi)
in arch/arm/mm/init.c
1.1 根据内存信息重新映射页表,此处为低端内存的线性映射
-->map_memory_bank(bank); -->create_mapping(&map); -->alloc_init_section(pgd, addr, next, phys, type); -->/*如果地址按SECTION对齐,只需一级页表,映射1MB空间*/ /*如果地址不是SECTION对齐,需二级页表*/ -->alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type); /*最终调用的是proc_info_list->proc->set_pte_ext,汇编代码在arch/arm/mm/proc-macros.S*/ -->set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0);
1.2 Allocate the bootmem bitmap page
bootmem分配器用每一bit表示一个物理页框的使用情况,该函数计算表示所有的物理页框共需申请多少页的内存。
函数以总的物理页框数为输入参数,返回bitmap需要使用的页数。
/* Convert a physical address to a Page Frame Number and back #define __phys_to_pfn(paddr) ((paddr) >> PAGE_SHIFT) #define __pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT) end_pfn,start_pfn物理内存的起止页框号, */ /** * bootmem_bootmap_pages - calculate bitmap size in pages * @pages: number of pages the bitmap has to represent */ unsigned long __init bootmem_bootmap_pages(unsigned long pages) { unsigned long bytes = bootmap_bytes(pages); return PAGE_ALIGN(bytes) >> PAGE_SHIFT; } static unsigned long __init bootmap_bytes(unsigned long pages) { unsigned long bytes = (pages + 7) / 8; return ALIGN(bytes, sizeof(long)); }
1.3 boot_pfn = find_bootmap_pfn(node, mi, boot_pages);
寻找1.2中计算出的bitmap使用的若干页该对应到物理页框的什么位置。寻找的依据是从kernel的bss段结束位置开始寻找,找到能够放置bootmap_pages个页框的内存位置。
static unsigned int __init find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages) { unsigned int start_pfn, i, bootmap_pfn; start_pfn = PAGE_ALIGN(__pa(_end)) >> PAGE_SHIFT; bootmap_pfn = 0; for_each_nodebank(i, mi, node) { struct membank *bank = &mi->bank[i]; unsigned int start, end; start = bank_pfn_start(bank); end = bank_pfn_end(bank); if (end < start_pfn) continue; if (start < start_pfn) start = start_pfn; if (end <= start) continue; if (end - start >= bootmap_pages) { bootmap_pfn = start; break; } } if (bootmap_pfn == 0) BUG(); return bootmap_pfn; }
1.4 init_bootmem_node
初始化pg_data_t->bdtat结构体,
将不同node的bdata添加到以bdata_list为首的链表。标记所有的bitmap位为1。
/* * node_bootmem_map is a map pointer - the bits represent all physical * memory pages (including holes) on the node. */ typedef struct bootmem_data { unsigned long node_min_pfn; unsigned long node_low_pfn; void *node_bootmem_map; unsigned long last_end_off; unsigned long hint_idx; struct list_head list; } bootmem_data_t;
/* * Called once to set up the allocator itself. */ static unsigned long __init init_bootmem_core(bootmem_data_t *bdata, unsigned long mapstart, unsigned long start, unsigned long end) { unsigned long mapsize; mminit_validate_memmodel_limits(&start, &end); bdata->node_bootmem_map = phys_to_virt(PFN_PHYS(mapstart)); bdata->node_min_pfn = start; bdata->node_low_pfn = end; link_bootmem(bdata); /* * Initially all pages are reserved - setup_arch() has to * register free RAM areas explicitly. */ mapsize = bootmap_bytes(end - start); memset(bdata->node_bootmem_map, 0xff, mapsize); bdebug("nid=%td start=%lx map=%lx end=%lx mapsize=%lx ", bdata - bootmem_node_data, start, mapstart, end, mapsize); return mapsize; } init_bootmem_core
1.5 free_bootmem_node(pgdat, bank_phys_start(bank), bank_phys_size(bank));
把节点下所有的页框对应的bitmap位都设为0,标记为空闲。
这里最终调用bootmem底层的__free函数和__reserve函数。
static int __init mark_bootmem_node(bootmem_data_t *bdata, unsigned long start, unsigned long end,int reserve, int flags) { unsigned long sidx, eidx; bdebug("nid=%td start=%lx end=%lx reserve=%d flags=%x ", bdata - bootmem_node_data, start, end, reserve, flags); BUG_ON(start < bdata->node_min_pfn); BUG_ON(end > bdata->node_low_pfn); sidx = start - bdata->node_min_pfn; eidx = end - bdata->node_min_pfn; if (reserve) return __reserve(bdata, sidx, eidx, flags); else __free(bdata, sidx, eidx); return 0; }
static int __init __reserve(bootmem_data_t *bdata, unsigned long sidx, unsigned long eidx, int flags) { unsigned long idx; int exclusive = flags & BOOTMEM_EXCLUSIVE; bdebug("nid=%td start=%lx end=%lx flags=%x ", bdata - bootmem_node_data, sidx + bdata->node_min_pfn, eidx + bdata->node_min_pfn, flags); for (idx = sidx; idx < eidx; idx++) if (test_and_set_bit(idx, bdata->node_bootmem_map)) { if (exclusive) { __free(bdata, sidx, idx); return -EBUSY; } bdebug("silent double reserve of PFN %lx ", idx + bdata->node_min_pfn); } return 0; }
static void __init __free(bootmem_data_t *bdata, unsigned long sidx, unsigned long eidx) { unsigned long idx; bdebug("nid=%td start=%lx end=%lx ", bdata - bootmem_node_data, sidx + bdata->node_min_pfn, eidx + bdata->node_min_pfn); if (bdata->hint_idx > sidx) bdata->hint_idx = sidx; for (idx = sidx; idx < eidx; idx++) if (!test_and_clear_bit(idx, bdata->node_bootmem_map)) BUG(); }
1.6 在bitmap中标记bitmap所占用的页框为使用状态
/* * Reserve the bootmem bitmap for this node. */ reserve_bootmem_node(pgdat, boot_pfn << PAGE_SHIFT, boot_pages << PAGE_SHIFT, OOTMEM_DEFAULT);