uclinux2.6(bf561)中的bootmem分析(3):init_bootmem_node

 
  
这个函数的实现在mm/bootmem.c中:
 
/*
 * 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);
 
     return mapsize;
}
 
unsigned long __init init_bootmem_node(pg_data_t *pgdat, unsigned long freepfn,
                   unsigned long startpfn, unsigned long endpfn)
{
     return init_bootmem_core(pgdat, freepfn, startpfn, endpfn);
}
当参数传递到 init_bootmem_core时,各个参数的对应值为:
mapstart取的是 memory_start >> PAGE_SHIFT ,即内核代码结束后的第一个页序号
start取的是 PAGE_OFFSET >> PAGE_SHIFT ,即0。
end取的是 memory_end >> PAGE_SHIFT ,即SDRAM的最后一个页号。
1             bdata成员的意义
从这个函数的实现可以看出它只初始化了pg_data_t这个结构体的bdata成员,让我们看看bootmem_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;
从这个初始化函数可以大致看出几个成员的意义。
l        node_bootmem_map
     bdata->node_bootmem_map = phys_to_virt(PFN_PHYS(mapstart));
在这行语句中,mapstart是内核代码结束后的第一个页序号,PFN_PHYS定义为:
#define PFN_PHYS(x)    ((x) << PAGE_SHIFT)
phys_to_virt则定义为:
#define phys_to_virt(vaddr) ((void *) (vaddr))
因此 node_bootmem_map保存了内核结束后第一个页的页面地址,而不是页号。
l        node_boot_start
     bdata->node_boot_start = PFN_PHYS(start);
取值为0。
l        node_low_pfn
     bdata->node_low_pfn = end;
指向SDRAM中最后一个页的页序号。
2             link_bootmem
这个函数实现为:
 
/*
 * link bdata in order
 */
static void __init link_bootmem(bootmem_data_t *bdata)
{
     bootmem_data_t *ent;
 
     if (list_empty(&bdata_list)) {
         list_add(&bdata->list, &bdata_list);
         return;
     }
     /* insert in order */
     list_for_each_entry(ent, &bdata_list, list) {
         if (bdata->node_boot_start < ent->node_boot_start) {
              list_add_tail(&bdata->list, &ent->list);
              return;
         }
     }
     list_add_tail(&bdata->list, &bdata_list);
}
它的作用就是将bdata放到一个叫bdata_list的链表中,bdata_list的定义在bootmem.c中:
static LIST_HEAD(bdata_list);
对于BF561来讲,这个函数将只调用一次,用红色标出的代码将不会执行。因此bdata_list的链表也将只有一个元素!
3             get_mapsize
get_mapsize的实现为:
 
/*
 * Given an initialised bdata, it returns the size of the boot bitmap
 */
static unsigned long __init get_mapsize(bootmem_data_t *bdata)
{
     unsigned long mapsize;
     unsigned long start = PFN_DOWN(bdata->node_boot_start);
     unsigned long end = bdata->node_low_pfn;
 
     mapsize = ((end - start) + 7) / 8;
     return ALIGN(mapsize, sizeof(long));
}
其中bdata->node_boot_start指向SDRAM的起始位置,其值为0。 bdata->node_low_pfn则为SDRAM最后一个页的页号。至此我们可以看出,bootmem是试图用一个二进制位表示一页是否占用,如果空闲则该位为0,如果已经使用则该位为1。
对于64M的SDRAM来讲,其页面大小为4K,因此其总共的页数为0x3fff(16K),所需要的字节数为0x800。
从这里还可以知道,bootmem用内核代码结束后的第1页来保存所有的SDRAM页面使用情况。
 

你可能感兴趣的:(list,struct,insert,UP,each,Allocation)