__unflatten_device_tree

来源:互联网 发布:html与css javascript 编辑:程序博客网 时间:2024/06/15 17:07

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_NODEif (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