static struct file_operations mem_fops =
{
.llseek = memory_lseek,
.read = read_mem,
.write = write_mem,
.mmap = mmap_mem,
.open = open_mem,
};
#include
#include
int main(void)
{
int fd;
char *rdbuf;
char *wrbuf = "butterfly";
int i;
fd = open("/dev/mem",O_RDWR);
if(fd < 0)
{
printf("open /dev/mem failed.");
}
read(fd,rdbuf,10);
for(i = 0;i < 10;i++)
{
printf("old mem[%d]:%c\n",i,*(rdbuf + i));
}
lseek(fd,5,0);
write(fd,wrbuf,10);
lseek(fd,0,0);//move f_ops to the front
read(fd,rdbuf,10);
for(i = 0;i < 10;i++)
{
printf("new mem[%d]:%c\n",i,*(rdbuf + i));
}
return 0;
}
[root@VOIP-IPCAM app]# ./memtest
old mem[0]:b
old mem[1]:u
old mem[2]:t
old mem[3]:t
old mem[4]:e
old mem[5]:r
old mem[6]:f
old mem[7]:l
old mem[8]:y
old mem[9]:!
new mem[0]:b
new mem[1]:u
new mem[2]:t
new mem[3]:t
new mem[4]:e
new mem[5]:b
new mem[6]:u
new mem[7]:t
new mem[8]:t
new mem[9]:e
00000000 62 75 74 74 65 62 75 74 74 65 72 66 6C 79 21 20 butterfly!
00000010 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
00000020 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
00000030 6F EF 00 F0 6F EF 00 F0 57 EF 00 F0 6F EF 00 F0 o...o...W...o...
00000040 02 11 00 C0 4D F8 00 F0 41 F8 00 F0 34 85 00 F0 ....M...A...4...
00000050 39 E7 00 F0 59 F8 00 F0 2E E8 00 F0 D2 EF 00 F0 9...Y...........
00000060 A4 E7 00 F0 F2 E6 00 F0 6E FE 00 F0 53 FF 00 F0 ........n...S...
00000070 53 FF 00 F0 A4 F0 00 F0 C7 EF 00 F0 1C 42 00 C0 S............B..
#include
#include
#include//mmap head file
int main (void)
{
int i;
int fd;
char *start;
char *buf = "butterfly!";
//open /dev/mem with read and write mode
fd = open ("/dev/mem", O_RDWR);
if (fd < 0)
{
printf("cannot open /dev/mem.");
return -1;
}
//map physical memory 0-10 bytes
start = (char *)mmap(0, 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(start < 0)
{
printf("mmap failed.");
return -1;
}
//Read old value
for (i = 0; i < 10; i++)
{
printf("old mem[%d]:%c\n", i, *(start + i));
}
//write memory
memcpy(start, buf, 10);
//Read new value
for (i = 0;i < 10;i++)
{
printf("new mem[%d]:%c\n", i,*(start + i));
}
munmap(start, 10); //destroy map memory
close(fd); //close file
return 0;
}
[root@VOIP-IPCAM app]# ./rwphy
old mem[0]:b
old mem[1]:u
old mem[2]:t
old mem[3]:t
old mem[4]:e
old mem[5]:b
old mem[6]:u
old mem[7]:t
old mem[8]:t
old mem[9]:e
new mem[0]:b
new mem[1]:u
new mem[2]:t
new mem[3]:t
new mem[4]:e
new mem[5]:r
new mem[6]:f
new mem[7]:l
new mem[8]:y
new mem[9]:!
“/dev/mem是个很好玩的东西,你竟然可以直接访问物理内存。这在LINUX下简直是太神奇了,这种感觉象一个小偷打算偷一个银行,可是这个银行戒备森严,正当这个小偷苦无对策时,突然发现在一个不起眼的地方有个后门,这个后门可以直接到银行的金库。”
Linux下/dev/mem和/dev/kmem的区别:
/dev/mem: 物理内存的全镜像。可以用来访问物理内存。
/dev/kmem: kernel看到的虚拟内存的全镜像。可以用来访问kernel的内容。
作用:
/dev/mem用来访问物理IO设备,比如X用来访问显卡的物理内存,或嵌入式中访问GPIO。用法一般就是open,然后mmap,接着可以使用map之后的地址来访问物理内存。这 其实就是实现用户空间驱动的一种方法。
/dev/kmem后者一般可以用来查看kernel的变量,或者用作rootkit之类的。参考1和2描述了用来查看kernel变量这个问题。
/dev/mem用法举例:
比如驱动(内核空间)中
vir_addr = kmalloc( size, GFP_KERNEL | GFP_DMA )
phy_addr = __pa( vir_addr );
申请了一段内存,然后得到__pa()得到它的物理地址,然后将该物理地址传到用户空间
然后在应用程序(用户空间)中
int map_fd = open("/dev/mem", O_RDWR);
map_addr = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, phy_addr);
这样就可以得到 在应用程序中 访问驱动程序中申请的内存的指针map_addr,可以实现应用程序和驱动程序访问同段内存,节省开销,实现内存共享
这是一种方法,把内核空间的内存映射到用户空间,内核空间内存-->物理地址(PA)-->用户空间 通过/dev/mem 和系统调用mmap
#include#include #include #include #include #include #include #include #include #include #include int page_size; #define PAGE_SIZE page_size #define PAGE_MASK (~(PAGE_SIZE-1)) void get_var (unsigned long addr) { off_t ptr = addr & ~(PAGE_MASK); off_t offset = addr & PAGE_MASK; int i = 0; char *map; static int kfd = -1; kfd = open("/dev/kmem",O_RDONLY); if (kfd < 0) { perror("open"); exit(0); } map = mmap(NULL,PAGE_SIZE,PROT_READ,MAP_SHARED,kfd,offset); if (map == MAP_FAILED) { perror("mmap"); exit(-1); } printf("%s\n",map+ptr); return; } int main(int argc, char **argv) { FILE *fp; char addr_str[11]="0x"; char var[51]; unsigned long addr; char ch; int r; if (argc != 2) { fprintf(stderr,"usage: %s System.map\n",argv[0]); exit(-1); } if ((fp = fopen(argv[1],"r")) == NULL) { perror("fopen"); exit(-1); } do { r = fscanf(fp,"%8s %c %50s\n",&addr_str[2],&ch,var); if (strcmp(var,"modprobe_path")==0) break; } while(r > 0); if (r < 0) { printf("could not find modprobe_path\n"); exit(-1); } page_size = getpagesize(); addr = strtoul(addr_str,NULL,16); printf("found modprobe_path at (%s) %08lx\n",addr_str,addr); get_var(addr); }
外国项目中的一段代码:
if((fdMem = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
{
fprintf(stderr, "Unable to open the /dev/mem interface !\n");
return;
}
map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fdMem, GPIO_ADDR & ~MAP_MASK);
if (map_base == (void *) -1)
{
fprintf(stderr, "Unable to map 0x%08x address\n", GPIO_ADDR);
close (fdMem);
return;
}
// Add offset for init (VD0) => PORTC8
virt_addr = map_base + 0x20;
// Configure GPIO
read_result = *((unsigned long *) virt_addr);
read_result &= (~(0x03 << 16));
read_result |= 0x01 << 16;
*((unsigned long *) virt_addr) = read_result;
// Add offset for VD0
virt_addr = map_base + 0x24;