1. 程式人生 > 其它 >奇小葩講裝置樹(2/5)-- Linux裝置樹詳解(二)檔案構成

奇小葩講裝置樹(2/5)-- Linux裝置樹詳解(二)檔案構成

技術標籤:linux裝置驅動

裝置樹就是描述單板資源以及裝置的一種文字檔案。至於出現的原因,基本的語法和使用方法,上一章節做了基本的介紹。本篇文章主要是更深層次的探討裝置檔案的構成。

1. devie tree的編譯

Device Tree檔案的格式為dts,包含的標頭檔案格式為dtsi,dts檔案是一種人可以看懂的編碼格式。但是uboot和linux不能直接識別,他們只能識別二進位制檔案,所以需要把dts檔案編譯成dtb檔案。dtb檔案是一種可以被kernel和uboot識別的二進位制檔案。把dts編譯成dtb檔案的工具是dtc。Linux原始碼目錄下scripts/dtc目錄包含dtc工具的原始碼。在Linux的scripts/dtc目錄下除了提供dtc工具外,也可以自己安裝dtc工具,linux下執行:sudo apt-get install device-tree-compiler安裝dtc工具。其中還提供了一個fdtdump的工具,可以反編譯dtb檔案

dtc工具的使用方法是:

dtc –I dts –O dtb –oxxx.dtb xxx.dts

dts和dtb檔案的轉換如圖1所示
在這裡插入圖片描述

2. Device Tree頭資訊

本章我們將採用例項解析一個dtb檔案,看看其原理是什麼樣的?
fdtdump工具使用,Linux終端執行ftddump –h,輸出以下資訊:

[email protected]:~/02_dtb$ fdtdump --h
Usage: fdtdump [options] <file>

Options: -[dshV]
  -d, --debug   Dump debug information while decoding the file
  -s, --scan    Scan for an embedded fdt in file
  -h, --help    Print this help and exit
  -V, --version Print version and exit

本文采用 jz2440.dtb檔案為例說明fdtdump工具的使用。Linux終端執行fdtdump

[email protected]:~/02_dtb$ fdtdump -d -s jz2440.dtb 
jz2440.dtb: found fdt at offset 0
/dts-v1/;
// magic:               0xd00dfeed
// totalsize:           0x1d1 (465)
// off_dt_struct:       0x48
// off_dt_strings:      0x188
// off_mem_rsvmap:      0x28
// version:             17
// last_comp_version:   16
// boot_cpuid_phys:     0x0
// size_dt_strings:     0x49
// size_dt_struct:      0x140

以上資訊便是Device Tree檔案頭資訊,儲存在dtb檔案的開頭部分。在Linux核心中使用struct fdt_header結構體描述。struct fdt_header結構體定義在scripts\dtc\libfdt\fdt.h檔案中

struct  fdt_header  {
   fdt32_t  magic;             /* magic word FDT_MAGIC */
   fdt32_t  totalsize;         /* total size of DT block */
   fdt32_t  off_dt_struct;        /* offset to  structure */
   fdt32_t  off_dt_strings;       /* offset to  strings */
   fdt32_t  off_mem_rsvmap;       /* offset to  memory reserve map */
   fdt32_t  version;               /* format version */
   fdt32_t  last_comp_version;    /* last compatible  version */

   /*  version 2 fields below */
   fdt32_t  boot_cpuid_phys;   /* Which physical CPU  id we're booting on */
   /*  version 3 fields below */
   fdt32_t  size_dt_strings;   /* size of the  strings block */

   /*  version 17 fields below */
   fdt32_t  size_dt_struct;       /* size of the  structure block */
};
/memreserve/ 33f00000 100000;
// 0048: tag: 0x00000001 (FDT_BEGIN_NODE)
/ {
// 0050: tag: 0x00000003 (FDT_PROP)
// 0188: string: model
// 005c: value
   model = "SMDK24440";
// 0068: tag: 0x00000003 (FDT_PROP)
// 018e: string: compatible
// 0074: value
   compatible = "samsung,smdk2440";
// 0088: tag: 0x00000003 (FDT_PROP)
// 0199: string: #address-cells
// 0094: value
   #address-cells = <0x00000001>;
// 0098: tag: 0x00000003 (FDT_PROP)
// 01a8: string: #size-cells
// 00a4: value
   #size-cells = <0x00000001>;
// 00a8: tag: 0x00000001 (FDT_BEGIN_NODE)
   memory {
// 00b4: tag: 0x00000003 (FDT_PROP)
// 01b4: string: device_type
// 00c0: value
       device_type = "memory";
// 00c8: tag: 0x00000003 (FDT_PROP)
// 01c0: string: reg
// 00d4: value
       reg = <0x30000000 0x00000002 0x00000003 0x69747264>;
// 00e4: tag: 0x00000002 (FDT_END_NODE)
   };
// 00e8: tag: 0x00000001 (FDT_BEGIN_NODE)
   chosen {
// 00f4: tag: 0x00000003 (FDT_PROP)
// 01c4: string: bootargs
// 0100: value
       bootargs = "noinitrd root=/dev/mtdblock4 rw init=/linuxrc console=ttySAC0,115200";
// 0148: tag: 0x00000002 (FDT_END_NODE)
   };
// 014c: tag: 0x00000001 (FDT_BEGIN_NODE)
   led {
// 0154: tag: 0x00000003 (FDT_PROP)
// 018e: string: compatible
// 0160: value
       compatible = "jz2440_led";
// 016c: tag: 0x00000003 (FDT_PROP)
// 01cd: string: pin
// 0178: value
       pin = <0x00050005>;
// 017c: tag: 0x00000002 (FDT_END_NODE)
   };
// 0180: tag: 0x00000002 (FDT_END_NODE)
};

fdtdump工具的輸出資訊即是以上結構中每一個成員的值,struct fdt_header結構體包含了Device Tree的私有資訊,並且Device Tree的檔案是以大端模式儲存。並且,頭部資訊和fdtdump的輸出資訊一致。

3. Device Tree檔案結構

DTB檔案佈局如下:
在這裡插入圖片描述
可以看出整個DTB分為四個部分:struct ftd_header、memory reservation block、structure block、strings block;

  1. struct ftd_header:用來表明各個分部的偏移地址,整個檔案的大小,版本號等;
  2. memory reservation block:在裝置樹中使用/memreserve/ 定義的保留記憶體資訊;
  3. structure block:儲存節點的資訊,節點的結構;
  4. strings block:儲存屬性的名字,單獨作為字串儲存;

3.1 DTB header

對於DTB header,其各個含義定義如下:

header field namedescription
magic用來識別DTB的。通過這個magic,kernel可以確定bootloader傳遞的引數block是一個DTB還是tag list
totalsizeDTB的total size
off_dt_structdevice tree structure block的offset
off_dt_stringsdevice tree strings block的offset
off_mem_rsvmapoffset to memory reserve map。有些系統,我們也許會保留一些memory有特殊用途(例如DTB或者initrd image),或者在有些DSP+ARM的SOC platform上,有寫memory被保留用於ARM和DSP進行資訊互動。這些保留記憶體不會進入記憶體管理系統
version該DTB的版本
last_comp_version相容版本資訊
boot_cpuid_phys我們在哪一個CPU(用ID標識)上booting
dt_strings_sizedevice tree strings block的size。和off_dt_strings一起確定了strings block在記憶體中的位置
dt_struct_sizedevice tree structure block的size。和off_dt_struct一起確定了device tree structure block在記憶體中的位置