Linux设备树简记

一. 设备树是一种描述硬件设备的方法,描述设备数的文件叫DTS(Device Tree Source),DTS采用树形的结构描述板级设备

在这里插入图片描述

  • 在设备树出现之前,板级硬件设备的相关信息都被编译进Linux内核中,导致内核代码臃肿且难以维护,所以引入了设备树,将内核与硬件设备代码解耦

  • .dtsi文件(板级公共文件,使用时类似头文件)描述的是如SOC级信息:SOC有几个CPU、主频是多少、各个外设的控制信息等;.dts文件描述的是板级信息:IIC设备、SPI设备等;一个完整设备树文件是由1个dts+n个dtsi文件组成。
    在这里插入图片描述

二. DTS、DTB和DTC:

  • DTB是二进制文件,DTS是源文件,使用DTC工具(scripts/dtc目录下)将DTS编译成DTB
  • 当制作了一块开发板,就需要根据板级设备制作.dts文件,并在arch/arm/boot/dts/Makefile文件下找到对应SOC,将.dts文件名添加上去
  • .dts文件基本不会重头写完,大都是在SOC厂商提供的.dts文件上进行修改

三. DTS语法:

  1. 参考 《Devicetree SpecificationV0.2.pdf》《Power_ePAPR_APPROVED_v1.12.pdf》
  2. 设备树是采用树形结构描述板子的设备信息的文件,每个设备都是一个节点,称为设备节点;每个节点都通过一些属性信息(键值对)来描述节点信息
  3. 节点命名格式node-name@unit-address
    • node-name是设备节点名字;unit-address是设备节点的地址,若没有可以不写
    • 如:cpu@0interrupt-controller@00a01000
  4. 节点标签label: node-name@unit-address,使用节点标签 &label可以方便访问设备节点
  5. 节点属性:不同设备有不同的节点属性,用户可以自定义属性,但有很多属性都是标准属性
  • compatible(兼容) 属性,用于将设备和驱动绑定;格式为 “manufacturer,model”,manufacturer表示驱动厂商,model表示驱动的名字;如compatible = ul-evk-wm8960",“fsl,imx-audio-wm8960”;fal表示的是飞思卡尔厂商,而后面则表示驱动名字;设备会根据compatible属性在Linux内核查找相对应的驱动

  • model属性,用于描述设备信息,如名字

  • status属性:表示设备的状态信息

    okay表明设备是可操作的
    disabled表明设备当前是不可操作的,但是在未来可以变为可操作的,比如热插拔设备插入以后。至于 disabled 的具体含义还要看设备的绑定文档
    fail表明设备不可操作,设备检测到了一系列的错误,而且设备也不大可能变得可操作
    fail-sss含义和fail相同,后面的 sss 部分是检测到的错误内容
  • #address-cells 和**#size-cells** 属性,可以在任何拥有子节点的设备中,用于描述子节点的地址信息属性

    • #address-cells 和#size-cells 表明了子节点应该如何编写reg属性值,reg属性格式为reg = <address1 length1 address2 length2 address3 length3……>
    • #address-cells表明起始地址address所占用的字长,#size-cells表明地址长度length所占用的字长
  • reg属性,描述设备的地址空间信息,一般是外设的寄存器地址范围

  • ranges属性,格式为 (child-bus-address,parent-bus-address,length),是一个地址映射转换表;若为空,则代表父地址空间和子地址空间完全相同。

四. 根节点compatible属性

  1. Linux内核会根据根节点的compatible属性,判断是否支持该设备;支持则会启动Linux内核,否则启动失败
    • 如在arch/arm/mach-imx/mach-imx6ul.c下,machine_desc 结构体中有个**.dt_compat** 成员变量,此成员变量保存着本设备兼容属性;只要根节点compatible属性和 .dt_compat 中任一值相等,则表示Linux内核支持该设备。

五. 向节点追加或修改内容

  1. .dts文件中通过**&label引用.dtsi文件中的节点,然后在这个节点增加或修改**内容,如

    &i2c1{
    /*要添加或修改的内容*/ 
    }
    

