linux内核设备树及编译( 二 )


3、linux内核对硬件的描述方式在以前的内核版本中:
1)内核包含了对硬件的全部描述;
2)bootloader会加载一个二进制的内核镜像,并执行它,比如uImage或者zImage;
3)bootloader会提供一些额外的信息,成为ATAGS,它的地址会通过r2寄存器传给内核;
ATAGS包含了内存大小和地址,kernel command line等等;
4)bootloader会告诉内核加载哪一款board,通过r1寄存器存放的machine type integer;
5)U-Boot的内核启动命令:bootm <kernel img addr>
6)Barebox变量:bootm.image (?)

linux内核设备树及编译

文章插图
 
现今的内核版本使用了Device Tree:
1)内核不再包含对硬件的描述,它以二进制的形式单独存储在另外的位置:the device tree blob
2)bootloader需要加载两个二进制文件:内核镜像和DTB
内核镜像仍然是uImage或者zImage;
DTB文件在arch/arm/boot/dts中,每一个board对应一个dts文件;
3)bootloader通过r2寄存器来传递DTB地址,通过修改DTB可以修改内存信息,kernel command line,以及潜在的其它信息;
4)不再有machine type;
5)U-Boot的内核启动命令:bootm <kernel img addr> - <dtb addr>
6)Barebox变量:bootm.image,bootm.oftree
linux内核设备树及编译

文章插图
 
有些bootloader不支持Device Tree,或者有些专门给特定设备写的版本太老了,也不包含 。为了解决这个问题,CONFIG_ARM_AppENDED_DTB被引进 。
它告诉内核,在紧跟着内核的地址里查找DTB文件;
由于没有built-in Makefile rule来产生这样的内核,因此需要手动操作:
cat arch/arm/boot/zImage arch/arm/boot/dts/myboard.dtb > my-zImagemkimage ... -d my-zImage my-uImage(cat这个命令,还能够直接合并两个mp3文件哦!so easy!)
另外,
CONFIG_ARM_ATAG_DTB_COMPAT选项告诉内核去bootloader里面读取ATAGS,并使用它们升级DT 。
4、DTB加载及解析过程
linux内核设备树及编译

文章插图
 
【linux内核设备树及编译】先从uboot里的do_bootm出发,根据之前描述,DTB在内存中的地址通过bootm命令进行传递 。在bootm中,它会根据所传进来的DTB地址,对DTB所在内存做一系列操作,为内核解析DTB提供保证 。上图为对应的函数调用关系图 。
在do_bootm中,主要调用函数为do_bootm_states,第四个参数为bootm所要处理的阶段和状态 。
在do_bootm_states中,bootm_start会对lmb进行初始化操作,lmb所管理的物理内存块有三种方式获取 。起始地址,优先级从上往下:
  1. 环境变量“bootm_low”
  2. 宏CONFIG_SYS_SDRAM_BASE(在tegra124中为0x80000000)
  3. gd->bd->bi_dram[0].start
大小:
  1. 环境变量“bootm_size”
  2. gd->bd->bi_dram[0].size
经过初始化之后,这块内存就归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所管理:

boot_fdt_add_mem_rsv_regions会将原先的内存DTB镜像所在的内存置为reserve,保证该段内存不会被其他非法使用,保证接下来的reload数据是正确的;
②boot_relocate_fdt会在bootmap区域中申请一块未被使用的内存,接着将DTB镜像内容复制到这块区域(即归lmb所管理的区域)
注:若环境变量中,指定“fdt_high”参数,则会根据该值,调用lmb_alloc_base函数来分配DTB镜像reload的地址空间 。若分配失败,则会停止bootm操作 。因而,不建议设置fdt_high参数 。接下来,do_bootm会根据内核的类型调用对应的启动函数 。与linux对应的是do_bootm_linux 。
  • ① boot_prep_linux
为启动后的kernel准备参数


推荐阅读