当使用compatible属性跟machine_desc中的dt_compat比较时,按照上述的优先级进行匹配。
那么代码是如何实现的呢?请看如下函数的调用过程:
asmlinkage __visible void __init start_kernel(void){
................
setup_arch(&command_line);
.................
}
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();
}
.....................
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 \
};
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)的一节的学习整理