六. 创建小型模板设备树,熟悉DTS语法

/* 
	简单实现如下内容
	1. I.MX6ULL 这个Cortex-A7架构的 32 位CPU
	2. I.MX6ULL 内部 ocram,起始地址 0x00900000,大小为 128KB(0x20000)
	3. aips1 = <0x02000000 0x100000>
    4. aips2 = <0x02100000 0x100000>
    5. aips3 = <0x02200000 0x100000>
	6. I.MX6ULL内部aips1域下的ecspi1 外设控制器,寄存器起始地址为0x02008000,大小为0x4000
	7. I.MX6ULL内部aips2域下的usbotg1外设控制器,寄存器起始地址为0x02184000,大小为0x4000
	8. I.MX6ULL内部aips3域下的rngb   外设控制器,寄存器起始地址为0x02284000,大小为0x4000
*/
/{
    #address-cells 	= <1>; 
    #size-cells 	= <0>;
    
    //CPU0节点
    cpu0:cpu@0{
        compatible  = "arm,Cortex-A7";
        device_type = "cpu";
        reg			= <0>;
    };
    
    //soc节点
    soc{
        compatible 		= "fal,IMx6ULL";
        ranges;			//表示父子地址空间完全相同
        
        //ocram子节点
    	ocram:sram@00900000{
        	compatible 		= "fal,lpm-sram";
            #address-cells  = <1>; 
    		#size-cells 	= <1>;
            reg 	   		= <0x00900000 0x20000>;
    	};
        
        //aips1子节点
        aips1:aips1@02000000{
          compatible 	  = "fal,aips-bus","simple-bus";  
          #address-cells  = <1>; 
    	  #size-cells 	  = <1>;          
          reg		 	  = <0x02000000 0x100000>;
          ranges;
          //ecspi1 外设控制器子节点
          ecspi1:ecspi@02008000{
              compatible	= "fsl,imx6ul-ecspi", "fsl,imx51-ecspi";       
          	  reg		 	= <0x02008000 0x4000>;
      		  status		= "disabled";              
          };
        };
        
        //aips2子节点
        aips2:aips2@02100000{
          compatible 	  = "fal,aips-bus","simple-bus";  
          #address-cells  = <1>; 
    	  #size-cells 	  = <1>;          
          reg		 	  = <0x02100000 0x100000>;
          ranges;
          //usbotg1 外设控制器子节点
          usbotg1:usb@02184000{
              compatible	= "fsl,imx6ul-usb", "fsl,imx27-usb";       
          	  reg		 	= <0x02184000 0x4000>;
      		  status		= "disabled";              
          };
        };
        
        //aips3子节点
        aips3:aips3@02200000{
          compatible 	  = "fal,aips-bus","simple-bus";  
          #address-cells  = <1>; 
    	  #size-cells 	  = <1>;          
          reg		 	  = <0x02200000 0x100000>;
          ranges;
          //rngb 外设控制器子节点
          rngb:rngb@02284000{
              compatible	= "fsl,imx6sl-rng", "fsl,imx-rng";       
          	  reg		 	= <0x02284000 0x4000>;
      		  status		= "disabled";              
          };
        }; 
        
    };
}

七. 设备树在系统中的体现

  1. Linux内核启动的时候会解析各个设备节点的信息,并根据设备节点名字在根文件系统的/proc/devicetree 目录下创建文件夹

在这里插入图片描述

  • #address-cells、#size-cells、compatible、model和name等文件,是根节点的属性信息
  • 其余文件夹对应的就是,根节点下的各个子节点
  1. 特殊节点:aliaseschosen

    • aliases子节点(在.dtsi文件)的意思为别名,该节点的主要功能就是给其他节点定义别名,方便访问;像是标签**&label**也是为了方便访问。
    • chosen子节点主要是为了uboot向Linux内核传递数据!里面有 bootargs属性!!!这个属性和uboot环境变量bootargs一模一样,因为 uboot向chosen节点添加并设置了bootarges属性

八. 绑定信息文档

  1. Linux 内核源码中有详细的.txt 文档描述了在设备树中如何添加一个硬件设备的节点,叫做绑定文档,路径为内核源码目录下的 /Documentation/devicetree/bindings

