In Linux-Systemen ist der Gerätebaum eine Baumdatenstruktur, die die Hardwarekonfiguration beschreibt. Er stammt aus dem Open Firmware-Standard und wird verwendet, um eine Schnittstelle zwischen Betriebssystemsoftware und Hardware zum Starten und Ausführen des Systems bereitzustellen. Der Gerätebaum kann die zur Unterstützung neuer Hardware erforderlichen Änderungen am Kernel reduzieren, die Wiederverwendung von Code verbessern, die Entwicklung von Linux-Unterstützungspaketen beschleunigen und die Unterstützung mehrerer Systeme durch ein einziges Kernel-Image ermöglichen. In diesem Artikel werden die grundlegenden Schritte und Methoden der DTS-Transplantation des Linux-Gerätebaums vorgestellt, einschließlich des Datenspeicherformats des Gerätebaums, der Syntax der Quellcodebeschreibung, der U-Boot- und Linux-Kernel-Unterstützung und des Analyseprozesses für Gerätebäume usw.
Schlüsselwörter: flacher Gerätebaum; DTS; Linux
Server von IBM, Sun und anderen Herstellern verwendeten ursprünglich Firmware (ein in Hardwaregeräte eingebettetes Programm mit
(wird verwendet, um eine Schnittstelle zwischen Software und Hardware bereitzustellen), dient zur Initialisierung der Systemkonfiguration und stellt eine Schnittstelle zwischen Betriebssystemsoftware und -hardware bereit
Port, um das System zum Laufen zu bringen. Später führten IBM, Sun usw. aus Gründen der Standardisierung und Kompatibilität gemeinsam die Firmware-Schnittstelle IEEE 1275
ein
Standards, sodass ihre Server wie IBM PowerPC pSeries, Apple PowerPC, Sun SPARC usw. alle Open
verwenden
Die Firmware erstellt zur Laufzeit die Gerätebauminformationen der Systemhardware und übergibt sie an den Kernel, um das System zu starten [1]. So
Zu den Vorteilen gehören die Verringerung der starken Abhängigkeit des Kernels von der Systemhardware, die Beschleunigung der Entwicklung von Supportpaketen und die Reduzierung von durch die Hardware verursachten Änderungen
Es reduziert den Bedarf und die Kosten und reduziert die Anforderungen an das Kernel-Design und die Kernel-Kompilierung.
Mit der Entwicklung des Linux/ppc64-Kernels wurde der Kernel-Code schrittweise von den ursprünglichen Versionen arch/ppc32 und arch/ppc64 auf
migriert
Vereinheitlichen Sie das Verzeichnis arch/powerpc und führen Sie die Open Firmware API in den Kernel-Code ein, um die Standard-Firmware-Schnittstelle zu verwenden [2].
Wenn der Linux-Kernel ausgeführt wird, muss er einige relevante Informationen über die Hardware kennen. Für diejenigen, die mit dem Parameter ARCH=powerpc kompiliert wurden
Kernel-Image: Diese Informationen müssen auf der Open Firmware-Spezifikation basieren und in Form eines Gerätebaums vorliegen [3]. Auf diese Weise startet der Kernel
Lesen und scannen Sie den von Open Firmware zur Laufzeit bereitgestellten Gerätebaum, um die Hardware-Geräteinformationen der Plattform zu erhalten und nach passenden Geräten zu suchen
Gerätetreiber und binden Sie den Treiber an das Gerät.
In eingebetteten PowerPCs wird im Allgemeinen Systemstartcode wie U-Boot anstelle von Open Firmware verwendet.
Frühes U-Boot nutzte die statische Datenstruktur struct bd_t in include/asm-ppc/u-boot.h, um grundlegende Informationen über das Board zu übertragen
Übergeben Sie es an den Kernel, der den Rest erledigt. Diese Art von Schnittstelle ist nicht flexibel genug, wenn sich die Hardware ändert, müssen Sie die Kompilierung und das Brennen neu anpassen
Schreiben Sie Bootcode und Kernel, und dieser ist nicht mehr für den aktuellen Kernel geeignet. Zur Anpassung an die Entwicklung des Kernels und des eingebetteten PowerPC
U-Boot nutzt die sich ständig ändernde Plattform und nutzt die Vorteile der standardmäßigen offenen Firmware und führt FDT mit flachem Gerätebaum wie folgt ein
Dynamische Schnittstelle unter Verwendung eines separaten FDT-Blobs (binäres großes Objekt, ein Container, der Binärdateien speichern kann)
Speichert an den Kernel übergebene Parameter [3]. Einige bestimmte Informationen, wie Cache-Größe, Interrupt-Routing usw., werden direkt vom Gerätebaum bereitgestellt,
Andere Informationen wie die MAC-Adresse, Frequenz, PCI-Busnummer usw. von eTSEC werden von U-Boot zur Laufzeit geändert.
U-Boot ersetzt bd_t durch einen flachen Gerätebaum und die Abwärtskompatibilität mit bd_t ist nicht mehr gewährleistet.
2 Gerätebaumkonzept
Einfach ausgedrückt ist der Gerätebaum eine baumförmige Datenstruktur, die die Hardwarekonfiguration beschreibt, mit einem und nur einem Wurzelknoten [4]. Es packt
Enthält Informationen zu CPU, physischem Speicher, Bus, serieller Schnittstelle, PHY und anderen Peripheriegeräten. Der Baum erbt Open
Definition des Firmware-IEEE-1275-Gerätebaums. Das Betriebssystem kann beim Start eine syntaktische Analyse dieser Struktur durchführen, um
zu konfigurieren
Richten Sie den Kernel ein und laden Sie den entsprechenden Treiber.
3 Gerätebaum-Speicherformat
U-Boot muss die Speicheradresse des Gerätebaums im Speicher an den Kernel übergeben. Der Baum besteht hauptsächlich aus drei Teilen: dem Kopf
(Header), Strukturblock (Strukturblock), Strings-Block (Strings-Block). Speicherung des Gerätebaums im Speicher
Speicherlayoutdiagramm 1 sieht wie folgt aus:
Abbildung 1 Diagramm des Gerätebaumspeicherformats
Abb. 1 Das Layout eines DT-Blocks
3.1 Kopfzeile
Der Header beschreibt hauptsächlich die grundlegenden Informationen des Gerätebaums, wie z. B. das magische Nummernflag des Gerätebaums, die Blockgröße des Gerätebaums und die Offset-Adresse des Strukturblocks
usw. Seine spezifische Struktur boot_param_header ist wie folgt. Die Werte in dieser Struktur werden im Big-Endian-Modus und im Offset ausgedrückt
Die Adresse wird relativ zur Startadresse des Gerätebaumkopfes berechnet.
3.2 Strukturblock
Der flache Gerätebaumstrukturblock ist eine linearisierte Baumstruktur. Zusammen mit dem Stringblock bildet er den Hauptteil des Gerätebaums mit Knoten
Speichern Sie die Geräteinformationen der Zielplatine im Formular. Im Strukturblock ist das Knotenstartflag das Konstantenmakro OF_DT_BEGIN_NODE,
Die Knotenendmarkierung ist das Makro OF_DT_END_NODE; die untergeordneten Knoten werden vor der Knotenendmarkierung definiert. Ein Knoten kann zusammenfassen
Es beginnt mit OF_DT_BEGIN_NODE, enthält den Knotenpfad, die Attributliste und die Liste der untergeordneten Knoten und endet schließlich mit
OF_DT_END_NODE beendet die Sequenz und jeder untergeordnete Knoten selbst hat eine ähnliche Struktur.
3.3 Strings-Block
Um Platz zu sparen, werden einige Attributnamen, insbesondere solche, die wiederholt und redundant vorkommen, extrahiert und separat gespeichert
zu einem String-Block. Dieser Block enthält eine Reihe von Attributnamenszeichenfolgen mit Endflags. Gespeichert im Strukturblock des Gerätebaums
Die Offset-Adresse dieser Zeichenfolgen, damit die Zeichenfolge mit dem Attributnamen leicht gefunden werden kann. Die Einführung von String-Blöcken erspart das Einbetten
Der Stauraum des Einbausystems ist knapp bemessen.
4 DTS-Darstellung des Gerätebaum-Quellcodes
Die Gerätebaum-Quellcodedatei (.dts) beschreibt den Gerätebaum der Systemhardwarekonfiguration in einem lesbaren und bearbeitbaren Textformat und unterstützt C/C++
Anmerkungen dazu: Die Struktur hat einen eindeutigen Wurzelknoten „/“, jeder Knoten hat seinen eigenen Namen und kann mehrere
enthalten
untergeordneter Knoten. Das Datenformat des Gerätebaums folgt dem Open Firmware IEEE-Standard 1275. In diesem Artikel wird der Gerätebaum nur kurz beschrieben
Für Details zum Datenlayout und zur Syntax sollten Entwickler von Linux-Board-Support-Paketen den IEEE 1275-Standard [5] und andere Dokumente [2] [4] konsultieren.
Geben Sie zur Veranschaulichung zunächst ein Beispiel für den Gerätebaum-Quellcode eines Minimalsystems, das auf dem PowerPC MPC8349E-Prozessor basiert.
Wie Sie sehen, gibt es in diesem Gerätebaum viele Knoten, und für jeden Knoten ist ein Knoteneinheitenname angegeben. Hinter jedem Attribut steht
Geben Sie den entsprechenden Wert an. Der in doppelte Anführungszeichen eingeschlossene Inhalt ist eine ASCII-Zeichenfolge und der in spitzen Klammern angegebene Inhalt ist eine 32-Bit-Hexadezimalzahl
Wert. Diese Baumstruktur ist eine vereinfachte Sammlung von Knoten und Attributen, die zum Starten des Linux-Kernels erforderlich sind, einschließlich des Grundmodus des Wurzelknotens
Informationen zum CPU- und physischen Speicherlayout sowie Informationen zu Befehlszeilenargumenten, die über den /chosen-Knoten an den Kernel übergeben werden.
/ { model = "MPC8349EMITX"; compatible = "MPC8349EMITX", "MPC834xMITX", "MPC83xxMITX"; \#address-cells = ; /* 32bit address */ \#size-cells = ; /* 4GB size */ cpus { \#address-cells = ; \#size-cells = ; PowerPC,8349@0 { device_type = "cpu"; reg = ; d-cache-line-size = ; /* 32 Bytes */ i-cache-line-size = ; d-cache-size = ; /* L1 dcache, 32K */ i-cache-size = ; timebase-frequency = ; /* from bootloader */ bus-frequency = ; clock-frequency = ; }; }; memory { device_type = "memory"; reg = ; /* 256MB */ }; chosen { name = "chosen"; bootargs = "root=/dev/ram rw console=ttyS0,115200"; linux,stdout-path = "/soc8349@e0000000/serial@4500"; }; };
4.1 Wurzelknoten
Der Ausgangspunkt des Gerätebaums wird als Wurzelknoten „/“ bezeichnet. Das Attributmodell gibt den Namen der Zielplatinenplattform oder des Zielmoduls an, Attribut
Der kompatible Wert gibt den Namen eines kompatiblen Entwicklungsboards in derselben Serie wie das Zielboard an. Für die meisten 32-Bit-Plattformen ist die Eigenschaft
Die Werte von #address-cells und #size-cells sind im Allgemeinen 1.
4.2 CPU-Knoten
Der /cpus-Knoten ist ein untergeordneter Knoten des Stammknotens, und für jede CPU im System gibt es einen entsprechenden Knoten. /cpus-Knoten
Es gibt keine erforderlichen Attribute, aber es empfiehlt sich, #address-cells = und #size-cells = anzugeben, die sich beide auf
beziehen
Verstehen Sie das Reg-Attributformat jedes CPU-Knotens, um die Nummerierung physischer CPUs zu erleichtern.
Dieser Knoten sollte Eigenschaften für jede CPU auf der Platine enthalten. Der CPU-Name wird normalerweise beispielsweise als PowerPC geschrieben
Freescale verwendet PowerPC,8349, um den MPC8349E-Prozessor in diesem Artikel zu beschreiben. Der Einheitenname des CPU-Knotens sollte
sein
Im Format cpu@0 muss dieser Knoten im Allgemeinen den Gerätetyp (fest auf „cpu“) angeben, den Eintrag des Daten-/Anweisungscache der ersten Ebene
Größe, die Größe des Daten-/Befehlscache der ersten Ebene, Kern, Bustaktfrequenz usw. Booten durch das System im obigen Beispiel
Der Code füllt taktfrequenzbezogene Elemente dynamisch aus.
4.3 Systemspeicherknoten
Dieser Knoten wird verwendet, um den physischen Speicherbereich auf der Zielplatine zu beschreiben. Er wird im Allgemeinen als /memory-Knoten bezeichnet. Es können ein oder mehrere Knoten vorhanden sein.
Wenn mehrere Knoten vorhanden sind, muss ihnen zur Unterscheidung die Geräteadresse folgen. Wenn nur eine Geräteadresse vorhanden ist, muss die Geräteadresse nicht geschrieben werden,
Der Standardwert ist 0.
Dieser Knoten enthält die Attribute des physischen Speichers auf der Platine. Im Allgemeinen müssen device_type (festgelegt auf „memory“) und reg angegeben werden
Attribute. Der Attributwert von reg wird in der Form angegeben, wie im obigen Beispiel gezeigt, der Zielplatinenspeicher startet
Die Adresse ist 0 und die Größe beträgt 256 MB.
4.4 /ausgewählter Knoten
Dieser Knoten ist etwas Besonderes. Normalerweise speichert Open Firmware variable Umgebungsinformationen, wie z. B. Parameter,
Standard-Eingabe- und Ausgabegerät.
Die Attributwerte bootargs und linux, stdout-path werden im Allgemeinen in diesem Knoten angegeben. Das Bootargs-Attribut ist so eingestellt, dass es an das interne
übergeben wird
Argumentzeichenfolge für die Kernel-Befehlszeile. Linux, stdout-path ist oft der Knotenpfadname eines Standard-Terminalgeräts und der Kernel verwendet diesen als Referenz
als Standardterminal.
U-Boot hat nach Version 1.3.0 Unterstützung für FDT mit flachem Gerätebaum hinzugefügt, U-Boot lädt den Linux-Kernel,
Nachdem das Ramdisk-Dateisystem (sofern verwendet) und die Gerätebaum-Binärdatei in den physischen Speicher gespiegelt wurden, wird Linux gestartet und ausgeführt
Vor dem Kernel wird die Binärdatei des Gerätebaums geändert. Dadurch wird der Gerätebaum mit den erforderlichen Informationen wie der MAC-Adresse
gefüllt
Anzahl der PCI-Busse usw. U-Boot füllt auch den Knoten „/chosen“ in der Gerätebaumdatei aus, einschließlich serieller Schnittstelle, Root
Gerät (Ramdisk, Festplatte oder NFS-Boot) und andere zugehörige Informationen.
4.5 System-on-Chip-SOC-Knoten
Dieser Knoten wird zur Beschreibung des System-on-Chip-SOC verwendet. Wenn der Prozessor ein SOC ist, muss dieser Knoten vorhanden sein. Top SOC Festival
Die im Punkt enthaltenen Informationen sind für alle Geräte in diesem SOC sichtbar. Der Knotenname sollte die Einheitenadresse dieses SOC enthalten, also dieses SOC
Die Basisadresse des speicherzugeordneten Registers. Der SOC-Knotenname wird in der Form /soc benannt, z. B. der SOC von MPC8349
Der Knoten ist „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系统中不可或缺的一个组件,值得你深入学习和掌握。
Das obige ist der detaillierte Inhalt vonDTS-Transplantation des Linux-Gerätebaums: Beschreiben und Übertragen von Hardwarekonfigurationsinformationen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!