title: uboot處理dtb
date: 2019/4/28 17:18:19
toc: true
uboot處理dtb
傳遞參數給內核
之前在分析內核啟動參數的時候,可以看到內核處理的dtb的地址是原來atag
的地址也就是R2
,所以就是在轉入kernel
參數為的第3個為dtb地址即可
我們的uboot是這么啟動的
bootm <uImage_addr> // 無設備樹,bootm 0x30007FC0
bootm <uImage_addr> <initrd_addr> <dtb_addr> // 有設備樹
所以就是講第4個參數讀取並轉換即可
/* 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);
}
}
最終的啟動流程如下
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字節)不能被占用
------------------------------
0x33f80000 ->| u-boot | 分析lds鏈接文件
------------------------------
| u-boot所使用的內存(棧等)|
------------------------------
| |
| |
| 空閑區域 |
| |
| |
| |
| |
------------------------------
0x30008000 ->| zImage |
------------------------------ uImage = 64字節的頭部+zImage
0x30007FC0 ->| uImage頭部 |
------------------------------
0x30004000 ->| 內核創建的頁表 | head.S
------------------------------
| |
| |
-----> ------------------------------
|
|
--- (內存基址 0x30000000)
正確操作
nand read.jffs2 30000000 device_tree
nand read.jffs2 0x30007FC0 kernel
bootm 0x30007FC0 - 30000000
破壞頁表不能啟動哦
nand read.jffs2 30004000 device_tree
nand read.jffs2 0x30007FC0 kernel
bootm 0x30007FC0 - 30004000
dtb修改
dtb的二進制文件還算簡單,可以直接來修改即可,具體的修改就是要注意一些字節長度和偏移
具體的步驟簡述一下,我覺得沒必要搞,還是dts文件方便
例子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也有現成的源代碼,需要移植,具體錯誤可以參考
cmd/fdt.c
在編譯文件時可以用"-I"選項指定頭文件目錄
比如: arm-linux-gcc -I <dir> -c -o ....,對於u-boot來說, 一般就是源碼的include目錄。
常用命令如下
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分區