Maison  >  Article  >  Tutoriel système  >  Transplantation DTS de l'arborescence des périphériques Linux : comment décrire et transférer les informations de configuration matérielle

Transplantation DTS de l'arborescence des périphériques Linux : comment décrire et transférer les informations de configuration matérielle

WBOY
WBOYavant
2024-02-13 11:27:12902parcourir

Dans les systèmes Linux, l'arborescence des périphériques est une structure de données en forme d'arborescence qui décrit la configuration matérielle. Elle provient du standard Open Firmware et est utilisée pour fournir une interface entre le logiciel du système d'exploitation et le matériel pour démarrer et exécuter le système. L'arborescence des périphériques peut réduire les modifications nécessaires au noyau pour prendre en charge le nouveau matériel, améliorer la réutilisation du code, accélérer le développement de packages de support Linux et permettre à une seule image du noyau de prendre en charge plusieurs systèmes. Cet article présentera les étapes et méthodes de base de la transplantation dts de l'arborescence de périphériques Linux, y compris le format de stockage des données de l'arborescence de périphériques, la syntaxe de description du code source, la prise en charge d'U-Boot et du noyau Linux et le processus d'analyse des arborescences de périphériques, etc.

Transplantation DTS de larborescence des périphériques Linux : comment décrire et transférer les informations de configuration matérielle

Mots clés : arborescence de périphériques plate ; DTS ; PowerPC ;

