| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 系统运维 -> Linux下访问处理器硬件信息原理:图形化工具RWLinux的诞生 -> 正文阅读 |
|
[系统运维]Linux下访问处理器硬件信息原理:图形化工具RWLinux的诞生 |
????大家好,这里是第五位面壁者。今天继续我们的学习之旅,同样视频会放在B站,PPT和视频录音的文字版本会在下面这些平台同步更新,欢迎各位大佬参观指导。 ? ????今天的这期内容,我给大家介绍一款我自己编写的可以在Linux下访问物理内存信息的图形化界面工具---RWLinux。 ????RWLinux只是一个偶然的产物,由于工作的原因,我需要经常在各种环境下访问和查看计算机的各种硬件信息,包括但不限于物理内存/IO端口/PCI配置空间/CPUMSR等。在UEFI Shell下有RU.efi供我们使用,在Windows下有ReadWriteEverying,但是在Linux下我发现似乎没有类似的集成工具,而是一个个分散的小工具,它们大多需要走一遍安装流程才能使用,而且各自都存在一些限制,最主要的还是,它们没有集成在一起。 ????在大多数情况下,其实这些缺憾其实无伤大雅,但是在某些场合,比如在远程某个客户发邮件说某款等待量产机型的USB口在Linux不识别优盘,我需要他帮我看一下发生fail时候USB的Port Status,这需要先找到USB Controller的PCIConfig?Space拿到MMIO的Bar,然后再去Bar Register显示的MemoryAddress去读取USB MMIO Register。在Linux下,这可能需要用到lspci+devmem/hexedit,待测环境可能不允许我们去安装软件,客户那边对接的人可能也没办法进行上述这堆涉及多个tool而且还基于命令行的操作。 ????我本身并不是Linux工程师,最一开始,只是本着学习Linux的目的进行了一下关于Linux下访问硬件信息的探索,RWLinux只是进行这些探索后的一个副产品。所以今天这期内容主要分为三个部分,先是介绍一下我所学习到的在Linux下访问硬件信息的原理和方法,随后介绍一些业界存在的主流工具以及限制,最后再介绍RWLinux界面以及下载方法。 ????想要在Linux下访问物理内存空间,就离不开/dev/mem,从系统的角度来看,/dev/mem是linux下的一个字符设备,这个设备文件是专门用来访问物理地址空间用的,里面的内容是物理地址空间的全镜像。什么是物理地址空间?在英特尔手册的第一卷3.3小节就给出过定义,所谓的物理地址空间就是处理器可以通过自己的地址总结访问到的内存空间。那么我现在提两个问题:第一个,USB的MMIO在不在物理地址空间里面?第二个,一个64bit的PC,装了根8G的内存条,那我写程序去读物理地址为0xFFFFFFF0的内容,所访问的数据在这根8G内存条里的什么位置?如果有同学在听完这两个问题后第一时间没有答案,先右上角叉掉这跟视频,然后下去把IO/MMIO/物理地址空间/DRAM空间/PCI地址空间的区别和联系搞清楚再回来,不然往后你可能根本不知道我在说什么。 ????刚才我们说到。/dev/mem是一个字符设备,里面的内容是物理地址空间的全镜像。Kernel为我们提供了这跟字符设备的驱动,放在/drivers/char/mem.c里。因此我们可以通过常规文件操作利用mem.c提供的驱动,把内存完全当作一个文件去对待,比如open/close/read/write等。如果你懒得去写程序进行文件操作,还可以用一个叫做hexedit的软件直接打开/dev/mem.c进行操作。Hexedit本身是一个十六进制编辑器,其工作方式和调用驱动的方法在本质上是一样的。使用hexedit查看和编辑/dev/mem的过程中会触发各种各样的系统调用,在系统调用里会根据设备文件的主设备号找到/dev/mem的设备文件驱动,所以到最后这两者其实殊途同归。 ????除了open/close/read/write等这些常规文件操作,我们还可以通过mmap机制操作文件。二者的区别简单来说就是,常规文件操作为了提高读写效率和保护磁盘,使用了存放于内核地址空间的Page Cache,这就造成了读文件时候需要先把文件页从磁盘拷贝到页缓存中,由于Page Cache处于内核空间,用户进程没办法直接访问,所以还需要把Page Cache中的数据再次拷贝到用户空间应用程序指定的buffer里,写操作也是一样。而mmap机制的思路是,先为待操作文件建立一个页表,这样相当于把文件的物理地址映射到了用户进程的虚拟地址上,当进程访问这段虚拟地址的时候去查询页表,因为之前只是建立了映射关系,所以必然会引发缺页异常,然后缺页异常会负责把物理页的数据填到虚拟页的位置上。这样的话,只需要进行一次拷贝操作,操作方式也从IO读写方式变成了直接操作内存,提高了文件的读取效率。正常思维下,如果我们想自己写程序通过/dev/mem操作物理内存,都是通过mmap的方式把/dev/mem映射到进程空间的虚拟地址上进行的,业界知名的devmem和我们随后介绍的RWLinux就是这种方式。下面我们结合mem.c的源码具体的来看一下上述三种方式的运作过程,加深记忆。 ????之前我们提到过,用户进程执行程序会触发系统调用,系统调用会根据主设备号寻找设备的驱动程序,然后会在驱动程序里面找一个叫做file_operation的结构体,通过结构体里的指针把控制器交给对应的函数,这个也是Linux设备驱动程序的基本原理。我们写程序读取/dev/mem的时候,只需要在程序里直接调用open/read/write这些文件操作函数就好,系统会帮我们找到/dev/mem对应的驱动函数文件,也就是这个mem.c,然后在mem.c里面找到file_operation再调取真正的驱动,比如read会调用read_mem;mmap的过程也是类似,比如下面这张图里,程序使用系统调用mmap映射/dev/mem到程序所在进程的虚拟空间,第一个参数表示被映射到的虚拟空间位置,写0代表让操作系统调配。这个mmap系统调用会经过类似的过程,根据主设备号找到/dev/mem对应的驱动程序文件,最后真正负责执行映射过程的其实还是mem.c里面的mmap_mem。 ????然后我们看一下mmap_mem的具体实现,先是一堆address range check,然后最后会到remap_pfn_range建立物理页和虚拟页的映射,range check是处于kernel安全机制的设计,毕竟/dev/mem是物理内存的全镜像,相当于整个系统的全部信息,如果让用户空间的程序随意方法任意地址,整个系统随时都可能并被某个非法操作干瘫痪。事实上,我们用刚才说的hexedit和devmem也不是什么地址都可以访问的。大家可以使用?cat /proc/iomem这个命令看一下你的内存空间分布,凡是显示System RAM和Kernel的基本都无法访问,运气不好的遇到保护机制严格的OS,用这两个工具可能只能访问1M以下的地址。比如我工作用的这台ubuntu,使用devmem访问1M这个问题,直接就给报错了。 ????这些限制主要是通过range_is_allowed这个函数实现的,这个函数里面又调用了devmem_is_allowed,??然后里面又调用了iomem_is_exclusive,在最后这个函数里我们可以看到,有一个内核配置选项CONFIG_STRICT_DEVMEM,如果不开启的话,限制是最小的。这个选项只能在编译内核的时候修改,没办法实时更改。不管是devmem还是hexedit都没有解决这个问题,不过大家不用担心,我的RWLinux解决了这个问题,思路很简单粗暴,写一个内核模块,使用kretprobe技术监测devmem_is_allowed,让它的返回值用于为1就可以。稍后在介绍RWLinux界面的时候给大家再演示一下。 ????Linux下访问IOPort的工具我还没找到,可能本来写程序实现就很简单,用的人也比较少,所以就没有专门的工具了。这里面涉及三个函数,我们需要先调用iopl提高进程对io端口的访问权限,为3的时候可以读写端口,为0的时候不可读写,后面这个ioperm其实算是iopl的子集,功能类似,这里只是为了保险多调用了一次,最后就可以使用IN/OUT函数操作IO端口了,这里很简单,网上也有很多描述,感兴趣的话大家可以参考源码看一下具体实现。 ????当你知道了怎么访问Memery和IO,基本就可以动手造轮子了,因为剩下的事情和操作系统关系不大,需要的是对x86架构有一定程序的了解。最简单的比如说PCIConfigSpace,如果你可以访问IO,就可以利用CF8/CFC访问256B的legacyPCI?Config?Space了,然后到了PCIE时代,配置空间扩展到了4K,于是产生了ECAM机制,把PCIE?configspace映射到了以PCIEBar为起始的memeryspace里,当然了我们还是可以使用CF8/CFC继续访问前256B。那这个PCIEBarAddress放在哪里呢,放在MCFG里,在ACPI兼容的系统里,我们可以先在1M一下某个位置暴力搜索RSDP,然后就找到了ACPITable的表头,然后可以通过RSDP指向的XSDT,在XSDTEntry里找到MCFG的存放位置,找到MCFG以后你会发现ACPISpec里面压根没有MCFG的定义,于是你需要在PCIFW Spec里找MCFG的定义,经过一番波折,你终于在MCFG里找到了PCIEBARAddress。你可以在程序里先用CFC/CFG8挨个去扫PCITree,遍历每一个BUS Dev Fun的VendorID/Dev ID,如果回应是全F,说明这个BDF代表的PCITarget不存在,然后把这些存在的BDF报给用户,用户就可以选择访问,根据访问configspace的offset选择所使用的方式。258B以内,legacy和ECAM都支持,256B以外,只支持ECAM。 在Linux下,可以直接使用shell自带命令lspci查看和访问pciconfigspace,大家可以使用这个命令验证自己程序的结果。 ????如果你可以顺利找到MCFG,相信找到其他的ACPITable也是很简单的事情,找到之后就可以对着ACPISpec去解释,这完全就是个力气活儿,我比较懒所以RWLinux暂时还没实现。社区里有开源软件isal和acpidump可以帮助我们decode系统里的acpi信息,大家可以使用这个软件验证自己程序的结果。 ????MSR这个是x86独有的东西,社区有提供开源软件msrtools,本质上还是利用了x86的RDMSR和WRMSR指令,使用这个两个指令的时候,把需要访问的MSR Address放在ECX里,读写的数据放在EDX:EAX里,EDX里放的是MSR高32bit,EAX里放的是MSR低32bit。不过使用这个tool也有个限制,那就是需要系统里有msr.ko或者是将msr模块编译进内核。大家也可以自己编写内核模块去实现,比如写个内核,进入到内核态以后,直接内联汇编操作ECX和EDX/EAX,但是我不确定Kernel是否允许我们胡搞到这种地步。因为日常工作里我操作MSR的机会比较少,所以这一块RWLinux并没有实现 ????接下了就给大家看一下RWLinux的界面,我希望这个工具可以做到通用性好,免安装,界面风格贴近RU。我当初考虑过使用python+Qt的方案,先用C语言把刚才所有系统调做成静态库,然后在python里面使用ctypes调用so,Python处理文本很方便,Qt制作界面容易,二者一结合可以说威力无边。但是我又担心Python+Qt会让程序变得臃肿而且对老系统有兼容性问题,所以我最后采取了古老的ncurses库,vim就是使用这个库实现终端界面的,既然每个Linux都可以运行Vim,那也可以运行我的RWLinux。使用方法很简单,先把RWLinux下载到本地,然后进入root用户,使用chmod777修改权限,然后直接./RWLinux就可以打开了,界面如上,默认会把所有的PCI Device都扫出来,在其他任意界面下摁F6也会跳到这个PCI Tree界面,然后在这里界面里面摁上下键,光标就会移动,再摁回车,就到了光对应的PCI Dev Fun配置空间了 ????进入到配置空间,按上下左右光标会跟着移动,直接摁数字键然后再按回车就完成的写入,PageDown/PageUp可以实现翻页。本来起始应该在Linux下给大家操作,但是我比较懒,Linux下录屏比较麻烦,大家就这么凑合看吧。 ????摁下F5会跳到内存空间访问,会提示输入地址,我这里输入的地址已经超过了4G,看起来也是可以访问的。 ????摁F8就可以访问IO地址空间,会提示输入base,我这里以80 port为base,基本上这就是RWLinux的全部功能。可以看到只是实现了功能,细节做的还是比较糙,距离Window下的ReadWriteEverying还差的很远,但是最近我没有时间去更新它。我把RWLinux的可执行文件放在了CSDN上,大家可以免积分直接下载,资源名字和PPT开篇里的名字一样,目前看起来还在审核。如果找不到或者使用起来有什么bug,欢迎大家发邮件到liwenlu_buaa@163.com指点。我的想法是,如果大家觉得这个工具还有些用处,我就继续更新丰富功能,如果无人问津,那做为一次学习Linux的课程实习了,这份PPT就当作实习报告,然后就此打住。 感谢各位的观看,本期内容到此结束。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/15 14:22:42- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |