从设备树(dtb格式数据)中解析出bootargs
Posted 正在起飞的蜗牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从设备树(dtb格式数据)中解析出bootargs相关的知识,希望对你有一定的参考价值。
1、函数调用关系
start_kernel
setup_arch
setup_machine_fdt
early_init_dt_scan_nodes //遍历设备树的节点,解析出重要的信息用于内核启动
of_scan_flat_dt //解析设备树的节点
early_init_dt_scan_chosen //用于解析chosen节点的函数
//函数调用
of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
(1)调用of_scan_flat_dt()函数遍历dtb的所有节点;
(2)将每个节点都调用early_init_dt_scan_chosen()函数进行解析,判断是不是chosen节点;
(3)如果是chosen节点,就解析处bootargs属性并保存到boot_command_line变量中;
2、dtb中bootargs的来源
(1)内核启动参数bootargs保存在设备树的chosen节点的bootargs属性;
(2)bootargs数据可以是在dts源文件中定义,也可以是uboot启动内核时传递给内核;
(3)优先级:uboot传递的bootargs参数优先级高于dts中定义的bootargs;
(4)如果是uboot传递的bootargs,在内核解压缩阶段就会调用atags_to_fdt()函数将tag中的bootargs参数转换成dtb的格式,写进dtb数据中;
3、of_scan_flat_dt()函数
int __init of_scan_flat_dt(int (*it)(unsigned long node,const char *uname, int depth,
void *data), void *data)
//dtb数据的地址,也就是根节点的地址
const void *blob = initial_boot_params;
const char *pathp;
int offset, rc = 0, depth = -1;
if (!blob)
return 0;
//从根节点遍历dtb中每个节点,返回的offset就是每个节点的地址
for (offset = fdt_next_node(blob, -1, &depth);
offset >= 0 && depth >= 0 && !rc;
offset = fdt_next_node(blob, offset, &depth))
//解析出节点名称
pathp = fdt_get_name(blob, offset, NULL);
if (*pathp == '/')
pathp = kbasename(pathp);
//回调函数:解析节点
rc = it(offset, pathp, depth, data);
return rc;
(1)此时设备树还是dtb格式的二进制数据,从dtb格式中解析节点和属性有提供专有函数,具体怎么解析出来的不用关心;
(2)blob:dtb数据的启动地址,也是根节点的地址;
(3)offset:表示节点的地址相对于根节点的偏移量,也是节点数据所在地址;
(4)depth:代表节点相对于根节点的深度,比如根节点深度是0,/chosen节点是1;
(5)it:是传递进来的设备树节点的解析函数,需要解析什么消息就传递进来相应的节点解析函数;
early_init_dt_scan_chosen()函数
int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
int depth, void *data)
int l;
const char *p;
pr_debug("search \\"chosen\\", depth: %d, uname: %s\\n", depth, uname);
//节点的深度要为1,数据不能使NULL,同时节点名字是"chosen"或者 "chosen@0"
if (depth != 1 || !data ||
(strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
return 0;
//解析initrd相关
early_init_dt_check_for_initrd(node);
/* 从chosen节点中解析出bootargs属性 */
p = of_get_flat_dt_prop(node, "bootargs", &l);
if (p != NULL && l > 0)
strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE)); //将bootargs拷贝到data中
//下面的代码就是从chosen节点中解析不到bootargs,采用默认的bootargs
#ifdef CONFIG_CMDLINE
#if defined(CONFIG_CMDLINE_EXTEND)
strlcat(data, " ", COMMAND_LINE_SIZE);
strlcat(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
#elif defined(CONFIG_CMDLINE_FORCE)
strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
#else
/* No arguments from boot loader, use kernel's cmdl*/
if (!((char *)data)[0])
strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
#endif
#endif /* CONFIG_CMDLINE */
pr_debug("Command line is: %s\\n", (char*)data);
/* break now */
return 1;
(1)判断传进来的节点是不是chosen节点,如果是则解析出bootargs,并保存到data中(也就是boot_command_line);
(2)如果找不到chosen节点,或者chosen节点的bootargs属性是空,则使用默认的CONFIG_CMDLINE;
以上是关于从设备树(dtb格式数据)中解析出bootargs的主要内容,如果未能解决你的问题,请参考以下文章
设备树——dtb格式到struct device node结构体的转换
设备树(dtb数据)匹配struct machine_desc结构体