Linux 学习笔记:Linux 设备树 — 设备树在系统中的体现

一、/proc/device-tree

Linux 内核启动的时候会解析设备树中各个节点的信息,并且在根文件系统的/proc/deive-tree 目录下根据节点名字创建不同的文件夹,如图所示:
在这里插入图片描述

/proc/device-tree 目录下是根节点 “/” 的所有属性和子节点。

二、根节点各个属性

根节点属性表现为一个个的文件:

  • #address-cells
  • #size-cells
  • compatible
  • model
  • name

既然是文件,那么可以查看其内容:

cat compatible

输出
在这里插入图片描述

三、根节点各个子节点

/proc/device-tree/ 下各个文件夹就是根节点 “/” 的各个子节点,比如:

  • soc
  • backlight
  • chosen
  • clocks

/proc/device-tree/ 目录就是设备树在根文件系统中的体现,同样是按照树形结构组织的,进入/proc/device-tree/soc 目录中就可以看到soc 节点的所有子节点。

在这里插入图片描述

四、根节点下的特殊节点

在根节点 “/” 中有两个特殊的子节点:aliaseschosen。

4.1 aliases 子节点

打开imx6ull.dtsi 文件,aliases 节点内容如下所示:

aliases {
		can0 = &flexcan1;
		can1 = &flexcan2;
		ethernet0 = &fec1;
		ethernet1 = &fec2;
		gpio0 = &gpio1;
		gpio1 = &gpio2;
		gpio2 = &gpio3;
		gpio3 = &gpio4;
		gpio4 = &gpio5;
		i2c0 = &i2c1;
		i2c1 = &i2c2;
		i2c2 = &i2c3;
		i2c3 = &i2c4;
		mmc0 = &usdhc1;
		mmc1 = &usdhc2;
		serial0 = &uart1;
		serial1 = &uart2;
		serial2 = &uart3;
		serial3 = &uart4;
		serial4 = &uart5;
		serial5 = &uart6;
		serial6 = &uart7;
		serial7 = &uart8;
		spi0 = &ecspi1;
		spi1 = &ecspi2;
		spi2 = &ecspi3;
		spi3 = &ecspi4;
		usbphy0 = &usbphy1;
		usbphy1 = &usbphy2;
	};

单词aliases 的意思是 “别名” ,因此aliases 节点的主要功能就是定义别名,定义别名的目的就是为了方便访问节点。不过我们一般会在节点命名的时候加上label,然后通过&label 来访问节点,这样也很方便,而且设备树里面有大量的使用&label 的形式来访问节点。

4.2 chosen 子节点

chosen 并不是一个真实的设备,chosen 节点主要是为了uboot 向linux 内核传递数据,重点是bootargs 参数。一般 .dts 文件中chosen 节点通常为空或者内容很少,imx6ull-alientek-emmc.dts 中chosen 节点内容如下所示:

chosen {
		stdout-path = &uart1;
	};

从上述代码可以看出,chosen 节点仅仅设置了属性 “stdout-path” , 表示标准输出使用 uart1 。但是当我们进入到/proc/device-tree/chosen 目录里面,会发现多了bootargs 这个属性。

输入cat 命令,查看bootargs 这个文件的内容,结果如下:

console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.10.100:/home/ljy/Linux/nfs/rootfs,proto=tcp rw ip=192.168.10.50:192.168.10.100:192.168.10.1:255.255.255.0::eth0:off

这个就是我们在uboot 中设置的bootargs 环境变量的值。现在有两个疑点:

  • 我们并没有在设备树中设置chosen 节点的bootargs 属性,那么这个属性是怎么产生的?
  • 为何bootargs 文件的内容和uboot 中bootargs 环境变量的值一样?它们之间有什么关系?

uboot 在启动Linux 内核的时候会将bootargs 的值传递给Linux 内核,bootargs 会作为Linux 内核的命令行参数,Linux 内核启动的时候会打印出命令行参数。

在这里插入图片描述

uboot 自己在chosen 节点里面添加了bootargs 属性,并且设置bootargs 属性的值为bootargs 环境变量的值。

在启动Linux 内核之前,只有uboot 知道bootargs 环境变量的值,并且uboot 也知道.dtb 设备树文件在DRAM 中的位置。

Uboot 源码中的实现

uboot 源码中,common/fdt_support.c 文件中发现了“chosen” 的处理,如下所示:

int fdt_chosen(void *fdt)
{
	int   nodeoffset;
	int   err;
	char  *str;		/* used to set string properties */

	err = fdt_check_header(fdt);
	if (err < 0) {
		printf("fdt_chosen: %s\n", fdt_strerror(err));
		return err;
	}

	/* find or create "/chosen" node. */
	nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
	if (nodeoffset < 0)
		return nodeoffset;

	str = getenv("bootargs");
	if (str) {
		err = fdt_setprop(fdt, nodeoffset, "bootargs", str,
				  strlen(str) + 1);
		if (err < 0) {
			printf("WARNING: could not set bootargs %s.\n",
			       fdt_strerror(err));
			return err;
		}
	}

	return fdt_fixup_stdout(fdt, nodeoffset);
}
  • 调用函数fdt_find_or_add_subnode 从设备树(.dtb) 中找到chosen 节点,如果没有找到的话就会子创建一个chosen 节点。
  • 调用fdt_setprop 向chosen 节点添加bootargs 属性,并且bootargs 属性的值就是环境变量bootargs 的内容。

uboot 加入bootargs 属性的流程

uboot 在设备树的chosen 节点加入bootargs 属性的流程如下:

在这里插入图片描述

五、内核解析DTB 文件

Linux 内核在启动的时候会解析DTB 文件,然后在/proc/device-tree 目录下生成相应的设备树根节点文件。Linux 内核解析DTB 文件的流程如下:

在这里插入图片描述

在start_kernel 函数中完成设备树节点解析的工作,最终实际工作的函数为unflatten_dt_node。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gdut_llkkyy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值