uboot处理dtb

uboot处理dtb

传递参数给内核#

之前在分析内核启动参数的时候,可以看到内核处理的dtb的地址是原来atag的地址也就是R2,所以就是在转入kernel参数为的第3个为dtb地址即可

我们的uboot是这么启动的

Copy
bootm <uImage_addr> // 无设备树,bootm 0x30007FC0 bootm <uImage_addr> <initrd_addr> <dtb_addr> // 有设备树

所以就是讲第4个参数读取并转换即可

Copy
/* 100ask for device tree, no initrd image used */ if (argc == 4) { //第三个参数0x32000000就是设备树地址 of_flat_tree = (char *) simple_strtoul(argv[3], NULL, 16); if (be32_to_cpu(*(ulong *)of_flat_tree) == OF_DT_HEADER) { printf ("\nStarting kernel with device tree at 0x%x...\n\n", of_flat_tree); cleanup_before_linux (); //把dtb的地址传到r2寄存器里 theKernel (0, bd->bi_arch_number, of_flat_tree); } else { printf("Bad magic of device tree at 0x%x!\n\n", of_flat_tree); } }

最终的启动流程如下

Copy
nand read.jffs2 0x30007FC0 kernel; // 读内核uImage到内存0x30007FC0 nand read.jffs2 32000000 device_tree; // 读dtb到内存32000000 bootm 0x30007FC0 - 0x32000000 // 启动, 没有initrd时对应参数写为"-"

dtb 地址选择#

使用mkimage -l arch/arm/boot/uImage来查看内核的加载地址,然后放置到正确的位置

  • 不要破坏u-boot本身
  • 内核本身的空间不能占用, 内核要用到的内存区域也不能占用
  • 内核启动时一般会在它所处位置的下边放置页表, 这块空间(一般是0x4000即16K字节)不能被占用
Copy
------------------------------ 0x33f80000 ->| u-boot | 分析lds链接文件 ------------------------------ | u-boot所使用的内存(栈等)| ------------------------------ | | | | | 空闲区域 | | | | | | | | | ------------------------------ 0x30008000 ->| zImage | ------------------------------ uImage = 64字节的头部+zImage 0x30007FC0 ->| uImage头部 | ------------------------------ 0x30004000 ->| 内核创建的页表 | head.S ------------------------------ | | | | -----> ------------------------------ | | --- (内存基址 0x30000000)

正确操作

Copy
nand read.jffs2 30000000 device_tree nand read.jffs2 0x30007FC0 kernel bootm 0x30007FC0 - 30000000

破坏页表不能启动哦

Copy
nand read.jffs2 30004000 device_tree nand read.jffs2 0x30007FC0 kernel bootm 0x30007FC0 - 30004000

dtb修改#

dtb的二进制文件还算简单,可以直接来修改即可,具体的修改就是要注意一些字节长度和偏移

具体的步骤简述一下,我觉得没必要搞,还是dts文件方便

Copy
例子1. 修改属性的值, 假设 老值: len 新值: newlen (假设newlen > len) a. 把原属性val所占空间从len字节扩展为newlen字节: 把老值之后的所有内容向后移动(newlen - len)字节 b. 把新值写入val所占的newlen字节空间 c. 修改dtb头部信息中structure block的长度: size_dt_struct d. 修改dtb头部信息中string block的偏移值: off_dt_strings e. 修改dtb头部信息中的总长度: totalsize 例子2. 添加一个全新的属性 a. 如果在string block中没有这个属性的名字, 就在string block尾部添加一个新字符串: 属性的名 并且修改dtb头部信息中string block的长度: size_dt_strings 修改dtb头部信息中的总长度: totalsize b. 找到属性所在节点, 在节点尾部扩展一块空间, 内容及长度为: TAG // 4字节, 对应0x00000003 len // 4字节, 表示属性的val的长度 nameoff // 4字节, 表示属性名的offset val // len字节, 用来存放val c. 修改dtb头部信息中structure block的长度: size_dt_struct d. 修改dtb头部信息中string block的偏移值: off_dt_strings e. 修改dtb头部信息中的总长度: totalsize

移植fdt#

uboot也有现成的源代码,需要移植,具体错误可以参考

Copy
cmd/fdt.c 在编译文件时可以用"-I"选项指定头文件目录 比如: arm-linux-gcc -I <dir> -c -o ....,对于u-boot来说, 一般就是源码的include目录。

常用命令如下

Copy
nand read.jffs2 32000000 device_tree // 从flash读出dtb文件到内存(0x32000000) fdt addr 32000000 // 告诉fdt, dtb文件在哪 fdt print /led pin // 打印/led节点的pin属性 fdt get value XXX /led pin // 读取/led节点的pin属性, 并且赋给环境变量XXX print XXX // 打印环境变量XXX的值 fdt set /led pin <0x00050005> // 设置/led节点的pin属性 fdt print /led pin // 打印/led节点的pin属性 nand erase device_tree // 擦除flash分区 nand write.jffs2 32000000 device_tree // 把修改后的dtb文件写入flash分区
posted @   zongzi10010  阅读(2880)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示
CONTENTS