dmi

在arch/arm64/kernel/efi.c 中会对dmi初始化,dmi的全程是Desktop Management Interface.属于smbios的一部分.
static int __init arm64_dmi_init(void)
{
    /*
     * On arm64, DMI depends on UEFI, and dmi_scan_machine() needs to
     * be called early because dmi_id_init(), which is an arch_initcall
     * itself, depends on dmi_scan_machine() having been called already.
     */
    dmi_scan_machine();
    if (dmi_available)
        dmi_set_dump_stack_arch_desc();
    return 0;
}
core_initcall(arm64_dmi_init);
可见是通过core_initcall(arm64_dmi_init);在kernel 初始化阶段自动运行的.
void __init dmi_scan_machine(void)
{
    char __iomem *p, *q;
    char buf[32];

    if (efi_enabled(EFI_CONFIG_TABLES)) {
    
        if (efi.smbios3 != EFI_INVALID_TABLE_ADDR) {

        }
        if (efi.smbios == EFI_INVALID_TABLE_ADDR)
            goto error;
        if (!dmi_present(buf)) {
            dmi_available = 1;
            goto out;
        }
    } else if (IS_ENABLED(CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK)) {

    }
 error:
    pr_info("DMI not present or invalid.\n");
 out:
    dmi_initialized = 1;
}
在dmi_scan_machine 中首先判断 efi.smbios3 != EFI_INVALID_TABLE_ADDR 或者 efi.smbios == EFI_INVALID_TABLE_ADDR,可见dmi是smbios的一部分,且smbios有两个标准smbios 和 smbios3
如果条件成立的话就通过memcpy_fromio(buf, p, 32);将32 byte copy到buf中。
在dmi_scan_machine 中如果条件不成立,且定义了CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK,就会在0xF0000, 0x10000 这个范围内找dmi的信息。
我们之关注efi.smbios3 != EFI_INVALID_TABLE_ADDR 或者 efi.smbios == EFI_INVALID_TABLE_ADDR 成立的情况。然后调用dmi_present
static int __init dmi_present(const u8 *buf)
{
    u32 smbios_ver;

    if (memcmp(buf, "_SM_", 4) == 0 &&
        buf[5] < 32 && dmi_checksum(buf, buf[5])) {
        smbios_ver = get_unaligned_be16(buf + 6);
        smbios_entry_point_size = buf[5];
        memcpy(smbios_entry_point, buf, smbios_entry_point_size);

        /* Some BIOS report weird SMBIOS version, fix that up */
        switch (smbios_ver) {
        case 0x021F:
        case 0x0221:
            pr_debug("SMBIOS version fixup (2.%d->2.%d)\n",
                 smbios_ver & 0xFF, 3);
            smbios_ver = 0x0203;
            break;
        case 0x0233:
            pr_debug("SMBIOS version fixup (2.%d->2.%d)\n", 51, 6);
            smbios_ver = 0x0206;
            break;
        }
    } else {
        smbios_ver = 0;
    }

    buf += 16;

    if (memcmp(buf, "_DMI_", 5) == 0 && dmi_checksum(buf, 15)) {
        if (smbios_ver)
            dmi_ver = smbios_ver;
        else
            dmi_ver = (buf[14] & 0xF0) << 4 | (buf[14] & 0x0F);
        dmi_ver <<= 8;
        dmi_num = get_unaligned_le16(buf + 12);
        dmi_len = get_unaligned_le16(buf + 6);
        dmi_base = get_unaligned_le32(buf + 8);

        if (dmi_walk_early(dmi_decode) == 0) {
            if (smbios_ver) {
                pr_info("SMBIOS %d.%d present.\n",
                    dmi_ver >> 16, (dmi_ver >> 8) & 0xFF);
            } else {
                smbios_entry_point_size = 15;
                memcpy(smbios_entry_point, buf,
                       smbios_entry_point_size);
                pr_info("Legacy DMI %d.%d present.\n",
                    dmi_ver >> 16, (dmi_ver >> 8) & 0xFF);
            }
            dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string));
            printk(KERN_DEBUG "DMI: %s\n", dmi_ids_string);
            return 0;
        }
    }

    return 1;
}
在dmi_present 中首先得到smbios_ver ,如果smbios_ver 不是NULL,则dmi_ver就等于smbios_ver。否则dmi_ver 重新计算.
        if (smbios_ver)
            dmi_ver = smbios_ver;
        else
            dmi_ver = (buf[14] & 0xF0) << 4 | (buf[14] & 0x0F);
最后后调用
        if (dmi_walk_early(dmi_decode) == 0) {
来将dmi中的信息存到kernel中方面其他程序查询.
static void __init dmi_decode(const struct dmi_header *dm, void *dummy)
{
    switch (dm->type) {
    case 0:        /* BIOS Information */
        dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
        dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
        dmi_save_ident(dm, DMI_BIOS_DATE, 8);
        break;
    case 1:        /* System Information */
        dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
        dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
        dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
        dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
        dmi_save_uuid(dm, DMI_PRODUCT_UUID, 8);
        break;
    case 2:        /* Base Board Information */
        dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
        dmi_save_ident(dm, DMI_BOARD_NAME, 5);
        dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
        dmi_save_ident(dm, DMI_BOARD_SERIAL, 7);
        dmi_save_ident(dm, DMI_BOARD_ASSET_TAG, 8);
        break;
    case 3:        /* Chassis Information */
        dmi_save_ident(dm, DMI_CHASSIS_VENDOR, 4);
        dmi_save_type(dm, DMI_CHASSIS_TYPE, 5);
        dmi_save_ident(dm, DMI_CHASSIS_VERSION, 6);
        dmi_save_ident(dm, DMI_CHASSIS_SERIAL, 7);
        dmi_save_ident(dm, DMI_CHASSIS_ASSET_TAG, 8);
        break;
    case 9:        /* System Slots */
        dmi_save_system_slot(dm);
        break;
    case 10:    /* Onboard Devices Information */
        dmi_save_devices(dm);
        break;
    case 11:    /* OEM Strings */
        dmi_save_oem_strings_devices(dm);
        break;
    case 38:    /* IPMI Device Information */
        dmi_save_ipmi_device(dm);
        break;
    case 41:    /* Onboard Devices Extended Information */
        dmi_save_extended_devices(dm);
    }
}
可见dmi的信息大概分成0/1/2/3/9/10/11/38/41.根据不同的type将信息存到不同的数组中。我们以System Information为例
dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
static void __init dmi_save_ident(const struct dmi_header *dm, int slot,
        int string)
{
    const char *d = (const char *) dm;
    const char *p;

    if (dmi_ident[slot])
        return;

    p = dmi_string(dm, d[string]);
    if (p == NULL)
        return;

    dmi_ident[slot] = p;
}
可见是存在dmi_ident这个数组中。这样我们就可以通过dmi_get_system_info 函数从dmi_ident 数组中拿到System Information


const char *dmi_get_system_info(int field)
{
    return dmi_ident[field];
}
EXPORT_SYMBOL(dmi_get_system_info);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值