Les serveurs d'IBM, Sun et d'autres fabricants utilisaient initialement un Firmware (un programme intégré dans les périphériques matériels, avec

(utilisé pour fournir une interface entre le logiciel et le matériel), utilisé pour initialiser la configuration du système et fournir une interface entre le logiciel du système d'exploitation et le matériel
port pour que le système soit opérationnel. Plus tard, pour des raisons de standardisation et de compatibilité, IBM, Sun, etc. ont lancé conjointement l'interface du micrologiciel IEEE 1275
normes, afin que leurs serveurs tels qu'IBM PowerPC pSeries, Apple PowerPC, Sun SPARC, etc. utilisent tous Open
Le micrologiciel construit les informations sur l'arborescence des périphériques du matériel du système au moment de l'exécution et les transmet au noyau pour démarrer le système [1]. Comme ça
Les avantages incluent la réduction de la forte dépendance du noyau à l'égard du matériel système, l'accélération du développement des packages de support et la réduction des changements causés par le matériel
Cela réduit la demande et les coûts, ainsi que les exigences en matière de conception et de compilation du noyau.

Avec le développement du noyau Linux/ppc64, le code du noyau a progressivement migré des arch/ppc32 et arch/ppc64 d'origine vers

Unifiez le répertoire arch/powerpc et introduisez l'API Open Firmware dans le code du noyau pour utiliser l'interface du firmware standard [2].
Lorsque le noyau Linux est en cours d'exécution, il a besoin de connaître certaines informations pertinentes sur le matériel. Pour ceux compilés avec le paramètre ARCH=powerpc
Image du noyau, ces informations doivent être basées sur la spécification Open Firmware et exister sous la forme d'une arborescence de périphériques [3]. De cette façon, le noyau démarre
Lisez et analysez l'arborescence des périphériques fournie par Open Firmware au moment de l'exécution pour obtenir les informations sur les périphériques matériels de la plate-forme et rechercher les périphériques correspondants
pilote de périphérique et liez le pilote au périphérique.

Dans PowerPC intégré, le code de démarrage du système tel que U-Boot est généralement utilisé à la place de l'Open Firmware.

Les premiers U-Boot utilisaient la structure de données statique struct bd_t dans include/asm-ppc/u-boot.h pour transférer des informations de base sur la carte
Remettez-le au noyau, qui gère le reste. Ce type d'interface n'est pas assez flexible. Si le matériel change, vous devez re-personnaliser la compilation et la gravure
. Écrivez le code de démarrage et le noyau, et ils ne conviennent plus au noyau actuel. Afin de s'adapter au développement du noyau et du PowerPC embarqué
Tirant parti de la plate-forme en constante évolution et absorbant les avantages de l'Open Firmware standard, U-Boot introduit une arborescence de périphériques plate comme celle-ci
Interface dynamique, utilisant un blob FDT distinct (grand objet binaire, un conteneur pouvant stocker des fichiers binaires)
Stocke les paramètres transmis au noyau [3]. Certaines informations, telles que la taille du cache, le routage des interruptions, etc., sont directement fournies par l'arborescence des périphériques,
D'autres informations, telles que l'adresse MAC d'eTSEC, la fréquence, le numéro de bus PCI, etc., sont modifiées par U-Boot au moment de l'exécution.
U-Boot remplace bd_t par une arborescence de périphériques plate et la compatibilité ascendante avec bd_t n'est plus garantie.

2 Concept d'arborescence des appareils En termes simples, l'arborescence des périphériques est une structure de données en forme d'arborescence qui décrit la configuration matérielle, avec un et un seul nœud racine [4]. Ça emballe
Contient des informations sur le processeur, la mémoire physique, le bus, le port série, le PHY et d'autres périphériques. L'arbre hérite d'Open
Définition de l'arborescence des périphériques du micrologiciel IEEE 1275. Le système d'exploitation peut effectuer une analyse syntaxique de cette structure au démarrage, afin de configurer
Configurez le noyau et chargez le pilote correspondant.

3 Format de stockage de l'arborescence des appareils U-Boot doit transmettre l'adresse de stockage de l'arborescence des périphériques en mémoire au noyau. L'arbre est principalement composé de trois parties : la tête
(En-tête), bloc de structure (Bloc de structure), bloc Strings (bloc Strings). Stockage de l'arborescence des appareils en mémoire
Le schéma d'agencement du stockage 1 est le suivant :
Figure 1 Diagramme du format de stockage de l'arborescence des appareils
Fig1 La disposition d'un bloc DT

En-tête 3.1 L'en-tête décrit principalement les informations de base de l'arborescence des périphériques, telles que l'indicateur du numéro magique de l'arborescence des périphériques, la taille du bloc de l'arborescence des périphériques et l'adresse de décalage du bloc de structure
etc. Sa structure spécifique boot_param_header est la suivante. Les valeurs dans cette structure sont exprimées en mode big-endian et offset
L'adresse est calculée par rapport à l'adresse de départ de la tête de l'arborescence des périphériques.

3.2 Bloc de structure Le bloc de structure arborescente plate des appareils est une structure arborescente linéarisée. Avec le bloc de chaînes, il forme le corps principal de l'arborescence des appareils, avec des nœuds
. Enregistrez les informations sur le périphérique de la carte cible dans le formulaire. Dans le bloc de structure, l'indicateur de début du nœud est la macro constante OF_DT_BEGIN_NODE,
La marque de fin de nœud est la macro OF_DT_END_NODE ; les nœuds enfants sont définis avant la marque de fin de nœud. Un nœud peut résumer
Il commence par OF_DT_BEGIN_NODE, inclut le chemin du nœud, la liste d'attributs, la liste des nœuds enfants et se termine enfin par
OF_DT_END_NODE termine la séquence et chaque nœud enfant lui-même a une structure similaire.

3.3 Bloc de cordes
Afin d'économiser de l'espace, certains noms d'attributs, notamment ceux qui apparaissent de manière répétée et redondante, sont extraits et stockés séparément
à un bloc de chaîne. Ce bloc contient un certain nombre de chaînes de noms d'attributs avec des indicateurs de fin. Stocké dans le bloc de structure de l'arborescence des appareils
Les adresses de décalage de ces chaînes, afin que la chaîne du nom d'attribut puisse être facilement trouvée. L'introduction de blocs de chaînes permet d'économiser l'intégration
L'espace de stockage du système intégré est restreint.

4 Représentation DTS du code source de l'arborescence des appareils
Le fichier de code source de l'arborescence des périphériques (.dts) décrit l'arborescence des périphériques de configuration matérielle du système dans un format texte lisible et modifiable, prenant en charge C/C++
Commentaires au passage, la structure a un nœud racine unique "/", chaque nœud a son propre nom et peut en contenir plusieurs
nœud enfant. Le format des données de l'arborescence des périphériques suit la norme Open Firmware IEEE 1275. Cet article ne décrit que brièvement l'arborescence des appareils
Pour la présentation et la syntaxe des données, les développeurs de packages de support de carte Linux doivent se référer à la norme IEEE 1275 [5] et à d'autres documents [2] [4] pour plus de détails.
Pour illustrer, donnons d’abord un exemple du code source de l’arborescence des périphériques d’un système minimal basé sur le processeur PowerPC MPC8349E.
Comme vous pouvez le voir, il existe de nombreux nœuds dans cette arborescence de périphériques, et chaque nœud a un nom d'unité de nœud spécifié. Derrière chaque attribut se trouve
Donnez la valeur correspondante. Le contenu entre guillemets doubles est une chaîne ASCII et le contenu indiqué entre crochets est un hexadécimal de 32 bits
valeur. Cette structure arborescente est un ensemble simplifié de nœuds et d'attributs requis pour démarrer le noyau Linux, y compris le mode de base du nœud racine
Informations, configuration du processeur et de la mémoire physique, il comprend également les informations sur les arguments de ligne de commande transmises au noyau via le nœud /chosen.

/ {
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 Nœud racine
Le point de départ de l'arborescence des périphériques est appelé le nœud racine "/". Le modèle d'attribut spécifie le nom de la plateforme ou du module de la carte cible, attribut
La valeur compatible indique le nom d'une carte de développement compatible dans la même série que la carte cible. Pour la plupart des plateformes 32 bits, la propriété
Les valeurs de #address-cells et #size-cells sont généralement 1.

4.2 Nœud CPU
Le nœud /cpus est un nœud enfant du nœud racine et il existe un nœud correspondant pour chaque processeur du système. /nœud CPU
Il n'y a pas d'attributs obligatoires, mais c'est une bonne pratique de spécifier #address-cells = et #size-cells =, qui font tous deux référence à
Comprenez le format d'attribut reg de chaque nœud CPU pour faciliter la numérotation des CPU physiques.

Ce nœud doit contenir les propriétés de chaque processeur de la carte. Le nom du processeur est généralement écrit comme PowerPC, par exemple
Freescale utilisera PowerPC,8349 pour décrire le processeur MPC8349E dans cet article. Le nom de l'unité du nœud CPU doit être
Le format de cpu@0, ce nœud doit généralement spécifier device_type (fixé à "cpu"), l'entrée du cache de données/instructions de premier niveau
Taille, taille du cache de données/instructions de premier niveau, cœur, fréquence d'horloge du bus, etc. Démarrage via le système dans l'exemple ci-dessus
Le code remplit dynamiquement les éléments liés à la fréquence d'horloge.

4.3 Nœud de mémoire système
Ce nœud est utilisé pour décrire la plage de mémoire physique sur la carte cible. Il est généralement appelé nœud /memory. Il peut y avoir un ou plusieurs nœuds.
Lorsqu'il y a plusieurs nœuds, ils doivent être suivis de l'adresse de l'unité pour les distinguer ; lorsqu'il n'y a qu'une seule adresse d'unité, l'adresse de l'unité n'a pas besoin d'être écrite,
La valeur par défaut est 0.

Ce nœud contient les attributs de la mémoire physique de la carte. Généralement, device_type (fixé à "memory") et reg doivent être spécifiés
Les attributs. La valeur d'attribut de reg est donnée sous la forme, comme le montre l'exemple ci-dessus, que la mémoire de la carte cible démarre
L'adresse est 0 et la taille est de 256 Mo d'octets.

4.4 /nœud choisi
Ce nœud est un peu spécial. Habituellement, Open Firmware stocke des informations variables sur l'environnement, telles que les paramètres,
Périphérique d'entrée et de sortie par défaut.
Les valeurs des attributs bootargs et linux, stdout-path sont généralement spécifiées dans ce nœud. L'attribut bootargs est configuré pour être transmis à l'interne
Chaîne d’argument pour la ligne de commande du noyau. Linux, stdout-path est souvent le nom du chemin du nœud d'un périphérique terminal standard, et le noyau l'utilisera comme référence
comme terminal par défaut.

U-Boot a ajouté la prise en charge de l'arborescence de périphériques plate FDT après la version 1.3.0, U-Boot charge le noyau Linux,
Une fois le système de fichiers Ramdisk (le cas échéant) et le binaire de l'arborescence des périphériques mis en miroir dans la mémoire physique, Linux est démarré et exécuté
Avant le noyau, il modifie le binaire de l'arborescence des périphériques. Il remplira l'arborescence des appareils avec les informations nécessaires telles que l'adresse MAC,
Nombre de bus PCI, etc. U-Boot remplira également le nœud "/chosen" dans le fichier de l'arborescence des périphériques, y compris le port série et la racine
Périphérique (disque RAM, disque dur ou démarrage NFS) et autres informations associées.

4.5 Système sur puce SOC Noeud
Ce nœud permet de décrire le système sur puce SOC. Si le processeur est un SOC, ce nœud doit exister. Meilleur festival SOC
Les informations contenues dans le point sont visibles par tous les appareils sur ce SOC. Le nom du nœud doit contenir l'adresse de l'unité de ce SOC, c'est-à-dire ce SOC
L'adresse de base du registre mappé en mémoire. Le nom du nœud SOC est nommé sous la forme /soc, comme le SOC de MPC8349
Le nœud est « soc8349 ».

在属性中应该指定device_type(固定为”soc”)、ranges、bus-frequency 等属性。ranges
属性值以的形式指定。SOC 节点还包含目标板使用的每个
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系统中不可或缺的一个组件,值得你深入学习和掌握。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer