uclinux初始化---------2

来源:互联网 发布:速食汤 知乎 编辑:程序博客网 时间:2024/05/16 09:10
asmlinkage void __init start_kernel(void)
{
 char * command_line;
 extern char saved_command_line[];

/*
 * Interrupts are still disabled. Do necessary setups, then
 * enable them
 */
 lock_kernel();
 printk(linux_banner);
 setup_arch(&command_line);
 printk("Kernel command line: %s/n", saved_command_line);
 parse_options(command_line);
 .....
 。。。
 
}
下面我们开始分析start_kernel这段代码,主要是三个函数
/*
 * Getting the big kernel lock.
 *
 * This cannot happen asynchronously,
 * so we only need to worry about other
 * CPU's.
 */
extern __inline__ void lock_kernel(void)
{
 if (!++current->lock_depth)
  spin_lock(&kernel_flag);
}
kernel_flag是一个内核大自旋锁,所有进程都通过这个大锁来实现向内核态的迁移。
只有获得这个大锁的处理器可以进入内核(如中断处理)。
这个函数相当简单,它获得全局内核锁--在任何一对lock_kernel/unlock_kernel函数里至多可以有一个CPU。
进程的lock_depth成员初始化为-1(参见kerenl/fork.c)。在它小于0时(若小于0则恒为-l),进程不拥有内核锁;当大于或等于0时,进程得到内核锁。
对于单cpu,该函数为空


void __init setup_arch(char **cmdline_p)
{
 struct param_struct *params = NULL;
 struct machine_desc *mdesc;
 char *from = default_command_line;
 int bootmap_size;
 unsigned long memory_start = (unsigned long)&_end_kernel;
 
 ROOT_DEV = MKDEV(0, 255);

 setup_processor();
 在该函数中,主要通过
for (list = &__proc_info_begin; list < &__proc_info_end ; list++)
  if ((processor_id & list->cpu_mask) == list->cpu_val)
   break;
这样一个循环来在..proc.info段中寻找匹配的processor_id,processor_id在前面的head_armv.S中设置

 mdesc = setup_architecture(machine_arch_type);//获得体系结构的信息
 machine_name = mdesc->name;

 if (mdesc->soft_reboot)
  reboot_setup("s");

 if (mdesc->param_offset)
  params = (struct param_struct*)
   (phys_to_virt(mdesc->param_offset));

 /*
  * Do the machine-specific fixups before we parse the
  * parameters or tags.
  */
 if (mdesc->fixup)
  mdesc->fixup(mdesc, params, &from, &meminfo);

分析传入的参数
 if (params) {
  struct tag *tag = (struct tag *)params;

  /*
   * Is the first tag the CORE tag?  This differentiates
   * between the tag list and the parameter table.
   */
  if (tag->hdr.tag == ATAG_CORE)
   parse_tags(mdesc->tagtable, mdesc->tagsize, tag);
  else
   parse_params(params);
 } 

meminfo结构表明了uclinux的内存情况
 if (meminfo.nr_banks == 0) {
  meminfo.nr_banks      = 1;
  meminfo.bank[0].start = PAGE_OFFSET;//PHYS_OFFSET;
  meminfo.bank[0].size  = MEM_SIZE;
 }
初始化为一个bank,起始地址PAGE_OFFSET,大小MEM_SIZE

 init_mm.start_code = (unsigned long) &_text;
 init_mm.end_code   = (unsigned long) &_etext;
 init_mm.end_data   = (unsigned long) &_edata;
 init_mm.brk    = (unsigned long) &_end;

 memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
 saved_command_line[COMMAND_LINE_SIZE-1] = '/0';
如果命令行中有参数mem=size@start,那么我们将更新meminfo,之后,cmdline_p  ==   "root=/dev/rom0"
 parse_cmdline(&meminfo, cmdline_p, from);


 bootmem_init(&meminfo); 初始化bootmem

 paging_init(&meminfo, mdesc);  // mem_map is set up here! 
 request_standard_resources(&meminfo, mdesc);//建立资源链表

 /*
  * Set up various architecture-specific pointers
  */
  设定初始化irq的函数
 init_arch_irq = mdesc->init_irq;

是否支持keyboard和显示设备,他们是用来做虚拟终端
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
 conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
 conswitchp = &dummy_con;
#endif
#endif
}


void __init bootmem_init(struct meminfo *mi)
{
 struct node_info node_info[NR_NODES], *np = node_info;
 unsigned int bootmap_pages, bootmap_pfn, map_pg;
 int node, initrd_node;

 bootmap_pages = find_memend_and_nodes(mi, np);
注:通过上述操作,bootmap_pages设置了描述所有内存使用情况所需要的pages,并且在该函数中初始化了np[0]的内容。

 bootmap_pfn   = find_bootmap_pfn(0, mi, bootmap_pages);
注:通过上述操作,bootmap_pfn设置了bootmem所在的初始页号。也就是说从bootmap_pfn到bootmap_pfn + bootmap_pages的内存页被用来描述初始化的时候的内存的用用情况
 initrd_node   = check_initrd(mi);  //do nothing 

 map_pg = bootmap_pfn;

 np += numnodes - 1;
 for (node = numnodes - 1; node >= 0; node--, np--) {
  /*
   * If there are no pages in this node, ignore it.
   * Note that node 0 must always have some pages.
   */
  if (np->end == 0) {
   if (node == 0)
    BUG();
   continue;
  }

  /*
   * Initialise the bootmem allocator.
   */
  init_bootmem_node(NODE_DATA(node), map_pg, np->start, np->end);
注:在该函数中初始化contig_page_data中的struct bootmem_data *bdata
bdata->node_bootmem_map = bootmem的启示地址
bdata->node_boot_start = 本节点物理内存的开始
bdata->node_low_pfn =本节点物理内存的结尾
同时保留了所有的页面,使得所有内存不能使用,不过在下面的函数中将会放开。

但是在free_bootmem_node_bank(node, mi);中设置所有内存可以分配
  free_bootmem_node_bank(node, mi);
  map_pg += np->bootmap_pages;

  /*
   * If this is node 0, we need to reserve some areas ASAP -
   * we may use bootmem on node 0 to setup the other nodes.
   */
  if (node == 0)
   reserve_node_zero(bootmap_pfn, bootmap_pages);
注意:在该函数中,保留了部分内存不能被分配,这些内存快包括:
reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext);  内核占用
reserve_bootmem_node(pgdat, bootmap_pfn << PAGE_SHIFT,
        bootmap_pages << PAGE_SHIFT);   bootmem占用


 if (map_pg != bootmap_pfn + bootmap_pages)
  BUG();
}
原创粉丝点击