九. 设备树OF操作函数

  1. 设备树中描述了节点设备的详细信息,在编写设备驱动的时候需要获得这些信息;Linux内核在include/linux/of.h文件中,定义了许多OF函数,用于获取节点设备的详细信息。

  2. Linux使用device_node结构体描述一个设备节点,该结构体中有一表示属性信息的结构体指针变量property

  3. /******************** 查找节点的OF函数 ********************/
    /*	from表示开始查找到节点,NULL则表示从根节点开始查找
    	name表示要查找节点的名字
    	返回值为查找到的节点地址,类型为device_node* ;返回NULL表示失败*/
    struct device_node *of_find_node_by_name(struct device_node*from, const char *name);
    
    /*函数通过 device_type 属性查找指定的节点*/
    struct device_node *of_find_node_by_type(struct device_node *from, const char *type);
    
    /*函数根据 device_type 和 compatible 这两个属性查找指定的节点*/
    struct device_node *of_find_compatible_node(struct device_node *from, const char *type,const char *compatible);
    
    /*函数通过 of_device_id 匹配表来查找指定的节点
      matches:of_device_id 匹配表,在此匹配表里面查找节点
      match	 :找到的匹配的 of_device_id*/
    struct device_node *of_find_matching_node_and_match(struct device_node
    *from,const struct of_device_id *matches, const struct of_device_id **match);
    
    /*通过路径来查找指定的节点
      path为带有全路径的节点名,可以使用 节点的别名 */
    inline struct device_node *of_find_node_by_path(const char *path);
    
  4. /*用于获取指定节点的父节点
      参数为要查找父节点的节点
      返回值为找到的父节点,没有则返回NULL*/
    struct device_node *of_get_parent(const struct device_node *node);
    
    /*迭代的查找子节点
      参数node为父节点;prev表示从哪一个节点开始迭代查找子节点,NULL表示从第一个子节点开始
      返回值为找到的下一个子节点*/
    struct device_node *of_get_next_child(const struct device_node *node,struct device_node *prev);
    
  5. /*通过 属性名字 查找指定的属性
      np为设备节点;name为属性名字;lenp为属性值的字节数(大小?)
      返回值为属性property结构体指针,即找到的属性地址*/
    property *of_find_property(const struct device_node *np,const char *name,int *lenp);
    
  6. /*获取属性中元素的数量
      proname: 需要统计元素数量的属性名字;elem_size:指定元素长度???
      返回值为属性中元素的数量*/
    int of_property_count_elems_of_size(const struct device_node *np, const char
    *propname,int elem_size);
    
  7. /*用于从 指定属性 中获取 指定标号 的 u32类型数据值
      proname:要读取的属性名字;index:要读取的指定值标号;out_value:读取到的值
      返回值:0成功,0<失败,-EINVAL属性不存在,-ENODATA未读取到,-EOVERFLOW溢出*/
    int of_property_read_u32_index(const struct device_node *np, const char *propname, u32 index, u32 *out_value)
    
  8. /*下面四个函数分别是读取属性中u8、u16、u32和u64类型的 数组数据
      const struct device_node *np			为设备节点 
      const char 			   *propname	为要读取的属性名字
      u8/u16/u32/u64 		   *out_value	为读取到的数组地址
      size_t				   sz			为要读取的数组元素数量
      返回值:0成功,0<失败,-EINVAL属性不存在,-ENODATA未读取到,-EOVERFLOW溢出*/
    int of_property_read_u8_array(......);
    int of_property_read_u16_array(......);
    int of_property_read_u32_array(......);
    int of_property_read_u64_array(......);
    
    /*下面四个函数分别是读取属性中u8、u16、u32和u64类型的 数据*/
    int of_property_read_u8(const struct device_node *np,const char *propname,u8 *out_value);
    int of_property_read_u16(......);
    int of_property_read_u32(......);
    int of_property_read_u64(......);
    
  9. /*读取属性中字符串值;返回值:0成功,<0失败*/
    int of_property_read_string(struct device_node *np,const char *propname,const char **out_string);
    
  10. int of_n_addr_cells(struct device_node *np);  //获取#address-cells 属性值
    int of_n_size_cells(struct device_node *np);  //获取#size-cells    属性值
    
  11. /*查看节点的 compatible属性 是否有包含 compat 指定的字符串,即检查设备节点的兼容性
      返回值:0不包含,>0包含*/
    int of_device_is_compatible(const struct device_node *device,const char *compat);
    
  12. /*函数用于获取地址相关属性,主要是reg或者assigned-addresses属性值
      index为要读取的地址标号,size为读取的地址长度,flags为参数
      返回值:读取到的地址数据首地址,NULL失败*/
    const __be32 *of_get_address(struct device_node *dev,int index,u64 *size,unsigned int *flags);
    
    /*将从设备树读取到的地址转换为物理地址
      返回值:得到的物理地址,OF_BAD_ADDR表示转换失败*/
    u64 of_translate_address(struct device_node *dev,const __be32 *in_addr);
    
  13. IIC、SPI、GPIO等外设,都有自已的一组寄存器即内存空间;Linux内核在文件include/linux/ioport.h中,用结构体resource描述一段内存空间。

     /*本质上是将 reg 属性值,转换为 resource 结构体类型
     	dev:设备节点;index:地址资源标号;r:得到的 resource 类型的资源值;
     	返回值:0成功,<0失败*/
     int of_address_to_resource(struct device_node *dev, int index, struct resource *r);
    
  14. of_iomap 函数来获取内存地址所对应的虚拟地址;本质是将reg属性值,转换为虚拟地址,若reg有多段,则可以用index参数指定完成地址映射的是哪一段。

     /*返回值:内存映射后的虚拟地址首地址,NULL失败*/
     void __iomem *of_iomap(struct device_node *np, int index);
    

