Linux下dmi信息分析工具dmidecode原理

news2024/11/16 15:37:27

dmidecode命令主要是通过DMI获取主机的硬件信息,其输出的信息包括BIOS、系统、主板、处理器、内存、缓存等等。它是通过SMBIOS(System Management BIOS)来获取信息的。SMBIOS是主板或系统制造者以标准格式显示产品管理信息所需遵循的统一规范。

什么是DMI?

DMI (Desktop Management Interface, DMI)的主要组成部分是Management InformationFormat (MIF)数据库,这个数据库包括了所有有关电脑系统和配件的信息。

百度百科到的资料:

DMI是指Direct Media Interface(直接媒体接口)的缩写,DMI是Intel(英特尔)公司开发用于连接主板南北桥的总线,取代了以前的Hub-Link总线。DMI采用点对点的连接方式,时钟频率为100MHz,由于它是基于PCI-Express总线,同样采用8bit/10bit(有效位宽8bit)编码因此具有PCI-E总线的优势。

在4系列芯片组没有取消前端总线FSB时,DMI 是Intel(英特尔)公司开发用于北桥(G)MCH(Graphics & Memory controller hub)和南桥ICH10/ICH7之间的芯片连接总线。DMI实现了上行与下行双向数据传输率,单通道单向传输速率达到2.5GT/s,采用8bit/10bit编码,共计4条通道。这个高速接口集成了高级优先服务,允许并发通讯和真正的同步传输能力。它的基本功能对于软件是完全透明的,因此早期的软件也可以正常操作。

从5系列芯片组开始的新构架设计中,前端总线被取消,北桥芯片的功能被整合进CPU中。显卡采用了PCI-E ×16的通道直连CPU,当多卡交火时分为×8+×8(双卡)或×8+×4+×4(三卡)(具体分配方式要参考主板设计)。因为PCI-E2.0的应用,DMI升级到DMI2.0,单通道单向传输速率达到5GT/s。同时DMI2.0也不再用于南北桥芯片的连接,而是用于CPU和芯片组(原南桥芯片组)的连接。如下图所示,下图展示的是北桥集成到CPU后的情况:

所以,我们现在可以知道,为何dmidecode工具可以获取主板,内存等信息了,因为很多关于系统硬件的底层信息都是通过DMI通道获取的,我们看一下dmidecode工具的帮助信息:

dmidecode 工具会读取/sys/firmware/dmi/tables/smbios_entry_point文件。

czl@czl-Vostro-3268:~$ sudo strace -e trace=open,close,openat dmidecode
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
close(3)                                = 0
# dmidecode 3.1
openat(AT_FDCWD, "/sys/firmware/dmi/tables/smbios_entry_point", O_RDONLY) = 3
close(3)                                = 0
Getting SMBIOS data from sysfs.
SMBIOS 3.0.0 present.
Table at 0x000E0000.

openat(AT_FDCWD, "/sys/firmware/dmi/tables/DMI", O_RDONLY) = 3
close(3)                                = 0

dmidecode的常见用法:

$ dmidecode                                                       # 打印所有硬件信息
$ dmidecode -q                                                  # 打印所有硬件信息,比较简洁
$ dmidecode -h                                                  # 获取帮助
$ dmidecode | grep 'Product Name'         # 以过滤的方式来查看指定的硬件信息
$ dmidecode --type bios                                # 查看BIOS相关的硬件信息
$ dmidecode --type system                          # 查看系统相关的硬件信息
$ dmidecode --type baseboard                  # 查看主板相关的硬件信息
$ dmidecode --type chassis                         # 查看机箱相关的硬件信息
$ dmidecode --type processor                    # 查看处理器相关的硬件信息
$ dmidecode --type memory                      # 查看内存相关的硬件信息
$ dmidecode |grep 'Serial Number'         # 查看主板的序列号
$ dmidecode -s system-serial-number  # 查看系统序列号
$ dmidecode -t 11                                           # 查看OEM信息
$ dmidecode -t 7                                             # 查看L1/L2/L3 Cache信息
$ dmidecode -t 4                                             # 查看CPU信息
$ dmidecode -t slot                                        #查看PCIE Slot槽位信息

take get pcie slot for example

czl@czl-Vostro-3268:~$ sudo dmidecode  -t slot
# dmidecode 3.1
Getting SMBIOS data from sysfs.
SMBIOS 3.0.0 present.

Handle 0x0024, DMI type 9, 17 bytes
System Slot Information
    Designation: SLOT1
    Type: x1 PCI Express
    Current Usage: Available
    Length: Short
    ID: 1
    Characteristics:
        3.3 V is provided
        PME signal is supported
    Bus Address: 0000:ff:1f.7

Handle 0x0025, DMI type 9, 17 bytes
System Slot Information
    Designation: SLOT2
    Type: x16 PCI Express 3
    Current Usage: Available
    Length: Long
    ID: 2
    Characteristics:
        3.3 V is provided
        PME signal is supported
    Bus Address: 0000:ff:1f.7

dmidecode打开文件

sudo strace -tt -T -v -f -e trace=file -o ./strace.log dmidecode

对应的内核代码在文件drivers/firmware/dmi_scan.c中:

获取机器型号的方法

method 1:

dmesg

method 2:

sudo dmidecode -t 1

内核中获取dmi信息

前面提到,用户空间dmidecode工具是通过/sys/firmware/dmi/tables/smbios_entry_point文件来获取dmi信息的,sysfs是内核空间创建的一个内存文件系统,则必然在内核中也有完备的dmi信息,那么在内核中如何获取呢?

在dmi的内核实现文件dmi_scan.c中,能找到如下几个接口,它们有被作为开放接口export出去,分别是:

u64 dmi_memdev_size(u16 handle);
void dmi_memdev_name(u16 handle, const char **bank, const char **device);
bool dmi_match(enum dmi_field f, const char *str);
int dmi_walk(void (*decode)(const struct dmi_header *, void *);
int dmi_get_bios_year(void);
bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp);
const struct dmi_device *dmi_find_device(int type, const char *name,const struct dmi_device *from);
int dmi_name_in_vendors(const char *str);
const char *dmi_get_system_info(int field);
const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list);
int dmi_check_system(const struct dmi_system_id *list);

其中,dmi_get_system_info就是我们要找的,它的参数包含如下类型,在内核中被广泛使用:

原理

dmi数据存储在哪里?

dmi数据是二进制数据,需要通过架构的IO操作读取到内核,内核为此创建了一个32字节的全局buffer保存,叫做static u8 smbios_entry_point[32];

关键逻辑是首先调用dmi_early_remap对存储smbios信息的区域进行映射,拿到虚拟地址后再dmi_smbios3_present/dmi_present中调用memcpy_fromio读进dmi_early_remap buffer中。最后设置dmi_available为1。

dmidecode就是将smbios_entry_point读取到用户空间解码发挥作用的。

execve("/usr/sbin/dmidecode", ["dmidecode"], 0x7fff725b3940 /* 26 vars */) = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\35\2\0\0\0\0\0"..., 832) = 832
close(3)                                = 0
openat(AT_FDCWD, "/sys/firmware/dmi/tables/smbios_entry_point", O_RDONLY) = 3
read(3, "_SM_\7\37\2\7s\0\0\0\0\0\0\0_DMI_\327D*\20\0\16\0\4\1\0", 32) = 31
read(3, "", 1)                          = 0
close(3)                                = 0
openat(AT_FDCWD, "/sys/firmware/dmi/tables/DMI", O_RDONLY) = 3
read(3, "\0\30\0\0\1\2I\352\3\0\220\337\t|\0\0\0\0\201\7\4\6\0\0Phoenix "..., 10820) = 4096
read(3, "RAM slot #33\0\0\21\"]\0:\0\377\377\0\0\0\0\0\0\t\0\1\1"..., 6724) = 4096
read(3, "\0\0\0\0\0NVD #61\0\0\21\"\271\0%\0\377\377 \0 \0\0\0\t\0\1\1"..., 2628) = 2628
read(3, "", 0)                          = 0
close(3)                                = 0
+++ exited with 0 +++

