您的位置:首页 > 运维架构 > Linux

Linux初始化内核临时页表之后的setup_memory函数

2009-12-20 23:44 477 查看
话说在linux内核初始化完内核临时页表来映射前8MB内存后,在欲望的驱使下,linux开始着手抢占
896MB以下的内存了。然而抢夺这896MB内存绝非易事。linux还有许多麻烦的事要做。比如说进攻和占领伊拉克等等。于是
setup_memory函数开始为linux策划和筹备此事。主要任务是建立一张与物理内存页框号对应的位图。如果该页框被占用则对应位图中的位被置
1,否则置0。在伙伴系统建立前对内存进行临时管理。在初始化内核最终页表时alloc_bootmem_low_pages内存分配函数就用到了这个位
图。

核心数据结构:

typedef struct bootmem_data { 
  unsigned long node_boot_start; /* 起始页框号0 */ 
  unsigned long node_low_pfn; /* 如果物理内存大于896MB,node_low_pfn为0x37FFF。 
                              如果物理内存小于等于896MB,node_low_pfn为物理内
                              存的最大页框号。*/ 
  void *node_bootmem_map; /* 位图的起始地址 */ 
  /* 下面三个变量的作用用于alloc_bootmem_low_pages函数 */ 
  unsigned long last_offset; 
  unsigned long last_pos; 
  unsigned long last_success; 
  } bootmem_data_t ; 
  创建位图的函数流程: 
  start_kernel->setup_arch->setup_memory->init_bootmem ->init_bootmem_core 
   linux/arch/i386/kernel/setup.c 
   在setup_memory()中执行 
   start_pfn = PFN_UP(init_pg_tables_end); /* start_pfn是指映射8MB所用页表之后第一个页框号。
                          PFN_UP的作用是把地址按页的大小进行对齐。也就是地址是4kb的整数倍大小。*/ 
      
    find_max_pfn(); /* 找到物理内存中最大页框号。放入max_pfn中。*/ 
    max_low_pfn=find_max_low_pfn(); /* 如果物理地址小于等于896MB,max_low_pfn=max_pfn。大于896MB时,
                                     max_low_pfn为896MB内存大小的最大页框号 */ 
    bootmap_size = init_bootmem(start_pfn,max_low_pfn); 
    进入init_bootmem中
    unsigned long __init init_bootmem (unsigned long start , unsigned long pages) 
    { 
       max_low_pfn = pages; 
       min_low_pfn = start ; 
       return( init_bootmem_core ( NODE_DATA (0), start , 0, pages)); 
    }
    再从init_bootmem 进入 init_bootmem_core 中,此函数创建位图 
    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 = (( end - start )+7)/8; /* mapsize为要创建的位图的大小 */ 
        pgdat->pgdat_next = pgdat_list ; 
        pgdat_list = pgdat; mapsize = (mapsize + (sizeof(long) - 1UL)) & ~(sizeof(long) - 1UL); 
        /* 按照4个字节大小进行对齐 */ 
        bdata->node_bootmem_map = phys_to_virt (mapstart << PAGE_SHIFT ); 
        /* bdata->node_bootmem_map 为位图的起始位置的线性地址 */
        bdata->node_boot_start = ( start << PAGE_SHIFT ); 
         /* 第一个页框的起始地址,就是0号页框的起始地址0x00000000 */
        bdata->node_low_pfn = end ; 
        memset (bdata->node_bootmem_map, 0xff, mapsize); /* 把位图中的每一位都置1,表示为占用状态。在接下去的函数中,会把内核可以使用的页框号对应的位置0。 */ 
       return mapsize; 
   } 
   回到setup_memory中,接着执行 
    register_bootmem_low_pages ( max_low_pfn ); 
   此函数的主要的功能是把内核可以使用的页框号(最大为max_low_pfn )在位图中对应的位置0。 
   由于有些页已经被内核数据占用,所以还要把这些页再置为1。就是调用 
   reserve_bootmem ( HIGH_MEMORY , ( PFN_PHYS (start_pfn) + bootmap_size + PAGE_SIZE -1) - ( HIGH_MEMORY )); 
   此函数把从1MB开始(HIGH_MEMORY定义为1024*1024)到位图结束所占用的页框号在位图中对应的位置1。
   然后根据不同的硬件配置再做一些扫尾的工作。
   return max_low_pfn;
   setup_memory函数结束。
   接着linux就会调用paging_init来完成它对896MB内存的抢夺了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: