Linux- machine_desc

概要

  * struct machine_desc - Board specific callbacks, called from ARC common code
 *    Provided by each ARC board using MACHINE_START()/MACHINE_END(), so
 *    a multi-platform kernel builds with array of such descriptors.
 *    We extend the early DT scan to also match the DT's "compatible" string
 *    against the @dt_compat of all such descriptors, and one with highest
 *    "DT score" is selected as global @machine_desc.

在这段关于machine_desc的描述中可以得出以下信息:

  • 在一个平台内核中存在一个machine_desc 数组
  • 对象用MACHINE_START和MACHINE_END构造
  • 用设备树中“compatible”字符串匹配machine_desc中的dt_compat属性
  • 在匹配过程中需要进行评分

数据结构

 * @name:        Board/SoC name
 * @dt_compat:        Array of device tree 'compatible' strings
 *                            (XXX: although only 1st entry is looked at)
 * @init_early:        Very early callback [called from setup_arch()]
 * @init_per_cpu:    for each CPU as it is coming up (SMP as well as UP)
 *                            [(M):init_IRQ(), (o):start_kernel_secondary()]
 * @init_machine:    arch initcall level callback (e.g. populate static
 *             platform devices or parse Devicetree)
 * @init_late:        Late initcall level callback

struct machine_desc {
    const char        *name;                         
    const char        **dt_compat;
    void            (*init_early)(void);
    void            (*init_per_cpu)(unsigned int);
    void            (*init_machine)(void);
    void            (*init_late)(void);

};

对象构造

构造通过宏实现

/*
 * 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 __section(".arch.info.init") = {            \
    .name        = _name,

#define MACHINE_END                \
};
构造例子如下:

static const char *hsdk_compat[] __initconst = {
    "snps,hsdk",
    NULL,           //以空指针结束

};

MACHINE_START(SIMULATION, "hsdk")
    .dt_compat    = hsdk_compat,
    .init_early     = hsdk_init_early,
MACHINE_END

从宏的定义可知所有声明的对象存储在 .arch.info.init,该段信息如下:

 .init.arch.info : {
        __arch_info_begin = .;   //开始
        *(.arch.info.init)
        __arch_info_end = .;      //结束
    }

遍历与评估

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;
}

/**
 * setup_machine_fdt - Machine setup when an dtb was passed to the kernel
 * @dt:        virtual address pointer to dt blob
 *
 * If a dtb was passed to the kernel, then use it to choose the correct
 * machine_desc and to setup the system.
 */
const struct machine_desc * __init setup_machine_fdt(void *dt)
{
    const struct machine_desc *mdesc;
    unsigned long dt_root;

    .....................

    mdesc = of_flat_dt_match_machine(NULL, arch_get_next_mach);
    .....................

    return mdesc;
}

/**
 * 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;
        }
    }

    ...........................

    return best_data;
}

/**
 * of_fdt_is_compatible - Return true if given node from the given blob has
 * compat in its compatible list
 * @blob: A device tree blob
 * @node: node to test
 * @compat: compatible string to compare with compatible list.
 *
 * Return: a non-zero value on match with smaller values returned for more
 * specific compatible values.
 */
static int of_fdt_is_compatible(const void *blob,
              unsigned long node, const char *compat)
{
    const char *cp;
    int cplen;
    unsigned long l, score = 0;

    cp = fdt_getprop(blob, node, "compatible", &cplen); //获取设备树中的compatible属性
    if (cp == NULL)
        return 0;
    while (cplen > 0) {
        score++;  //最佳匹配值为1,越大匹配度越低
        if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
            return score;
        l = strlen(cp) + 1; // compatible数组中下一个对象
        cp += l;
        cplen -= l;
    }

    return 0;
}

/*
 * of_flat_dt_match - Return true if node matches a list of compatible values
 */
static int __init of_flat_dt_match(unsigned long node, const char *const *compat)
{
    unsigned int tmp, score = 0;

    if (!compat)
        return 0;

    while (*compat) { //遍历machine_desc对象中的dt_compat字符串数组,直至空
        tmp = of_fdt_is_compatible(initial_boot_params, node, *compat);
        if (tmp && (score == 0 || (tmp < score)))
            score = tmp;
        compat++;
    }

    return score;
}

Linux中,machine数组是一个用于存储支持的硬件平台信息的数组。它定义在`arch/x86/kernel/machine_kexec.c`文件中。该数组的每个元素都是一个结构体,包含了特定硬件平台的相关信息。 这些信息包括硬件平台的名称、处理器类型、内存布局、中断控制器等。通过这些信息,Linux内核可以根据不同的硬件平台进行适配和配置。 machine数组的定义如下: ``` struct machine_desc { const char *name; // 硬件平台的名称 const char *alias; // 硬件平台的别名 const char *probe_type; // 硬件平台的探测类型 const char *dt_compat; // 设备树兼容性字符串 void (*init_irq)(void); // 中断控制器初始化函数 void (*init_machine)(void); // 硬件平台初始化函数 void (*init_late)(void); // 后期初始化函数 void (*init_early)(void); // 早期初始化函数 void (*init_time)(void); // 时间子系统初始化函数 void (*init_irqchip)(void); // 中断芯片初始化函数 void (*init_heartbeat)(void); // 心跳初始化函数 void (*init_pci)(void); // PCI子系统初始化函数 void (*init_pci_early)(void); // 早期PCI子系统初始化函数 void (*init_pci_dma)(void); // PCI DMA初始化函数 void (*init_apic_mappings)(void); // APIC映射初始化函数 void (*init_topology)(void); // 拓扑结构初始化函数 void (*init_memory_mapping)(void); // 内存映射初始化函数 void (*init_memory_mapping_late)(void); // 后期内存映射初始化函数 void (*init_mem_mapping)(void); // 内存映射初始化函数 void (*init_mem_mapping_late)(void); // 后期内存映射初始化函数 void (*init_early_late_memtest)(void); // 早期和后期内存测试函数 void (*init_early_late_memtest_late)(void); // 后期内存测试函数 void (*init_early_late_memtest_end)(void); // 内存测试结束函数 void (*init_early_late_memtest_end_late)(void); // 后期内存测试结束函数 }; ``` 每个硬件平台都会在该数组中注册一个对应的结构体,以便在系统启动时被正确地初始化和配置。通过这种方式,Linux内核可以支持多种不同的硬件平台。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值