驱动开发过程中的内存访问.
转载自http://winceblog.blogspot.com/2007/02/blog-post_17.html
1.CPU访问设备寄存器:
在ARM中可以直接将设备的寄存器映射到ARM的存储空间中,我们需要使用几个函数将硬件寄存器地址映射到系统空间:
如果已知硬件的虚拟地址,可以使用VirtualAlloc,VirtualCopy,
如果已知硬件的物理地址,需要使用MmMapIoSpace映射.
2.CPU与DMA或其它硬件交换数据。
DMA需要使用物理地址,因为DMA访问内存时不会向CPU一样先经过MMU,所以它使用物理地址。如果硬件需要与CPU交互数据,比如CPU需要将图像画到LCD控制器使用的内存中,LCD才会将其显示出来。我们在设置硬件硬件时需要将CPU使用的虚拟地址转换成物理地址,再告诉硬件物理地址。通常有以下几种办法:
<!--[if !supportLists]-->1. <!--[endif]-->为该硬件保留一块内存空间。一般用于内存使用量比较大的,且地址不再改变的设备,例如LCD控制器。
记录下该块内存的物理地址给硬件使用,计算出该块内存的虚拟地址地址给CPU使用。
<!--[if !supportLists]-->2. <!--[endif]-->当驱动需要访问硬件时才将虚拟地址转换成物理地址,一般用在内存空间经常变化的场合。例如块设备的驱动,文件系统或者其它上层程序读写数据时并不会保证每次使用同一段地址。这种情况下,可以使用LockPages函数将虚拟地址转换成物理地址。
<!--[if !supportLists]-->3. <!--[endif]-->分配一块物理地址,这可以用在内存地址不需要变化,且用量不大的情况,这时可以用AllocPhysMem分配一块地址,同时得到物理地址与虚拟地址。
标签: BaseKnowledge
5 条评论:
时间 7/3/07 15:36 ,
匿名 说...
很高兴microsun兄的blog一直在写,给我们更多学习的机会.
对文中一个问题不明白,想请教一下:wince是通过VirtualAlloc和VirtualCopy(或者调用MmmapIoSpace函数)来实现动态虚拟地址映射,以便APP访问.我的理解二者是等效的,
VirtualAlloc分配一块合适大小的虚拟地址
VirtualCopy把物理地址和虚拟地址绑定;
而MmmapIoSpace是直接把物理地址映射到虚拟地址的,内部也是调用VirtualAlloc和VirtualCopy实现的.
文中提到的" 如果已知硬件的虚拟地址,可以使用VirtualAlloc,VirtualCopy, 如果已知硬件的物理地址,需要使用MmMapIoSpace映射."是什么意思呢?
时间 10/3/07 21:38 ,
Blog by Braden 说...
兄弟不好意思啦,这几天网坏了没有上网.
MmmapIoSpace内部是不是调用VirtualAlloc, VirtualCopy我就不知道了.但它确实是两种不同的映射硬件地址的方法.
文中提到的" 如果已知硬件的虚拟地址,可以使用VirtualAlloc,VirtualCopy, 如果已知硬件的物理地址,需要使用MmMapIoSpace映射."是什么意思呢?
就是说,如果想用硬件的物理地址来访问就可以用MmmapIospace,如果想用虚拟地址就用VirtualAlloc & VirtualCopy,这纯粹是习惯问题.
时间 12/3/07 10:05 ,
匿名 说...
在HELP中看到以下关于地址映射的程序:
lpv = VirtualAlloc(0, SIZE, MEM_RESERVE, PAGE_NOACCESS);
bRet = VirtualCopy(lpv, PHYSADDR>>8, SIZE, PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL);
这两个函数的第四个参数是针对同一个虚拟地址的吗?为什么不相同呢?
时间 17/3/07 10:32 ,
匿名 说...
请教一下虚实地址映射的问题.
(1)能否这样理解: 在OAL访问I/O,只需要在OEMAddressTable中做CPU到虚拟的映射? 而在驱动或应用程序中访问I/O,既可以通过OEMAddressTable+VirtualCopy方式,也可以直接用MmMapIoSpace?
也就是说经过OEMAddressTable,实现的只是CPU物理地址到OS内核虚拟地址的一次映射,如果需要在应用程序中访问,还要再用VirtuaAlloc+VirtualCopy做一个内核到当前进程的二次映射?
(2)关于virtualcopy()的第二个参数既可以是经过OEMAddressTable得到的内核段虚拟地址,也可以是物理地址.只是后者需要把页属性设置成page_physical并且对应的第二个参数源地址需要右移8位来实现对齐.
(3)什么情况下要设置成page_physical ? 如果我在程序中访问挂在ISA总线上的数据采集卡上的寄存器,需要配置成page_physical吗?
时间 16/4/07 11:16 ,
匿名 说...
楼上的1,2两点理解应该是对的.
如果是在ARM处理器上访问ISA设备,可以用先用CreateBusAccessHandle读取总线物理地址,再用HalTranslateBusAddress把总线地址转化为CPU物理地址,接着用MmMapIoSpace直接建立物理地址到当前APP的虚拟空间的映射,最后用read_port_xxx,write_port_xxx操作寄存器.
请microsun大哥指点下:)