注意其中的raw_table_read函数实现。

除此之外,dmi仅仅是一个 sysfs中创建的子目录

callstack

[  129.107667] Hardware name: Dell Inc. Vostro 3268/0TJYKK, BIOS 1.11.1 12/11/2018
[  129.107667] Call Trace:
[  129.107669]  dump_stack+0x6d/0x8b
[  129.107670]  raw_table_read+0x24/0x30
[  129.107672]  sysfs_kf_bin_read+0x4d/0x80
[  129.107673]  kernfs_fop_read+0xad/0x1a0
[  129.107675]  __vfs_read+0x1b/0x40
[  129.107676]  vfs_read+0x8e/0x130
[  129.107678]  ksys_read+0xa7/0xe0
[  129.107679]  __x64_sys_read+0x1a/0x20
[  129.107681]  do_syscall_64+0x57/0x190
[  129.107682]  entry_SYSCALL_64_after_hwframe+0x5c/0xc1
[  129.107683] RIP: 0033:0x7f01e2dd1031

参考资料

https://blog.csdn.net/zhangliang19950813/article/details/105763801

结束

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/173540.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QA特辑 | 以万变钳制黑灰产之变的验证码产品设计逻辑的答案,都在这里

1月12 日下午,就验证码的攻防对抗问题,顶象反欺诈专家大卫从验证码的破解手段讲起,从防御角度深度剖析如何应对黑灰产的攻击以及验证码在产品能力设计层面应该考虑哪些问题。 直播也吸引了众多关注验证码的观众前来围观,针对验证…

vue3性能优化

文章目录1. Lighthouse1.1 性能参数2. rollup-plugin-visualizer(打包代码块分析)3. vite配置优化4. PWA离线缓存技术5. 其他优化1. Lighthouse 谷歌浏览器自带的 DevTools 也可以全局安装Lighthouse # 安装 yarn global add lighthouse# 使用 lighth…

Android app集成微信支付

Android app集成微信支付 鉴于微信支付的文档入口不太容易找到、以及文档中有些逻辑不通或者容易产生歧义或者缺失一些信息的情况,记录下此次接入的流程和需要关注的一些点。 使用的是app支付-> APP支付产品介绍 首先阅读介绍等,了解一些基础的概念…

c++数据结构-图(详解附算法代码,一看就懂)

图(Graph)是一种复杂的非线性结构,它可以描述数据间的关系,被广泛使用。图 G 由两个集合 V 和 E 组成,记为 。V是顶点的有穷非空集合,E是边的集合。通常,也将 G 的顶点集和边集表示为 V(G) 和 E…

尚医通-登录注册搭建-JWT(二十八)

