Ubuntu 24.04 安装 pciutils 和 devmem2 教程

在 Linux 系统开发和底层调试中,pciutilsdevmem2 是两个非常实用的工具。pciutils 提供了 lspcisetpci 等命令用于查看和配置 PCI 设备;devmem2 则用于直接读写物理内存地址,常用于寄存器调试和嵌入式开发。

本文介绍在 Ubuntu 24.04 LTS 上安装和使用这两个工具的方法。

一、安装 pciutils

pciutils 在 Ubuntu 官方源中直接可用,安装非常简单:

sudo apt update
sudo apt install -y pciutils

安装完成后,可以验证版本:

$ lspci --version
lspci version 3.10.0

pciutils 常用命令

# 列出所有 PCI 设备
lspci

# 显示详细信息(树形结构)
lspci -tv

# 显示设备的详细配置信息
lspci -vvv

# 以数字方式显示(十六进制)
lspci -nn

# 查看 VGA/显卡设备
lspci -v -s $(lspci | grep -i vga | awk '{print $1}')

# 查看网络设备
lspci -v -s $(lspci | grep -i ethernet | awk '{print $1}')

# 配置 PCI 设备寄存器(需 root)
setpci -s 00:00.0 COMMAND=0x0007

二、安装 devmem2

Ubuntu 24.04 官方源中没有直接提供 devmem2,需要从源码编译安装。devmem2 原始源码来自 busybox 项目。

方法一:从源码编译安装(推荐)

# 安装编译工具
sudo apt install -y build-essential git

# 下载源码
git clone https://git.busybox.net/devmem2
cd devmem2

# 编译
make

# 安装到系统路径
sudo cp devmem2 /usr/local/bin/
sudo chmod +x /usr/local/bin/devmem2

# 验证安装
devmem2 --help 2>&1 || echo "devmem2 已安装"

方法二:手动编译(无需 git)

如果服务器无法访问 git,可以手动创建源码文件编译:

# 安装编译工具
sudo apt install -y gcc

# 创建源码文件
cat > devmem2.c <<'EOF'
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>

#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)

#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)

int main(int argc, char **argv) {
    int fd;
    void *map_base, *virt_addr;
    unsigned long read_result, writeval;
    off_t target;
    int access_type = 'w';

    if(argc < 2) {
        fprintf(stderr, "\nUsage:\t%s { address } [ type [ data ] ]\n"
            "\taddress : memory address to act upon\n"
            "\ttype    : access operation type : [b]yte, [h]alfword, [w]ord\n"
            "\tdata    : data to be written\n\n",
            argv[0]);
        exit(1);
    }
    target = strtoul(argv[1], 0, 0);

    if(argc > 2)
        access_type = tolower(argv[2][0]);

    if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
    map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK);
    if(map_base == (void *) -1) FATAL;

    virt_addr = map_base + (target & MAP_MASK);

    switch(access_type) {
        case 'b':
            read_result = *((unsigned char *) virt_addr);
            break;
        case 'h':
            read_result = *((unsigned short *) virt_addr);
            break;
        case 'w':
            read_result = *((unsigned long *) virt_addr);
            break;
        default:
            fprintf(stderr, "Illegal data type '%c'.\n", access_type);
            exit(2);
    }
    printf("Value at address 0x%lx (%p): 0x%lx\n", target, virt_addr, read_result);

    if(argc > 3) {
        writeval = strtoul(argv[3], 0, 0);
        switch(access_type) {
            case 'b':
                *((unsigned char *) virt_addr) = writeval;
                read_result = *((unsigned char *) virt_addr);
                break;
            case 'h':
                *((unsigned short *) virt_addr) = writeval;
                read_result = *((unsigned short *) virt_addr);
                break;
            case 'w':
                *((unsigned long *) virt_addr) = writeval;
                read_result = *((unsigned long *) virt_addr);
                break;
        }
        printf("Written 0x%lx; readback 0x%lx\n", writeval, read_result);
    }

    if(munmap(map_base, MAP_SIZE) == -1) FATAL;
    close(fd);
    return 0;
}
EOF

# 编译
gcc -o devmem2 devmem2.c

# 安装
sudo cp devmem2 /usr/local/bin/
sudo chmod +x /usr/local/bin/devmem2

方法三:使用 devmem(busybox)

Ubuntu 24.04 还提供了一个 busybox 内置的 devmem 命令,功能类似:

sudo apt install -y busybox

# 使用 busybox devmem
sudo busybox devmem 0x10000000

# 读取 32 位
sudo busybox devmem 0x10000000 32

# 写入 32 位
sudo busybox devmem 0x10000000 32 0x12345678

三、devmem2 使用方法

# 读取物理地址(默认 32 位)
sudo devmem2 0x10000000

# 读取 8 位(byte)
sudo devmem2 0x10000000 b

# 读取 16 位(halfword)
sudo devmem2 0x10000000 h

# 读取 32 位(word,默认)
sudo devmem2 0x10000000 w

# 写入值到物理地址
sudo devmem2 0x10000000 w 0x12345678

# 写入 8 位值
sudo devmem2 0x10000000 b 0xFF

四、注意事项

  • devmem2 需要 root 权限才能访问 /dev/mem,必须使用 sudo
  • 直接读写物理内存有风险,操作不当可能导致系统崩溃,请确认地址后再写入
  • 在某些云服务器或虚拟机中,/dev/mem 可能被内核限制访问(CONFIG_STRICT_DEVMEM=y),需要内核支持才能使用
  • ARM/嵌入式平台上常用于读取 GPIO 寄存器、UART 寄存器等,x86 平台上多用于调试硬件设备
  • pciutils 中的 setpci 可用于直接读写 PCI 配置空间,无需 devmem2

五、总结

本文介绍了在 Ubuntu 24.04 上安装 pciutils 和 devmem2 的完整流程:

  • pciutils:直接 apt install pciutils,提供 lspci/setpci 等命令
  • devmem2:需从源码编译或使用 busybox devmem 替代
  • 两者都是 Linux 底层开发和硬件调试的必备工具

如果在编译或使用过程中遇到问题,欢迎留言交流!

发表回复

后才能评论