考试首页 | 考试用书 | 培训课程 | 模拟考场 | 考试论坛  
  当前位置:操作系统 > Linux > 文章内容
  

Linux基础教程:Linux设备树(Devicetree)

 [ 2016年2月18日 ] 【

根节点

一个最简单的设备树必须包含根节点,cpus节点,memory节点。根节点的名字及全路径都是“/”,至少需要包含model和 compatible两个属性。model属性我们在属性那节已经说过是用来描述产品型号的,类型为字符串,推荐的格式为 “manufacturer,model-number”(非强制的)。根节点的model属性描述的是板子的型号或者芯片平台的型号,如:
model = "Atmel AT91SAM9G20 family SoC"
model = "Samsung SMDK5420 board based on EXYNOS5420"

从软件的层面讲model属性仅仅表示一个名字而已,没有更多的作用。compatible属性则不同,该属性决定软件如何匹配硬件对硬件进行初始化。属性那一节我们说过compatible属性的类型是字符串数组,按照范围从小到大的顺序排列,每个字符串表示一种匹配类型。根节点的 compatible属性表示平台如何匹配,比如‘compatible = "samsung,smdk5420", "samsung,exynos5420", "samsung,exynos5"’,表示软件应该首先匹配'samsung,smdk5420',这个是一款开发板。如果无法匹配,再试着匹配"samsung,exynos5420",这个是一款芯片平台。如果还是无法匹配,还可以试着匹配 "samsung,exynos5",这是一个系列的芯片平台。这里说的匹配是指软件根据该信息找到对应的代码,如对应的初始化函数。

根节点表示的是整个板子或者芯片平台,所以在系统初始化比较早的时候就需要确认是什么平台,怎样初始化。对于Linux,是通过在 start_kernel函数调用setup_arch函数实现的。不同的架构,setup_arch函数的实现不同,对于arm架构,setup_arch函数源代码位于arch/arm/kernel/setup.c中。以下是该函数的部分源代码(代码来自内核版本4.4-rc7 的官方版本,本节后边所有代码都来自该版本)。

 935 void __init setup_arch(char **cmdline_p)
 936 {
 937    const struct machine_desc *mdesc;
 938
 939    setup_processor();
 940    mdesc = setup_machine_fdt(__atags_pointer);
 941    if (!mdesc)
 942        mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);
 943    machine_desc = mdesc;
 944    machine_name = mdesc->name;


第940行setup_machine_fdt函数的输入是设备树(DTB)首地址,返回的mdesc是描述平台信息的结构体。还记得我们在概述那节说过启动程序如uboot把设备树读到内存中,然后在启动内核的同时将设备树首地址传给内核,此处__atags_pointer就是启动程序传给内核的设备树地址(此时内存中的设备树已经是DTB形式)。setup_machine_fdt中的fdt是flat device tree的缩写,fdt的意思是说设备树在内存中是在一块连续地址存储的,fdt和dtb说的都是同一个东西。setup_machine_tags是在设备树初始化失败的时候才调用的,所以不用管他。machine_desc和machine_name都是静态全局变量,用来保存指针方便后边引用的。为了更好的理解setup_machine_fdt具体实现了什么功能,我们首先看下machine_desc结构体。不同的架构,该结构体定义差别很大,arm架构源代码位于arch/arm/include/asm/mach/arch.h,复制如下:
 
 27 struct machine_desc {
 28    unsigned int        nr;    /* architecture number  */
 29    const char      *name;      /* architecture name    */
 30    unsigned long      atag_offset;    /* tagged list (relative) */
 31    const char *const  *dt_compat; /* array of device tree
 32                          * 'compatible' strings */
 33
 34    unsigned int        nr_irqs;    /* number of IRQs */
 35
 36 #ifdef CONFIG_ZONE_DMA
 37    phys_addr_t    dma_zone_size;  /* size of DMA-able area */
 38 #endif
 39
 40    unsigned int        video_start;    /* start of video RAM  */
 41    unsigned int        video_end;  /* end of video RAM */
 42
 43    unsigned char      reserve_lp0 :1; /* never has lp0    */
 44    unsigned char      reserve_lp1 :1; /* never has lp1    */
 45    unsigned char      reserve_lp2 :1; /* never has lp2    */
 46    enum reboot_mode    reboot_mode;    /* default restart mode */
 47    unsigned        l2c_aux_val;    /* L2 cache aux value  */
 48    unsigned        l2c_aux_mask;  /* L2 cache aux mask    */
 49    void            (*l2c_write_sec)(unsigned long, unsigned);
 50    const struct smp_operations *smp;  /* SMP operations  */
 51    bool            (*smp_init)(void);
 52    void            (*fixup)(struct tag *, char **);
 53    void            (*dt_fixup)(void);
 54    long long      (*pv_fixup)(void);
 55    void            (*reserve)(void);/* reserve mem blocks  */
 56    void            (*map_io)(void);/* IO mapping function  */
 57    void            (*init_early)(void);
 58    void            (*init_irq)(void);
 59    void            (*init_time)(void);
 60    void            (*init_machine)(void);
 61    void            (*init_late)(void);
 62 #ifdef CONFIG_MULTI_IRQ_HANDLER
 63    void            (*handle_irq)(struct pt_regs *);
 64 #endif
 65    void            (*restart)(enum reboot_mode, const char *);
 66 };
 67

