首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

Linux设备树详解(一) 基础知识

  • 24-03-05 06:41
  • 4382
  • 7865
blog.csdn.net

关于设备树,之前就经过详细的系统培训,但是本着会用就行的原则,对各个知识点都没有进行系统的总结。都是用到哪里学哪里,时间长了,基本也忘记了。所以对于后期知识各个知识点进行总结,本章主要讨论一下内容,能看懂和修改对应模块的dts文件。

  1. dts的引入
  2. dts的基本语法和基本格式介绍
  3. dts的组成,各个模块使用方法

1. dts为何物

在传统Linux内核中,ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/mach-xxx,比如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data,这些板级细节代码对内核来讲只不过是垃圾代码。而采用Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码。导致ARM的merge工作量较大,其次ARM很多的代码都是垃圾,代码里面有若干愚蠢的table,而多个人在维护这个table,从而导致了冲突。最后linux发出

 Gaah.Guys, this whole ARM thing is a f*cking pain in the ass.

    之后经过一些讨论,对ARM平台的相关code做出如下相关规范调整,这个也正是引入DTS的原因。

    1、ARM的核心代码仍然保存在arch/arm目录下
    2、ARM SoC core architecture code保存在arch/arm目录下
    3、ARM SOC的周边外设模块的驱动保存在drivers目录下
    4、ARM SOC的特定代码在arch/arm/mach-xxx目录下
    5、ARM SOC board specific的代码被移除,由DeviceTree机制来负责传递硬件拓扑和硬件资源信息。

    本质上,Device Tree改变了原来用code方式将HW配置信息嵌入到内核代码的方法,改用bootloader传递一个DB的形式。对于嵌入式系统,在系统启动阶段,bootloader会加载内核并将控制权转交给内核,此外,还需要把上述的三个参数信息传递给kernel,以便kernel可以有较大的灵活性。在linux kernel中,Device Tree的设计目标就是如此。
    在devie tree中,可描述的信息包括:

    1、CPU的数量和类别
    2、内存基地址和大小
    3、总线和桥
    4、外设连接
    5、中断控制器和中断的使用情况
    6、GPIO控制器和GPIO使用情况
    7、clock控制器和clock使用情况

    它基本就是一棵电路板上的CPU、总线、设备组成的树,Bootloader会将这棵树传递给内核,然后内核来识别这棵树,并根据它展开出Linux内核中的platform_device、i2c_client、spi_device等设备,而这些设备用到的内存、IRQ等资源,也被传递给内核,内核会将这些资源绑定给展开的相应设备

    2. DTS基本知识

    2.1 dts

    硬件的相应信息都会写在.dts为后缀的文件中,每一款硬件可以单独写一份xxxx.dts,一般在Linux源码中存在大量的dts文件,对于arm架构可以在arch/arm/boot/dts找到相应的dts,一个dts文件对应一个ARM的machie。

    2.2 dtsi

    值得一提的是,对于一些相同的dts配置可以抽象到dtsi文件中,然后类似于C语言的方式可以include到dts文件中,对于同一个节点的设置情况,dts中的配置会覆盖dtsi中的配置。

    2.3 dtc

    dtc是编译dts的工具,可以在Ubuntu系统上通过指令apt-get install device-tree-compiler安装dtc工具,不过在内核源码scripts/dtc路径下已经包含了dtc工具;

    2.4 dtb

    dtb(Device Tree Blob),dts经过dtc编译之后会得到dtb文件,dtb通过Bootloader引导程序加载到内核。所以Bootloader需要支持设备树才行;Kernel也需要加入设备树的支持;

    3. DTS结构

    /dts-v1/;
    / {
        node1 {
            a-string-property = "A string";
            a-string-list-property = "first string", "second string";
            // hex is implied in byte arrays. no '0x' prefix is required
            a-byte-data-property = [01 23 34 56];
            child-node1 {
                first-child-property;
                second-child-property = <1>;
                a-string-property = "Hello, world";
            };
            child-node2 {
            };
        };
        node2 {
            an-empty-property;
            a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */
            child-node1 {
            };
        };
    };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    device tree的基本单元是node。这些node被组织成树状结构,除了root node,每个node都只有一个parent。一个device tree文件中只能有一个root node。每个node中包含了若干的property/value来描述该node的一些特性。每个node用节点名字(node name)标识,节点名字的格式是node-name@unit-address。如果该node没有reg属性(后面会描述这个property),那么该节点名字中必须不能包括@和unit-address。unit-address的具体格式是和设备挂在那个bus上相关。例如对于cpu,其unit-address就是从0开始编址,以此加一。而具体的设备,例如以太网控制器,其unit-address就是寄存器地址。root node的node name是确定的,必须是“/”。 也就是说设备树源文件的结构为

    • 1个root节点”/”;
    • root节点下面含一系列子节点,“node1” and “node2”
    • 节点node1和下又含有一系列子节点,“child-node1” and “child-node2”
    • 各个节点都有一系列属性
      • 这些属性可能为空,如an-empty-property
      • 可能为字符串,如a-string-property
      • 可能为字符串树组,如a-string-list-property
      • 可能为Cells(由u32整数组成),如second-child-property

    4 DTS语法介绍

    了解了基本的device tree的结构后,我们总要把这些结构体现在device tree source code上来。在linux kernel中,扩展名是dts的文件就是描述硬件信息的device tree source file,在dts文件中,一个node被定义成:

    [label:] node-name[@unit-address] {
       [properties definitions]
       [child nodes]
    } 
    
    • 1
    • 2
    • 3
    • 4

    “[]”表示option,因此可以定义一个只有node name的空节点,label方便在dts文件中引用
    基本数据类型:

    • text string(以null结束),以双引号括起来,如:
      • string-property = “a string”
    • cells 是32位无符号整形数,以尖括号括起来,如
      • cell-property = <0xbeef 123 0xabcd1234>
    • binary data 以方括号括起来,如:
      • binary-property = [0x01 0x23 0x45 0x67];
    • 不同类型数据可以在同一个属性中存在,以逗号分格,如:
      • mixed-property = “a string”, [0x01 0x23 0x45 0x67], <0x12345678>;
    • 多个字符串组成的列表也使用逗号分格,如:
      • string-list = “red fish”,“blue fish”;

    5 dts的组成

    5.1 标准属性

    5.1.1 compatible

    每一个dts文件都是由一个root的根节点组成,内核通过根节点“/”的兼容性即可判断它启动的是什么设备,其代码结构如下

    / {
    	model = "Spreadtrum SC9830A-5 V1.0.0 Smartphone Board";
    
    	compatible = "sprd,sp9830a-5h10-ga1", "sprd,sc9830";
    
    	chosen {
    		bootargs = "earlycon=sprd_serial,0x70100000,115200n8 loglevel=8 console=ttyS1,115200n8 init=/init root=/dev/ram0 rw androidboot.hardware=sc9830";
    		linux,initrd-start = <0x85500000>;
    		linux,initrd-end = <0x855a3212>;
    	};
    };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    1. model属性值是,它指定制造商的设备型号。推荐的格式是:“manufacturer,model”,其中manufacturer是一个字符串描述
      制造商的名称,而型号指定型号。
    2. compatible属性值是,指定了系统的名称,是一个字符串列表,它包含了一个“<制造商>,<型号>”形式的字符串。重要的是要指定一个确切的设备,并且包括制造商的名字,以避免命名空间冲突。
    3. chosen 节点不代表一个真正的设备,但功能与在固件和操作系统间传递数据的地点一样,如根参数,取代以前bootloader的启动参数,控制台的输入输出参数等

    5.1.2 #address-cells和#size-cells

    • #address-cells = <1>: 基地址、片选号等绝对起始地址所占字长,单位uint32
    • #size-cells = <1>: 长度所占字长,单位uint32
    soc {
    	#address-cells = <1>;
    	#size-cells = <1>;
    	serial {
    		compatible = "ns16550";
    		reg = <0x4600 0x100>;
    		clock-frequency = <0>;
    		interrupts = <0xA 0x8>;
    		interrupt-parent = <&ipic>;
    	};
    };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    5.1.3 CPU addressing

    在讨论寻址时,CPU节点代表了最简单的情况。 每个CPU都分配有一个唯一的ID,并且没有与CPU ID相关联的大小。

      cpus {
            #address-cells = <1>;
            #size-cells = <0>;
            cpu@0 {
                compatible = "arm,cortex-a9";
                reg = <0>;
            };
            cpu@1 {
                compatible = "arm,cortex-a9";
                reg = <1>;
            };
        };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在cpus节点,#address-cells被设置成了1,#size-cells被设置成了0。这是说子reg值是单独的uint32,它用无大小字段表示地址。在此情况下,这两个cpu分配到的地址为0和1。Cpu节点的#size-cells是0因为每个cpu只分配到了一个单独的地址。
    你仍然需要注意reg值班需要与节点名的值相匹配。按照惯例,如果一个节点有一个reg属性,那么这个节点名称必须包括unit-address,这是reg属性的第一个address值。

    5.1.4 Memory Mapped Devices

    与在cpu节点中单独的address值不同,内存映射设备被分配了一系列将要响应的地址,因此不仅需要包含内存的基地址而且还需要映射地址的长度,因此需要使用#size-cells用来表示在每个子reg元组中长度字段的大小。在以下示例中,每个address值为1 cell(32 bits),每个长度值也是1 cell,这在32 bit系统是比较典型的。64 bit设备也许会为#address-cells和#size-cells使用数值2,在device tree中获取64 bit addressing。

    /dts-v1/;
    
    / {
        #address-cells = <1>;
        #size-cells = <1>;
        ...
        serial@101f0000 {
            compatible = "arm,pl011";
            reg = <0x101f0000 0x1000 >;
        };
    
        serial@101f2000 {
            compatible = "arm,pl011";
            reg = <0x101f2000 0x1000 >;
        };
    
        gpio@101f3000 {
            compatible = "arm,pl061";
            reg = <0x101f3000 0x1000
                   0x101f4000 0x0010>;
        };
    
        interrupt-controller@10140000 {
            compatible = "arm,pl190";
            reg = <0x10140000 0x1000 >;
        };
    
        spi@10115000 {
            compatible = "arm,pl022";
            reg = <0x10115000 0x1000 >;
        };
        ...
    };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    5.1.5 Non Memory Mapped Devices

    处理器总线的其它设备为非内存映射设备。他们有地址范围,但不能被CPU直接寻址。母设备的驱动程序将代替CPU进行间接访问。以i2c设备为例,每个设备都分配了一个地址,但没有长度或范围与之相匹配。这与CPU地址分配很相似。

     i2c@1,0 {
         compatible = "acme,a1234-i2c-bus";
         #address-cells = <1>;
         #size-cells = <0>;
         reg = <1 0 0x1000>;
         rtc@58 {
             compatible = "maxim,ds1338";
             reg = <58>;
         };
     };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5.1.6 Ranges (Address Translation)

    我们已经讨论过如何向设备分配地址,但此时这些地址只是本地设备节点,还没有说明如何从那些地址里映射到cpu可以使用的地址。根节点经常描述地址空间的CPU视图。根节点的子节点已经使用了CPU的address domain,所以不需要任何明确的映射。例如,serial@101f0000设备被直接分配了地址0x101f0000。
    根节点的非直接子节点是无法使用CPU的address domain的。为了在deivce tree获取内存映射地址必须指定如何从一个域名将地址转换到另一个。Ranges属性就用于此目的。以下是添加了ranges属性的device tree示例。

    /dts-v1/;
    / {
        compatible = "acme,coyotes-revenge";
        #address-cells = <1>;
        #size-cells = <1>;
        ...
        external-bus {
            #address-cells = <2>
            #size-cells = <1>;
            ranges = <0 0  0x10100000   0x10000     // Chipselect 1, Ethernet
                      1 0  0x10160000   0x10000     // Chipselect 2, i2c controller
                      2 0  0x30000000   0x1000000>; // Chipselect 3, NOR Flash
    
            ethernet@0,0 {
                compatible = "smc,smc91c111";
                reg = <0 0 0x1000>;
            };
    
            i2c@1,0 {
                compatible = "acme,a1234-i2c-bus";
                #address-cells = <1>;
                #size-cells = <0>;
                reg = <1 0 0x1000>;
                rtc@58 {
                    compatible = "maxim,ds1338";
                    reg = <58>;
                };
            };
    
            flash@2,0 {
                compatible = "samsung,k8f1315ebm", "cfi-flash";
                reg = <2 0 0x4000000>;
            };
        };
    };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    Ranges是一个地址转换列表。每个输入ranges表格的是包含子地址的元组,母地址和子地址空间的范围大小。每个字段的大小都由获取的子地址的#address-cells值,母地址的#address-cell值和子地址的#size-cells值而定。以外部总线为例,子地址是2 cells,母地址是1 cell,大小也为1 cell。转换三个ranges:

    • Offset 0 from chip select 0 is mapped to address range 0x10100000…0x1010ffff
    • Offset 0 from chip select 1 is mapped to address range 0x10160000…0x1016ffff
    • Offset 0 from chip select 2 is mapped to address range 0x30000000…0x30ffffff

    例如上面的总线是有片选的,就需要描述片选及片选的偏移量,在说明地址时,还需要说明地址映射范围

    5.1.7 status

    device tree中的status标识了设备的状态,使用status可以去禁止设备或者启用设备,看下设备树规范中的status可选值

    valueDescription
    “okay”表示设备正在运行
    “disabled”表示该设备目前尚未运行,但将来可能会运行
    “fail”表示设备无法运行。 在设备中检测到严重错误,确实如此没有修理就不可能投入运营
    “fail-sss”表示设备无法运行。 在设备中检测到严重错误,它是没有修理就不可能投入运营。 值的sss部分特定于设备并指示检测到的错误情况

    5.2 中断映射

    与遵循树的自然结构而进行的地址转换不同,机器上的任何设备都可以发起和终止中断信号。另外地址的编址也不同于中断信号,前者是设备树的自然表示,而后者者表现为独立于设备树结构的节点之间的链接。 下图显示了设备的自然结构以及每个节点在逻辑中断树中的位置。
    在这里插入图片描述
    上图包括以下部分:

    • open-pic中断控制器是中断树的根
    • 中断树根有三个子设备,它们将中断直接路由到open-pic
      • device1
      • PCI host controller
      • GPIO Controller
    • 存在三个中断域; 一个以开放式pic节点为根,一个在PCI主桥节点,一个在GPIO Controller节点上
    • 有两个nexus节点; 一个位于PCI主桥,一个位于GPIO控制器。
    属性属性值描述
    #interruptsprop-encoded-array一个设备节点属性,该属性主要描述了中断的HW interrupt ID以及类型
    #interrupt-parentphandle该属性主要描述了该设备的interrupt request line连接到哪一个interrupt controller,那些没有 interrupt-parent 的节点则从它们的父节点中继承该属性
    #interrupts-extendedphandle prop-encoded-array列出了设备生成的中断,当设备连接到多个中断控制器
    #interrupt-cellsu32这是中断控制器节点的属性,用来标识这个控制器需要几个单位做中断描述符(类似于 #address-cells 和 #size-cells),则子节点的interrupts一个cell三个32bits整型值: <中断域 中断 触发方式>
    #interrupt-controllerempty一个空属性用来声明这个node接收中断信号

    下面显示了具有PCI总线控制器和采样中断的设备片段

    soc {
    	compatible = "simple-bus";
    	#address-cells = <1>;
    	#size-cells = <1>;
    	open-pic {
    		clock-frequency = <0>;
    		interrupt-controller;
    		#address-cells = <0>;
    		#interrupt-cells = <2>;
    	};
    	pci {
    		#interrupt-cells = <1>;
    		#size-cells = <2>;
    		#address-cells = <3>;
    		interrupt-map-mask = <0xf800 0 0 7>;
    		interrupt-map = <
    		/ * IDSEL 0x11 - PCI slot 1* /
    		0x8800 0 0 1 &open-pic 2 1 / * INTA* /
    		0x8800 0 0 2 &open-pic 3 1 / * INTB* /
    		0x8800 0 0 3 &open-pic 4 1 / * INTC* /
    		0x8800 0 0 4 &open-pic 1 1 / * INTD* /
    		/ * IDSEL 0x12 - PCI slot 2* /
    		0x9000 0 0 1 &open-pic 3 1 / * INTA* /
    		0x9000 0 0 2 &open-pic 4 1 / * INTB* /
    		0x9000 0 0 3 &open-pic 1 1 / * INTC* /
    		0x9000 0 0 4 &open-pic 2 1 / * INTD* /
    	>;
    	};
    };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    5.3 特殊节点

    aliases节点为了解决节点路径名过长的问题,引入了节点别名的概念,可以引用到一个全路径的节点。如/external-bus/ethernet@0,0,但当用户想知道具体内容的时候显得太累赘,“哪个设备是eth0?”

    aliases {
            ethernet0 = &eth0;
            serial0 = &serial0;
        };
    • 1
    • 2
    • 3

    当为设备分配一个标识符的时候,操作系统更倾向于使用aliases

    文章目录

    • 本文说明
    • 修改方法(基于样题环境)
    • 产生修改方案的逻辑过程
      • 查看build_chain.sh中的下载代码的部分
      • 查找机器上已有的fisco-bcos文件
      • 处理fisco-bcos版本号问题
      • 方案形成和实验

    本文说明

    本文是【手把手教程】职业学校技能大赛“区块链技术应用”赛项-样题-区块链部署&运维&测试部分(任务1-2,1-3)这篇文章的补充。解决了离线环境下脚本build_chain.sh无法从github下载fisco二进制文件的问题。
    如图所示,因为没有外网环境,所以脚本无法连接github下载fisco二进制文件

    考虑到比赛环境不允许连接外网,而脚本build_chain.sh中有从github下载fisco的二进制文件的命令,我们可以做如下调整:

    1. 调整build_chain.sh中下载代码的部分,跳过下载二进制文件
    2. 但这样我们需要提供下载好的二进制文件(前提是比赛环境中至少有一份已经准备好的fisco-bcos二进制文件。可以用find命令找一找)

    在比赛时,可以按照后文介绍的方法,实现上述1,2两点调整。首先介绍修改方法(基于样题的虚拟机环境),之后附上这样修改的逻辑,便于比赛环境中灵活应用。

    修改方法(基于样题环境)

    把原文档中运行bash build_chain.sh ...那一步,替换为下面这些

    sudo su
    cd /root/tools
    
    rm -rf nodes		# 如果存在nodes,先删掉
    # 自己创建好目录,并准备好fisco-bcos(直接用虚拟机上现成的)
    mkdir nodes
    mkdir nodes/192.168.157.128
    mkdir nodes/192.168.157.129
    cp ./webase-deploy/nodes/127.0.0.1/fisco-bcos nodes/192.168.157.129
    cp ./webase-deploy/nodes/127.0.0.1/fisco-bcos nodes/192.168.157.128
    cp ./webase-deploy/nodes/127.0.0.1/fisco-bcos nodes
    
    # 修改build_chain.sh,跳过下载代码的部分
    vim build_chain.sh
    
    # 修改如下位置:
    1654 #dir_must_not_exists "${output_dir}"		# 因为我们手动创建了nodes目录,这里如果不注释掉这行,运行脚本会报错[WARN] /root/tools/brtest/nodes DIR exists, please clean old DIR!
    
    # 下面这部分注释掉,并添加一行(1679):
    1678 # download fisco-bcos and check it
    1679 bin_path=${output_dir}/${bcos_bin_name}		# 添加这行是因为这行是download_bin函数里的内容,它修改了全局变量bin_path,所以要加在这里,否则可能影响后面的代码运行
    1680 #if [ -z ${docker_mode} ];then
    1681 #    if [[ -z ${bin_path} ]];then
    1682 #        download_bin
    1683 #    else
    1684 #        check_bin
    1685 #    fi
    1686 #fi
    
    # 查看fisco-bcos的版本号,并运行脚本,指定版本号
    ./nodes/fisco-bcos -v
    FISCO-BCOS Version : 2.7.2
    Build Time         : 20210201 10:03:03
    Build Type         : Linux/clang/Release
    Git Branch         : HEAD
    Git Commit Hash    : 4c8a5bbe44c19db8a002017ff9dbb16d3d28e9da
    # 运行脚本,注意指定版本号(从上面看到是2.7.2)
    bash build_chain.sh -f ipconf -p 30330,20230,8545 -v 2.7.2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    这时就完成了原本的bash build_chain.sh ...这一步,可以按原教程继续了。

    产生修改方案的逻辑过程

    这部分作为补充,介绍前述修改方案的产生过程(分析过程)

    查看build_chain.sh中的下载代码的部分

    打开build_chain.sh,查找下载代码的部分

    sudo su
    cd /root/tools/
    vim build_chain.sh
    
    # (下面部分是在vim中进行的)
    # (可选)显示行号,方便参考本文进行定位
    :set nu
    # 查找脚本中下载代码的命令位置
    # 这里我们根据脚本运行的报错中的[INFO]信息来找。
    /Downloading fisco-bcos binary from
    # 回车。这时可以看到,在1551行的位置找到相应的[INFO]信息
    1540 download_bin()
    1541 {
    1542     if [ "${x86_64_arch}" != "true" ];then exit_with_clean "We only offer x86_64 precompiled fisco-bcos binary, your OS architecture is not x86_64. Please compile from source."     ; fi
    1543     bin_path=${output_dir}/${bcos_bin_name}
    1544     package_name="fisco-bcos.tar.gz"
    1545     if [ -n "${macOS}" ];then
    1546         package_name="fisco-bcos-macOS.tar.gz"
    1547     fi
    1548 
    1549     Download_Link="https://github.com/FISCO-BCOS/FISCO-BCOS/releases/download/v${compatibility_version}/${package_name}"
    1550     local cdn_download_link="${cdn_link_header}/FISCO-BCOS/releases/v${compatibility_version}/${package_name}"
    1551     LOG_INFO "Downloading fisco-bcos binary from ${Download_Link} ..." 
    1552     if [ $(curl -IL -o /dev/null -s -w %{http_code} "${cdn_download_link}") == 200 ];then
    1553         curl -#LO "${Download_Link}" --speed-time 20 --speed-limit 102400 -m "${download_timeout}" || {
    1554             LOG_INFO "Download speed is too low, try ${cdn_download_link}"
    1555             curl -#LO "${cdn_download_link}"
    1556         }
    1557     else
    1558         curl -#LO "${Download_Link}"
    1559     fi
    1560     if [[ "$(ls -al . | grep tar.gz | awk '{print $5}')" -lt "1048576" ]];then
    1561         exit_with_clean "Download fisco-bcos failed, please try again. Or download and extract it manually from ${Download_Link} and use -e option."
    1562     fi
    1563     tar -zxf ${package_name} && mv fisco-bcos ${bin_path} && rm ${package_name}
    1564     chmod a+x ${bin_path}
    1565 }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    我们来理解这段代码。它定义了一个函数download_bin(),是从github上下载${package_name}这个文件(1558行 curl -#LO命令),然后解压(1563行 tar-zxf),解压后得到的文件名为fisco-bcos。把fisco-bcos移动到${bin_pach}目录下(1563行 mv),并删除了刚下载的${package_name}文件(1563行 rm)

    那么,这个函数download_bin()是在哪里调用的呢?我们在vim中查找:

    /download_bin
    # 回车。然后点击n寻找下一个,直到看到这个:
    1677 # download fisco-bcos and check it
    1678 if [ -z ${docker_mode} ];then
    1679     if [[ -z ${bin_path} ]];then
    1680         download_bin
    1681     else
    1682         check_bin
    1683     fi
    1684 fi
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    可见,该函数在1680行被调用。逻辑是,如果本地没有相关文件${bin_path},就下载(1680行,调用download_bin函数),否则检查已有文件(1682行,check_bin函数)。那么我们可能可以把这段(1678-1684)注释掉以跳过下载过程,但同时必须手动准备好原本由download_bin下载的fisco-bcos文件

    查找机器上已有的fisco-bcos文件

    如果机器上已有ficso-bcos文件,那么就可以直接搬过来用,从而能够跳过上述的download_bin部分。

    sudo su
    cd /root/tools
    find . -name fisco-bcos
    
    ./nodes/192.168.157.129/fisco-bcos
    ./nodes/192.168.157.128/fisco-bcos
    ./webase-deploy/nodes/127.0.0.1/fisco-bcos
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这里找到三个fisco-bcos,其中前两个是我之前搭建区块链是生成的,webase-deploy里的是虚拟机中自带的。那么,应该可以直接把webase-deploy里的fisco-bcos拿来用,从而跳过build_chain.sh里的下载部分。

    不过这里还有一个问题:虚拟机中自带的fisco-bcos和脚本下载的fisco-bcos版本不一致,这是通过diff命令看出的

    $ diff ./nodes/192.168.157.129/fisco-bcos ./webase-deploy/nodes/127.0.0.1/fisco-bcos
    二进制文件 ./nodes/192.168.157.129/fisco-bcos 和 ./webase-deploy/nodes/127.0.0.1/fisco-bcos 不同
    
    • 1
    • 2

    因此,我们还需要修改build_chain.sh中关于fisco-bcos版本号的设置问题,防止之后因为版本号不匹配造成问题。

    处理fisco-bcos版本号问题

    这里有两个问题:

    1. 如何知道fisco-bcos二进制文件的版本号
    2. 需要定位build_chain.sh中规定fisco-bcos版本号的位置
    vim build_chain.sh
    
    • 1

    考虑前面我们在1682行看到,如果二进制文件已经存在,会通过check_bin函数来检查。我们来看看check_bin函数是怎么做的:

    1569 check_bin()
    1570 {
    1571     echo "Checking fisco-bcos binary..."
    1572     bin_version=$()
    1573     if ! ${bin_path} -v | grep -q 'FISCO-BCOS';then
    1574         exit_with_clean "${bin_path} is wrong. Please correct it and try again."
    1575     fi
    1576     bin_version=$(${bin_path} -v | grep -i version | grep -oe "[2-9]*\.[0-9]*\.[0-9]*")
    1577     if version_gt "${compatibility_version}" "${bin_version}";then
    1578         exit_with_clean "${bin_version} is less than ${compatibility_version}. Please correct it and try again."
    1579     fi
    1580     echo "Binary check passed."
    1581 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    可见,1576-1579行在检查版本号。于是从1576行知道fisco-bcos -v可以查看二进制文件fisco-bcos的版本号信息。另外,1578行在比较版本号和${compatibility_version}之间的关系,而download_bin函数中指定下载版本(1549行,见前文)也是${compatibility_version},因此我们知道只要指定该字段为我们想要的版本号,即可解决fisco-bcos版本号问题。

    那么我们追踪${compatibility_version}这个变量:

    1672 # use default version as compatibility_version
    1673 if [ -z "${compatibility_version}" ];then
    1674     compatibility_version="${default_version}"
    1675 fi
    # 1674行可见,如果没有指定版本号,则使用default_version来设置compatibility_version
    
      50 compatibility_version=""
      51 default_version="2.8.0"
    # 51行可见,default_version是2.8.0
    
      57 help() {
      58     cat << EOF
      59 Usage:
      60     -l <IP list>                        [Required] "ip1:nodeNum1,ip2:nodeNum2" e.g:"192.168.0.1:2,192.168.0.2:3"
      61     -f <IP list file>                   [Optional] split by line, every line should be "ip:nodeNum agencyName groupList p2p_port,channel_port,jsonrpc_port". eg "127.0.0.1:4 age     ncy1 1,2 30300,20200,8545"
      62     -v <FISCO-BCOS binary version>      Default is the latest v${default_version}
    # usage中又见可以通过-v来指定版本号
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    至此,我们知道可以通过fisco-bcos -v查看我们需要的版本号信息,然后直接在运行build_chain.sh时用-v指定版本号。或者,也可以直接修改build_chain.sh中的default_version。我们不妨采用第一种方案。

    方案形成和实验

    我新建一个目录用于实验。把build_chain.sh和ipconf复制近来,然后尝试我们的方案:

    1. 修改build_chain.sh
    2. 复制虚拟机上自带的fisco-bcos过来
    3. 离线运行脚本(把主机网线拔了hhh),注意指定版本号
    sudo su
    cd /root/tools
    mkdir brtest
    cp build_chain.sh brtest/
    cp ipconf brtest/
    
    cd brtest
    mkdir nodes
    mkdir nodes/192.168.157.128
    mkdir nodes/192.168.157.129
    cp ../webase-deploy/nodes/127.0.0.1/fisco-bcos nodes/192.168.157.129
    cp ../webase-deploy/nodes/127.0.0.1/fisco-bcos nodes/192.168.157.128
    cp ../webase-deploy/nodes/127.0.0.1/fisco-bcos nodes		# 尽管最后的结果中nodes目录下是没有fisco-bcos的,但是在脚本运行过程中这里会有。如果不在这里复制一份fisco-bcos,运行脚本会报错:cp: 无法获取'/root/tools/brtest/nodes/fisco-bcos' 的文件状态(stat): 没有那个文件或目录
    
    vim build_chain.sh
    # 修改如下位置:
    1654 #dir_must_not_exists "${output_dir}"		# 因为我们手动创建了nodes目录,这里如果不注释掉这行,运行脚本会报错:[WARN] /root/tools/brtest/nodes DIR exists, please clean old DIR!
    
    # 下面这部分注释掉,并添加一行:
    1678 # download fisco-bcos and check it
    1679 bin_path=${output_dir}/${bcos_bin_name}		# 添加这行是因为这行是download_bin函数里的内容,它修改了全局变量bin_path,所以要加在这里,否则可能影响后面的代码运行
    1680 #if [ -z ${docker_mode} ];then
    1681 #    if [[ -z ${bin_path} ]];then
    1682 #        download_bin
    1683 #    else
    1684 #        check_bin
    1685 #    fi
    1686 #fi
    
    # 网线拔掉然后继续(
    # 首先查看我们的fisco-bcos的版本号
    ./nodes/fisco-bcos -v
    FISCO-BCOS Version : 2.7.2
    Build Time         : 20210201 10:03:03
    Build Type         : Linux/clang/Release
    Git Branch         : HEAD
    Git Commit Hash    : 4c8a5bbe44c19db8a002017ff9dbb16d3d28e9da
    # 运行脚本,注意指定版本号(从上面看到是2.7.2)
    bash build_chain.sh -f ipconf -p 30330,20230,8545 -v 2.7.2
    ==============================================================
    Generating CA key...
    ==============================================================
    Generating keys and certificates ...
    Processing IP=192.168.157.129 Total=2 Agency=agencyA Groups=1
    Processing IP=192.168.157.129 Total=2 Agency=agencyB Groups=2
    Processing IP=192.168.157.128 Total=3 Agency=agencyC Groups=1,2
    ==============================================================
    Generating configuration files ...
    Processing IP=192.168.157.129 Total=2 Agency=agencyA Groups=1
    Processing IP=192.168.157.129 Total=2 Agency=agencyB Groups=2
    Processing IP=192.168.157.128 Total=3 Agency=agencyC Groups=1,2
    ==============================================================
    Group:1 has 5 nodes
    Group:2 has 5 nodes
    ==============================================================
    [INFO] IP List File    : ipconf
    [INFO] Start Port      : 30330 20230 8545
    [INFO] Server IP       : 192.168.157.129:2 192.168.157.129:2 192.168.157.128:3
    [INFO] Output Dir      : /root/tools/brtest/nodes
    [INFO] CA Path         : /root/tools/brtest/nodes/cert/
    ==============================================================
    [INFO] Execute the download_console.sh script in directory named by IP to get FISCO-BCOS console.
    e.g.  bash /root/tools/brtest/nodes/192.168.157.129/download_console.sh -f
    ==============================================================
    [INFO] All completed. Files in /root/tools/brtest/nodes
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    这样看来,应该是成功了。

    注:本文转载自blog.csdn.net的奇小葩的文章"https://blog.csdn.net/u012489236/article/details/97137007"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
    复制链接
    复制链接
    相关推荐
    发表评论
    登录后才能发表评论和回复 注册

    / 登录

    评论记录:

    未查询到任何数据!
    回复评论:

    分类栏目

    后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

    热门文章

    101
    推荐
    关于我们 隐私政策 免责声明 联系我们
    Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
    Scroll to Top