/dev/mem

/dev/mem是物理内存的全映像,可以用来访问物理内存,一般用法是open("/dev/mem",O_RDWR|O_SYNC),然后mmap,接着就可以用mmap的地址来访问物理内存,这实际上就是实现用户空间驱动的一种方法。

有几个论据倾向于用户空间编程,有时编写一个所谓的用户空间设备驱动对比钻研内核是一个明智的选择,用户空间驱动的好处在于:

  1. 完整的C库可以链接,驱动可以进行许多奇怪的任务,而不用依靠外面的程序(实现使用策略的工具程序,常常随着驱动自身发布)。  
  2. 程序员可以在驱动代码上运行常用的调试器,而不必调试一个运行中的内核的弯路。  
  3. 如果一个用户空间驱动挂起了,你可以简单地杀死它。用户空间驱动出现问题不可能挂起整个系统,除非被控制的硬件真的疯掉了。  
  4. 用户内存是可交换的,不像内核内存。这样一个不常使用却有很大一个驱动的设备不会占据别的程序可以用到的RAM,除了在它实际在用时。  
  5. 一个精心设计的 驱动程序仍然可以如同内核空间驱动一样允许对设备的并行存取。  
  6. 如果你必须编写一个封闭源码的驱动,用户空间的选项使你容易辨明不明朗的许可的情况和改变的内核接口带来的问题。  

但是,用户空间的设备驱动有几个缺点,最重要的是:

  1. 中断在用户空间无法使用,在某些平台上有对这个限制的解决方法,例如在IA32体系结构上的vm86系统调用。  
  2. 只可能通过内存映射/dev/mem来使用DMA,而且只有特权用户可以这样做。  
  3. 存取I/O端口只能在调用ioperm或者iopl只有,此外,不是所有的平台都支持这些系统调用,而存取/dev/port可能太慢而无效率,这些系统调用和设备文件都要求特权用户。  
  4. 响应时间慢,因为需要上下文切换在用户和硬件之间传递消息和动作。  
  5. 更坏的是,如果驱动已经被交换到硬盘,响应时间会长到不可接受,使用mlock系统调用可能会有帮助,但是你需要经常锁住许多内存页,因为一个用户空间程序依赖大量的库代码,mlock也限制在授权用户上。  
  6. 最重要的设备不能在用户空间处理,包括网络接口和块设备。  

综上,用户空间驱动不能做的事情毕竟太多,感兴趣的应用程序还是存在:对SCSI扫描器设备的支持(由SANE包实现)和CD刻录机(由cdrecord和别的工具实现)。在两种情况下,用户级别的设备情况依赖"SCSI generic"内核驱动,它输出了底层的SCSI功能给用户程序,因此它们可以驱动它们自己的硬件。

当你开始处理新的没有用过的硬件时,通过开发用户空间驱动,你可以学习去管理你的硬件,不必担心挂起整个系统,一旦你完成了,在一个内核模块中封装软件就会是一个简单的操作了。

Notes: 新内核已经限制/dev/mem中1M以上的内存访问,这是一个可配置的选项CONFIG_STRICT_DEVMEM,在我的机器上已经选择n了,可是好像还是只能映射1M一下物理内存。

在ULCC中通过mmap映射物理内存地址到虚拟地址,实现物理页的noncacheable,这主要是通过映射/dev/mem修改PAT中的页面属性达到的。X86的页面属性表(PAT)能够在页面粒度上设置内存属性,PAT是对MTRR的补充,通过MTRR可以为物理地址区域设置内存类型,但是PAT比MTRR更灵活,因为它可以在页面级别设置属性,而且硬件上也不限制属性设置的数量。PAT相当灵活,即使多个虚拟地址映射到同一个物理内存地址,也不会引起内存类型的冲突,通过PAT能够设置多种类型的内存属性,其中最常用的有4种:Write-BackUcachedWrite-CombinedUncached-Minux

  1. fm = open("/dev/mem", O_RDWR|O_SYNC);  
  2. mmap((void *)addr, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fm, pfn<<PAGE_SHIFT);  

/dev/kmem:内核看到的虚拟内存的全映像,可以用来访问kernel的内容。

 

What Is /proc/kcore?
None of the files in /proc are really there--they're all, "pretend," files made up by the kernel, to give you information about the system and don't take up any hard disk space.

/proc/kcore is like an "alias" for the memory in your computer. Its size is the same as the amount of RAM you have, and if you read it as a file, the kernel does memory reads.

展开阅读全文

linux下mmap /dev/mem后读内存死机

09-20

我的程序在后面有,然后我生成可执行文件,读0地址的内容时死机,求指教。rn[code=C/C++]rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn//memory dumprn//: dump memory ranging from addr to len+addr-1 do a filern//: memdump addr len filenamernvoid main(unsigned char argc, unsigned char *argv[]) rn int fd;rn FILE * outfile;rn off_t addr;rn off_t len=256;rn char filename[256]="memdumpout.bin";rnrn off_t startaddr;rn off_t offset;rn int numpages;rn size_t size=0x1000; //4k is page size of memrn off_t mapped_startaddr;rn// Test first if arguments are OKrn// first argument is executable name, which must be "memdump"rn if(strcmp(argv[0],"memdump")!=0)rn return -1;rn// OK, we support default len=256 and filename $PWD/memdumpout.bin rn// but addr is a mustrn if(argc<2||argc>4)rn return -2;//Error, Invalid number of parametersrn sscanf(argv[2],"%x",&addr);rn startaddr=addr&(~(size-1));rn offset=addr-startaddr;rn numpages=(len+offset-1)/0x1000;rn size*=numpages;rnrn if(argc>=3) rn sscanf(argv[2],"%d",&len);rn if(argc==4)rn sscanf(argv[3],"%s",&filename);rn if( argc==4) rn sscanf(argv[3],"%x",&len);rn rn rn outfile=fopen(filename,"wb");rn fd=open("/dev/mem",O_RDWR|O_SYNC);rn mapped_startaddr=mmap(0,size,PROT_READ|PROT_WRITE, MAP_SHARED,fd,startaddr);rn fwrite((unsigned char *)(mapped_staraddr+offset),1,len,outfile);rn munmap(mapped_startaddr,size);rn fclose(outfile);rn close(fd);rnrn[/code] 论坛

没有更多推荐了,返回首页