在包含我正在使用的Zynq SoC的一部分的ARM Cortex-A9上,内存区域被标记为“正常”,“设备”或“有序排列”。Zynq技术参考手册中对此进行了描述,但据我了解,这更普遍地是ARM的属性。显然,对于存储器映射设备(在FPGA架构中包括许多设备)具有强排序的存储器访问能力应该会在某种程度上简化软件,因此需要进行设置。
我正在使用UIO驱动程序将设备内存映射到用户空间,该驱动程序的大部分运行在该用户空间中。根据此参考,UIO驱动程序将其映射的内存设置为“设备/强排序”。不幸的是,这是我唯一能找到的参考,在我开始从代码中删除内存屏障之前,我想对正在发生的事情有更多的信心。
目前我还不清楚Linux内核如何表示特定类型的内存区域。在我看来,MT_*
属性沿这些方向表示某些东西,但是我找不到每种类型的定义。我也无法弄清楚UIO驱动程序如何指定特定的内存。
无论是一般术语还是理想情况下有关UIO的关于在Linux中如何设置内存属性的任何指示都将特别有用。我很高兴以指向文档的形式获得它。
这有几个部分。
在包括Zynq-7000的ARMv7上,通过转换表描述符配置的内存区域属性将内存表示为给定类型。有多种配置这些方法的方法,其机制在《ARM体系结构参考手册ARMv7-A》的B3.8节中进行了描述。Zynq技术参考手册也很有用,该手册相对于ARM而言不完整,但更易于处理。
大致而言,感兴趣的B
位是C
(可缓冲)位,(可缓存)位和3个TEX
(类型扩展)位。这些可以直接设置,也可以通过在SCTLR.TRE
设置位时通过重定向来设置(这实际上允许使用PRRR
andNMRR
寄存器进行自定义重新映射-可能不止于此,但我无法立即看到结果)。
转换表描述符是在Linux中的内存管理单元(MMU)子系统中设置的。显然,这是非常特定于体系结构的,相关的ARM位在arch / arm / mm中。通过mmu.c查看如何在不同类型上配置不同的内存属性很有趣。
接下来的内容是投机性的,但我认为是正确的。
核心UIO驱动程序通过调用在物理设备上设置其相关的内存保护pgprot_noncached()
。现在,我认为这是委托给特定于体系结构的实现的,在ARMv7的情况下,它是arch / arm / include / asm / pgtable.h中定义的宏,并决定设置该L_PTE_MT_UNCACHED
标志。
该L_PTE_MT_UNCACHED
常数是在依次组拱/臂/包括/ ASM / pgtable-2level.h。该文件中有很多文档描述了各种常量所代表的含义。对于每种类型的值被重新映射到B
,C
和TEX
位,或者通过TRE
重定向或通过构造一个查找表拱/臂/毫米/ PROC-macros.S。我认为TRE重定向寄存器(PRRR
和NMRR
)是在arch / arm / mm / proc-v7-2level.S中配置的。如果跟踪这些内容,则会得到与查找表相同的值(查找表引用了arch / arm / include / asm / pgtable-2level-hwdef.h中定义的常量。-请注意,这些常量是用于小页表描述符的,与mmu.c
)中使用的常量不同
这在哪里离开我们?所述UIO驱动器配置一块内存作为pgprot_noncached()
暗示其是L_PTE_MT_UNCACHED
,这又意味着TEX = 000
,B = 0
和C = 0
。查看参考手册中的设置,我们看到这对应于一个无缓冲的,有序的,可共享的内存区域(表示为“强类型”)。
显然,要更改设备(可能允许缓冲写入),我们需要修改内存的驱动程序配置以使用例如pgprot_writecombine()
将内存类型设置为正常但关闭缓存的驱动程序。还有一个pgprot_device()
宏,它也可以设置设备内存类型(可缓冲)和缓存,但是带有一些我尚未正确理解的其他标志(我认为它们用于配置页表项的软件“ Linux”版本(如果硬件不支持它,那么它就不相关了)。