写一个读写/dev/mem的示例

以下是一个简单的 /dev/mem 读写示例代码,包含详细注释和安全提示。请注意:直接操作物理内存极其危险,可能导致系统崩溃或硬件损坏,仅用于学习或底层开发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
#include <stdint.h>

#define PAGE_SIZE sysconf(_SC_PAGESIZE)
#define PHY_ADDR 0x100000 // 示例地址(可根据需求修改)

int main() {
int fd;
void *map_base;
void *virt_addr;
uint32_t read_result;

// 1. 打开 /dev/mem 设备(需root权限)
fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd == -1) {
perror("open /dev/mem failed");
return EXIT_FAILURE;
}

// 2. 计算映射参数(按页对齐)
size_t map_size = PAGE_SIZE;
off_t map_offset = (off_t)(PHY_ADDR & ~(PAGE_SIZE - 1)); // 对齐到页边界
size_t page_offset = PHY_ADDR - map_offset;

// 3. 映射物理内存到用户空间
map_base = mmap(
NULL,
map_size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
map_offset
);

if (map_base == MAP_FAILED) {
perror("mmap failed");
close(fd);
return EXIT_FAILURE;
}

// 4. 计算目标地址的虚拟指针(使用volatile防止编译器优化)
volatile uint32_t *target_addr = (volatile uint32_t *)((char*)map_base + page_offset);

// 5. 示例操作:读取 -> 修改 -> 写入
read_result = *target_addr;
printf("Original value at 0x%x: 0x%08x\n", PHY_ADDR, read_result);

*target_addr = 0xDEADBEEF; // 写入新值
printf("New value written: 0x%08x\n", 0xDEADBEEF);

read_result = *target_addr; // 验证写入
printf("Current value: 0x%08x\n", read_result);

// 6. 清理资源
if (munmap(map_base, map_size) == -1) {
perror("munmap failed");
}
close(fd);

return EXIT_SUCCESS;
}

关键说明

  1. 地址选择

    • PHY_ADDR 需根据具体硬件手册设置(如外设寄存器地址)。
    • 示例使用 0x100000(典型BIOS区域,仅用于演示,实际可能无权限)。
  2. 安全要求

    • 必须使用root权限运行sudo ./program
    • 内核需启用 /dev/mem 访问(非CONFIG_STRICT_DEVMEM 环境)。
  3. 风险警告

    • 错误地址可能导致系统崩溃/数据损坏。
    • 避免在关键生产环境使用。
  4. 编译命令

    1
    gcc -o mem_io mem_io.c

典型输出(取决于目标地址内容)

1
2
3
Original value at 0x100000: 0x00000000
New value written: 0xdeadbeef
Current value: 0xdeadbeef

建议在嵌入式开发或内核模块中优先使用更安全的方法(如设备驱动),而非直接操作 /dev/mem