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

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

 [ 2016年2月18日 ] 【

第221行检查fdt指针是否为空并且调用early_init_dt_verify函数,该函数代码位于drivers/of/fdt.c,这个函数算是of模块(还记得么?是open firmware的缩写)的第一个函数,复制代码如下:

1060
1061 bool __init early_init_dt_verify(void *params)
1062 {
1063    if (!params)
1064        return false;
1065
1066    /* check device tree validity */
1067    if (fdt_check_header(params))
1068        return false;
1069
1070    /* Setup flat device-tree pointer */
1071    initial_boot_params = params;
1072    of_fdt_crc32 = crc32_be(~0, initial_boot_params,
1073                fdt_totalsize(initial_boot_params));
1074    return true;
1075 }

early_init_dt_verify首先检查fdt头部的合法性,然后设置fdt全局变量以及计算crc。这个 initial_boot_params变量后边在访问设备树的时候还会用到。继续看前边第224行,of_flat_dt_match_machine 函数算是of模块的第二个函数吧,在分析这个函数前,我们首先分析���个函数的第二个参数arch_get_next_mach,这是一个函数指针,arm架构的实现位于arch/arm/kernel/devtree.c,复制代码如下:

190 static const void * __init arch_get_next_mach(const char *const **match)
191 {
192    static const struct machine_desc *mdesc = __arch_info_begin;
193    const struct machine_desc *m = mdesc;
194
195    if (m >= __arch_info_end)
196        return NULL;
197
198    mdesc++;
199    *match = m->dt_compat;
200    return m;
201 } 

这个函数很简单,注意的是mdesc是静态局部变量,第一次调用指向__arch_info_begin,后边每次调用都mdesc++,如果超过了__arch_info_end就返回NULL。以上代码说明在__arch_info_begin和__arch_info_end两个地址之间存储着多个machine_desc变量(也可能是一个),该函数遍历这些变量,通过match参数返回所有machine_desc结构体的 dt_compat变量指针。问题是__arch_info_begin和__arch_info_end地址是怎么来的呢?在arch/arm /kernel/vmlinux.lds.S连接脚本中定义了.arch.info.init段,__arch_info_begin和 __arch_info_end地址分别是该段的首尾地址。

188    .init.arch.info : {
189        __arch_info_begin = .;
190        *(.arch.info.init)
191        __arch_info_end = .;
192    }

那么.init.arch.info段的内容怎么来的呢?这就要参考DT_MACHINE_START和MACHINE_END宏了,arm架构的定义在arch/arm/include/asm/mach/arch.h文件,如下所示:

 94 #define DT_MACHINE_START(_name, _namestr)      \
 95 static const struct machine_desc __mach_desc_##_name    \
 96  __used                        \
 97  __attribute__((__section__(".arch.info.init"))) = {    \
 98    .nr    = ~0,              \
 99    .name      = _namestr,
100
101 #endif

从该宏代码看出他定义了一个machine_desc类型的静态局部变量,该变量位于.arch.info.init段中。参考arch/arm /mach-exynos/exynos.c中如下代码,以下代码在.arch.info.init段定义了一个名字为 __mach_desc_EXYNOS_DT,类型为machine_desc的静态局部变量,并且该变量的dt_compat字符串矩阵中有"samsung,exynos5420"的字符串。

277 static char const *const exynos_dt_compat[] __initconst = {
278    "samsung,exynos3",
279    "samsung,exynos3250",
280    "samsung,exynos4",
281    "samsung,exynos4210",
282    "samsung,exynos4212",
283    "samsung,exynos4412",
284    "samsung,exynos4415",
285    "samsung,exynos5",
286    "samsung,exynos5250",
287    "samsung,exynos5260",
288    "samsung,exynos5420",
289    "samsung,exynos5440",
290    NULL
291 };
 
319 DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
320    /* Maintainer: Thomas Abraham */
321    /* Maintainer: Kukjin Kim */
322    .l2c_aux_val    = 0x3c400001,
323    .l2c_aux_mask  = 0xc20fffff,
324    .smp        = smp_ops(exynos_smp_ops),
325    .map_io    = exynos_init_io,
326    .init_early = exynos_firmware_init,
327    .init_irq  = exynos_init_irq,
328    .init_machine  = exynos_dt_machine_init,
329    .init_late  = exynos_init_late,
330    .dt_compat  = exynos_dt_compat,
331    .reserve    = exynos_reserve,
332    .dt_fixup  = exynos_dt_fixup,
333 MACHINE_END


我们已经知道了get_next_compat指针的具体实现了,现在继续看of_flat_dt_match_machine。从第 732行开始的循环就是遍历.arch.info.init段中所有的dt_compat变量,然后通过of_flat_dt_match计算一个分数,并且寻找那个分数最小的。

 713 /**
 714  * of_flat_dt_match_machine - Iterate match tables to find matching machine.
 715  *
 716  * @default_match: A machine specific ptr to return in case of no match.
 717  * @get_next_compat: callback function to return next compatible match table.
 718  *
 719  * Iterate through machine match tables to find the best match for the machine
 720  * compatible string in the FDT.
 721  */
 722 const void * __init of_flat_dt_match_machine(const void *default_match,
 723        const void * (*get_next_compat)(const char * const**))
 724 {
 725    const void *data = NULL;
 726    const void *best_data = default_match;
 727    const char *const *compat;
 728    unsigned long dt_root;
 729    unsigned int best_score = ~1, score = 0;
 730       
 731    dt_root = of_get_flat_dt_root();
 732    while ((data = get_next_compat(&compat))) {
 733        score = of_flat_dt_match(dt_root, compat);
 734        if (score > 0 && score < best_score) {
 735            best_data = data;
 736            best_score = score;
 737        }
 738    }
 ....
 759    return best_data;
 760 }
 761

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