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

当使用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=0x%08x, r2=0x%08x\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)的一节的学习整理

猜你喜欢

转载自blog.csdn.net/weixin_43326587/article/details/107053728