dtc(device tree compiler)中'-@'参数的作用

在谷歌的文档中:
编译和验证 | Android 开源项目 | Android Open Source Project

使用 dtc 编译 .dts 时,您必须添加选项 -@ 以在生成的 .dtbo 中添加 symbols 节点。symbols 节点包含所有带标签节点的列表,DTO 库可使用这个列表作为参考。

在kernel的文档中:
Devicetree Overlay Notes — The Linux Kernel documentation
先给出了一个例子
[foo.dts](base dtb)

/* FOO platform */
/dts-v1/;
/ {
        compatible = "corp,foo";

        /* shared resources */
        res: res {
        };

        /* On chip peripherals */
        ocp: ocp {
                /* peripherals that are always instantiated */
                peripheral1 { ... };
        };
};

[bar.dts](overlay dt)

/dts-v1/;
/plugin/;
&ocp {
        /* bar peripheral */
        bar {
                compatible = "corp,bar";
                ... /* various properties and child nodes */
        };
};

[foo+bar.dts] (merge之后)

/* FOO platform + bar peripheral */
/ {
        compatible = "corp,foo";

        /* shared resources */
        res: res {
        };

        /* On chip peripherals */
        ocp: ocp {
                /* peripherals that are always instantiated */
                peripheral1 { ... };

                /* bar peripheral */
                bar {
                        compatible = "corp,bar";
                        ... /* various properties and child nodes */
                };
        };
};

As a result of the overlay, a new device node (bar) has been created so a bar platform device will be registered and if a matching device driver is loaded the device will be created as expected.

If the base DT was not compiled with the -@ option then the “&ocp” label will not be available to resolve the overlay node(s) to the proper location in the base DT. In this case, the target path can be provided. The target location by label syntax is preferred because the overlay can be applied to any base DT containing the label, no matter where the label occurs in the DT.

是不是和我一样没有看懂呢?看来只有实践才能出真知,我今天使用i.mx8mn evk board做一个探究。
根据上面的描述,猜测-@与设备树中的lable,target path有关。众所周知,dtc使用phandle属性标识lable,每个phandle属性的值在它所属的dts中都是独一无二的,kernel或者uboot通过phandle找到lable对应的target path,但是overlay dt是独立编译的,那么dtc是怎么给overlay dt中引用的lable分配phandle属性的呢?答案是不分配,dtc会给overlay dt分配一个fixups节点,uboot根据这个节点提供的信息在base dtb中寻找相应target path,并给他添加phandle属性。
0、搭建测试环境
给8mn的设备树中添加一个自己的节点my_node,并给它一个my_lable:

// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
 * Copyright 2019 NXP
 */

#include <dt-bindings/usb/pd.h>
#include "imx8mn.dtsi"

