跳转至

Linux 内核调试工具devmem介绍

在调试驱动和内核过程中,进场会遇到一些问题,这里介绍一个内核调试工具devmem,很可能已经很多用上了。

1. devmem初识

devmem 是一个 Linux 命令行工具,用于在用户空间直接访问系统内存。这个工具允许开发者读取或写入特定物理地址上的内存内容,通常用于嵌入式系统的调试和开发过程中。

比如说在开发过程中,配置了某个寄存器的值,但是这个时候你无法判定这个寄存器的值是多少,想要去获取,可能需要写一个驱动,在驱动中去映射寄存器地址,转为虚拟地址就可以访问。但是这样很麻烦,但是有这个devmem,就可以直接通过devmem去读取寄存器的值,只是作为一个命令去操作非常方便。

devmem 命令格式:

Usage: devmem ADDRESS [WIDTH [VALUE]]
Read/write from physical address
 ADDRESS Address to act upon
 WIDTH Width (8/16/...)
 VALUE Data to be written

ADDRESS : 物理地址

WIDTH:位宽

VALUE:值

2. Devmem 在内核中配置

内核配置文件打开

CONFIG_DEVMEM = y

image-20231129233301711

图2.1 内核配置menuconfig

devmem 命令确实依赖于 Linux 系统中的 /dev/mem 设备文件。

devmem 使用了mmap系统调用,将物理内存映射到用户空间的虚拟地址空间。这样,物理内存的某个范围就可以像访问普通内存一样通过指针进行访问。

3. 应用层使用devmem

根据前面知识:

devmem 使用了mmap系统调用;

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>

#define BASE_ADDRESS 0x12345678  // 替换为你要访问的基地址
#define REGISTER_OFFSET 0x04      // 替换为你要访问的寄存器相对于基地址的偏移量

int main() {
    int mem_fd;
    void *mapped_base, *mapped_dev_base;
    off_t dev_base = BASE_ADDRESS;

    // 打开 /dev/mem 设备文件
    mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
    if (mem_fd == -1) {
        perror("Error opening /dev/mem");
        return EXIT_FAILURE;
    }

    // 映射物理地址到用户空间
    mapped_base = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, dev_base & ~(getpagesize() - 1));
    if (mapped_base == (void *)-1) {
        perror("Error mapping /dev/mem into user space");
        close(mem_fd);
        return EXIT_FAILURE;
    }

    // 计算相对于映射基地址的偏移量
    mapped_dev_base = mapped_base + (dev_base & (getpagesize() - 1));

    // 读取寄存器的值
    unsigned int reg_value = *((volatile unsigned int *)(mapped_dev_base + REGISTER_OFFSET));
    printf("Current value of the register: 0x%08X\n", reg_value);

    // 写入新的值到寄存器
    unsigned int new_value = 0xABCD;
    *((volatile unsigned int *)(mapped_dev_base + REGISTER_OFFSET)) = new_value;
    printf("New value written to the register: 0x%08X\n", new_value);

    // 解除映射并关闭文件
    if (munmap(mapped_base, getpagesize()) == -1) {
        perror("Error unmapping /dev/mem");
    }
    close(mem_fd);

    return EXIT_SUCCESS;
}

4. 实际应用举例

4.1 设备驱动配置调试,对寄存器的查询

在配置驱动的过程中,对于SOC某些寄存器配置,想重新查询可以使用devmem

比如:笔者在使用配置SPI 寄存器后发现SPI 无时钟信号,发现pinctrl未起作用,这里就可以通过读取pin的寄存器的值进行判断是否有配置。

evk_8mq:/ # devmem 0x30330210 4  axaaaaas  evk_8mq:/ #

4.2 内存映射区域的调试:

对于一些外设,特定的内存映射区域用于与外设进行通信。通过 devmem,开发人员可以检查和修改这些内存映射区域的内容,以验证硬件状态或进行调试。

5. 结语

DEVMEM 是一个比较常用的工具,特别是在查询SOC寄存器值的有比较方便的作用,对于Linux 内核调试是一种工具的一种,后续还将分享一些其他工具。