Linux Kernel Boot CMDLINE Processing

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;

}

 

④     调试打印信息:略

http://blog.chinaunix.net/uid-25721104-id-299027.html

<think>好的,我需要帮助用户修改Android系统中的BOARD_KERNEL_CMDLINE参数。首先,我需要确认这个参数的位置。根据用户提供的引用[1]和[3],BOARD_KERNEL_CMDLINE通常定义在Android设备目录的BoardConfigCommon.mk文件中,比如device/telechips/tcc88xx-common/BoardConfigCommon.mk。用户需要找到对应的设备目录,这可能因设备型号而异。 接下来,用户需要编辑该文件,找到BOARD_KERNEL_CMDLINE的定义行。例如,原来的可能是BOARD_KERNEL_CMDLINE := console=ttyTCC,115200n8。用户可以根据需求添加或修改参数,比如添加quiet参数来抑制内核日志输出,或者调整console设置。 修改后,必须重新编译内核和系统镜像,使用make命令。但用户需要注意,不同Android版本的编译流程可能不同,尤其是Android 10之后的变动。此外,修改内核命令行参数可能会影响系统启动,比如错误的参数导致无法启动,所以建议在能恢复的设备上操作,并备份原有配置。 用户可能还想知道如何验证修改是否生效,可以查看/proc/cmdline或者在启动时的dmesg输出。另外,引用[2]提到quiet参数影响printk的打印级别,这可能需要用户进一步了解内核日志级别的设置。引用[4]提到init进程的启动过程,但修改cmdline主要在内核启动阶段,可能涉及不到init,但了解整体启动流程有帮助。 用户可能的问题还包括参数的具体作用,比如如何调试或有哪些常用参数。需要确保回答结构清晰,分步骤说明,同时提醒注意事项和验证方法。</think>### 修改 `BOARD_KERNEL_CMDLINE` 参数的步骤 #### 1. **定位定义文件** `BOARD_KERNEL_CMDLINE` 参数通常在 Android 设备的 **BoardConfig.mk** 或 **BoardConfigCommon.mk** 文件中定义。根据引用 [1] 和 [3],路径可能为: ```bash device/<厂商>/<平台>/BoardConfigCommon.mk # 示例:device/telechips/tcc88xx-common/BoardConfigCommon.mk ``` #### 2. **修改参数值** 在文件中找到 `BOARD_KERNEL_CMDLINE` 的定义行,例如: ```makefile BOARD_KERNEL_CMDLINE := console=ttyTCC,115200n8 ``` 添加或修改参数。例如,添加 `quiet` 参数以抑制内核日志输出: ```makefile BOARD_KERNEL_CMDLINE := console=ttyTCC,115200n8 quiet ``` #### 3. **重新编译内核** 需重新编译内核和系统镜像以生效: ```bash source build/envsetup.sh lunch <设备型号> make -j$(nproc) ``` **注意**:Android 10 及以上版本可能需使用 `m` 或 `mmma` 命令[^4]。 #### 4. **验证修改** 刷入新镜像后,通过以下命令验证参数是否生效: ```bash adb shell cat /proc/cmdline ``` --- ### 关键注意事项 1. **参数兼容性**:某些参数可能导致启动失败(如错误的控制台设备名)。 2. **设备差异性**:不同厂商的设备配置文件路径可能不同。 3. **调试参数**: - `quiet`:降低内核日志级别(引用 [2] 中提到的 `printk` 级别变化)。 - `loglevel=<N>`:直接设置内核日志级别(0=紧急,7=调试)。 - `init=/path/to/init`:指定自定义初始化程序(引用 [4] 中 init 进程相关)。 --- ### 示例:添加启动调试参数 若需启用内核调试并保留控制台输出: ```makefile BOARD_KERNEL_CMDLINE := console=ttyTCC,115200n8 loglevel=7 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值