/ {
        chosen {
                stdout-path = &uart2;
        };

        gpio-leds {
                compatible = "gpio-leds";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_gpio_led>;

                status {
                        label = "yellow:status";
                        gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>;
                        default-state = "on";
                };
        };

        my_lable: my_node {
                compatible = "Maximus Sun";
        };
        ...

1、在overlay dt中使用target path
如果想容易点实现dt overlay功能,最简单的办法是在overlay dt中使用target path
写一个overlay dt,这个文件将会merge到我在base dt中创建的节点。注意我这里使用了target path:
[my_overlay_dt-a.dts]

/dts-v1/;
/plugin/;

&{/my_node} {
        maximus = "Maximus_Sun";

        handsome {
                first_name = "Maximus";
                second_name = "Sun";
        };
};

使用dtc编译,然后dump出来

maximus@maximus-OptiPlex-7090:~/dtbo$ dtc -O dtb -o my_overlay_dt-a.dtb my_overlay_dt-a.dts
maximus@maximus-OptiPlex-7090:~/dtbo$ dtc -O dts -o dtbo_a.dts my_overlay_dt-a.dtb
maximus@maximus-OptiPlex-7090:~/dtbo$ vim dtbo_a.dts
/dts-v1/;

/ {

        fragment@0 {
                target-path = "/my_node";

                __overlay__ {
                        maximus = "Maximus_Sun";

                        handsome {
                                first_name = "Maximus";
                                second_name = "Sun";
                        };
                };
        };
};

注意到dtc添加了一个target-path属性
使用mkdtimg打包

mkdtimg create dtbo.img imx8mn-evk.dtb --id=0 my_overlay_dt-a.dtb --id=1

其中第一个dtb是base dtb,第二个dtb是overlay dtb
将生成的dtbo.img烧进对应的partition即可正常启动,可以在/proc/device-tree/下面找到自己的节点:


image.png

2、在overlay dt中使用lable
将overlay dt中的target path更换为label
[my_overlay_dt-a.dts]

/dts-v1/;
/plugin/;

&my_lable {
        maximus = "Maximus_Sun";

        handsome {
                first_name = "Maximus";
                second_name = "Sun";
        };
};

使用dtc编译,然后dump出来

/dts-v1/;

/ {

        fragment@0 {
                target = <0xffffffff>;

                __overlay__ {
                        maximus = "Maximus_Sun";

                        handsome {
                                first_name = "Maximus";
                                second_name = "Sun";
                        };
                };
        };

        __fixups__ {
                my_node = "/fragment@0:target:0";
        };
};

注意到target-path属性已经被target替代,target属性被赋了一个无效值,并且增加了fixups节点。
重复之前步骤,uboot启动失败了,看一下给出的提示:

failed on fdt_overlay_apply()
base fdt does did not have a /__symbols__ node
make sure you've compiled with -@
Failed to apply overlay 1

所以在编译base dtb的时候需要添加-@参数来生成symbols节点,所以我在AOSP的编译脚本中手动添加了-@参数,重复上面的步骤,成功启动,my_node也出现在设备树节点列表中:


image.png

(不少资料都说overlay dt编译时也需要添加-@参数,但是其实是不起作用的,-@并不会给overlay dt添加symbols节点,也不会影响运行)
3、-@做了什么?
首先,对base dt使用-@进行编译,dtc会添加一个symbols节点,它记录了base dt中所有lable对应的target path,这一点可以通过dump base dtb看出来:

        __symbols__ {
                cpu_pd_wait = "/cpus/idle-states/cpu-pd-wait";
                A53_0 = "/cpus/cpu@0";
                A53_1 = "/cpus/cpu@1";
                A53_2 = "/cpus/cpu@2";
                A53_3 = "/cpus/cpu@3";
                A53_L2 = "/cpus/l2-cache0";
                a53_opp_table = "/opp-table";
                resmem = "/reserved-memory";
                osc_32k = "/clock-osc-32k";
                osc_24m = "/clock-osc-24m";
                clk_ext1 = "/clock-ext1";
                clk_ext2 = "/clock-ext2";
                clk_ext3 = "/clock-ext3";
                clk_ext4 = "/clock-ext4";
                hsiomix_pd = "/power-domains/hsiomix-pd";
                usb_otg1_pd = "/power-domains/usbotg1-pd";
                gpumix_pd = "/power-domains/gpumix-pd";
                dispmix_pd = "/power-domains/dispmix-pd";
                mipi_pd = "/power-domains/mipi-pd";
                ...

同样可以在下位机中cat symbols节点下面的属性得到证实

evk_8mn:/proc/device-tree/__symbols__ # cat my_lable
/my_nodeevk_8mn:/proc/device-tree/__symbols__ #

继续深究,打开vendor/nxp-opensource/uboot-imx/scripts/dtc/libfdt/fdt_overlay.c中的fdt_overlay_apply函数定义部分

int fdt_overlay_apply(void *fdt, void *fdto)
{
        uint32_t delta;
        int ret;

        FDT_RO_PROBE(fdt);
        FDT_RO_PROBE(fdto);

        ret = fdt_find_max_phandle(fdt, &delta);
        if (ret)
                goto err;

        ret = overlay_adjust_local_phandles(fdto, delta);
        if (ret)
                goto err;

        ret = overlay_update_local_references(fdto, delta);
        if (ret)
                goto err;

        ret = overlay_fixup_phandles(fdt, fdto);
        if (ret)
                goto err;

        ret = overlay_merge(fdt, fdto);
        if (ret)
                goto err;

        ret = overlay_symbol_update(fdt, fdto);
        if (ret)
                goto err;

        /*
         * The overlay has been damaged, erase its magic.
         */
        fdt_set_magic(fdto, ~0);

        return 0;

err:
        /*
         * The overlay might have been damaged, erase its magic.
         */
        fdt_set_magic(fdto, ~0);

        /*
         * The base device tree might have been damaged, erase its
         * magic.
         */
        fdt_set_magic(fdt, ~0);

        return ret;
}

看函数名字也可以猜出这里是做什么的,看来uboot在做merge工作的时候大部分工作在处理phandle,打开overlay_fixup_phandles函数定义部分:

static int overlay_fixup_phandles(void *fdt, void *fdto)
{
        int fixups_off, symbols_off;
        int property;

        /* We can have overlays without any fixups */
        fixups_off = fdt_path_offset(fdto, "/__fixups__");
        if (fixups_off == -FDT_ERR_NOTFOUND)
                return 0; /* nothing to do */
        if (fixups_off < 0)
                return fixups_off;

        /* And base DTs without symbols */
        symbols_off = fdt_path_offset(fdt, "/__symbols__");
        if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
                return symbols_off;

        fdt_for_each_property_offset(property, fdto, fixups_off) {
                int ret;

                ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
                if (ret)
                        return ret;
        }

        return 0;
}

uboot找到overlay dtb中的fixups节点,和base dtb的symbols节点,之后的fdt_for_each_property_offset是一个宏定义,其实是在遍历fixups节点中的属性,并根据属性提供的内容在symbols节点中找到正确的target path,

#define fdt_for_each_property_offset(property, fdt, node)   \
      for (property = fdt_first_property_offset(fdt, node); \
         property >= 0;                 \
         property = fdt_next_property_offset(fdt, property))

overlay_fixup_phandle根据前面收集到的信息为overlay dtb创建正确的phandle属性
到这里-@参数的作用就可以弄清楚了,所以说如果我们的overlay dts中使用到了lable,编译base dts的时候就一定要加-@,如果overlay dts仅仅使用target path,就可以不使用-@编译base dts

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容