这几天遇到了64bit Win8下的一个Bug,我们的chip是支持ScatterGather的,但是在做DMA之前,我们修改对应的Memory却没有生效。
DMA传输出去的内容还是之前没有改过的。
回来的路上,看了下面这篇文章,终于明白其中的原因了。www.microsoft.com/whdc/driver/kernel/dma.mspx
Device跟Memory进行传输DMA的时候,Device能访问的地址访问受Device本身的寻址范围所限。
在我的环境下,Chip是32bit的Bus,所以只能访问0-4G的地址,而系统是64bit的,有些Memory(Mem1)的物理地址在4G以上的空间。
导致Device无法直接拿到,所以OS会额外在0-4G的物理地址开了一块Memory(Mem2),就是所谓的Map Register。
OS把4G以上的Mem1的内容Copy到Mem2,所以DMA拿的其实是Mem2的内容,这就是为什么我修改Mem1,DMA传输的数据却没有变化。
那OS把4G以上的Mem1 copy到4G以下的Mem2是在什么时候做的呢?答案就是NdisMAllocateNetBufferSGList。
所以只要在Call NdisMAllocateNetBufferSGList之前修改数据还是会生效的。
Windows在两种情况下会用到Map Register这种copy memory的机制。
1. Device不支持ScatterGather。
2. 需要DMA的内存的物理地址无法被Device的总线直接访问到。
那篇链接的文档里面关于DMA的操作有很详细的描述。