分析内核源码,设备树【转】

转自:http://blog.csdn.net/fight_onlyfor_you/article/details/78092204

U-Boot需要将设备树在内存中的存储地址传给内核。该树主要由三大部分组成:头(Header)、结构块(Structure block)、字符串块(Strings block)。

设备树在内存中的存储布局图如下


1.1 头(header)

1.2 结构块(struct block)

 扁平设备树结构块是线性化的树形结构,和字符串块一起组成了设备树的主体,以节点形式保存目标板的设备信息

在结构块中,节点起始标志为32位常值宏OF_DT_BEGIN_NODE,节点结束标志为宏OF_DT_END_NODE

子节点定义在节点结束标志前。一个节点的基本结构如下所示:

(1).
节点起始标志OF_DT_BEGIN_NODE(即0x0000_0001);
 (2). 节点路径或者节点单元名(version < 3以及节点路径表示,version > 16时以节点单元名表示);
 (3). 填充字节保证四字节对齐;
 (4). 节点属性。

每个属性以常值宏OF_DT_PROP 开始,后面依次为属性值的字节长度、属性名在字符串块中的偏移值, (5).
如果存在子节点,则定义子节点

(6). 节点结束标志OF_DT_END_NODE(即0x0000_0002)。

1.3 字符串块(Strings block)

1.4 设备树源码 DTS 表示

设备树源码文件(.dts)以可读可编辑的文本形式描述系统硬件配置设备树,支持
C/C++方式的注释,该结构有一个唯一的根节点“/”,每个节点都有自己的名字并可以包含多个子节点。设备树的数据格式遵循了 Open
Firmware IEEE standard
1275。这个设备树中有很多节点,每个节点都指定了节点单元名称。每一个属性后面都给出相应的值。以双引号引出的内容为 ASCII
字符串,以尖括号给出的是 32 位的16进制值。这个树结构是启动 Linux 内核所需节点和属性简化后的集合,包括了根节点的基本模式信息、CPU
和物理内存布局,它还包括通过/chosen 节点传递给内核的命令行参数信息。

1.5 machine_desc结构

内核提供了一个重要的结构体struct machine_desc
,这个结构体在内核移植中起到相当重要的作用,内核通过machine_desc结构体来控制系统体系架构相关部分的初始化。machine_desc结构体通过MACHINE_START宏来初始化,在代码中,
通过在mian->setup_arch中调用setup_machine_fdt来获取。

1.6 设备节点结构体

1.7 属性结构体

三、设备树初始化及解析

分析Linux内核的源码,可以看到其对扁平设备树的解析流程如下

of_allnodes

源码如下

在init目录下的main.c中的start_kernel函数中

进入这个setup_arch

其余代码先省略

查看setup_machine_fdt函数

这里调用了early_init_dt_scan_nodes函数

来看看这个函数

看看这个fdt_next_node函数

上面还有一个很重要的地方

这里,这里对这个initial_boot_parems进行赋值,这里这个指针指向了设备树的虚拟起始地址

在这里进行偏移,详细信息看这里的代码

chosen属性

chosen
节点并不代表一个真实的设备,只是作为一个为固件和操作系统之间传递数据的地方,比如引导参数。chosen
节点里的数据也不代表硬件。通常,chosen 节点在.dts 源文件中为空,并在启动时填充。在我们的示例系统中,固件可以往 chosen
节点添加以下信息:

chosen {

bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200"; //节点属性
    linux,initrd-start = <0x85500000>; //节点属性
    linux,initrd-end = <0x855a3212>; //节点属性
};

1.2 根节点"/"

设备树有且仅有一个根节点,即“/”,根节点下包含很多子节点,例入下图,根节点为"/",根节点的子节点为"chosen",根节点的属性包含"compatible","#address-cells","#size-cells","interrupt-parent"等。属性model指明了目标板平台或模块的名称,属性compatible值指明和目标板为同一系列的兼容的开发板名称。对于大多数32位平台,属性#address-cells和#size-cells的值一般为1。#address-cells
= <1>; 1表示地址32位,2表示地址64位。#size-cells =
<1>;1表示rangs的每部分占一个cell,依此类推

{
    compatible = "sprd,spx15";
    #address-cells = <1>;
    #size-cells = <1>;
    interrupt-parent = <&gic>;

chosen {
        bootargs = "loglevel=8 console=ttyS1,115200n8 init=/init root=/dev/ram0 rw";
        linux,initrd-start = <0x85500000>;
        linux,initrd-end = <0x855a3212>;
    };
}

所以本函数就是读取根节点的"#address-cells","#size-cells"属性

1.3 memory节点
     
