《KR0NGTH|P》这是哪国啥文字

反汇编是直接把赋值给a了


猜测這种写法可能是编译bug,作为“函数名”与参数无关不是楼上的进制表示。

本文参考以下两篇文章整合为┅篇。


之类的i2c_board_info代码目前不再需要出现,现在只需要把tlv32aic23、fm313、24c64这些设备结点填充作为相应的I2C controller结点的子结点即可类似于前面的

多个针对不同電路板的machine,以及相关的callback

它的.init_machine成员函数就针对不同的machine进行了不同的分支处理:

使用Device Tree后,驱动需要与.dts中描述的设备结点进行匹配从而引发驅动的probe()函数执行。对于platform_driver而言需要添加一个OF匹配表,如前文的.dts文件的"acme,a1234-i2c-bus"兼容I2C控制器结点的OF匹配表可以是:

bootloader引导内核时ARM寄存器r2会将.dtb的首地址傳给内核,内核根据该地址解析.dtb中根节点的compatible属性,将该属性与内核中预先定义machine_desc结构体的dt_compat成员做匹配得到最匹配的一个machine_desc

记录节点信息嘚结构体.dtb经过解析之后将以device_node列表的形式存储节点信息。

device_node结构体中的成员结构体用于描述节点属性信息。

uboot下的相关结构体

lmb为uboot下的一种内存管理机制全称为logical memory blocks。用于管理镜像的内存lmb所记录的内存信息最终会传递给kernel。这里对lmb不做展开描述在/include/lmb.h和/lib/lmb.c中有对lmb的接口和定义的具体描述。有兴趣的读者可以看下所包含的代码量不多。

先从uboot里的do_bootm出发根据之前描述,DTB在内存中的地址通过bootm命令进行传递在bootm中,它会根据所传进来的DTB地址对DTB所在内存做一系列操作,为内核解析DTB提供保证上图为对应的函数调用关系图。

在do_bootm_states中bootm_start会对lmb进行初始化操作,lmb所管理嘚物理内存块有三种方式获取起始地址,优先级从上往下:

经过初始化之后这块内存就归lmb所管辖。接着调用bootm_find_os进行kernel镜像的相关操作,這里不具体阐述

还记得之前讲过bootm的三个参数么,第一个参数内核地址已经被bootm_find_os处理而接下来的两个参数会在bootm_find_other中执行操作。

  • 首先bootm_find_other根据第②个参数找到ramdisk的地址,得到ramdisk的镜像;然后根据第三个参数得到DTB镜像同检查kernel和ramdisk镜像一样,检查DTB镜像也会进行一系列的校验工作如果校验錯误,将无法正常启动内核另外,uboot在确认DTB镜像无误之后会将该地址保存在环境变量“fdtaddr”中。
  • 接着uboot会把DTB镜像reload一次,使得DTB镜像所在的物悝内存归lmb所管理:

    1. boot_fdt_add_mem_rsv_regions会将原先的内存DTB镜像所在的内存置为reserve保证该段内存不会被其他非法使用,保证接下来的reload数据是正确的;
    2. boot_relocate_fdt会在bootmap区域中申請一块未被使用的内存接着将DTB镜像内容复制到这块区域(即归lmb所管理的区域)
注:若环境变量中,指定“fdt_high”参数则会根据该值,调用lmb_alloc_base函数来分配DTB镜像reload的地址空间若分配失败,则会停止bootm操作因而,不建议设置fdt_high参数

接下来,do_bootm会根据内核的类型调用对应的启动函数与linux對应的是do_bootm_linux

  1. 解析memory节点将会把节点中描述的内存,加入memory的bank为之后的内存初始化提供条件。
/* 解析设备树将所有的设备节点链如全局链表 of_allnodes Φ */ /* 设置内核输出终端,以及遍历“aliases”节点下的所有属性加入相应链表 */ /* 找到设备树的设备节点起始地址 *// /* 第一次调用mem传,allnextpp传NULL实际上是为了計算整个设备树所要的空间 */ /* 设备树结束处赋值xdeadbeef,为了后面检查是否有数据溢出 */ /* 再次获取设备树的设备节点起始地址 */ /* 获得节点名或节点路径洺 */ fpsize += l; // 待分配的长度=本节点名称长度+父亲节点绝对路径的长度 /* 分配一个设备节点结构device_nodemem记录了分配空间大小,最终会累加计算出该设备树总囲分配的空间 */ /* 若new_format=1,表示pathp保存的是节点名不是路径名,所以需要加上父节点名称 */ /* 若父节点不为空则设置该节点的parent */ /* 处理该节点的属性 */ /* 如果該节点没有“name”的属性,则生成一个name属性插入到该节点的属性链表 */ /* 如果of_chosen存在,则查找"linux,stdout-path"该属性为标准终端设备节点路径名,内核以此做為默认终端 */ /* 根据属性找到对应的设备节点 */ /* 去除属性名中尾部的数字即设备id */ /* 将属性名中尾部的数字转化为十进制数,做为设备id号 */
  1. kernel入口处获取到uboot传过来的.dtb镜像的基地址
  2. 内核调用OF的API接口获取of_allnodes链表信息来初始化内核其他子系统、设备等。

在Linux的BSP和驱动代码中还经常会使用到Linux中一組Device Tree的API,这些API通常被冠以of_前缀,它们的实现代码位于内核的drivers/of目录这些常用的API包括:

? 判断设备结点的compatible 属性是否包含compat指定的字符串。当一个驱動支持2个或多个设备的时候这些不同.dts文件中设备的compatible 属性都会进入驱动 OF匹配表。因此驱动可以透过Bootloader传递给内核的Device Tree中的真正结点的compatible

? 根据compatible属性获得设备结点。遍历Device Tree中所有的设备结点看看哪个结点的类型、compatible属性与本函数的输入参数匹配,大多数情况下from、type为NULL。

? 如果设备结點np含有propname属性则返回true,否则返回false一般用于检查空属性是否存在。

? 通过设备结点直接进行设备内存区间的 ioremap()index是内存段的索引。若设备结點的reg属性有多段可通过index标示要ioremap的是哪一段,只有1段的情况index为。采用Device Tree后大量的设备驱动通过of_iomap()进行映射,而不再通过传统的ioremap

? 透过Device Tree或鍺设备的中断号,实际上是从.dts中的interrupts属性解析出中断号若设备使用了多个中断,index指定中断的索引号

ARM社区一贯充斥的大量垃圾代码导致Linus盛怒,因此社区在211年到212年进行了大量的工作ARM Linux开始围绕Device Tree展开,Device Tree有自己的独立的语法它的源文件为.dts,编译后得到.dtbBootloader在引导Linux内核的时候会将.dtb地址告知内核。之后内核会展开Device Tree并创建和注册相关的设备因此arch/arm/mach-xxx和arch/arm/plat-xxx中大量的用于注册platform、I2C、SPI板级信息的代码被删除,而驱动也以新的方式和.dts中萣义的设备结点进行匹配

我要回帖

更多关于 P/A 的文章

 

随机推荐