以上是我在学习过程中的总结,不当之处请在评论区指出。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 等保2.0标准中对技术安全要求主要包括信息安全类要求(简记为x)、服务保证类要求(简记为s)、其他安全保护类要求(简记为g)和数据设备类要求(简记为f)。 a. 信息安全类要求(x)是等保2.0标准中的一项重要要求,它涉及了信息系统的安全保护、安全管理和信息安全技术的实施要求,包括身份认证、访问控制、审计、加密等内容。 b. 服务保证类要求(s)也是等保2.0标准中的一项重要要求,它主要围绕着信息系统的可用性、可靠性和稳定性进行要求,包括灾备备份、容灾恢复、业务连续性等内容。 c. 其他安全保护类要求(g)是等保2.0标准中的一项综合要求,主要涉及到对软硬件安全配置、网络安全和物理环境安全等方面的要求,包括网络隔离、漏洞修复、环境监控等内容。 d. 数据设备类要求(f)是等保2.0标准中专门对数据安全进行要求的一项内容,它主要包括数据备份、数据恢复、数据存储、数据传输等方面的安全要求。 综上所述,a、b、c、d选项所描述的等保2.0标准中对技术安全要求的分工是正确的。 ### 回答2: 等保2.0标准中对技术安全要求主要包含了信息安全类要求、服务保证类要求、其他安全保护类要求和数据设备类要求。 a. 信息安全类要求指的是对信息系统的各种组成部分、信息传输和处理过程以及相关的信息安全协议、算法等进行安全要求和控制。这是等保2.0标准中非常重要的一部分。 b. 服务保证类要求主要涉及系统的可用性、可靠性、灾备能力、响应能力等方面的要求。这些要求旨在确保信息系统随时可用,并且能够及时处理异常情况。 c. 其他安全保护类要求主要包括物理环境安全、人员安全、网络安全、应用软件安全等方面的要求。这些要求涉及到信息系统运行环境的各个方面和安全管理控制的要求。 d. 数据设备类要求主要涉及到数据的存储、传输、备份、还原等方面的要求。这些要求着重保护重要数据的安全性和完整性。 所以以上说法都正确,它们都是等保2.0标准中对技术安全方面的要求的不同分类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值