memory节点用于描述目标板上物理内存范围,一般称作/memory节点,可以有一个或多个。当有多个节点时,需要后跟单元地址予以区分;只有一个单元地址时,可以不写单元地址,默认为0。此节点包含板上物理内存的属性,一般要指定device_type(固定为"memory")和reg属性。其中reg的属性值以<起始地址
空间大小>的形式给出,如下示例中目标板内存起始地址为0x80000000,大小为0x20000000字节。 
memory {
    device_type = "memory";
    reg = <0x80000000 0x20000000>;
};

在看看解析设备树这一块

原文地址:https://www.cnblogs.com/sky-heaven/p/8534724.html

时间: 2024-10-30 05:33:47

分析内核源码,设备树【转】的相关文章

Linux内核(2) - 分析内核源码如何入手(上)

透过现象看本质,兽兽们无非就是一些人体艺术展示.同样往本质里看过去,学习内核,就是学习内核的源代码,任何内核有关的书籍都是基于内核,而又不高于内核的. 既然要学习内核源码,就要经常对内核代码进行分析,而内核代码千千万,还前仆后继的不断往里加,这就让大部分人都有种雾里看花花不见的无助感.不过不要怕,孔老夫子早就留给我们了应对之策:敏于事而慎于言,就有道而正焉,可谓好学也已.这就是说,做事要踏实才是好学生好同志,要遵循严谨的态度,去理解每一段代码的实现,多问多想多记.如果抱着走马观花,得过且过的态度

Linux内核(3) - 分析内核源码如何入手(下)

下面的分析,米卢教练说了,内容不重要,重要的是态度.就像韩局长对待日记的态度那样,严谨而细致. 只要你使用这样的态度开始分析内核,那么无论你选择内核的哪个部分作为切入点,比如USB,比如进程管理,在花费相对不算很多的时间之后,你就会发现你对内核的理解会上升到另外一个高度,一个抱着情景分析,抱着0.1内核完全注释,抱着各种各样的内核书籍翻来覆去的看很多遍又忘很多遍都无法达到的高度.请相信我! 让我们在Linux社区里发出号召:学习内核源码,从学习韩局长开始! 态度决定一切:从初始化函数开始 任小强

Linux内核源码分析方法

  一.内核源码之我见 Linux内核代码的庞大令不少人“望而生畏”,也正因为如此,使得人们对Linux的了解仅处于泛泛的层次.如果想透析Linux,深入操作系统的本质,阅读内核源码是最有效的途径.我们都知道,想成为优秀的程序员,需要大量的实践和代码的编写.编程固然重要,但是往往只编程的人很容易把自己局限在自己的知识领域内.如果要扩展自己知识的广度,我们需要多接触其他人编写的代码,尤其是水平比我们更高的人编写的代码.通过这种途径,我们可以跳出自己知识圈的束缚,进入他人的知识圈,了解更多甚至我们一

Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938393.html 在分析start_kernel函数的时候,其中有构架相关的初始化函数setup_arch. 此函数根据构架而异,对于ARM构架的详细分析如下: void __init setup_arch(char **cmdlin

Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938395.html 前面粗略分析start_kernel函数,此函数中基本上是对内存管理和各子系统的数据结构初始化.在内核初始化函数start_kernel执行到最后,就是调用rest_init函数,这个函数的主要使命就是创建并启动内核线

Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938396.html 在基本分析完内核启动流程的之后,还有一个比较重要的初始化函数没有分析,那就是do_basic_setup.在内核init线程中调用了do_basic_setup,这个函数也做了很多内核和驱动的初始化工作,详解

Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装

原文:Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装 Linux内核分析(一) 从本篇博文开始我将对linux内核进行学习和分析,整个过程必将十分艰辛,但我会坚持到底,同时在博文中如果那些地方有问题还请各位大神为我讲解. 今天我们会分析到以下内容: 1.      Linux体系结构简介 2.      Linux内核源码简介 3.      Linux内核配置.编译.安装 l  Linux体系结构简介 1.       Linux体系结构(linux系统构成)

Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 【转】

原文地址:Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938390.html 在构架相关的汇编代码运行完之后,程序跳入了构架无关的内核C语言代码:init/main.c中的start_kernel函数,在这个函数中Linux内核开始真正进入初始化阶段, 下面我就顺这代码逐个函数的解释,但是这里并不会过于深入

Linux tcp被动打开内核源码分析

[我是从2个角度来看,其实所谓2个角度,是发现我分析源码时,分析重复了,写了2个分析报告,所以现在都贴出来.] [如果你是想看看,了解一下内核tcp被动打开时如何实现的话,我觉得还是看看概念就可以了,因为即使看了源码,过一个个礼拜你就忘了,如果是你正在修改协议栈,为不知道流程而发愁,那么希望你能看看源码以及注释,希望你给你帮助.] 概念: tcp被动打开,前提是你listen,这个被动打开的前提.你listen过后,其实创建了一个监听套接字,专门负责监听,不会负责传输数据. 当第一个syn包到达