欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Linux DeviceTree学习(三)

程序员文章站 2024-01-23 14:51:28
...

Linux DeviceTree学习(三)

5 设备树移植

5.1 创建设备树文件

以下内容是最简单的设备树文件:

/dts-v1/;

/ {
	#address-cells = <0x1>;
	#size-cells = <0x1>;
	model = "sunxi-v3s";
	compatible = "allwiner,sun8i-v3s";

	chosen {
		#address-cells = <0x1>;
		#size-cells = <0x1>;
		ranges;
		bootargs = "earlyprintk=ttyS0,115200 loglevel=8 initcall_debug=1 console=ttyS0,115200 init=/linuxrc initrd=0x00358000,0x170004";
	};

	cpus {
		#address-cells = <0x1>;
		#size-cells = <0x0>;
		[email protected] {
			compatible = "arm,cortex-a7";
			device_type = "cpu";
			reg = <0x0>;
		};
	};

	memory {
		device_type = "memory";
		reg = <0x0 0x4000000>;		//dtb的存放位置要在该区域内
	};
};

主要内容有根节点的属性、根节点下还有chosen、cpus、memory等几个子节点。
编译成dtb:

./dtc –I dts –O dtb –o sunxi-v3s-v1a-tc05.dtb sunxi-v3s-v1s.dts

5.2 创建machine结构体

/arch/arm/mach-sunxi/sunxi.c

static const char * const sun8i_dt_compat[] =
{
	"allwiner,sun8i-v3s",
	NULL,
};

DT_MACHINE_START(AM780, "am780-tc05-dt")
	.atag_offset	= 0x100,
	.init_machine	= sunxi_dev_init,
	.init_early     = sunxi_init_early,
	.map_io		= sunxi_map_io,
#ifdef CONFIG_OF
	.init_irq	= sun8i_gic_init,
#endif
	.handle_irq	= gic_handle_irq,
	.restart	= sun8i_restart,
	.timer		= &sunxi_timer,
	.dt_compat	= sun8i_dt_compat,	//要与根节点的属性匹配
	.reserve	= sun8i_reserve,
	.fixup		= sun8i_fixup,
	.nr_irqs	= NR_IRQS,
#ifdef CONFIG_SMP
	.smp		= smp_ops(sunxi_smp_ops),
#if defined(CONFIG_ARCH_SUN8IW6) || defined(CONFIG_ARCH_SUN8IW9)
	.smp_init	= smp_init_ops(sun8i_smp_init_ops),
#endif
#endif
MACHINE_END

5.3 配置内核支持Device Tree

make ARCH=arm menuconfig
Boot options  --->
[*] Flattened Device Tree support  
(0) Compressed ROM boot loader base address
(0) Compressed ROM boot loader BSS address
[ ] Use appended device tree blob to zImage (EXPERIMENTAL)

5.4 移植过程疑难点

5.4.1 根节点属性与板子信息匹配

所创建的设备树是否使用与当前开发板,第一个要点就是根节点的属性值要与板子的属性值相匹配,即:名字相等即可。
若不匹配咋回报以下错误,无法启动内核:
Error: unrecognized/unsupported device tree compatible list:
[‘allwiner,sun8i-v3s’ ] ——>此处打印的信息是来自于设备树文件中根节点的属性

Available machine support:

ID (hex) NAME
ffff_ffff allwiner,sun8i-v3s——>此处的信息是来自于DT_MACHINE_START中mdesv中的nr和name,使能Device Tree时nr无需关注(nr为机器码)。
Please check your kernel config and/or bootloader.

排除方法:
1) 首先确认Kernel是否支持Device Tree;
2) 其次确认dtb文件是否能够被Kernel正常解析,获取到根节点的属性信息;
3) 查找mdesv中的成员.dt_compat(const型)的值是否与根节点的属性值相匹配。

5.4.2 paging_init( ) Faild

该函数的条用流程如下:

start_kernel( )->start_arch( )->paging_init( )->devicemap_init( )->
early_alloc( )->early_alloc_aligned( )->memblock_alloc( )->
memblock_alloc_base( )
  • 是由于Kernel启动时,在物理地址的最高处,申请PAGE_SIZE(4KB)大小的内存用于存放中断向量表时,无法申请到内存所导致。
  • 具体原因是因为移植设备树时,在根节点下没有创建memory子节点所导致的。

5.4.3 访问非法内存

出现以下log:

Unable to handle kernel paging request at virtual address C3ffC000

该log的信息表示,0xC3ffC000的地址不可访问,导致异常。
具体是原因如下:
0x03ffC000——dtb的首地址

fdt_base=0x03ffc000-->virtual_adddr=0xC3ffc000

memory节点信息如下:

memory {
		device_type = "memory";
		reg = <0x0 0x03ffc000>;
	};

由于fdt_base未纳入kernel的虚拟地址页表内,因此改地址不可访问,进而导致异常。
修改点:将dtb的首地址纳入Kernel映射的页表内,如下:
Memory节点修改如下:

memory {
		device_type = "memory";
		reg = <0x0 0x03400000>;
	};

设备树dtb文件的首地址改为:0x8000+0x800000(在内核的入口地址上偏移8M)。

参考博客:
Linux设备树解析
ARM Linux 3.x的设备树(Device Tree)–宋宝华
宋牧春:Linux设备树文件结构与解析深度分析(1)