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>;
cpu@0 {
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)