目录: (1)前台用户系统-登录注册-需求分析 (2)前台用户系统-登录注册-搭建环境 (3)前台用户系统-手机登录-基本实现 (4)前台用户系统-手机登录-整合JWT (…

【JUC并发编程】使用多线程可能带来什么问题

【JUC并发编程】使用多线程可能带来什么问题? 文章目录【JUC并发编程】使用多线程可能带来什么问题?什么是多线程并发为什么会出现线程带来的安全性问题可见性问题原子性问题有序性问题活跃性问题性能问题引起线程切换的几种方式什么是多线程 多线程意味着你能够在同一个应用…

Linux的ZONE_DMA,ZONE_NORMAL,ZONE_HIGHMEM及分配页释放页函数的简单介绍

Linux的ZONE_DMA,ZONE_NORMAL,ZONE_HIGHMEM及分配页释放页函数的简单介绍简单介绍一下页:Linux 区:分配页系统调用释放页系统调用简单介绍一下页: 内核把物理页作为内存管理的基本单位。 尽管处理器的最小可寻址单位通常为字(甚至…

ZooKeeper-分布式锁实现

4.11)Zookeeper分布式锁-概念 •在我们进行单机应用开发,涉及并发同步的时候,我们往往采用synchronized或者Lock的方式来解决多线程间的代码同步问题,这时多线程的运行都是在同一个JVM之下,没有任何问题。 •但当我们的应用是分…

【JavaScript】实现简易购物车

💻【JavaScript】实现简易购物车 🏠专栏:有趣实用案例 👀个人主页:繁星学编程🍁 🧑个人简介:一个不断提高自我的平凡人🚀 🔊分享方向:目前主攻前端…

客快物流大数据项目(一百零四):为什么选择Elastic Search作为存储服务

文章目录 为什么选择Elastic Search作为存储服务 一、​​​​​​​​​​​​​​ElasticSearch简介

【GD32F427开发板试用】懒人新手试用

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站。作者:东东_dxGGN2 我收到的开发板是GD32F427R-START,MCU是GD32F427RKT6,如下图(座机拍的见谅) 测试流…

【C++】从0到1入门C++编程学习笔记 - 核心编程篇:内存分区模型

文章目录一、程序运行前二、程序运行后三、new 操作符C程序在执行时,将内存大方向划分为4个区域 代码区:存放函数体的二进制代码,由操作系统进行管理的全局区:存放全局变量和静态变量以及常量栈区:由编译器自动分配释…

2022年回顾 | 被磨砺,被厚待

岁末年首, 最宜盘点过往的时光。 回顾2022团结一心,攻坚克难, 祝福2023大展宏图,鹏程万里。 2022我们遇到了"卷土重来"、 “挥之不去”, 也等到了"再也不见"和 “永远下线”。 2022是一个&…

HTML中的table标签与a标签

这里写自定义目录标题一、table标签1、什么是table标签2、table标签中长见到的标签3、例子代码及其结果二、a标签1、什么是a标签2、a标签中常见的属性3、例子代码及其结果一、table标签 1、什么是table标签 table标签表示整体的一个表格 2、table标签中长见到的标签 <tr…

基于Spring Boot和Spring Cloud实现微服务架构

首先&#xff0c;最想说的是&#xff0c;当你要学习一套最新的技术时&#xff0c;官网的英文文档是学习的最佳渠道。因为网上流传的多数资料是官网翻译而来&#xff0c;很多描述的重点也都偏向于作者自身碰到的问题&#xff0c;这样就很容易让你理解和操作出现偏差&#xff0c;…

采用特殊硬件指令对密码学算法加速

1. 引言 Armando Faz-Hermandez等人2018年论文《SoK: A Performance Evaluation of Cryptographic Instruction Sets on Modern Architectures》&#xff0c;开源代码见&#xff1a; https://github.com/armfazh/flo-shani-aesni&#xff08;C语言&#xff09; slide见&…

Java高手速成 | 多态性实战

多态性&#xff08;polymorphism&#xff09;是OOP最强大、最有用的特性。截至目前&#xff0c;多态性用到了所讲的所有其他OOP概念和特性。在通向精通Java语言编程的征程上&#xff0c;多态性是最高级别概念站点。 一个对象具有跟另一不同类的对象一样的行为&#xff0c;或者具…

QT5.14.2使用回顾

前面已有博客介绍了QT的安装和配置VS2019配置Qt5.14.2以及在线配置Qt5.15.2&#xff0c;这里再接着该版本说明下QT的使用&#xff0c;主要是汇总下之前博客中的内容&#xff1a;Ubuntu下的基本知识点&#xff08;二&#xff09;QT4.8.6工程到QT5.12.1的迁移注意前面安装时候&am…

小程序开发超好用的UI组件——Vant Weapp

Vant Weapp 是有赞前端团队开源的一套小程序 UI 组件库&#xff0c;助力开发者快速搭建小程序应用。它所使用的是 MIT 开源许可协议&#xff0c;对商业使用比较友好,官网地址&#xff1a;https://vant-contrib.gitee.io/vant-weapp/#/home 安装 Vant 组件库 在小程序项目中&a…

设计模式学习(十):lterator迭代器模式

一、什么是Iterator模式使用Java语言显示数组arr中的元素时&#xff0c;我们可以使用下面这样的for循环语句遍历数组。for (int i 0; i < arr.length; i){system.out.println(arr[i]); }请注意这段代码中的循环变量i。该变量的初始值是o&#xff0c;然后会递增为1,2&#x…