bootargs=console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc
rootfstype=ext3
console=ttySAC2,115200 控制台使用串口2,波特率115200.
root=/dev/mmcblk0p2 rw
根文件系统在SD卡端口0设备(iNand)第2分区,根文件系统是读可写的
init=/linuxrc linux的进程1(init进程)的路径
rootfstype=ext3 根文件系统的类型是ext3
uboot中有一个命令叫bdinfo,这个命令可以打印出gd->
bd中记录的所有硬件相关的全局变量的值,因此可以得知DDR配置信息
#define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)
#define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2)
/* The list must start with an ATAG_CORE node
列表必须以ATAG_CORE节点开始*/
#define ATAG_CORE 0x54410001 atag list启动幻数
/*
* r1 = machine no机器编号, r2 = atags标签,
* r8 = phys_offset, r9 = cpuid, r10 = procinfo
*/
__vet_atags:
tst r2, #0x3 @ aligned?对齐 11
bne 1f
ldr r5, [r2, #0] @ is first tag ATAG_CORE?
cmp r5, #ATAG_CORE_SIZE
cmpne r5, #ATAG_CORE_SIZE_EMPTY
bne 1f
ldr r5, [r2, #4]
ldr r6, =ATAG_CORE
cmp r5, r6
bne 1f
mov pc, lr @ atag pointer is ok
1: mov r2, #0
mov pc, lr
ENDPROC(__vet_atags)
void __vet_atags(struct tag* atag_list)
{
if(atag_list & 0x3)
goto err_clear;
if(!(atag_list->hdr.size == ARAG_CORE_SIZE && agag_list->hdr.tag ==
ATAG_CORE)){
goto err_clear;
}
return;
err_clear:
atag_list = 0;
return;
}
1内核选中CONFIG_ARM_APPENDED_DTB,这样编译出的dtb就存放在内核i
mg的末尾,内核可以自己取出dtb。
2内核选中CONFIG_ARM_ATAG_DTB_COMPAT,指定atags和dtb的兼容。
3uboot传递atags指针到r2,启动内核
4内核自己取出dtb,然后将r2指针内的atags通过atags_to_fdt()
函数解析并合并到dtb中,最后使用合并好的dtb。
上面是内核初步的对照查看结构是否合适(tag的头部是否正)
/* Arch code calls this early on, or if not, just before other parsing. */
Arch代码会在其他解析之前尽早调用此功能,如果不是,则调
用此功能
#define COMMAND_LINE_SIZE 256
/* Untouched command line saved by arch-specific code. */
拱形特定代码保存的未修改的命令行。
char __initdata boot_command_line[COMMAND_LINE_SIZE];
引导完成后,将删除标记为__
init的函数和标记为__initdata的数据结构
void __init parse_early_param(void)
{
static __initdata int done = 0;
static __initdata char tmp_cmdline[COMMAND_LINE_SIZE];
if (done)
return;
/* All fall through to do_early_param. */
strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);
parse_early_options(tmp_cmdline);
done = 1;
}
void __init parse_early_options(char *cmdline)
{
parse_args("early options", cmdline, NULL, 0, do_early_param);
}
/* Check for early params. */
检查早期参数。
static int __init do_early_param(char *param, char *val)
{
const struct obs_kernel_param *p;
for (p = __setup_start; p < __setup_end; p++) {
if ((p->early && strcmp(param, p->str) == 0) ||
(strcmp(param, "console") == 0 &&
strcmp(p->str, "earlycon") == 0)
) {
if (p->setup_func(val) != 0)
printk(KERN_WARNING
"Malformed early option '%s'\n", param);
}
}
/* We accept everything at this stage. */
return 0;
}
#if 0
#define DEBUGP printk
#else
#define DEBUGP(fmt, a...)
#endif
/* Args looks like "foo=bar,bar2 baz=fuz wiz". */
int parse_args(const char *name,
char *args,
const struct kernel_param *params,
unsigned num,
int (*unknown)(char *param, char *val))
{
char *param, *val;
DEBUGP("Parsing ARGS: %s\n", args);
/* Chew leading spaces */
args = skip_spaces(args);
while (*args) {
int ret;
int irq_was_disabled;
args = next_arg(args, ¶m, &val);
irq_was_disabled = irqs_disabled();
ret = parse_one(param, val, params, num, unknown);
if (irq_was_disabled && !irqs_disabled()) {
printk(KERN_WARNING "parse_args(): option '%s' enabled "
"irq's!\n", param);
}
switch (ret) {
case -ENOENT:
printk(KERN_ERR "%s: Unknown parameter `%s'\n",
name, param);
return ret;
case -ENOSPC:
printk(KERN_ERR
"%s: `%s' too large for parameter `%s'\n",
name, val ?: "", param);
return ret;
case 0:
break;
default:
printk(KERN_ERR
"%s: `%s' invalid for parameter `%s'\n",
name, val ?: "", param);
return ret;
}
}
/* All parsed OK. */
return 0;
}
struct kernel_param {
const char *name;
const struct kernel_param_ops *ops;
u16 perm;
u16 flags;
union {
void *arg;
const struct kparam_string *str;
const struct kparam_array *arr;
};
};