linux设备驱动程序——设备树(1)-dtb转换成device_node

本设备树解析基于arm平台

从start_kernel开始

linux最底层的初始化部分在HEAD.s中,这是汇编代码,我们暂且不作过多讨论,在head.s完成部分初始化之后,就开始调用C语言函数,而被调用的第一个C语言函数就是start_kernel,start kernel原型是这样的:
asmlinkage __visible void __init start_kernel(void)
{
...
setup_arch(&command_line);
...
}
而对于设备树的处理,基本上就在setup_arch()这个函数中。

在这篇文章中,我们分析的方法就是持续地跟踪linux源代码,但是鉴于linux源代码的复杂性,只将程序中相关性较强的部分贴出来进行分析,因为如果去深究细节部分,那只会自讨苦吃。

博主为整个函数调用流程画了一张思维导图,结合思维导图阅读更加清晰,点此下载,博主也将其贴在了文章最后,需要下载查看,网页上查看可能不清晰。

setup_arch

可以看到,在start_kernel()中调用了setup_arch(&command_line);

void __init setup_arch(char **cmdline_p)
{
    const struct machine_desc *mdesc;
    mdesc = setup_machine_fdt(__atags_pointer);
    ...
    arm_memblock_init(mdesc);
    ...
    unflatten_device_tree();
    ...
}

这三个被调用的函数就是主要的设备树处理函数,setup_machine_fdt()函数根据传入的设备树dtb的首地址完成一些初始化操作。

arm_memblock_init()函数主要是内存相关,为设备树保留相应的内存空间,保证设备树dtb本身存在于内存中而不被覆盖。用户可以在设备树中设置保留内存,这一部分同时作了保留指定内存的工作。

unflatten_device_tree()从命名可以看出,这个函数就是对设备树具体的解析,事实上在这个函数中所做的工作就是将设备树各节点转换成相应的struct device_node结构体。

下面我们再来通过代码跟踪仔细分析,先从setup_machine_fdt()开始。

setup_machine_fdt(__atags_pointer)

__atags_pointer这个全局变量存储的就是r2的寄存器值,是设备树在内存中的起始地址,将设备树起始地址传递给setup_machine_fdt,对设备树进行解析。接着跟踪setup_machine_fdt()函数:

const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
{
    const struct machine_desc *mdesc, *mdesc_best = NULL;                    
    if (!dt_phys || !early_init_dt_verify(phys_to_virt(dt_phys)))           ——————part 1
	    return NULL;

    mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach);       ——————part 2

    early_init_dt_scan_nodes();                                             ——————part 3
    ...
}

第一部分先将设备树在内存中的物理地址转换为虚拟地址,然后再检查该地址上是否有设备树的魔数(magic),魔数就是一串用于识别的字节码,如果没有或者魔数不匹配,表明该地址没有设备树文件,函数返回,否则验证成功,将设备树地址赋值给全局变量initial_boot_params。

第二部分of_flat_dt_match_machine(mdesc_best, arch_get_next_mach),逐一读取设备树根目录下的compatible属性。

将compatible中的属性一一与内核中支持的硬件单板相对比,匹配成功后返回相应的machine_desc结构体指针。

machine_desc结构体中描述了单板相关的一些硬件信息,这里不过多描述。

主要的的行为就是根据这个compatible属性选取相应的硬件单板描述信息,一般compatible属性名就是"厂商,芯片型号"。

第三部分就是扫描设备树中的各节点,主要分析这部分代码。

void __init early_init_dt_scan_nodes(void)
{
    of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
    of_scan_flat_dt(early_init_dt_sc
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值