Linux 시스템에서 장치 트리는 하드웨어 구성을 설명하는 트리 모양의 데이터 구조입니다. 이는 개방형 펌웨어 표준에서 유래되었으며 시스템을 시작하고 실행하기 위해 운영 체제 소프트웨어와 하드웨어 간의 인터페이스를 제공하는 데 사용됩니다. 장치 트리는 새로운 하드웨어를 지원하고, 코드 재사용을 개선하고, Linux 지원 패키지 개발을 가속화하고, 단일 커널 이미지를 활성화하여 여러 시스템을 지원하기 위해 커널에 필요한 변경 사항을 줄일 수 있습니다. 이 기사에서는 장치 트리의 데이터 저장 형식, 소스 코드 설명 구문, U-Boot 및 Linux 커널 지원, 장치 트리에 대한 구문 분석 프로세스 등을 포함하여 Linux 장치 트리 dts 이식의 기본 단계와 방법을 소개합니다.
키워드: 플랫 장치 트리 Linux
;IBM, Sun 및 기타 제조업체의 서버는 처음에 펌웨어(하드웨어 장치에 내장된 프로그램,
(소프트웨어와 하드웨어 간의 인터페이스를 제공하는 데 사용), 시스템 구성을 초기화하고 운영 체제 소프트웨어와 하드웨어 간의 인터페이스를 제공하는 데 사용됩니다
시스템을 가동하고 실행하기 위한 포트입니다. 이후 표준화와 호환성을 위해 IBM, Sun 등이 공동으로 펌웨어 인터페이스 IEEE 1275
를 출시했습니다.
IBM PowerPC pSeries, Apple PowerPC, Sun SPARC 등과 같은 서버가 모두 Open
을 사용하도록 표준을 준수합니다.
펌웨어는 런타임에 시스템 하드웨어의 장치 트리 정보를 구축하고 이를 커널에 전달하여 시스템을 시작합니다[1]. 이렇게
이점에는 시스템 하드웨어에 대한 커널의 과도한 의존도 감소, 지원 패키지 개발 속도 향상, 하드웨어로 인한 변경 감소 등이 포함됩니다
수요와 비용을 줄이고 커널 설계 및 컴파일 요구 사항을 줄입니다.
Linux/ppc64 커널이 개발됨에 따라 커널 코드는 원래의 arch/ppc32 및 arch/ppc64에서
로 점진적으로 마이그레이션되었습니다.
arch/powerpc 디렉토리를 통합하고 표준 펌웨어 인터페이스를 사용하기 위해 커널 코드에 Open Firmware API를 도입합니다[2].
Linux 커널이 실행 중일 때 하드웨어에 대한 일부 관련 정보를 알아야 합니다. ARCH=powerpc 매개변수로 컴파일된 경우
커널 이미지, 이 정보는 Open Firmware 사양을 기반으로 해야 하며 장치 트리 형태로 존재해야 합니다[3]. 이런 식으로 커널이 시작됩니다
런타임 시 Open Firmware에서 제공하는 장치 트리를 읽고 스캔하여 플랫폼의 하드웨어 장치 정보를 얻고 일치하는 장치를 검색하세요
장치 드라이버를 선택하고 드라이버를 장치에 바인딩합니다.
임베디드 PowerPC에서는 일반적으로 Open Firmware 대신 U-Boot와 같은 시스템 부팅 코드가 사용됩니다.
초기 U-Boot는 보드에 대한 기본 정보를 전송하기 위해 include/asm-ppc/u-boot.h의 정적 데이터 구조 struct bd_t를 사용했습니다
나머지를 처리하는 커널에 이를 전달합니다. 이런 종류의 인터페이스는 유연성이 충분하지 않습니다. 하드웨어가 변경되면 편집 및 굽기를 다시 사용자 정의해야 합니다
부팅 코드와 커널을 작성했는데 더 이상 현재 커널에 적합하지 않습니다. 커널 및 임베디드 PowerPC 개발에 적응하기 위해
끊임없이 변화하는 플랫폼의 장점과 표준 개방형 펌웨어의 장점을 흡수한 U-Boot는 이와 같은 플랫 디바이스 트리 FDT를 도입합니다
별도의 FDT blob(바이너리 대형 객체, 바이너리 파일을 저장할 수 있는 컨테이너)을 사용하는 동적 인터페이스
커널에 전달된 매개변수를 저장합니다[3]. 캐시 크기, 인터럽트 라우팅 등과 같은 일부 특정 정보는 장치 트리에서 직접 제공됩니다.
eTSEC의 MAC 주소, 주파수, PCI 버스 번호 등과 같은 기타 정보는 런타임 시 U-Boot에 의해 수정됩니다.
U-Boot는 bd_t를 플랫 장치 트리로 대체하며 bd_t와의 이전 버전 호환성은 더 이상 보장되지 않습니다.
2 장치 트리 개념
간단히 말해서, 장치 트리는 루트 노드가 하나만 있는 하드웨어 구성을 설명하는 트리 모양의 데이터 구조입니다[4]. 포장됩니다
CPU, 물리적 메모리, 버스, 직렬 포트, PHY 및 기타 주변 장치에 대한 정보가 포함되어 있습니다. 트리는 Open
을 상속받습니다.
펌웨어 IEEE 1275 장치 트리 정의. 운영 체제는 시작 시 이 구조의 구문 분석을 수행하여 다음을 구성할 수 있습니다.
커널을 설정하고 해당 드라이버를 로드합니다.
3 장치 트리 저장 형식
U-Boot는 메모리에 있는 장치 트리의 저장 주소를 커널에 전달해야 합니다. 나무는 주로 머리
세 부분으로 구성됩니다.
(헤더), 구조체 블록(Structure 블록), 문자열 블록(Strings 블록). 메모리에 장치 트리 저장
스토리지 레이아웃 다이어그램 1은 다음과 같습니다.
그림 1 장치 트리 저장 형식 다이어그램
그림1 DT 블록의 레이아웃
3.1 헤더
헤더는 주로 디바이스 트리 매직 넘버 플래그, 디바이스 트리 블록 크기, 구조 블록의 오프셋 주소 등 디바이스 트리의 기본 정보를 설명합니다
등. 구체적인 구조 boot_param_header는 다음과 같습니다. 이 구조의 값은 빅엔디안 모드와 오프셋으로 표현됩니다
주소는 장치 트리 헤드의 시작 주소를 기준으로 계산됩니다.
3.2 구조 블록
플랫 장치 트리 구조 블록은 문자열 블록과 함께 노드가 있는 장치 트리의 본체를 형성하는 선형화된 트리 구조입니다.
타겟 보드의 장치 정보를 양식에 저장합니다. 구조 블록에서 노드 시작 플래그는 상수 매크로 OF_DT_BEGIN_NODE,
입니다.
노드 끝 표시는 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 루트 노드
장치 트리의 시작점을 루트 노드 "/"라고 합니다. 속성 모델은 대상 보드 플랫폼 또는 모듈의 이름인 속성
을 지정합니다.
Compatible 값은 타겟 보드와 동일한 시리즈의 호환 가능한 개발 보드 이름을 나타냅니다. 대부분의 32비트 플랫폼의 경우 속성
#address-cells 및 #size-cells의 값은 일반적으로 1입니다.
4.2 CPU 노드
/cpus 노드는 루트 노드의 자식 노드로, 시스템의 각 CPU마다 해당 노드가 있습니다. /cpus 노드
필수 속성은 없지만 #address-cells = 및 #size-cells =를 지정하는 것이 좋습니다. 둘 다
를 참조합니다.
물리적 CPU 번호 지정을 용이하게 하기 위해 각 CPU 노드의 등록 속성 형식을 이해합니다.
이 노드에는 보드의 각 CPU에 대한 속성이 포함되어야 합니다. CPU 이름은 일반적으로 PowerPC로 작성됩니다(예:
).
Freescale은 이 기사에서 MPC8349E 프로세서를 설명하기 위해 PowerPC,8349를 사용합니다. CPU 노드의 유닛 이름은
이어야 합니다.
CPU@0 형식인 이 노드는 일반적으로 첫 번째 수준 데이터/명령 캐시의 항목인 device_type("cpu"로 고정됨)을 지정해야 합니다
크기, 첫 번째 수준 데이터/명령어 캐시의 크기, 코어, 버스 클럭 주파수 등 위 예의 시스템을 통해 부팅
코드는 클록 주파수 관련 항목을 동적으로 채웁니다.
4.3 시스템 메모리 노드
이 노드는 대상 보드의 물리적 메모리 범위를 설명하는 데 사용됩니다. 일반적으로 /memory 노드라고 합니다.
노드가 여러 개인 경우 구별하기 위해 단위 주소가 뒤에 와야 합니다. 단위 주소가 하나만 있으면 단위 주소를 쓸 필요가 없습니다.
기본값은 0입니다.
이 노드에는 보드의 물리적 메모리 속성이 포함되어 있습니다. 일반적으로 device_type("memory"로 고정) 및 reg를 지정해야 합니다
속성. reg의 속성값은 위의 예시처럼 Target Board Memory Start
형태로 주어집니다.
주소는 0이고 크기는 256M바이트입니다.
4.4 /선택된 노드
이 노드는 조금 특별합니다. 일반적으로 Open Firmware는 매개변수와 같은 다양한 환경 정보를 저장합니다.
기본 입력 및 출력 장치입니다.
bootargs 및 linux, stdout-path 속성 값은 일반적으로 이 노드에 지정됩니다. bootargs 속성이 내부
로 전달되도록 설정되었습니다.
커널 명령줄에 대한 인수 문자열입니다. Linux에서 stdout-path는 종종 표준 터미널 장치의 노드 경로 이름이며 커널은 이를 참조로 사용합니다
기본 터미널로.
U-Boot는 버전 1.3.0 이후 플랫 장치 트리 FDT에 대한 지원을 추가했으며, U-Boot는 Linux 커널을 로드합니다.
Ramdisk 파일 시스템(사용된 경우)과 장치 트리 바이너리가 물리적 메모리에 미러링된 후 Linux가 시작되고 실행됩니다
커널 이전에 장치 트리 바이너리를 수정합니다. MAC 주소,
등 필요한 정보로 장치 트리를 채웁니다.
PCI 버스 수 등 U-Boot는 직렬 포트, 루트를 포함하여 장치 트리 파일의 "/chosen" 노드도 채웁니다.
장치(Ramdisk, 하드 디스크 또는 NFS 부팅) 및 기타 관련 정보.
4.5 시스템 온 칩 SOC 노드
이 노드는 시스템 온 칩 SOC를 설명하는 데 사용됩니다. 프로세서가 SOC인 경우 이 노드가 있어야 합니다. 최고의 SOC 페스티벌
점에 포함된 정보는 이 SOC의 모든 장치에 표시됩니다. 노드 이름에는 이 SOC의 단위 주소, 즉 이 SOC
가 포함되어야 합니다.
메모리 매핑된 레지스터의 기본 주소입니다. SOC 노드 이름은 MPC8349
의 SOC와 같이 /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 중국어 웹사이트의 기타 관련 기사를 참조하세요!