ARM Cortex A 上的内存区域如何在 Linux 下表示为 "device" 或 "strongly ordered"

How are memory regions on ARM Cortex A denoted as "device" or "strongly ordered" under Linux

在构成我正在使用的 Zynq SoC 一部分的 ARM Cortex-A9 上,内存区域被标记为“正常”、“设备”或“强有序”。 Zynq technical reference manual 中对此进行了描述,但我理解它是更笼统的 属性 ARM。显然,对内存映射设备(包括许多 FPGA 结构)进行强顺序内存访问的能力应该会在一定程度上简化软件,因此需要设置。

我正在使用 UIO 驱动程序将设备内存映射到用户空间,大部分驱动程序在其中运行。根据 this reference,UIO 驱动程序将其映射内存设置为“device/strongly 有序”。不幸的是,这是我能找到的唯一参考,在我开始从我的代码中删除内存栅栏之前,我想对正在发生的事情更有信心。

目前我不清楚 Linux 内核如何表示特定类型的内存区域。在我看来,MT_* 属性表示这些方面的内容,但我找不到每种类型的定义。我也不知道 UIO 驱动程序是如何指定特定内存的。

任何关于如何在 Linux 中设置内存属性的指示,无论是一般性的还是理想情况下参考 UIO 的,都将非常有帮助。我很高兴以文档指针的形式获得它。

这有几个部分。

在包含 Zynq-7000 的 ARMv7 上,内存由通过翻译 table 描述符配置的内存区域属性表示为给定类型。有多种方法可以配置这些,机制在 ARM Architecture Reference Manual ARMv7-A. Also useful is the Zynq technical reference manual 的 B3.8 节中进行了描述,它在 ARM 方面不太完整,但更容易处理。

广义上,感兴趣的位是 B(可缓冲)位、C(可缓存)位和 3 个 TEX(类型扩展)位。这些可以直接设置,或者在设置 SCTLR.TRE 位时通过重定向设置(这有效地允许使用 PRRRNMRR 寄存器进行自定义重新映射 - 可能不止于此,但我无法立即看到是什么)。

翻译 table 描述符在内存管理单元 (MMU) 子系统的 Linux 中设置。这显然是非常特定于体系结构的,相关的 ARM 位可以在 arch/arm/mm. It's interesting to look through mmu.c 中找到,以了解如何在不同类型上配置不同的内存属性。

下面的内容有点推测性,但我认为是准确的。

核心UIO驱动通过调用pgprot_noncached()在物理设备上设置相关内存保护。现在,我 认为 这被委托给架构特定的实现,在 ARMv7 的情况下是 arch/arm/include/asm/pgtable.h 中定义的宏,并决定设置 L_PTE_MT_UNCACHED旗帜.

L_PTE_MT_UNCACHED 常量又在 arch/arm/include/asm/pgtable-2level.h. There is a nice bit of documentation in that file that describes what the various constants represent. The value for each type is remapped to the B, C and TEX bits, either through the TRE redirection or through a look-up table configured in arch/arm/mm/proc-macros.S. The TRE redirection registers (PRRR and NMRR) I think are configured in arch/arm/mm/proc-v7-2level.S. If you track those through, you get the same values as the look-up table (which references constants defined in arch/arm/include/asm/pgtable-2level-hwdef.h 中设置 - 请注意,这些常量用于小页 table 描述符,与 mmu.c 中使用的不同)

这会给我们留下什么? UIO 驱动程序将一块内存配置为 pgprot_noncached() 意味着它是 L_PTE_MT_UNCACHED,这又意味着 TEX = 000B = 0C = 0。在参考手册中查看这些设置,我们看到这对应于一个无缓冲的、强顺序的、可共享的内存区域(表示为“强类型”)。

很明显,要更改设备(可能允许缓冲写入),我们需要修改内存的驱动程序配置以使用例如pgprot_writecombine() 这会将内存类型设置为正常但缓存关闭。还有一个 pgprot_device() 宏,它还设置了设备内存类型(可缓冲)和缓存关闭,但是还有一些我还没有正确理解的附加标志(我认为它们用于配置软件“Linux" 版本的页面 table 条目用于硬件不支持它的情况,因此在支持时不相关)。