linux设备树的平台信息认证之匹配过程简析

    技术2022-07-10  170

    linux设备树的平台信息认证之匹配过程简析

    1. start_kernel() 函数定义在init/main.c2. setup_arch()函数定义在arch/arm/kernel/setup.c3. setup_machine_fdt()函数定义在arch/arm/kernel/devtree.c4. of_flat_dt_match_machine();//定义在drivers/of/ftd.c

    当使用compatible属性跟machine_desc中的dt_compat比较时,按照上述的优先级进行匹配。 那么代码是如何实现的呢?请看如下函数的调用过程:

    1. start_kernel() 函数定义在init/main.c

    asmlinkage __visible void __init start_kernel(void)................ setup_arch(&command_line); .................

    2. setup_arch()函数定义在arch/arm/kernel/setup.c

    void __init setup_arch(char **cmdline_p){ const struct machine_desc *mdesc; setup_processor(); /*__atags_pointer 地址里既可能是dtb首地址也可能是ATAGS地址,所以先使用dtb的函数setup_machine_fdt来判断下,如果不是 就使用函数setup_machine_tags*/ mdesc = setup_machine_fdt(__atags_pointer); if (!mdesc) mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type); if (!mdesc) { early_print("\nError: invalid dtb and unrecognized/unsupported machine ID\n"); early_print(" r1=0xx, r2=0xx\n", __machine_arch_type, __atags_pointer); if (__atags_pointer) early_print(" r2[]=%*ph\n", 16, phys_to_virt(__atags_pointer)); dump_machine_table(); } .....................

    3. setup_machine_fdt()函数定义在arch/arm/kernel/devtree.c

    const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys){ const struct machine_desc *mdesc, *mdesc_best = NULL; .................................................. /*dtb文件传入的是物理地址,需要转换为虚拟地址,所以phys_to_virt(dt_phys)*/ if (!dt_phys || !early_init_dt_verify(phys_to_virt(dt_phys))) return NULL; /*查看一下函数early_init_dt_verify(),函数early_init_dt_verify是检查头部?看看头部有没有magic*/ //bool __init early_init_dt_verify(void *params) //{ //if (!params) // return false; /* check device tree validity */ // if (fdt_check_header(params)) // return false; /* Setup flat device-tree pointer */ // initial_boot_params = params;//并且把dtb的地址保存在全局变量 initial_boot_params中 // of_fdt_crc32 = crc32_be(~0, initial_boot_params, // fdt_totalsize(initial_boot_params)); // return true; //} // 以上都只是做一些简单的检查,下面的才是重要的 mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach); /* 找到最匹配的machine_desc ,第二个参数arch_get_next_mach是个函数指针,我们来看一下arch_get_next_mach()函数. static const void * __init arch_get_next_mach(const char *const **match) { static const struct machine_desc *mdesc = __arch_info_begin; const struct machine_desc *m = mdesc; if (m >= __arch_info_end) return NULL; mdesc++; *match = m->dt_compat; return m; } */

    这里需要强调下arch_get_next_mach()函数,取出一个machine_desc,返回其中的dt_compat成员,每调用一次arch_get_next_mach()函数,返回下一个machine_desc的dt_compat成员。 内核中有多个machine_desc,这些结构体有一个段属性值,在编译的时候,会将多个machine_desc结构体放在一起,如下示意图。 取出的machine_desc的dt_compat成员用来跟设备树中的compatible进行比较匹配,

    MACHINE_START(DAVINCI_DM365_EVM, "DaVinci DM365 EVM") .atag_offset = 0x100, .map_io = dm365_evm_map_io, .init_irq = dm365_init_irq, .init_time = dm365_init_time, .init_machine = dm365_evm_init, .init_late = davinci_init_late, .dma_zone_size = SZ_128M, MACHINE_END

    下面的__section__(".arch.info.init")为段属性 段属性等于这个值的所有的结构体都会放在一起(见上示意图)

    /* * Set of macros to define architecture features. * This is built into a table by the linker. */ #define MACHINE_START(_type, _name) \ static const struct machine_desc __mach_desc_##_type \ __used \ __attribute__((__section__(".arch.info.init"))) = { \ .name = _name, #define MACHINE_END \ };

    4. of_flat_dt_match_machine();//定义在drivers/of/ftd.c

    get_next_compat(&compat)取出一个machine_desc的成员dt_compat 来跟根节点中的compatible的值进行比较(查看of_flat_dt_match(dt_root, compat);)得到他们的score,这score是如何而来呢,见如下dts根节点,按顺序跟"samsung,smdk2440"匹配成功就是1,依次+1。score的值越小,匹配度越高。

    / { model = "SMDK24440"; compatible = "samsung,smdk2440", "samsung,smdk2410", "samsung,smdk24xx"; ................................... }; /** * of_flat_dt_match_machine - Iterate match tables to find matching machine. * * @default_match: A machine specific ptr to return in case of no match. * @get_next_compat: callback function to return next compatible match table. * * Iterate through machine match tables to find the best match for the machine * compatible string in the FDT. */ const void * __init of_flat_dt_match_machine(const void *default_match, const void * (*get_next_compat)(const char * const**)) { const void *data = NULL; const void *best_data = default_match; const char *const *compat; unsigned long dt_root; unsigned int best_score = ~1, score = 0; dt_root = of_get_flat_dt_root(); while ((data = get_next_compat(&compat))) { score = of_flat_dt_match(dt_root, compat); if (score > 0 && score < best_score) { best_data = data; best_score = score; } } if (!best_data) { const char *prop; int size; pr_err("\n unrecognized device tree list:\n[ "); prop = of_get_flat_dt_prop(dt_root, "compatible", &size); if (prop) { while (size > 0) { printk("'%s' ", prop); size -= strlen(prop) + 1; prop += strlen(prop) + 1; } } printk("]\n\n"); return NULL; } pr_info("Machine model: %s\n", of_flat_dt_get_machine_name()); return best_data; }

    根据韦东山的学习视频《linux设备树详解》中对设备树中平台信息的处理(选择machine_desc)的一节的学习整理

    Processed: 0.013, SQL: 9