2021-05-12 14:32:11
我眼中的Linux裝置樹(Device tree)
概述
裝置樹(Device tree)是一套用來描述硬體屬相的規則。ARM Linux採用裝置樹機制源於2011年3月份Linux創始人Linus Torvalds發的一封郵件,在這封郵件中他提倡ARM平台應該參考其他平台如PowerPC的裝置樹機制描述硬體。因為在此之前,ARM平台還是採用舊的機制,在kernel/arch/arm/plat-xxx目錄和kernel/arch/arm/mach-xxx目錄下用程式碼描述硬體,如註冊platform裝置,宣告裝置的resource等。因為這些程式碼都是用來描述晶片平台及板級差異的,所以對於核心來講都是垃圾程式碼。因為嵌入式平台中很多公司的晶片採用的都是ARM架構,隨著Android的成功,這些程式碼越來越多。據說常見的平台如s3c2410板級目錄下邊的程式碼有數萬行,難怪Linux Torvalds會說“this whole ARM thing is a fucking pain in the ass”。
核心中關於裝置樹的文件位於kernel/Documentation/devicetree/目錄。裝置樹是Power.org組織定義的一套規範,規範文件可以在官網上找到,目前最新的版本是https://www.power.org/documentation/epapr-version-1-1/。核心中裝置樹相關的函數都是以of開頭的,我推測原因是裝置樹機制是源於IEEE 1275 Open Firmware standard規範的,相關的程式碼都是繼承下來的。如果想快速了解下裝置樹怎麼用,可以參考http://devicetree.org/Device_Tree_Usage。
裝置樹是從軟體使用的角度描述硬體的,不是從硬體設計的角度描述的。我們在寫裝置樹時沒有必要按照硬體邏輯生搬硬套,也不要指望通過閱讀裝置樹弄清楚硬體是如何設計的。對於軟體可以自動識別的硬體,如USB裝置,PCI裝置,也是沒有必要通過裝置樹描述的。
我個人覺得規範內容是可以分為兩個層次的。第一層是關於裝置樹組織形式的,如裝置樹結構,節點名字的構成等,第一個層次是基礎,是理解第二個層次的前提。第二層是關於裝置樹內容的,如多核CPU怎樣描述,一個具體的裝置如何描述。第二層可以看成是第一層的具體應用。相對來說第二層內容更多,更具體,根據描述的內容不同,定義規範的方式也有差別,比如關於CPU,記憶體,中斷這些基礎的內容,是在epapr中說明的,而關於外設的規範是在專門的地方說明的。
DTS(Device tree syntax,另一種說法是Device tree source)是裝置樹原始檔,為了方便閱讀及修改,採用文字格式。DTC(Device tree compiler)是一個小工具,負責將DTS轉換成DTB(Device tree blob)。DTB是DTS的二進位制形式,供機器使用。使用中,我們首先根據硬體修改DTS檔案,然後在編譯的時候通過DTC工具將DTS檔案轉換成DTB檔案,然後將DTB檔案燒寫到機器上(如emmc,磁碟等儲存媒介)。系統啟動時,fastboot(或者類似的啟動程式,如Uboot)在啟動核心前將DTB檔案讀到記憶體中,跳轉到核心執行的同時將DTB起始地址傳給核心。核心通過起始地址就可以根據DTB的結構解析整個裝置樹。說裝置樹的規範可以分成兩個層次,是針對DTS的,關於DTB的結構不在此範圍內。DTB僅僅是為了方便機器使用而對DTS的轉換而已(也可以說DTS僅是為了方便人類使用而對DTB的一種描述)。
裝置樹首先是一個樹形結構,並且是一棵樹。除了根節點外其他子節點都有唯一的父節點,節點下可以有子節點和屬性(子節點可以看成是樹枝,屬性可以看成是葉子)。屬性由名字和值組成(名字是必須的,但是值不是必須的,如果只要根據是否存在這個屬性就可以表示我們想要的功能,那麼可以不需要有值)。
下邊是我們從核心程式碼中擷取的一個DTS片段。“/”表示根節點。“model = "Newflow AM335x NanoBone"”是根節點下邊的屬性。“cpus”是根節點的一個子節點。“cpu0-supply = <&dcdc2_reg>”是“cpu@0”子節點下的屬性。節點下的屬性用來表示節點的特性,子節點和父節點具有一定的從屬關係。真實的硬體不可能是這樣規則的樹形結構,所以裝置樹僅是軟體開發人員為了描述硬體而做的一個近似表示而已,連抽象都算不上。
/ {
model = "Newflow AM335x NanoBone";
compatible = "ti,am33xx";
cpus {
cpu@0 {
cpu0-supply = <&dcdc2_reg>;
};
};
memory {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
leds {
compatible = "gpio-leds";
led@0 {
label = "nanobone:green:usr1";
gpios = <&gpio1 5 0>;
default-state = "off";
};
};
};
更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2016-01/127337p2.htm
相關文章