devmem 是一个在 Linux 系统下用于直接访问物理内存的命令行工具,它能让用户在用户空间对指定的物理内存地址进行读写操作。以下是关于它的使用方法介绍:
安装 devmem
在大多数 Linux 发行版中,devmem 通常包含在 util-linux 软件包内。你可以通过以下命令来安装:
sudo apt-get update
sudo apt-get install util-linux
基本使用方法
读取内存
要读取指定物理内存地址处的数据,可使用以下命令格式:
sudo devmem2 0x2050000000
sudo devmem2 0x2050000000 b 0x55
Usage: devmem2 { address } [ type [ data ] ]
address : memory address to act upon
type : access operation type : [b]yte, [h]alfword, [w]ord, [l]ong
data : data to be written
问题1:
报错Operation not permitted
修改内核编译config选项:
CONFIG_STRICT_DEVMEM disable
问题2:
报错Invalid argument
内核编译config选项:
CONFIG_X86_PAT disable ;
CONFIG_EXPERT enable
devmem工具实现代码
#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, [l]ong\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;
printf("/dev/mem opened.\n");
fflush(stdout);
/* Map one page */
map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK);
if(map_base == (void *) -1) FATAL;
printf("Memory mapped at address %p.\n", map_base);
fflush(stdout);
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 int/*long*/ *) virt_addr);
break;
case 'l':
read_result = *((unsigned long *) virt_addr);
break;
default:
fprintf(stderr, "Illegal data type '%c'.\n", access_type);
exit(2);
}
printf("Value at address 0x%X (%p): 0x%lX\n", target, virt_addr, read_result);
fflush(stdout);
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':
//printf("%p\n", virt_addr);
//printf("0x%X\n", writeval);
*((unsigned int/*long*/ *) virt_addr) = writeval;
//*((unsigned char *) (virt_addr+0)) = writeval;
//*((unsigned char *) (virt_addr+1)) = (writeval >> 8);
//*((unsigned char *) (virt_addr+2)) = (writeval >> 16);
//*((unsigned char *) (virt_addr+3)) = (writeval >> 24);
read_result = *((unsigned int/*long*/ *) virt_addr);
break;
case 'l':
*((unsigned long *) virt_addr) = writeval;
read_result = *((unsigned long *) virt_addr);
break;
}
printf("Written 0x%lX; readback 0x%lX\n", writeval, read_result);
fflush(stdout);
}
if(munmap(map_base, MAP_SIZE) == -1) FATAL;
close(fd);
return 0;
}
Linux应用层操作寄存器
除了直接使用devmem,我们也可以在Linux应用层自己实现一个devmem。
devmem的实现原理,就是打开/dev/mem,然后通过mmap映射物理地址,从而实现读写寄存器。因此,我们只要实现这些操作,就可以自己实现类似devmem的功能。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#define MAP_SIZE 0x80000
#define base 0x40000000
int main(int argc, char **argv)
{
int fd = open("/dev/mem",O_RDWR|O_NDELAY);
if (fd < 0)
{
printf("open /dev/mem error!\n");
return -1;
}
void *map_base = mmap(NULL,MAP_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,base);
if (map_base == MAP_FAILED)
return -1;
printf("%x \n",*(volatile unsigned int*)(map_base));
close(fd);
munmap(map_base,MAP_SIZE);
return 0;
}
7019

被折叠的 条评论
为什么被折叠?



