/dev/mem是物理内存的全映像,可以用来访问物理内存,用mmap来访问物理内存以及外设的IO资源,是实现用户空间驱动的一种方法
我们先用hexedit来看下/dev/mem,hexedit /dev/mem 可以物理内存的信息,当然肉眼是无法看的毕竟是16进制。
00000000 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 S...S...S...S...
00000010 53 FF 00 F0 53 FF 00 F0 CC E9 00 F0 53 FF 00 F0 S...S.......S...
00000020 A5 FE 00 F0 87 E9 00 F0 53 FF 00 F0 46 E7 00 F0 ........S...F...
00000030 46 E7 00 F0 46 E7 00 F0 57 EF 00 F0 53 FF 00 F0 F...F...W...S...
00000040 22 00 00 C0 4D F8 00 F0 41 F8 00 F0 FE E3 00 F0 "...M...A.......
00000050 39 E7 00 F0 59 F8 00 F0 2E E8 00 F0 D4 EF 00 F0 9...Y...........
00000060 A4 F0 00 F0 F2 E6 00 F0 6E FE 00 F0 53 FF 00 F0 ........n...S...
00000070 ED EF 00 F0 53 FF 00 F0 C7 EF 00 F0 EC 57 00 C0 ....S........W..
00000080 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 S...S...S...S...
00000090 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 S...S...S...S...
000000A0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 S...S...S...S...
000000B0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 S...S...S...S...
000000C0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 S...S...S...S...
000000D0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 S...S...S...S...
000000E0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 S...S...S...S...
000000F0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 S...S...S...S...
不过可以用mmap将/dev/mem 映射出来,然后可以对其读写可以实现用户空间的内核操作。先来说下mmap函数,
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
共6个参数含义分别如下:
l addr如果为null,那么有内核选择一个映射的地址,如果不为null,那内核会把参数当做映射的提示(映射的地址就在所提示的附近,不会百分百确保的)
l  length表示映射长度
l prot表示对映射的保护, 可以是可执行,可读,可写或不可访问,PROT_EXEC,PROT_READ,PROT_WRITE,PROT_NONE
l flag表示是否对其他进程可见,MAP_SHARED表示其他进程可见。
l fd需要映射的文件描述符
l offset指向fd的编译
接下去我们用mmap来映射/dev/mem,编写代码如下:
#include
#include
#include
#include
#include
#include
int
main ()
{
unsigned char *map_base;
FILE *f;
int n, fd;
fd = open ("/dev/mem", O_RDWR | O_SYNC);
if (fd == -1)
{
printf ("open /dev/mem fail!\n");
return (-1);
}
map_base =
mmap (NULL, 0xff, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x20000);
if (map_base == 0)
{
printf ("NULL pointer!\n");
}
else
{
printf ("map Successfull!\n");
}
unsigned long addr;
unsigned char content;
int i = 0;
for (; i < 0xf; ++i)
{
addr = (unsigned long) (map_base + i);
content = map_base[i];
printf ("address: 0x%lx value: 0x%x\t\t", addr,
(unsigned int) content);
map_base[i] = (unsigned char) i;
content = map_base[i];
printf ("address: 0x%lx value: 0x%x\t\t", addr,
(unsigned int) content);
map_base[i] = (unsigned char) i;
content = map_base[i];
printf ("address: 0x%lx new value: 0x%x\n", addr,
(unsigned int) content);
}
close (fd);
munmap (map_base, 0xff);
return (1);
}
编译后,执行如下:
map Successfull!
address: 0x7fbaafb5e000 value: 0x0 address: 0x7fbaafb5e000 new value: 0x0
address: 0x7fbaafb5e001 value: 0x0 address: 0x7fbaafb5e001 new value: 0x1
address: 0x7fbaafb5e002 value: 0x0 address: 0x7fbaafb5e002 new value: 0x2
address: 0x7fbaafb5e003 value: 0x0 address: 0x7fbaafb5e003 new value: 0x3
address: 0x7fbaafb5e004 value: 0x0 address: 0x7fbaafb5e004 new value: 0x4
address: 0x7fbaafb5e005 value: 0x0 address: 0x7fbaafb5e005 new value: 0x5
address: 0x7fbaafb5e006 value: 0x0 address: 0x7fbaafb5e006 new value: 0x6
address: 0x7fbaafb5e007 value: 0x0 address: 0x7fbaafb5e007 new value: 0x7
address: 0x7fbaafb5e008 value: 0x0 address: 0x7fbaafb5e008 new value: 0x8
address: 0x7fbaafb5e009 value: 0x0 address: 0x7fbaafb5e009 new value: 0x9
address: 0x7fbaafb5e00a value: 0x0 address: 0x7fbaafb5e00a new value: 0xa
address: 0x7fbaafb5e00b value: 0x0 address: 0x7fbaafb5e00b new value: 0xb
address: 0x7fbaafb5e00c value: 0x0 address: 0x7fbaafb5e00c new value: 0xc
address: 0x7fbaafb5e00d value: 0x0 address: 0x7fbaafb5e00d new value: 0xd
address: 0x7fbaafb5e00e value: 0x0 address: 0x7fbaafb5e00e new value: 0xe
例子将物理地址起始地址0x20000, 长度为0xf映射出来了,然后进行了读写操作。这里0x7fbaafb5e000是mmap函数返回的映射地址。第二次执行的时候,会发现内存中的值已经是上次修改过的值了并非全0.。
大家可以把0x20000地址改成0x000地址(3G)地址,然后长度改成0xffffff,会出现段错误。系统的内存是段保护的,可以随便修改内存中的值系统是要崩溃的。
/dev/mem还可以用来检测系统甚至给系统打补丁,为了防止/dev/mem被注入代码,可以设置系统配置选项CONFIG_STRICT_DEVMEM=y。
此外还有port和kmem,/dev/port同/dev/mem,不过访问的是I/O端口。
/dev/kmem也同/dev/mem,不过其访问的是虚拟内存而不是物理内存。