ARM64内存属性及MAIR配置
·
原文地址:https://blog.csdn.net/suifengershi2000/article/details/122805722
内存属性
内存属性分为2类:
- Normal型:SRAM或者DRAM那样的内存空间,一般都是过cache的(当然也可不过cache,如外设访问的地址空间,标记为NC)
- device型:设备寄存器那样的IO空间,都不会过cache。Device属性的内存空间还有下面三种子属性,都有打开和关闭的定义。
- G(gather:对多个memory的访问可以合并);nG与之相反
- R(Reordering:对内存访问指令进行重排);nR与之相反
- E(Early Write Acknowledgement hint:写操作的ack可提早应答);nE与之相反
MAIR配置
MAIR寄存器定义如下:
Linux预先定义了6种内存属性,分别存在MAIR寄存器的attr0~attr5。内存页表属性部分可以选择这个寄存器的某个index,范围(0~5)作为自己的属性。
/*
* 上面内容我们说到了, 页表entry表明内存是普通内存, 就是结合这里的初始化来指明的,
* PMD_ATTRINDX(MT_NORMAL)是4, 这其实是一个index, 指向MAIR寄存器的[4*8+7:4*8],
* MAIR寄存器一共有8组, KERNEL用了6组, 每组有8bit, 每个bit都有相应的含义.
* 具体参考手册, 这里就不细说了, 点到为止
*/
/*
* Memory region attributes for LPAE:
*
* n = AttrIndx[2:0]
* n MAIR
* DEVICE_nGnRnE 000 00000000
* DEVICE_nGnRE 001 00000100
* DEVICE_GRE 010 00001100
* NORMAL_NC 011 01000100
* NORMAL 100 11111111
* NORMAL_WT 101 10111011
*/
ldr x5, = MAIR(0x00, MT_DEVICE_nGnRnE) | \
MAIR(0x04, MT_DEVICE_nGnRE) | \
MAIR(0x0c, MT_DEVICE_GRE) | \
MAIR(0x44, MT_NORMAL_NC) | \
MAIR(0xff, MT_NORMAL) | \
MAIR(0xbb, MT_NORMAL_WT)
msr mair_el1, x5 # 写入预定义的5种内存属性值


Linux kernel中的页表属性
如上所述,Linux在cpu初始化时建立了6种页表属性索引
ARM64 cpu可以通过页表中设置的页表属性配置,决定其内存或寄存器访问行为(DEVICE_nGnRE/nGnRE/GRE、NORMAL_NC/WT/NORMAL)。
#define ioremap(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
#define ioremap_nocache(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
#define ioremap_wc(addr, size) __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC))
#define ioremap_wt(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
#define PROT_DEVICE_nGnRnE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRIDX(MT_DEVICE_nGnRnE))
#define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRIDX(MT_DEVICE_nGnRE))
#define PROT_NORMAL_NC (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRIDX(MT_NORMAL_NC))
#define PROT_NORMAL_WT (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRIDX(MT_NORMAL_WT))
#define PROT_NORMAL (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRIDX(MT_NORMAL))
#define PTE_ATTRINDX(t) (_AT(pteval_t, (t)) << 2)
PTE_ATTRINDX在页表中的位置 bit[4:2]
关于使用页表的场景(参考 linux kernel 4.9):
-
内核代码中使用alloc_pages从伙伴系统内存中申请
-
设备驱动代码使用device-tree预留内存地址建立页表映射访问(内存或寄存器,使用ioremap较多)
ioremap() / ioremap_wc() pci_iomap() | |-> pci_iomap_range() | |-> ioremap() pci_iomap_wc() | |-> pci_iomap_wc_range() | |-> ioremap_wc() -
设备驱动一致性内存,dma_alloc_coherent如何使用内存?attrindex使用哪个?
arch/arm64/mm/dma-mapping.c | |-> swiotlb_dma_ops | |-> __dma_alloc(dev, size, dma_handle, flags, attrs) | |-> prot = __get_dma_pgprot(attr, PAGE_KERNEL, false); // PAGE_KERNEL = __pgprot(PROT_NORMAL) | // coherent=false | // prot最终修改为 PTE_ATTRINDX(MT_NORMAL_NC) |-> ptr = __dma_alloc_coherent(dev, size, dma_handle, flags, attrs); | |-> coherent_ptr = dma_common_contiguous_remap(page, size, VM_USERMAP, prot, NULL) | |-> dma_common_pages_remap(pages, size, VM_USERMAP, prot, NULL); //建立NORMAL页表
问题
- PoC与PoU的区别和使用范围?
- 内存Inner和Outer域如何界定?
- 多核cpu或多cluster cpu如果跑一个系统则是inner的
- 一般cpu与DMA,cpu与GPU都是outer的
更多推荐

所有评论(0)