u-boot环境变量bootargs就是要传递给kernel的参数,如:
bootargs=console=ttymxc0 init=/init androidboot.console=ttymxc0 video=mxcdi0fb:RGB24,CPT-WVGA di0_primary video=mxcdi1fb:RGB666,AUO ldb=single,di=1,ch1_map=JEIDA gpu_nommu gpu_memory=32M calibration lpj=3997696 pty.legacy_count=32 quiet
u-boot中对环境变量的修改,可以用下面的方式:
sprintf(tz, "tz=%d", value);
s = getenv("bootargs");
sprintf(buf, "%s %s", s, tz);
setenv("bootargs", buf);
kernel中两个重要的宏:
在include/linux/init.h中
#define __setup(str, fn) \
__setup_param(str, fn, fn, 0)
#define early_param(str, fn) \
__setup_param(str, fn, fn, 1)
__setup与early_param不同的是,early_param 宏注册的内核选项必须要在其他内核选项之前被处理。
在函数start_kernel中,parse_early_param处理early_param定义的参数,parse_args处理__setup定义的参数。
kernel/printk.c
static int __init console_setup(char *str)
{
char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for index */
char *s, *options, *brl_options = NULL;
int idx;
#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
if (!memcmp(str, "brl,", 4)) {
brl_options = "";
str += 4;
} else if (!memcmp(str, "brl=", 4)) {
brl_options = str + 4;
str = strchr(brl_options, ',');
if (!str) {
printk(KERN_ERR "need port name after brl=\n");
return 1;
}
*(str++) = 0;
}
#endif
/*
* Decode str into name, index, options.
*/
if (str[0] >= '0' && str[0] <= '9') {
strcpy(buf, "ttyS");
strncpy(buf + 4, str, sizeof(buf) - 5);
} else {
strncpy(buf, str, sizeof(buf) - 1);
}
buf[sizeof(buf) - 1] = 0;
if ((options = strchr(str, ',')) != NULL)
*(options++) = 0;
#ifdef __sparc__
if (!strcmp(str, "ttya"))
strcpy(buf, "ttyS0");
if (!strcmp(str, "ttyb"))
strcpy(buf, "ttyS1");
#endif
for (s = buf; *s; s++)
if ((*s >= '0' && *s <= '9') || *s == ',')
break;
idx = simple_strtoul(s, NULL, 10);
*s = 0;
__add_preferred_console(buf, idx, options, brl_options);
console_set_on_cmdline = 1;
return 1;
}
__setup("console=", console_setup);
static int __init init_setup(char *str)
{
unsigned int i;
execute_command = str;
/*
* In case LILO is going to boot us with default command line,
* it prepends "auto" before the whole cmdline which makes
* the shell think it should execute a script with such name.
* So we ignore all arguments entered _before_ init=... [MJ]
*/
for (i = 1; i < MAX_INIT_ARGS; i++)
argv_init[i] = NULL;
return 1;
}
__setup("init=", init_setup);
arch/arm/mach-mx5/early_setup.c
static int __init di1_setup(char *__unused)
{
primary_di = 1;
return 1;
}
__setup("di1_primary", di1_setup);
static int __init di0_setup(char *__unused)
{
primary_di = 0;
return 1;
}
__setup("di0_primary", di0_setup);
drivers/video/fbmem.c:
static int __init video_setup(char *options)
{
int i, global = 0;
if (!options || !*options)
global = 1;
if (!global && !strncmp(options, "ofonly", 6)) {
ofonly = 1;
global = 1;
}
if (!global && !strchr(options, ':')) {
fb_mode_option = options;
global = 1;
}
if (!global) {
for (i = 0; i < FB_MAX; i++) {
if (video_options[i] == NULL) {
video_options[i] = options;
break;
}
}
}
return 1;
}
__setup("video=", video_setup);
其中
video=mxcdi0fb:RGB24,CPT-WVGA di0_primary 表示主屏幕(RGB)显示,video=mxcdi1fb:RGB666,AUO表示分离屏(LVDS)显示。
drivers/video/mxc/ldb.c:
static int __init ldb_setup(char *options)
{
if (!strcmp(options, "=off")) {
g_enable_ldb = MXC_DISABLE;
return 1;
} else
g_enable_ldb = MXC_ENABLE;
if (!strlen(options))
return 1;
else if (!strsep(&options, "="))
return 1;
if (!strncmp(options, "di0", 3))
g_di0_used = true;
if (!strncmp(options, "di1", 3))
g_di1_used = true;
if (!strncmp(options, "single", 6)) {
strsep(&options, ",");
if (!strncmp(options, "di=0", 4)) {
g_chan_mode_opt = LDB_SIN_DI0;
g_di0_used = true;
} else {
g_chan_mode_opt = LDB_SIN_DI1;
g_di1_used = true;
}
} else if (!strncmp(options, "separate", 8)) {
g_chan_mode_opt = LDB_SEP;
g_di0_used = true;
g_di1_used = true;
} else if (!strncmp(options, "dual", 4)) {
strsep(&options, ",");
if (!strncmp(options, "di=", 3)) {
if (simple_strtoul(options + 3, NULL, 0) == 0) {
g_chan_mode_opt = LDB_DUL_DI0;
g_di0_used = true;
} else {
g_chan_mode_opt = LDB_DUL_DI1;
g_di1_used = true;
}
}
} else if (!strncmp(options, "split", 5)) {
strsep(&options, ",");
if (!strncmp(options, "di=", 3)) {
if (simple_strtoul(options + 3, NULL, 0) == 0) {
g_chan_mode_opt = LDB_SPL_DI0;
g_di0_used = true;
} else {
g_chan_mode_opt = LDB_SPL_DI1;
g_di1_used = true;
}
}
} else
return 1;
if ((strsep(&options, ",") != NULL) &&
!strncmp(options, "ch0_map=", 8)) {
if (!strncmp(options + 8, "SPWG", 4))
g_chan_bit_map[0] = LDB_BIT_MAP_SPWG;
else
g_chan_bit_map[0] = LDB_BIT_MAP_JEIDA;
}
if (!(g_chan_mode_opt == LDB_SIN_DI0 ||
g_chan_mode_opt == LDB_SIN_DI1) &&
(strsep(&options, ",") != NULL) &&
!strncmp(options, "ch1_map=", 8)) {
if (!strncmp(options + 8, "SPWG", 4))
g_chan_bit_map[1] = LDB_BIT_MAP_SPWG;
else
g_chan_bit_map[1] = LDB_BIT_MAP_JEIDA;
}
return 1;
}
__setup("ldb", ldb_setup);
板级初始化文件arch/arm/mach-mx5/mx53_a1001em.c中:
static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags,
char **cmdline, struct meminfo *mi)
{
struct tag *t;
struct tag *mem_tag = 0;
int total_mem = SZ_512M;
int left_mem = 0;
int gpu_mem = SZ_128M;
int fb_mem = SZ_32M;
char *str;
mxc_set_cpu_type(MXC_CPU_MX53);
for_each_tag(mem_tag, tags) {
if (mem_tag->hdr.tag == ATAG_MEM) {
total_mem = mem_tag->u.mem.size;
break;
}
}
for_each_tag(t, tags) {
if (t->hdr.tag == ATAG_CMDLINE) {
str = t->u.cmdline.cmdline;
str = strstr(str, "mem=");
if (str != NULL) {
str += 4;
left_mem = memparse(str, &str);
}
str = t->u.cmdline.cmdline;
str = strstr(str, "gpu_nommu");
if (str != NULL)
gpu_data.enable_mmu = 0;
str = t->u.cmdline.cmdline;
str = strstr(str, "gpu_memory=");
if (str != NULL) {
str += 11;
gpu_mem = memparse(str, &str);
}
break;
}
}
...
}
init/main.c:
static int __init debug_kernel(char *str)
{
console_loglevel = 10;
return 0;
}
static int __init quiet_kernel(char *str)
{
console_loglevel = 4;
return 0;
}
early_param("debug", debug_kernel);
early_param("quiet", quiet_kernel);
init/calibrate.c
static int __init lpj_setup(char *str)
{
preset_lpj = simple_strtoul(str,NULL,0);
return 1;
}
__setup("lpj=", lpj_setup);
u-boot参数直接传递到android应用层:
system/core/init/init.c
static void import_kernel_nv(char *name, int in_qemu)
{
char *value = strchr(name, '=');
if (value == 0) {
if (!strcmp(name, "calibration"))
calibration = 1;
else if (!strcmp(name, "mksnapshot"))
mksnapshot = 1;
return;
}
*value++ = 0;
if (*name == 0) return;
if (!in_qemu)
{
/* on a real device, white-list the kernel options */
if (!strcmp(name,"qemu")) {
strlcpy(qemu, value, sizeof(qemu));
} else if (!strcmp(name,"androidboot.console")) {
strlcpy(console, value, sizeof(console));
} else if (!strcmp(name,"androidboot.mode")) {
strlcpy(bootmode, value, sizeof(bootmode));
} else if (!strcmp(name,"androidboot.serialno")) {
strlcpy(serialno, value, sizeof(serialno));
} else if (!strcmp(name,"androidboot.baseband")) {
strlcpy(baseband, value, sizeof(baseband));
} else if (!strcmp(name,"androidboot.carrier")) {
strlcpy(carrier, value, sizeof(carrier));
} else if (!strcmp(name,"androidboot.bootloader")) {
strlcpy(bootloader, value, sizeof(bootloader));
} else if (!strcmp(name,"androidboot.hardware")) {
strlcpy(hardware, value, sizeof(hardware));
} else if (!strcmp(name,"boot_type")) {
strlcpy(boot_type, value, sizeof(boot_type));
}
} else {
/* in the emulator, export any kernel option with the
* ro.kernel. prefix */
char buff[32];
int len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name );
if (len < (int)sizeof(buff)) {
property_set( buff, value );
}
}
}