一、設備樹在系統中的體現
Linux 內核啟動的時候會解析設備樹中各個節點的信息,并且在根文件系統的 /proc/device/tree 目錄下根據節點名字創建不同文件夾,如圖所示:
上圖就是目錄/proc/device-tree 目錄下的內容,/proc/device-tree 目錄下是根節點“/”的所有屬性和子節點。
1、根節點“/”各個屬性
根節點屬性屬性表現為一個個的文件(圖中細字體文件),如圖中的“#address-cells”、“#size-cells”、“compatible”、“model”和“name”這 5 個文件,它們在設備樹中就是根節點的 5 個屬性。可以輸入 cat 命令來查看 model 和 cat compatible 這兩個文件的內容:
cat model
cat compatible
2、根節點“/”各子節點
圖中各個文件夾(圖中粗字體文件夾)就是根節點“/”的各個子節點,比如 “aliases”、“backlight”、“chosen”和“clocks”等等。
/proc/device-tree 目錄就是設備樹在根文件系統中的體現,同樣是按照樹形結構組織的,進入/proc/device-tree/soc 目錄就可以看到 soc 節點的所有子節點:
和根節點“/”一樣,上圖中的所有文件分別為 soc 節點的屬性文件和子節點文件夾。
二、特殊節點
在根節點“/”中有兩個特殊的子節點:aliases 和 chosen
1、aliases 子節點
打開 imx6ull.dtsi 文件,aliases 節點內容如下所示:
aliases {
can0 = &flexcan1;
can1 = &flexcan2;
ethernet0 = &fec1;
ethernet1 = &fec2;
gpio0 = &gpio1;
gpio1 = &gpio2;
......
spi0 = &ecspi1;
spi1 = &ecspi2;
spi2 = &ecspi3;
spi3 = &ecspi4;
usbphy0 = &usbphy1;
usbphy1 = &usbphy2;
};
單詞 aliases 的意思是“別名”,因此 aliases 節點的主要功能就是定義別名,定義別名的目的就是為了方便訪問節點。不過一般會在節點命名的時加上label,然后通過 &label 來訪問節點,這樣也很方便,而且設備樹里面大量的使用 &label 的形式來訪問節點。
2、chosen 子節點
chosen 并不是一個真實的設備,chosen 節點主要是為了 uboot 向 Linux 內核傳遞數據,重點是 bootargs 參數。一般 .dts 文件中 chosen 節點通常為空或者內容很少,imx6ull-alientek-emmc.dts 中 chosen 節點內容如下所示:
chosen {
stdout-path = &uart1;
};
從示例代碼中可以看出,chosen 節點僅僅設置了屬性“stdout-path”,表示標準輸
出使用 uart1。但是當我們進入到 /proc/device-tree/chosen 目錄里面,會發現多了 bootargs 這個屬性,如圖所示:
輸入 cat 命令查看 bootargs 這個文件的內容,結果如圖所示:
從圖可以看出,bootargs 這個文件的內容為“console=ttymxc0,115200……”,這個就是在 uboot 中設置的 bootargs 環境變量的值。
現在有兩個疑點:
①、我們并沒有在設備樹中設置 chosen 節點的 bootargs 屬性,那么圖中 bootargs 這個屬性是怎么產生的?
②、為何 bootargs 文件的內容和 uboot 中 bootargs 環境變量的值一樣?它們之間有什么關系?
前面講解 uboot 的時候說過,uboot 在啟動 Linux 內核的時候會將 bootargs 的值傳遞給 Linux 內核,bootargs 會作為 Linux 內核的命令行參數,Linux 內核啟動的時候會打印出命令行參數(也就是 uboot 傳遞進來的 bootargs 的值),如圖所示:
既然 chosen 節點的 bootargs 屬性不是我們在設備樹里面設置的,那么只有一種可能,那就是 uboot 自己在 chosen 節點里面添加了 bootargs 屬性!并且設置 bootargs 屬性的值為 bootargs 環境變量的值。因為在啟動 Linux 內核之前,只有 uboot 知道 bootargs 環境變量的值,并且 uboot 也知道.dtb 設備樹文件在 DRAM 中的位置。
在 uboot 源碼中全局搜索“chosen”這個字符串,在 common/fdt_support.c 文件中發現了“chosen”的身影,fdt_support.c 文件中有個 fdt_chosen 函數,此函數內容如下所示:
int fdt_chosen(void *fdt)
{
int nodeoffset;
int err;
char *str; /* used to set string properties */
err = fdt_check_header(fdt);
if (err < 0) {
printf('fdt_chosen: %sn', fdt_strerror(err));
return err;
}
/* find or create '/chosen' node. */
nodeoffset = fdt_find_or_add_subnode(fdt, 0, 'chosen');
if (nodeoffset < 0)
return nodeoffset;
str = getenv('bootargs');
if (str) {
err = fdt_setprop(fdt, nodeoffset, 'bootargs', str,
strlen(str) + 1);
if (err < 0) {
printf('WARNING: could not set bootargs %s.n',
fdt_strerror(err));
return err;
}
}
return fdt_fixup_stdout(fdt, nodeoffset);
}
第 14 行:調用函數 fdt_find_or_add_subnode 從設備樹(.dtb)中找到 chosen 節點,如果沒有找到的話就會自己創建一個 chosen 節點。
第 18 行:讀取 uboot 中 bootargs 環境變量的內容。
第 20 行:調用函數 fdt_setprop 向 chosen 節點添加 bootargs 屬性,并且 bootargs 屬性值就是環境變量 bootargs 的內容。
整個流程是如圖所示:
圖中框起來的部分就是函數 do_bootm_linux 函數的執行流程,也就是說
do_bootm_linux 函數會通過一系列復雜的調用,最終通過 fdt_chosen 函數在 chosen 節點中加入了 bootargs 屬性。而我們通過 bootz 命令啟動 Linux 內核的時候會運行 do_bootm_linux 函數。
三、Linux 內核解析 DTB 文件
Linux 內核在啟動的時候會解析 DTB 文件,然后在 /proc/device-tree 目錄下生成相應的設備樹節點文件。接下來我們簡單分析一下 Linux 內核是如何解析 DTB 文件的,流程如圖所示:
從圖中可以看出,在 start_kernel 函數中完成了設備樹節點解析的工作,最終實際工作的函數為 unflatten_dt_node。
上一篇:【IMX6ULL學習筆記】十五、設備樹DTS操作函數
下一篇:【IMX6ULL學習筆記】十三、DTS語法
推薦閱讀最新更新時間:2025-03-26 13:26



設計資源 培訓 開發板 精華推薦
- 迅為IMX6開發板Android應用-AndroidStudio-calculator測試
- 玩轉 ESP32 + Arduino (二十) SIM800L上傳數據到OneNet(新版Mqtts)
- 玩轉 ESP32 + Arduino (二十一) SPIFFS文件系統 (已棄用)
- 玩轉 ESP32 + Arduino (二十二) SIM800L上傳數據到阿里IOT(溫濕度和LBS)(NTP對時)
- 玩轉 ESP32 + Arduino (二十三) 多文件系統及全局變量
- 玩轉 ESP32 + Arduino (二十四) SD卡讀寫
- 玩轉 ESP32 + Arduino (二十五) SSD1306庫驅動OLED
- 玩轉 ESP32 + Arduino(二十六) 按鍵控制庫 OneButton
- 玩轉 ESP32 + Arduino(二十七) ESP對象