• 从设备树(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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    (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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    (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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    (1)判断传进来的节点是不是chosen节点,如果是则解析出bootargs,并保存到data中(也就是boot_command_line);
    (2)如果找不到chosen节点,或者chosen节点的bootargs属性是空,则使用默认的CONFIG_CMDLINE;

  • 相关阅读:
    Docker中安装Oracle数据库
    红外遥控器 数据格式,按下及松开判断
    带你刷(牛客网)C语言百题(第四天)
    Hive企业实战ORC表数据翻倍,颠覆你认知的Cluster by作用?
    k8s 1.22.3使用持久化卷之存储类StorageClass+NFS pv动态供应
    MySQL习题
    8.31总结 Element-UI
    排列置换环上构造:1025T3
    WeetCode2滑动窗口系列
    虚拟机安装Ubuntu+graphviz生成图
  • 原文地址:https://blog.csdn.net/weixin_42031299/article/details/126073223