源码分析
获取源码
$ git clone https://github.com/clbr/radeontop.git
主要⽂文件
源⽂文件
* detect.c
获取 PCI 显卡 id、匹配 radeon/amdgpu、对 vram、gtt 进⾏行行读写测试判断、获取显卡家族、初始化显卡运⾏行行信息结构
体 bits。
* dump.c
将显卡运⾏行行信息进⾏行行⽂文件存储操作。
* family_str.c
提供显卡家族字符串串数组,⽤用以获取#显卡代码名,打印在终端。
* radeontop.c
主程序⼊入⼝口、程序输⼊入参数解析、显卡判定以及显存映射等。
* ticks.c
开辟线程运⾏行行 collector 函数,获取负载信息。
* ui.c
curses 图形输出、将显卡负载信息计算并显示在终端中。
头⽂文件
* r600_pci_ids.h
提供 AMD 显卡 id 以及对应 家族。
* radeontop.h
其它源⽂文件的函数声明以及显卡家族的枚举数组。
流程分析
根据程序⼊入⼝口参数,设定如下⼏几个参数:
* ticks
Samples per second
* color
Enable colors
* forcemem
Force the /dev/mem path
* dump
Dump data to file
执⾏行行 init_pci 函数,获取 pciaddr(显卡 device_id):
1. 探测 pci 显卡设备,获取 busid、device_id
2. 根据设备 id 获取显卡家族型号,以及 drm_fd,判断 radeone/amdgpu 的 drm ⽀支持
3. use_ioctl 默认为 0,运⾏行行 get_drm_value(即drmCommandWriteRead)对drm io操作,对 use_ioctl 重新赋
值,成功为 1,失败则 0
4. 根据 use_ioctl 确定 是否⾛走 /dev/mem(use_ioctl = 0)
5. ⽂文件操作,打开 /dev/mem,获取 GPU 寄存器器访问,并尝试 mmap 映射
6. 判断内核对 vram 的版本⽀支持。
7. 对 radeon/amdgpu 进⾏行行⼀一次测试:对 gtt 以及 vram 空间获取、读写
获取显卡代号,如:CAICOS、POLARIS10
运⾏行行 initbits,初始化显卡负载信息——bits_t 结构体
运⾏行行 collect,开辟线程,进⾏行行显卡信息获取
根据获取的显卡信息,计算通过 curses 输出图形化界⾯面到终端
运⾏行行现象
我们直接看两张图,分别是 HD7450 和 RX 560 两张显卡:
HD7450 可以正常运⾏行行,⽽而后者不不⾏行行,运⾏行行打印信息如图,根据前⾯面的流程分析,最主要的区别在于 use_ioctl 这⼀一变量量。
在不不改变内核配置的前提下,RX 560 在运⾏行行 drmCommandWriteRead(drm io操作) 时会返回⼀一个负值,作为失败的反馈,
⽽而 HD7450 则是成功的。
这还不不算导致 mmap 错误的直接原因,还在下⾯面,如图所示:
由于 use_ioctl=0,因⽽而会⾛走这⼀一个判断,毫⽆无疑问,就是在这⾥里里映射失败的,导致错误。归根结底在于 /dev/mem 的访问上出
了了问题。
⽆无法使⽤用的原因
/dev/mem 提供着对系统内存的访问,并可以在 kernel 中设置限制访问。
某些应⽤用程序(如Xorg)需要从⽤用户空间直接访问物理理内存。 因⽽而存在特殊⽂文件 /dev/mem来提供这种访问。 若攻击者具有根
访问权限,则可以从此⽂文件查看和更更改内核内存,这是不不安全的。
因⽽而引⼊入了了 CONFIG_STRICT_DEVMEM 这⼀一内核选项来阻⽌止⾮非设备内存访问(最初命名为
CONFIG_NONPROMISC_DEVMEM)。
⽽而 radeontop 对于 amdgpu 驱动,⽬目前仅⽀支持 /dev/mem 路路径,对于这些卡,radeontop ⽆无法成功运⾏行行在限制 /dev/mem 访问
的 Ubuntu 内核上。
基于以上原因,我们 amdgpu 显卡⽆无法直接运⾏行行 radeontop,运⾏行行会发⽣生 map 映射错误。
解决⽅方式
需要修改内核配置,开启 access to /dev/mem 这⼀一选项即可: