本身boot中给定的bootmap这个bit位标定page使用情况需要一个位置来存储,两个函数bootmem_bootmap_pages用来计算当前管理的内存页数目需要多大的内存用来保存bit位。find_bootmap_pfn用来找到这个位置对应的pfn。这个位置关键变量打印结果:
bootmem_bootmap_pages start_pfn=0x30000, end_pfn=0x34000, boot_pages=0x1, boot_pfn=0x303cf
具体放置位置find_bootmap_pfn函数计算方式是在内核代码最后的位置_end下一个位置放这个内容。_end=0xc03cebf4,所以bootmap_pfn = pa(0xc03cebf4)>>12 +1。其中pa表示转换为物理地址,也就是0xc000_0000编程0x3000_0000,最后计算结果就是0x303cf。
node_set_online(node) 设置map全部为1,表示所有页面都被使用
pgdat = NODE_DATA(node); 之后便获取这个节点的管理数据结构gpdat
init_bootmem_node(pgdat, boot_pfn, start_pfn, end_pfn); 初始化pgdat结构体中的bootmem_data 结构体
|---->init_bootmem_core(pgdat, freepfn, startpfn, endpfn)
typedef struct pglist_data {
struct zone node_zones[MAX_NR_ZONES];
struct zonelist node_zonelists[MAX_NR_ZONES];
int nr_zones;
#ifdef CONFIG_FLAT_NODE_MEM_MAP
struct page *node_mem_map;
#endif
struct bootmem_data *bdata;
#ifdef CONFIG_MEMORY_HOTPLUG
/*
* Must be held any time you expect node_start_pfn, node_present_pages
* or node_spanned_pages stay constant. Holding this will also
* guarantee that any pfn_valid() stays that way.
*
* Nests above zone->lock and zone->size_seqlock.
*/
spinlock_t node_size_lock;
#endif
unsigned long node_start_pfn;
unsigned long node_present_pages; /* total number of physical pages */
unsigned long node_spanned_pages; /* total size of physical page
range, including holes */
int node_id;
wait_queue_head_t kswapd_wait;
struct task_struct *kswapd;
int kswapd_max_order;
} pg_data_t;
/*
* 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_boot_start;
unsigned long node_low_pfn;
void *node_bootmem_map;
unsigned long last_offset;
unsigned long last_pos;
unsigned long last_success; /* Previous allocation point. To speed
* up searching */
struct list_head list;
} bootmem_data_t;
管理结构体的初始化
/*
* Called once to set up the allocator itself.
*/
static unsigned long __init init_bootmem_core(pg_data_t *pgdat,
unsigned long mapstart, unsigned long start, unsigned long end)
{
bootmem_data_t *bdata = pgdat->bdata;
unsigned long mapsize;
bdata->node_bootmem_map = phys_to_virt(PFN_PHYS(mapstart));
bdata->node_boot_start = PFN_PHYS(start);
bdata->node_low_pfn = end;
link_bootmem(bdata);
/*
* Initially all pages are reserved - setup_arch() has to
* register free RAM areas explicitly.
*/
mapsize = get_mapsize(bdata);
memset(bdata->node_bootmem_map, 0xff, mapsize);
//init_bootmem_core node_boot_start=805306368, node_low_pfn=212992, node_bootmem_map=c03cf000, last_offset=0, last_pos=0, last_success=0
return mapsize;
}
init_bootmem_core node_boot_start=0x30000000, node_low_pfn=0x34000, node_bootmem_map=c03cf000, mapsize=0x800, last_offset=0, last_pos=0, last_success=0
free_bootmem_node函数对test_and_clear_bit(i, bdata->node_bootmem_map)开始位置的bit位清除为0。传入的是SDRAM的开始位置和大小,也就是现在内存全部可以使用状态。
reserve_bootmem_node函数是针对使用的bit位图页表位置对应的bit设置为保留。
resetve_bootmem_node addr=0x303cf000, size=0x1000, initrd_node=-2
reserve_bootmem_node(pgdat, boot_pfn << PAGE_SHIFT, boot_pages << PAGE_SHIFT);
|---->reserve_bootmem_core(pgdat->bdata, physaddr, size)
static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long addr,
unsigned long size)
{
unsigned long sidx, eidx;
unsigned long i;
/*
* round up, partially reserved pages are considered
* fully reserved.
*/
BUG_ON(!size);
BUG_ON(PFN_DOWN(addr) >= bdata->node_low_pfn);
BUG_ON(PFN_UP(addr + size) > bdata->node_low_pfn);
sidx = PFN_DOWN(addr - bdata->node_boot_start);
eidx = PFN_UP(addr + size - bdata->node_boot_start);
for (i = sidx; i < eidx; i++)
if (test_and_set_bit(i, bdata->node_bootmem_map)) {
#ifdef CONFIG_DEBUG_BOOTMEM
printk("hm, page %08lx reserved twice.\n", i*PAGE_SIZE);
#endif
}
}
此处的位置bit位保留主要是针对内核代码段数据和bss段等数据进行数据保留。第二段对swapper_pg_dir位置pgd数据保存位置进行置位保留。最后
reserve_node_zero(pgdat)
|---->reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext);
|
|---->reserve_bootmem_node(pgdat, __pa(swapper_pg_dir),
PTRS_PER_PGD * sizeof(pgd_t));
|
|
|---->if (res_size)
|----> reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size);