设备树(dtb数据)匹配struct machine_desc结构体

1、函数调用关系

start_kernel
	setup_arch
		setup_machine_fdt	//解析dtb数据,得到匹配的struct machine_desc结构体,这是用来描述板级配置的
			early_init_dt_verify	//校验dtb数据
			of_flat_dt_match_machine	//匹配最符合的struct machine_desc结构体
				get_next_compat(其实就是arch_get_next_mach)	//读取编译进内核的struct machine_desc结构体的dt_compat属性
				of_flat_dt_match	//将struct machine_desc结构体的dt_compat属性和根节点的"compatible"属性进行匹配,匹配度越好返回的分数越小

2、struct machine_desc结构体匹配逻辑

(1)struct machine_desc结构体描述板级资源的,每块板子都有自己对应的struct machine_desc结构体,一般都是定义在mach-xxx文件中;
(2)在编译内核时,内核一般会把同架构下的mach-xxx目录都编译进去,定义的struct machine_desc结构体会被链接到一起,在链接脚本中会有标号来表示起始和结束的地址;
(3)内核启动过程中会根据起始、结束地址去遍历struct machine_desc结构体,将每个结构体的dt_compat变量和设备树根节点的compatible进行匹配,匹配度最高的struct machine_desc结构体将用于后续内核启动;
(4)如果都匹配不上会有一个默认的struct machine_desc结构体;

3、DT_MACHINE_START宏 和 MACHINE_START宏

#define MACHINE_START(_type,_name)			\
static const struct machine_desc __mach_desc_##_type	\
 __used							\
 __attribute__((__section__(".arch.info.init"))) = {	\
	.nr		= MACH_TYPE_##_type,		\
	.name		= _name,

#define MACHINE_END				\
};

#define DT_MACHINE_START(_name, _namestr)		\
static const struct machine_desc __mach_desc_##_name	\
 __used							\
 __attribute__((__section__(".arch.info.init"))) = {	\
	.nr		= ~0,				\
	.name		= _namestr,			\
};

(1)两个宏都是定义一个struct machine_desc变量,区别在于初始化的值不同;
(2)MACHINE_START宏是之前采用的方式,在定义时会初始化nr值,nr是机器码,用于和uboot启动内核时传递的机器码进行匹配;
(3)DT_MACHINE_START宏是设备树采用的方式,nr值在设备树中是没有使用的,在定义时nr值统一被初始化成~0。设备树是将根节点的compatible和struct machine_desc的dt_compat变量进行匹配。

4、新旧版本内核中machine_desc结构体的差异

(1)这里新旧版本的划分以设备树技术为标准,没有支持设备树的内核为旧版本,支持设备树的内核为新版本;
(2)旧版本内核中用MACHINE_START宏定义machine_desc结构体;新版本内核用DT_MACHINE_START宏定义machine_desc结构体;
(3)旧版本内核匹配machine_desc结构体是根据nr变量(机器码),和uboot启动内核时传递的机器码进行匹配;
(4)新版本内核匹配machine_desc结构体时依靠dt_compat变量,本质上是字符串,和dts文件根节点的compatible属性进行匹配;

5、arch_get_next_mach()函数

5.1、内核链接脚本

OUTPUT_ARCH(arm)
ENTRY(stext)
jiffies = jiffies_64;
SECTIONS
{
	······
	
	.init.arch.info : {
	__arch_info_begin = .;
	*(.arch.info.init)
	__arch_info_end = .;
	}

    ······
}

(1)".arch.info.init"属性是用DT_MACHINE_START宏 和 MACHINE_START宏定义struct machine_desc结构体时赋予的,struct machine_desc结构体会被链接在一起;
(2)__arch_info_begin:表示内核中struct machine_desc结构体的起始地址;
(3)__arch_info_end:表示内核中struct machine_desc结构体的结束地址;
总结:所有struct machine_desc结构体会被链接在一起,类似于数组,__arch_info_begin相当于数组起始地址,__arch_info_end相当于数组的结束地址;

5.2、arch_get_next_mach()函数源码

static const void * __init arch_get_next_mach(const char *const **match)
{
	//struct machine_desc的起始地址
	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;	//dt_compat变量是保存的字符串,用于和根节点的compatible属性进行匹配;
	return m;
}

(1)函数会遍历内核中所有的struct machine_desc结构体,返回对应的struct machine_desc结构体指针和dt_compat变量的值;
(2)dt_compat变量的值拿去和根节点的conpatible属性进行匹配;

6、of_flat_dt_match_machine()函数

const void * __init of_flat_dt_match_machine(const void *default_match,
		const void * (*get_next_compat)(const char * const**))
{
	const void *data = NULL;
	
	//向将最匹配的machine_desc结构体设置成默认结构体
	const void *best_data = default_match;
	
	const char *const *compat;
	unsigned long dt_root;
	unsigned int best_score = ~1, score = 0;

	//获取dtb数据的根节点
	dt_root = of_get_flat_dt_root();
	
	//循环条件是遍历完内核中的machine_desc结构体
	//其中get_next_compat函数指针就是arch_get_next_mach()函数
	while ((data = get_next_compat(&compat))) {
		//将读取到的machine_desc结构体和根节点的compatible属性进行匹配,匹配度越高返回的score越小
		score = of_flat_dt_match(dt_root, compat);
		if (score > 0 && score < best_score) {
			best_data = data;
			best_score = score;
		}
	}

	//如果best_data是NULL则代表当前没有可用的machine_desc结构体,打印根节点的compatible属性
	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;
	}

	//打印根节点的model属性值
	pr_info("Machine model: %s\n", of_flat_dt_get_machine_name());

	return best_data;
}

(1)调用of_flat_dt_match_machine()函数会传入一个默认的machine_desc结构体,如何设备树和内核已有的machine_desc结构体没有匹配上的,则使用默认的machine_desc结构体;
(2)best_score变量是记录匹配度的,初始值是"best_score = ~1",只有匹配分数小于best_score 才会替换最匹配的machine_desc结构体,我猜测一点都不匹配soce应该是0xFFFFFFFF;

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正在起飞的蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值