从以上结构体的注释可以看出,该结构体包含了非常多的信息。注意第31行的dt_compat变量,该变量就是用来匹配设备树的compatible属性的。

setup_machine_fdt函数的实现也是架构相关的,arm架构源代码位于arch/arm/kernel/devtree.c,复制代码如下:

203 /**     
204  * setup_machine_fdt - Machine setup when an dtb was passed to the kernel
205  * @dt_phys: physical address of dt blob
206  * 
207  * If a dtb was passed to the kernel in r2, then use it to choose the
208  * correct machine_desc and to setup the system.
209  */
210 const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
211 {   
212    const struct machine_desc *mdesc, *mdesc_best = NULL;
213
214 #ifdef CONFIG_ARCH_MULTIPLATFORM
215    DT_MACHINE_START(GENERIC_DT, "Generic DT based system")
216    MACHINE_END
217
218    mdesc_best = &__mach_desc_GENERIC_DT;
219 #endif
220
221    if (!dt_phys || !early_init_dt_verify(phys_to_virt(dt_phys)))
222        return NULL;
223
224    mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach);
225
226    if (!mdesc) {
227        const char *prop;
228        int size;
229        unsigned long dt_root;
230
231        early_print("\nError: unrecognized/unsupported "
232                "device tree compatible list:\n[ ");
233
234        dt_root = of_get_flat_dt_root();
235        prop = of_get_flat_dt_prop(dt_root, "compatible", &size);
236        while (size > 0) {
237            early_print("'%s' ", prop);
238            size -= strlen(prop) + 1;
239            prop += strlen(prop) + 1;
240        }
241        early_print("]\n\n");
242
243        dump_machine_table(); /* does not return */
244    }
245
246    /* We really don't want to do this, but sometimes firmware provides buggy data */
247    if (mdesc->dt_fixup)
248        mdesc->dt_fixup();
249
250    early_init_dt_scan_nodes();
251
252    /* Change machine number to match the mdesc we're using */
253    __machine_arch_type = mdesc->nr;
254
255    return mdesc;
256 }

本文纠错】【告诉好友】【打印此文】【返回顶部
将考试网添加到收藏夹 | 每次上网自动访问考试网 | 复制本页地址,传给QQ/MSN上的好友 | 申请链接 | 意见留言 TOP
关于本站  网站声明  广告服务  联系方式  站内导航  考试论坛
Copyright © 2007-2013 中华考试网(Examw.com) All Rights Reserved