博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设备树学习:内核对设备树的处理
阅读量:5008 次
发布时间:2019-06-12

本文共 4878 字,大约阅读时间需要 16 分钟。

内核版本:linux-4.19

之前系统的学习了有关设备树的一些知识,时间长了总会有忘记的时候,所以现在把所学到的知识记录下来。

系统启动后,内核会执行一段汇编代码,汇编代码暂不分析,我们从 start_kernel 开始。

优先被初始化的信息

调用流程:

start_kernel    -->setup_arch        -->setup_machine_fdt            -->early_init_dt_verify         /* 验证设备树文件 */            -->of_flat_dt_match_machine     /* 与内核中注册的 machine_desc 进行比较, 最终获取到与之匹配的 machine_desc */                -->arch_get_next_mach       /* 获取到 machine_desc 的 dt_compat 属性 */            -->early_init_dt_scan_nodes     /* 获取到设备树中 chosen、{size,address}-cells、memory 信息 */

early_init_dt_verify 代码:

bool __init early_init_dt_verify(void *params){    if (!params)        return false;    /* 验证设备树的 magic */    if (fdt_check_header(params))        return false;    /* 设置 device-tree 指针 */    initial_boot_params = params;    of_fdt_crc32 = crc32_be(~0, initial_boot_params,                fdt_totalsize(initial_boot_params));    return true;}

of_flat_dt_match_machine 代码:

获取到最为匹配的 machine_desc。

const void * __init of_flat_dt_match_machine(const void *default_match,        const void * (*get_next_compat)(const char * const**)){    ...        while ((data = get_next_compat(&compat))) {            score = of_flat_dt_match(dt_root, compat);            if (score > 0 && score < best_score) {                best_data = data;                best_score = score;            }        }    ...        return best_data;}

early_init_dt_scan_nodes 代码:

/* 扫描 /chosen 节点,处理 bootargs 并保存至 boot_command_line */of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);/* 获取 {size,address}-cells 信息 */of_scan_flat_dt(early_init_dt_scan_root, NULL);/* 设置 memeory */of_scan_flat_dt(early_init_dt_scan_memory, NULL);

通过 early_init_dt_scan_memory 函数,最后调用 memblock_add 来完成 memory 的设置。

设备树展开

接下来,内核会展开设备树,并将节点构建为 device_node。便于系统管理、使用。

调用流程:

start_kernel    -->setup_arch        -->unflatten_device_tree            -->__unflatten_device_tree                -->unflatten_dt_nodes(blob, NULL, dad, NULL);       /* First pass, scan for size */                    -->fdt_next_node                                /* 获取每个 node 的 offsize, 并统计整体大小 */                -->unflatten_dt_nodes(blob, mem, dad, mynodes);     /* Second pass, do actual unflattening */                    -->populate_node

device_node 结构:

struct device_node {    const char *name;   /* 节点的 name 属性 */    const char *type;   /* 节点的 device_type 属性 */    phandle phandle;    const char *full_name;    struct fwnode_handle fwnode;    struct  property *properties;   /* 节点的属性 */    struct  property *deadprops;    /* removed properties */    struct  device_node *parent;    struct  device_node *child;    struct  device_node *sibling;#if defined(CONFIG_OF_KOBJ)    struct  kobject kobj;#endif    unsigned long _flags;    void    *data;#if defined(CONFIG_SPARC)    const char *path_component_name;    unsigned int unique_id;    struct of_irq_controller *irq_trans;#endif};

property 结构:

struct property {    char    *name;  /* 属性名字 */    int length;     /* 属性值长度 */    void    *value; /* 属性值指针 */    struct property *next;#if defined(CONFIG_OF_DYNAMIC) || defined(CONFIG_SPARC)    unsigned long _flags;#endif#if defined(CONFIG_OF_PROMTREE)    unsigned int unique_id;#endif#if defined(CONFIG_OF_KOBJ)    struct bin_attribute attr;#endif};

这些 device_node 构成一棵树,根节点为: of_root。

device_node 转换为 platform_device

调用流程:

arch_initcall_sync(of_platform_default_populate_init);    -->of_platform_default_populate        -->of_platform_populate            -->of_platform_bus_create                -->of_platform_device_create_pdata                    -->of_device_alloc                    -->of_device_add

这时涉及到 initcall 调用问题,应该会在总结。

of_device_alloc 代码:

struct platform_device *of_device_alloc(struct device_node *np, const char *bus_id, struct device *parent){    ...    platform_device_alloc       /* 分配 platform_device */    ...    of_address_to_resource      /* 解析 address 资源 */    ...    of_irq_to_resource_table    /* 解析 irq 资源 */    ...}

of_device_add 代码:

int of_device_add(struct platform_device *ofdev){    BUG_ON(ofdev->dev.of_node == NULL);    ofdev->name = dev_name(&ofdev->dev);    ofdev->id = PLATFORM_DEVID_NONE;    set_dev_node(&ofdev->dev, of_node_to_nid(ofdev->dev.of_node));    return device_add(&ofdev->dev);     /* 添加 device */}
哪些 device_node 可以转换为 platform_device?    1. 根节点下含有 compatile 属性的子节点    2. 如果一个结点的 compatile 属性含有这些特殊的值 ("simple-bus", "simple-mfd", "isa", "arm,amba-bus") 之一,       那么它的子结点(需含 compatile 属性)也可以转换为 platform_device    3. i2c, spi 等总线节点下的子节点,应该交给对应的总线驱动程序来处理,它们不应该被转换为 platform_device。

of_default_bus_match_table 表:

const struct of_device_id of_default_bus_match_table[] = {    { .compatible = "simple-bus", },    { .compatible = "simple-mfd", },    { .compatible = "isa", },#ifdef CONFIG_ARM_AMBA    { .compatible = "arm,amba-bus", },#endif /* CONFIG_ARM_AMBA */    {} /* Empty terminated list */};

转载于:https://www.cnblogs.com/GyForever1004/p/10400266.html

你可能感兴趣的文章
58. Length of Last Word(js)
查看>>
前端面试题汇总(持续更新...)
查看>>
如何成为F1车手?
查看>>
QT自定义消息
查看>>
Save (Not Permitted) Dialog Box
查看>>
装饰模式(Decorator)
查看>>
任务13:在Core Mvc中使用Options
查看>>
利用Excel 2010数据透视图实现数字的可视化的图形直观展示
查看>>
Sort Colors
查看>>
iview树的修改某个节点,树刷新后自动展开你刚才展开的所有节点
查看>>
oracle服务起不来以及无法监听问题解决
查看>>
Mvc--Html.ActionLink()的用法
查看>>
delphi 基础书籍推荐
查看>>
《面向对象程序设计》2018年春学期寒假及博客作业总结
查看>>
iOS开发UI之KVC(取值/赋值) - KVO (观察某个对象的某个属性的改变)
查看>>
1.7 将一个MxN矩阵所有为0的元素所在行和列全部置0
查看>>
删除U盘时提示无法停止‘通用卷’设备的解决方法!!不要每次都硬拔了,对电脑有不小的损害!!!...
查看>>
Java中接口与接口和类之间的关系
查看>>
芯片TPS70925
查看>>
linux shell 发送email 附件
查看>>