Linux システムでは、デバイス ツリーはハードウェア構成を記述するツリー データ構造です。これはオープン ファームウェア標準に由来し、システムを起動して実行するためのオペレーティング システム ソフトウェアとハードウェア間のインターフェイスを提供するために使用されます。デバイス ツリーは、新しいハードウェアをサポートするためにカーネルに必要な変更を減らし、コードの再利用を改善し、Linux サポート パッケージの開発を加速し、単一のカーネル イメージで複数のシステムをサポートできるようにします。この記事では、デバイス ツリーのデータ ストレージ形式、ソース コード記述構文、U-Boot および Linux カーネルのサポート、デバイス ツリーの解析プロセスなど、Linux デバイス ツリー dts 移植の基本的な手順と方法を紹介します。
キーワード: フラット デバイス ツリー、DTS、PowerPC、Linux
IBM、Sun、およびその他のメーカーのサーバーは、当初ファームウェア (ハードウェア デバイスに組み込まれたプログラムであり、
を備えたもの) を使用していました。
(ソフトウェアとハードウェア間のインターフェイスを提供するために使用されます)、システム構成を初期化し、オペレーティング システム ソフトウェアとハードウェア間のインターフェイスを提供するために使用されます
システムを起動して実行するためのポート。その後、標準化と互換性を目的として、IBM、Sun などが共同でファームウェア インターフェイス IEEE 1275
を発売しました。
IBM PowerPC pSeries、Apple PowerPC、Sun SPARC などのサーバーはすべて Open
を使用します。
ファームウェアは実行時にシステム ハードウェアのデバイス ツリー情報を構築し、それをカーネルに渡してシステムを起動します [1]。それで###
利点としては、カーネルのシステム ハードウェアへの大きな依存の軽減、サポート パッケージの開発の加速、ハードウェアによる変更の削減などがあります。
これにより、需要とコストが削減され、カーネルの設計とコンパイルの要件が軽減されます。
Linux/ppc64 カーネルの開発に伴い、カーネル コードは元の Arch/ppc32 および Arch/ppc64 から
Linux カーネルの実行時には、ハードウェアに関するいくつかの関連情報を知る必要があります。 ARCH=powerpc パラメータを使用してコンパイルされた
の場合
カーネル イメージ、この情報はオープン ファームウェア仕様に基づいており、デバイス ツリーの形式で存在する必要があります [3]。このようにして、カーネルが起動します
実行時にオープン ファームウェアによって提供されるデバイス ツリーを読み取り、スキャンして、プラットフォームのハードウェア デバイス情報を取得し、一致するデバイスを検索します
デバイスドライバーを選択し、ドライバーをデバイスにバインドします。
組み込み PowerPC では、通常、Open Firmware の代わりに U-Boot などのシステム ブート コードが使用されます。
それをカーネルに渡し、カーネルが残りを処理します。このようなインターフェイスは十分な柔軟性がありません。ハードウェアが変更された場合は、コンパイルと書き込みを再カスタマイズする必要があります
ブート コードとカーネルを作成すると、それは現在のカーネルには適さなくなります。カーネルと組み込み PowerPC
の開発に適応するため
プラットフォームは常に変化しているため、U-Boot では、標準のオープン ファームウェアの利点を吸収してフラット デバイス ツリー FDT を導入しています。
別個の FDT BLOB (バイナリ ラージ オブジェクト、バイナリ ファイルを保存できるコンテナ) を使用した動的インターフェイス
カーネルに渡されるパラメータを保存します [3]。キャッシュ サイズ、割り込みルーティングなどの特定の情報は、デバイス ツリー
によって直接提供されます。
eTSEC の MAC アドレス、周波数、PCI バス番号などのその他の情報は、実行時に U-Boot によって変更されます。
U-Boot は bd_t をフラット デバイス ツリーに置き換え、bd_t との下位互換性は保証されなくなりました。
2 デバイスツリーの概念
簡単に言うと、デバイス ツリーはハードウェア構成を記述するツリー状のデータ構造であり、ルート ノードは 1 つだけです [4]。を含む ###
CPU、物理メモリ、バス、シリアル ポート、PHY、およびその他の周辺デバイスに関する情報が含まれます。ツリーは Open を継承します
ファームウェア IEEE 1275 デバイス ツリー定義。オペレーティング システムは、起動時にこの構造を構文解析して構成できます。
カーネルをセットアップし、対応するドライバーをロードします。
3 デバイスツリーの保存形式
U-Boot は、メモリ内のデバイス ツリーのストレージ アドレスをカーネルに渡す必要があります。ツリーは主に 3 つの部分で構成されます。 Head
ストレージ レイアウト図 1 は次のとおりです。
図 1 デバイスツリーの保存形式図
図1 DTブロックのレイアウト
3.1 ヘッダー
ヘッダには、デバイスツリーのマジックナンバーフラグ、デバイスツリーのブロックサイズ、ストラクチャブロックのオフセットアドレスなど、主にデバイスツリーの基本情報が記述されます
で表現されます。
アドレスは、デバイス ツリー ヘッドの開始アドレスを基準にして計算されます。
3.2 構造ブロック
フラットデバイスツリー構造ブロックは線形化されたツリー構造であり、文字列ブロックとともにノード
です。
ノード終了マークはマクロ OF_DT_END_NODE であり、子ノードはノード終了マークの前に定義されます。ノードは要約できます
OF_DT_BEGIN_NODE で始まり、ノード パス、属性リスト、子ノード リストが含まれ、 で終わります。
OF_DT_END_NODE でシーケンスが終了し、各子ノード自体も同様の構造になります。
3.3 文字列ブロック
スペースを節約するために、一部の属性名、特に繰り返し重複して出現する属性名は、個別に抽出されて保存されます
文字列ブロックに。このブロックには、終了フラグを持つ多数の属性名の文字列が含まれています。
はデバイスツリーの構造ブロックに格納されます
これらの文字列のオフセット アドレス。これにより、属性名の文字列を簡単に見つけることができます。文字列ブロックの導入により埋め込みが節約されます
内蔵システムの保管スペースは限られています。
4 デバイス ツリーのソース コードの DTS 表現
デバイス ツリー ソース コード ファイル (.dts) は、システム ハードウェア構成デバイス ツリーを読み取り可能および編集可能なテキスト形式で記述し、C/C
をサポートします。
メソッドに関するコメント。構造には一意のルート ノード「/」があり、各ノードには独自の名前があり、複数の
を含めることができます。
子ノード。デバイスツリーのデータ形式は、Open Firmware IEEE 標準 1275 に従います。この記事では、デバイス ツリーの
について簡単に説明するだけです。
データのレイアウトと構文については、Linux ボード サポート パッケージの開発者は、IEEE 1275 標準 [5] およびその他のドキュメント [2] [4] を参照してください。
これを説明するために、まず、PowerPC MPC8349E プロセッサーに基づく最小システムのデバイス ツリー ソース コードの例を示します。
ご覧のとおり、このデバイス ツリーには多数のノードがあり、各ノードにはノード ユニット名が指定されています。各属性の後には
が続きます
対応する値を与えてください。二重引用符で囲まれた内容は ASCII 文字列であり、山括弧で囲まれた内容は 32 ビットの 16 進数
です。
価値。このツリー構造は、ルート ノードの基本モードを含む、Linux カーネルの起動に必要なノードと属性の簡略化されたコレクションです。
CPU および物理メモリのレイアウトに関する情報に加え、/chosen ノードを通じてカーネルに渡されるコマンド ライン引数の情報も含まれます。
リーリー
4.1 ルートノード
デバイスツリーの始点をルートノード「/」と呼びます。属性モデルは、ターゲット ボード プラットフォームまたはモジュールの名前、属性
を指定します。
互換性の値は、ターゲット ボードと同じシリーズの互換性のある開発ボードの名前を示します。ほとんどの 32 ビット プラットフォームの場合、プロパティ
#address-cells と #size-cells の値は通常 1 です。
4.2 CPU ノード
/cpus ノードはルート ノードの子ノードであり、システム内の各 CPU に対応するノードがあります。 /cpu ノード
必須のプロパティはありませんが、
も参照する #address-cells = および #size-cells = を指定することをお勧めします。
各 CPU ノードの reg 属性形式を理解し、物理 CPU の番号付けを容易にします。
のように PowerPC と表記されます。
Freescale では、この記事で MPC8349E プロセッサについて説明するために PowerPC,8349 を使用します。 CPU ノードのユニット名は
である必要があります。
cpu@0 の形式では、このノードは通常、device_type (「cpu」に固定) と、第 1 レベルのデータ/命令キャッシュのエントリを指定する必要があります。
サイズ、1次データ/命令キャッシュのサイズ、コア、バスクロック周波数など。上記の例ではシステムを介して起動しています
コードはクロック周波数関連の項目を動的に入力します。
このノードは、ターゲット ボード上の物理メモリ範囲を記述するために使用されます。通常、/memory ノードと呼ばれます。1 つまたは複数のノードが存在します。
複数のノードがある場合は、ノードを区別するためにユニットアドレスを続ける必要がありますが、ユニットアドレスが 1 つだけの場合は、ユニットアドレスを記述する必要はありません (
)
デフォルトは 0 です。
このノードにはボード上の物理メモリの属性が含まれており、通常、device_type ("memory" に固定) と reg
アドレスは0、サイズは256Mバイトです。
このノードは少し特殊です。通常、Open Firmware はパラメータ、 などの変数環境情報を保存します。
デフォルトの入出力デバイス。
通常、bootargs および linux、stdout-path 属性値はこのノードで指定されます。 bootargs 属性はカーネルに渡されるように設定されています
カーネルコマンドラインの引数文字列。 Linux の場合、stdout-path は標準端末デバイスのノード パス名であることが多く、カーネルはこれを
として使用します。
デフォルトの端末として。
U-Boot は、バージョン 1.3.0 以降のフラット デバイス ツリー FDT のサポートを追加しました。U-Boot は Linux カーネルをロードします。
を実行します。
カーネルの前に、デバイス ツリー バイナリが変更されます。デバイス ツリーに MAC アドレス、
などの必要な情報が入力されます。
PCIバス数などU-Boot は、シリアル ポート、ルート
を含むデバイス ツリー ファイルの「/chosen」ノードにも入力します。
デバイス (Ramdisk、ハードディスク、または NFS ブート) およびその他の関連情報。
このノードは、システム オン チップ SOC を記述するために使用されます。プロセッサが SOC の場合、このノードが存在する必要があります。上位の SOC セクション
ドットに含まれる情報は、この SOC 上のすべてのデバイスに表示されます。ノード名には、この SOC のユニット アドレス (この SOC
) が含まれている必要があります。
メモリマップドレジスタのベースアドレス。 SOC ノード名は /soc の形式で名前が付けられます (MPC8349 の SOC
など)。
ノードは「soc8349」です。
在属性中应该指定device_type(固定为”soc”)、ranges、bus-frequency 等属性。ranges
属性值以
SOC 设备子节点,应该在设备树中尽可能详细地描述此SOC 上的外围设备。如下给出带有
看门狗设备的SOC 节点DTS 示例。
soc8349@e0000000 { \#address-cells = ; \#size-cells = ; device_type = "soc"; compatible = "simple-bus"; ranges = ; /* size 1MB */ reg = ; bus-frequency = ; /* from bootloader */ { device_type = "watchdog"; compatible = "mpc83xx_wdt"; reg = ; /* offset: 0x200 */ }; };
4.6 其他设备节点
分级节点用来描述系统上的总线和设备,类似物理总线拓扑,能很方便的描述设备间的
关系。对于系统上的每个总线和设备,在设备树中都有其节点。对于这些设备属性的描述和
定义请详细参考IEEE 1275 标准及本文参考文献[2]。
设备树的中断系统稍显复杂,设备节点利用interrupt-parent 和interrupts 属性描述到中
断控制器的中断连接。其中interrupt-parent 属性值为中断控制器节点的指针,#interrupts 属
性值描述可触发的中断信号,其值格式与中断控制器的interrupt-cells 属性值有关。一般
#interrupt-cells 属性值为2,interrupts 属性就对应为一对描述硬件中断号和中断触发方式的
十六进制值。
5 扁平设备树编译
根据嵌入式板的设备信息写设备树源码文件(.dts)通常比较简单,但是手写二进制的
扁平设备树(.dtb)就显得比较复杂了。设备树编译器dtc 就是用来根据设备树源码的文本
文件生成设备树二进制镜像的。dtc 编译器会对输入文件进行语法和语义检查,并根据Linux
内核的要求检查各节点及属性,将设备树源码文件(.dts)编译二进制文件(.dtb),以保证
内核能正常启动。dtc 编译器的使用方法如下所示[6]:
dtc [ -I dts ] [ -O dtb ] [ -o opt_file ] [ -V opt_version ] ipt_file
2.6.25 版本之后的内核源码已经包含了dtc 编译器。在配置编译内核时选中
CONFIG_DTC,会自动生成设备树编译器dtc。将编写的目标板设备树文件mpc8349emitx.dts
放到内核源码的arch/powerpc/boot/dts/目录下,利用内核Makefile 生成blob 的简单规则,使
用以下命令亦可完成设备树的dtc 编译:
$ make mpc8349emitx.dtb
6 U-Boot 相关设置说明
为使 U-Boot 支持设备树,需要在板子配置头文件中设置一系列宏变量。如本文在
MPC8349E 处理器目标板中移植的U-Boot 配置如下: /* pass open firmware flat tree */ \#define CONFIG_OF_LIBFDT 1 \#undef CONFIG_OF_FLAT_TREE \#define CONFIG_OF_BOARD_SETUP 1 \#define CONFIG_OF_HAS_BD_T 1 \#define CONFIG_OF_HAS_UBOOT_ENV 1 启动引导代码U-Boot 在完成自己的工作之后,会加载Linux 内核,并将扁平设备树的 地址传递给内核,其代码形式如下: \#if defined(CONFIG_OF_FLAT_TREE) || defined(CONFIG_OF_LIBFDT) if (of_flat_tree) { /* device tree; boot new style */ /* \* Linux Kernel Parameters (passing device tree): \* r3: pointer to the fdt, followed by the board info data \* r4: physical pointer to the kernel itself \* r5: NULL \* r6: NULL \* r7: NULL */ (*kernel) ((bd_t *)of_flat_tree, (ulong)kernel, 0, 0, 0); /* does not return */ } \#endif
arch/powerpc 内核的入口有且只有一个,入口点为内核镜像的起始。此入口支持两种调
用方式,一种是支持Open Firmware 启动,另一种对于没有OF 的引导代码,需要使用扁平
设备树块,如上示例代码。寄存器r3 保存指向设备树的物理地址指针,寄存器r4 保存为内
核在物理内存中的地址,r5 为NULL。其中的隐含意思为:假设开启了mmu,那么这个mmu
的映射关系是1:1 的映射,即虚拟地址和物理地址是相同的。
7 Linux 内核对设备树的解析
扁平设备树描述了目标板平台中的设备树信息。每个设备都有一个节点来描述其信息,
每个节点又可以有子节点及其相应的属性。内核源码中include/linux/of.h 及drivers/of/base.c
等文件中提供了一些Open Firmware API,通过这些API,内核及设备驱动可以查找到相应
的设备节点,读取其属性值,利用这些信息正确地初始化和驱动硬件。
图2 内核及驱动对扁平设备树的解析
Fig2 Interaction from kernel and drivers with the FDT blob
8 结论
通过本文,你应该对Linux设备树dts移植有了一个基本的了解,它是一种描述和传递硬件配置信息的有效方式,可以适应嵌入式Linux系统的多样化需求。当然,设备树也不是一成不变的,它需要根据具体的硬件平台和内核版本进行定制和修改。总之,设备树是Linux系统中不可或缺的一个组件,值得你深入学习和掌握。
以上がLinux デバイス ツリー dts 移植: ハードウェア構成情報を記述して転送する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。