__unflatten_device_tree

void __unflatten_device_tree(struct boot_param_header blob,struct device_node **mynodes,void (*dt_alloc)(u64 size, u64 align))
1.解析设备树头信息
2.计算设备节点的个数,根据个数来为设备节点分配内存
3.从设备树上将设备节点解析出来
4.解析完成后,校验一下解析的结果
mem:从ram分配的起始地址,也就是of_allnodes 指针指向的地址
np:设备节点地址
pp:属性地址
ap:别名地址
主要执行的函数是:
unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);
其中,blob:设备树头信息指针(initial_boot_params)。mem:设备节点分配的空间地址start:设备树信息开始的地方,allnextp:指向设备节点头(of_allnodes)。
/**
* unflatten_dt_node - Alloc and populate a device_node from the flat tree
* @blob: The parent device tree blob
* @mem: Memory chunk to use for allocating device nodes and properties
* @p: pointer to node in flat tree
* @dad: Parent struct device_node
* @allnextpp: pointer to ->allnext from last allocated device_node
* @fpsize: Size of the node path up at the current depth.
*/
unsigned long unflatten_dt_node(struct boot_param_header *blob,unsigned long mem,unsigned long *p,struct device_node *dad,struct device_node ***allnextpp,unsigned long fpsize)
{
struct device_node *np;
struct property *pp, **prev_pp = NULL;
char *pathp;
u32 tag;
unsigned int l, allocl;
int has_name = 0;
int new_format = 0;

tag = be32_to_cpup((__be32 *)(*p));          //每个有孩子的设备节点,其tag一定是OF_DT_BEGIN_NODE
if (tag != OF_DT_BEGIN_NODE) {
    pr_err("Weird tag at start of node: %x\n", tag);
    return mem;
}
*p += 4;                                //地址+4,这样指向节点的名称
pathp = (char *)*p;
l = allocl = strlen(pathp) + 1;            //该节点名称的长度
*p = ALIGN(*p + l, 4);                    ///*p 指向带分析的属性

/* version 0x10 has a more compact unit name here instead of the full
 * path. we accumulate the full path size using "fpsize", we'll rebuild
 * it later. We detect this because the first character of the name is
 * not '/'.
 */

 /*计算fullpath的长度 */
if ((*pathp) != '/') {
    new_format = 1;
    if (fpsize == 0) {  //根节点
        /* root node: special case. fpsize accounts for path
         * plus terminating zero. root node only has '/', so
         * fpsize should be 2, but we want to avoid the first
         * level nodes to have two '/' so we use fpsize 1 here
         */
        fpsize = 1;
        allocl = 2;    //要分配的长度
    } else {
        /* account for '/' and path size minus terminal 0
         * already in 'l'
         */
        fpsize += l;    //要分配的长度=本节点名称长度+父亲节点绝对路径的长度
        allocl = fpsize;
    }
}

/* 分配一个设备节点 */
//mem = 0 , np就是分配的 struct device node 大小的内存的指针
np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,  
            __alignof__(struct device_node));
//下面是判断,填充np,构造出device  node
/* allnextpp指向前一个设备链表的指针 */
if (allnextpp) {                            //第二次扫描 nextpp 存在要进入 if 内执行
     memset(np, 0, sizeof(*np));
    np->full_name = ((char *)np) + sizeof(struct device_node);
    if (new_format) {
        char *fn = np->full_name;
        /* rebuild full path for new format */
        if (dad && dad->parent) {
            strcpy(fn, dad->full_name);    //把父亲节点绝对路径先拷贝

ifdef DEBUG

            if ((strlen(fn) + l + 1) != allocl) {
                pr_debug("%s: p: %d, l: %d, a: %d\n",
                    pathp, (int)strlen(fn),
                    l, allocl);
            }

endif

            fn += strlen(fn);
        }
        *(fn++) = '/';
        memcpy(fn, pathp, l);                //拷贝本节点的名称
    } else
        memcpy(np->full_name, pathp, l);
    prev_pp = &np->properties;                //prev_pp指向节点的属性
    **allnextpp = np;                        //当前节点插入链表
    *allnextpp = &np->allnext;
    if (dad != NULL) {                        //父亲节点不为空
        np->parent = dad;                //指向父亲节点
        /* we temporarily use the next field as `last_child'*/
        if (dad->next == NULL)            //第一个孩子
            dad->child = np;                //child指向第一个孩子
        else
            dad->next->sibling = np;        //把np插入next,这样孩子节点形成链表
        dad->next = np;                    //指向最新挂接的child node
    }
    kref_init(&np->kref);
}

/* process properties */
/*分析设备的属性*/
while (1) {
    u32 sz, noff;
    char *pname;

    tag = be32_to_cpup((__be32 *)(*p));
    if (tag == OF_DT_NOP) {                    //空属性,则跳过
        *p += 4;
        continue;
    }

    /* tag不是属性则退出,对于有孩子节点退出时为OF_DT_BEGIN_NODE;
     * 对于叶子节点退出时为OF_DT_END_NODE.
     */                
    if (tag != OF_DT_PROP)     
        break;
    *p += 4;                                //地址加4                
    sz = be32_to_cpup((__be32 *)(*p));        //属性的大小,是以为占多少整形指针计算的。例如网卡interrupts = <35 2 36 2 40 2>;,其值为24
    noff = be32_to_cpup((__be32 *)((*p) + 4));
    *p += 8;                                //指向value
    if (be32_to_cpu(blob->version) < 0x10)
        *p = ALIGN(*p, sz >= 8 ? 8 : 4);

    pname = of_fdt_get_string(blob, noff);    //属性名称
    if (pname == NULL) {
        pr_info("Can't find property name in list !\n");
        break;
    }
    if (strcmp(pname, "name") == 0)        //如果有名称为name的属性
        has_name = 1;
    l = strlen(pname) + 1;
    pp = unflatten_dt_alloc(&mem, sizeof(struct property),
                __alignof__(struct property)); //分配属性结构
    if (allnextpp) {
        /* We accept flattened tree phandles either in
         * ePAPR-style "phandle" properties, or the
         * legacy "linux,phandle" properties.  If both
         * appear and have different values, things
         * will get weird.  Don't do that. */
        if ((strcmp(pname, "phandle") == 0) ||
            (strcmp(pname, "linux,phandle") == 0)) {
            if (np->phandle == 0)
                np->phandle = be32_to_cpup((__be32*)*p);
        }
        /* And we process the "ibm,phandle" property
         * used in pSeries dynamic device tree
         * stuff */
        if (strcmp(pname, "ibm,phandle") == 0)
            np->phandle = be32_to_cpup((__be32 *)*p);
        pp->name = pname;            //属性名
        pp->length = sz;                //长度
        pp->value = (void *)*p;        //属性值
        *prev_pp = pp;                //属性插入属性链表
        prev_pp = &pp->next;
    }
    *p = ALIGN((*p) + sz, 4);            //指向下一个属性
}
/* with version 0x10 we may not have the name property, recreate
 * it here from the unit name if absent
 */
if (!has_name) {                        //如果没有name,就创建一个
    char *p1 = pathp, *ps = pathp, *pa = NULL;
    int sz;

    while (*p1) {
        if ((*p1) == '@')
            pa = p1;
        if ((*p1) == '/')
            ps = p1 + 1;
        p1++;
    }
    if (pa < ps)
        pa = p1;
    sz = (pa - ps) + 1;
    pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
                __alignof__(struct property));
    if (allnextpp) {
        pp->name = "name";
        pp->length = sz;
        pp->value = pp + 1;
        *prev_pp = pp;
        prev_pp = &pp->next;
        memcpy(pp->value, ps, sz - 1);   //名字的值只去其中的@钱的字符,例如pcie@ffe0a000-> pcie
        ((char *)pp->value)[sz - 1] = 0;
        pr_debug("fixed up name for %s -> %s\n", pathp,
            (char *)pp->value);
    }
}
if (allnextpp) {                                        //如果有属性链表
    *prev_pp = NULL;
    np->name = of_get_property(np, "name", NULL);          //设置节点的名称
    np->type   = of_get_property(np, "device_type", NULL);//设置设备类型

    if (!np->name)
        np->name = "<NULL>";
    if (!np->type)
        np->type = "<NULL>";
}
while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) {//对于tag为这2个取值
    if (tag == OF_DT_NOP)                                //空属性则指向下个属性
        *p += 4;
    else
        mem = unflatten_dt_node(blob, mem, p, np, allnextpp,
                    fpsize);                            //OF_DT_BEGIN_NODE则表明其还有子节点,所以递归分析其子节点
    tag = be32_to_cpup((__be32 *)(*p));
}
if (tag != OF_DT_END_NODE) {                            //对于叶子节点或者分析完成
    pr_err("Weird tag at end of node: %x\n", tag);
    return mem;
}
*p += 4;
return mem;

}
设备树中的cpu 设备
enable-method ,通过这个名称,找到cpu.ops,也就是smp_spin_table_ops

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值