(会把传入的参数存一个字符串中)
LINUX内核源码版本:linux-3.0.86
kernel_entry(0, machid, bd->bi_boot_params);bd->bi_boot_params=0x40000100
R0=0,r1=machid,r2=0x40000100.由上节的此函数从UBOOT转入LINUX代继续执行,转入的首地址由vmlinux.lds.s文件可知在/arch/arm/kernel/head.s中的
__HEAD
ENTRY(stext)
定义处。从UBOOT转入LINUX执行的大致流程如下(细节不做分析,不在本节分析范畴)
ldr r13, =__mmap_switched @ address to jump to after
@ mmu has been enabled
mov r3, r13
mov pc, r3 //
通过上面代码转入__mmap_switched定义的址处继续执行
__mmap_switched在head-common.S (arch\arm\kernel)中定义
__mmap_switched:下面注释是当前相关寄存器中代表的值
/*
* r0 = cp#15 control register
* r1 = machine ID
* r2 = atags/dtb pointer
* r9 = processor ID
*/
b start_kernel //这儿函数转入C代码中执行,其中的参数值如上面注释
上面代码是UBOOT转入LINUX执行的大概流程,细节不在本节分析。下面就是正式进入LINUX代码初始化等相关流程。我们此节中只分析解析UBOOT传入参数的流程。通过分析代码解析参数的流程分两部分:
start_kernel->parse_early_param->parse_early_options->parse_one->handle_unknown(do_early_param) 实现在还未解析UBOOT传入的传数前从串口输出调试信息。这个时候输出调试信息需要调用early_printk或printk函数都可以,实现原理和解析之后的输出原理本质一样的。采用了一个默认的输出配置。
boot_command_line =CONFIG_CMDLINE="console=ttySAC0,115200"采用的默认配置,在LINUX配置文件中去定义的。
parse_early_param>parse_early_options(boot_command_line)->parse_args("early options", cmdline, NULL, 0, do_early_param)->parse_one(param, val, params, num, unknown)
->handle_unknown(param, val);handle_unknown=Do_early_param
/* Check for early params. */
static int __init do_early_param(char *param, char *val)
//param=”console=“ val=”ttySAC0,115200”
{
const struct obs_kernel_param *p;
for (p = __setup_start; p < __setup_end; p++) {
if ((p->early && strcmp(param, p->str) == 0) ||
//查询到满足条件的函数为/kernel/printk.c
//__setup("console=", console_setup);,这儿查询的原理为__setup_start为__section(.init.setup)段的开始地址,对这个区域内的所有成员一一扫描,在我们的代码中未查询到p->early=1同时p->str=”console=”成员
(strcmp(param, "console") == 0 &&
strcmp(p->str, "earlycon") == 0)//第二个条件我们代码中了未满足,因此我们系统是不是支持在UBOOT传入参数解析前就输出调试信息的。
) {
if (p->setup_func(val) != 0)
printk(KERN_WARNING"Malformed early option '%s'\n", param);
}
}
/* We accept everything at this stage. */
return 0;
}
上面解析中用了这个boot_command_line是如何得到的,大胆猜应该是UBOOT传入的字符串变量。
setup_arch->setup_machine_tags
if (__atags_pointer)
tags = phys_to_virt(__atags_pointer);这个地址是在UBOOT转入LINUX执行时把传入的标记址存储地址传给LINUX的存储地方。__atags_pointer=0x40000100.,因此对这个地址的操作就是对UBOOT传入参数的操作。
strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
saved_command_line=boot_command_line=static_command_line
通过上面的准备工作下面正式进入解析UBOOT传入的串口相关参数执行流程。
parse_args->parse_one->handle_unknown(param, val)=unknown_bootoption
nknown_bootoption函数把前面分解后的引导参数又重新恢复成原来的模样,因为通过上面执行流程分解成了param val两部分,这儿又重新合成为console=ttySAC0,115200n8。
if (obsolete_checksetup(param))
strncmp(line, p->str, n)//查找我们已初始化的设置函数。对于串口就是__setup("console=", console_setup);
p->setup_func(line + n)=console_setup(ttySAC0,115200n8)
通过上面分析找进入了我们本机针对UBOOT传入参数而注册同名函数执行流程。
onsole_setup(ttySAC0,115200n8)//kernel/printk.c
__add_preferred_console(buf, idx, options, brl_options);
//buf=ttySAC0,115200n8
Idx=0
Options=115200n8
Brl_options=null;
selected_console=0代表确定用那个操控台来做串口的输出信息显示端口。这个很重要。后面在PRINTK打印原理中会有用到,到时具体分析。
__add_preferred_console这个函数把上面解析得到的东西赋值一个全局变量
static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];对于串口参数则这个变量得到的相关值为
struct console_cmdline
{
char name[8]=”ttySAC0”; /* Name of the driver */
int index=0; /* Minor dev. to use */
char *options=”115200n8”; /* Options for the driver */
#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
char *brl_options; /* Options for braille driver */
#endif
};本节分析达到了准备材料的目的。为LINUX内核准备了UBOOT传入参数的解析和分类准备。后面就可以直接使用了。
兴趣交流群抠抠: 461283592