Chinaunix首页 | 论坛 | 博客
  • 博客访问: 449085
  • 博文数量: 40
  • 博客积分: 1410
  • 博客等级: 军士长
  • 技术积分: 1396
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-22 19:26
个人简介

嵌入式系统工程师,从事视频、图像、网络、虚拟化等方面的底层软件开发与优化。

文章存档

2014年(4)

2013年(10)

2012年(14)

2011年(12)

分类:

2012-04-13 22:24:50

BootLoader可以向Linux传递参数,编译内核时也可以配置boot options

调试中使用的U-Boot bootargs如下:

noinitrd root=/dev/mtdblock3 rw console=ttySAC0,115200 init=/linuxrc mem=64M

内核版本:

2.6.35.7

内核的处理参数的整体过程如下:

u-boot将配置参数地址通过寄存器传递给内核

内核(arch/arm/kernel/head-common.S 中的 __mmap_switched)将这个地址存入__atags_pointer(定义于arch/arm/kernel/setup.c)

setup_arch() 函数

void __init setup_arch(char **cmdline_p)

{

         struct tag *tags = (struct tag *)&init_tags;

         struct machine_desc *mdesc;

         char *from = default_command_line; 编译内核时配置的Boot Options

 

         unwind_init();

 

         setup_processor();

         mdesc = setup_machine(machine_arch_type);

         machine_name = mdesc->name;

 

         if (mdesc->soft_reboot)

                   reboot_setup("s");

 

         if (__atags_pointer)                                               检查BootLoader是否传入参数

                   tags = phys_to_virt(__atags_pointer);

         else if (mdesc->boot_params)

                   tags = phys_to_virt(mdesc->boot_params);  machine descriptor中传入的启动参数地址(arch/arm/mach-s3c2440/mach-mini2440.c)

 

         /*

          * If we have the old style parameters, convert them to

          * a tag list.

          */

         if (tags->hdr.tag != ATAG_CORE)

                   convert_to_tag_list(tags);

         if (tags->hdr.tag != ATAG_CORE)

                   tags = (struct tag *)&init_tags;       使用default init_tags,其中内存的定义是: 起始地址:0x30000000,大小是16M

 

         if (mdesc->fixup)

                   mdesc->fixup(mdesc, tags, &from, &meminfo);

 

         if (tags->hdr.tag == ATAG_CORE) {

                   if (meminfo.nr_banks != 0)                如果内存已经初始化,则忽略mem TAG

                            squash_mem_tags(tags);

                   save_atags(tags);

                   parse_tags(tags);             解析TAGS,其中如果U-boot传入ATAG_CMDLINE,则使用U-boot传入的bootargs覆盖default_command_line

         }

 

         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;

 

         /* parse_early_param needs a boot_command_line */

         strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);         defualt_command_line拷入boot_command_line

 

         /* populate cmd_line too for later use, preserving boot_command_line */

         strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);

         *cmdline_p = cmd_line;

 

         parse_early_param();               大部分参数的early属性为0,即大部分参数在早期不处理,如noinitrdconsole

 

         paging_init(mdesc);

         request_standard_resources(&meminfo, mdesc);

        

         ***************

}

 

 

start_kernel(init/main.c)函数中,

setup_arch(&command_line); 通过command_line返回参数列表,或者是编译之前配置的Boot Options,或者是bootloader传入的bootargs

****

setup_command_line(command_line); 其中,将command_line拷贝进static_command_line

***

printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);

parse_early_param();      该函数中定义了静态变量done,并且在setup_arch函数中调用之后,已经设置为1,所以此次调用直接返回

parse_args("Booting kernel", static_command_line, __start___param,

                      __stop___param - __start___param,

                      &unknown_bootoption); 解析并处理setup paramsstartstop两个变量在链接脚本中定义,我传进的参数都被unknow_boototion处理。

参数处理结束

 

几点说明:

      ATAG, params(options, args)是两个不同的概念,ATAG以特定的数据结构的形式由bootloader存入,Linux Kernel取出; params以字符串的形式。可以说cmd_line只是bootloader传入的TAG之一。

#ifndef CONFIG_CMDLINE_FORCE

static int __init parse_tag_cmdline(const struct tag *tag)

{

         strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);   

如果u-boot传入“ATAG_CMDLINE TAG,则使用其cmdline覆盖default_command_line

         return 0;

}

 

__tagtable(ATAG_CMDLINE, parse_tag_cmdline);

#endif /* CONFIG_CMDLINE_FORCE */

 

      TAG处理函数,定义在arch/arm/kernel/setup.c中;init/main.c中,定义了一些parmas处理函数。

 

      unknow_bootoption函数处理在params列表中找不到的boot option,

static int __init unknown_bootoption(char *param, char *val)

{

DBGTRACE("Unkown boot option: %s: %s\n", param, val);

         /* Change NUL term back to "=", to make "param" the whole string. */

         if (val) {                                 将参数还原成“=”连接的名值对

                   /* param=val or param="val"? */

                   if (val == param+strlen(param)+1)

                            val[-1] = '=';

                   else if (val == param+strlen(param)+2) {

                            val[-2] = '=';

                            memmove(val-1, val, strlen(val)+1);

                            val--;

                   } else

                            BUG();

         }

 

         /* Handle obsolete-style parameters */

         if (obsolete_checksetup(param)) 如果是废弃的参数,则忽略

                   return 0;

 

         /* Unused module parameter. */

         if (strchr(param, '.') && (!val || strchr(param, '.') < val)) 如果是不适用的模块参数,忽略

                   return 0;

 

         if (panic_later)

                   return 0;

 

         if (val) {     如果参数的值不为空,则初始化成环境变量,存在envp_init

                   /* Environment option */

                   unsigned int i;

                   for (i = 0; envp_init[i]; i++) {

                            if (i == MAX_INIT_ENVS) {

                                     panic_later = "Too many boot env vars at `%s'";

                                     panic_param = param;

                            }

                            if (!strncmp(param, envp_init[i], val - param))

                                     break;

                   }

                   envp_init[i] = param;

         } else {      如果参数值为空,则初始化成命令行参数,存放在argv_init

                   /* Command line option */

                   unsigned int i;

                   for (i = 0; argv_init[i]; i++) {

                            if (i == MAX_INIT_ARGS) {

                                     panic_later = "Too many boot init vars at `%s'";

                                     panic_param = param;

                            }

                   }

                   argv_init[i] = param;

         }

         return 0;

}

 

     调试打印信息:略

阅读(2325) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~