内存属性的来源
在 ARM64(AArch64)下,每个内存访问的"属性"由两方面决定:
- 
页表/MAIR_ELx(Memory Attribute Indirection Register):软件定义虚拟地址到物理地址的 memory type; 
- 
CPU 访存模型:结合 TLB/缓存/一致性域,决定实际的可见性和顺序。 
基本分类
ARMv8 把内存分为两大类:
(1) Normal memory
- 
可缓存,面向常规 RAM。 
- 
特性: - 
允许乱序访问、合并、推测、prefetch。 
- 
缓存一致性通过互联(CCI/CMN/DSU 等)保证。 
 
- 
- 
用途:一般代码段、数据段、内核堆栈等。 
(2) Device memory
- 
用于 MMIO(寄存器/外设)。 
- 
特性: - 
不能合并、推测或重排。 
- 
CPU 访问顺序严格保留(对同一设备的访问)。 
- 
可能 bypass 缓存(uncacheable)。 
 
- 
Normal Memory 属性
由 Outer/Inner cacheability 决定(通过页表 AttrIndx → MAIR 映射):
- 
Write-back cacheable:最常用,正常的缓存策略。 
- 
Write-through cacheable:写时同时更新 cache + memory。 
- 
Non-cacheable:直接访问 DRAM,不进 cache。 
额外属性:
- 
Shareability:Non-shareable / Inner-shareable / Outer-shareable - 
Inner-shareable:在一个 cluster 内核之间一致。 
- 
Outer-shareable:在多个 cluster 之间一致。 
- 
Non-shareable:CPU 自己私有(很少用)。 
 
- 
Device Memory 类型(ARMv8 推荐使用 nGnRE/nGnRnE)
常见的几类(AttrIndx 配置):
- 
Device-nGnRnE (Non-Gathering, Non-Reordering, No Early-Write-Ack) - 最严格,常用于强顺序 IO。
 
- 
Device-nGnRE (Non-Gathering, Non-Reordering, Early-Write-Ack) - 
允许写入"提前完成"但仍无重排/合并。 
- 
Linux 常用这个作为默认 MMIO。 
 
- 
- 
Device-GRE (Gathering, Reordering, Early-Write-Ack) - 宽松一些,允许合并/重排;适合 FIFO 类设备。
 
小贴士 :Linux 内核里
ioremap()默认用的是 Device-nGnRE,即 MMIO 安全模式。
内存顺序直觉(Normal vs Device)
- 
Normal memory :可能乱序,需要 内存 屏障 (barrier) 保证顺序。 
- 
Device memory :同一个设备的读写顺序不会乱,但和 Normal memory 之间的顺序 不一定符合直觉 → 所以驱动里常见 wmb(); writel();。
Linux 内核里的常用对应
Linux 在 ARM64 下会通过 pgprot_* 和 ioremap_* 宏来配置:
|---------------------------------|-----------------------------------------------------------------|------------------------|
| 内核 API                          | 内存类型                                                            | 底层属性                   |
| 普通内存 (malloc, vmalloc, kmalloc) | Normal, WB cacheable, Inner-shareable                           | AttrIndx 指向 Write-back |
| ioremap()                       | Device-nGnRE                                                    | 安全 MMIO                |
| ioremap_wc()                    | Normal, Write-combining                                         | 用于帧缓冲/PCIe 显存          |
| ioremap_cache()                 | Normal, Write-back                                              | 有时映射外设 RAM             |
| dma_alloc_coherent()            | Normal, WB + shareable(I/O coherent 平台) 或 Device uncached(非一致性) | 看硬件                    |
MAIR_ELx 配置(内存属性寄存器)
每个 EL 有一个 MAIR_ELx(Memory Attribute Indirection Register):
- 
8 个 slot(AttrIndx = 0..7)。 
- 
每个 slot 8 bit: - 
高 4 位 = outer 属性 
- 
低 4 位 = inner 属性 
 
- 
Linux 启动时会填好:
- 
比如 AttrIndx=0 → Normal WB Cacheable 
- 
AttrIndx=1 → Device-nGnRE 
- 
AttrIndx=2 → Normal Non-cacheable 
- 
... 
页表的 PTE[AttrIndx] 决定使用哪个 slot。
小结
- 
Normal memory = 程序代码和数据,缓存友好,但可能乱序,需要 barrier。 
- 
Device memory = MMIO,强顺序,不缓存,但和 Normal memory 交互时仍要 barrier。 
- 
Linux 内核 抽象 API( ioremap, dma_alloc_*)帮你选择合适的属性。
- 
驱动编程口诀: - 
写设备寄存器前要 wmb()(确保数据已写到内存)。 
- 
读设备寄存器后要 rmb()(确保状态之后的数据有效)。 
 
-