在装有Linux 4.9.0的Xilinx ZynqMP嵌入式系统上访问部分DDR内存时,出现对齐错误。
我们从Linux系统的内存顶部隐藏了一些MB,并使用ioremap将其映射到专用驱动程序中。存储器通过mmap接口暴露给嵌入式系统上的用户空间。我们使用这个内存块在不同的处理器(RPU,APU,Host)之间进行通信。
static int genmem_mmap(struct file *pFile, struct vm_area_struct *pVma)
{
struct aim_mem_device *pInst;
int ret;
/* get private data */
pInst = (struct aim_mem_device*)(pFile->private_data);
....[Some checks omitted here ]...
/* mapping */
pVma->vm_page_prot = pgprot_noncached(pVma->vm_page_prot);
ret = remap_pfn_range(
pVma, /* user vma to map to */
pVma->vm_start, /* target user address to start at */
pVma->vm_pgoff + ((pInst->res.start)>>PAGE_SHIFT),/* physical address of kernel memory */
pVma->vm_end - pVma->vm_start, /* size of map area */
pVma->vm_page_prot /* page protection flags for this mapping */
);
....[Some checks omitted here ]...
return ret;
}
不幸的是,这在用户空间中的memcpy上引发了一个未处理的对齐错误,其大小未对齐到8字节。我找到了一些关于pgprot_noncached和MT_DEVICE_nGnRnE的信息,这导致了严格的对齐设置。然而,我真的不知道我有什么替代方案。因为我正在与其他处理器通信,所以我需要非缓存设置。
# [ 509.376525] esmartd[1505]: unhandled alignment fault (11) at 0x7f80b24032, esr 0x92000021
[ 509.384674] pgd = ffffffc0341bf000
[ 509.388038] [7f80b24032] *pgd=0000000034bba003[ 509.392283] , *pud=0000000034bba003
, *pmd=0000000033c24003[ 509.397740] , *pte=01e800003f000f43
[ 509.401224]
[ 509.402717]
[ 509.404174] CPU: 0 PID: 1505 Comm: esmartd Not tainted 4.9.0-aim2-00054-g1ccf631 #183
[ 509.411995] Hardware name: ZynqMP AIM APXX (DT)
[ 509.416850] task: ffffffc034136e80 task.stack: ffffffc033e14000
[ 509.422757] PC is at 0x7f80bafe94
[ 509.426042] LR is at 0x401200
[ 509.429001] pc : [<0000007f80bafe94>] lr : [<0000000000401200>] pstate: 00000000
[ 509.436384] sp : 0000007ffffe0040
[ 509.439676] x29: 0000007ffffe0040 x28: 0000000000000000
[ 509.444963] x27: 0000000000000000 x26: 0000000000000000
[ 509.450262] x25: 0000000000000000 x24: 0000000000000000
[ 509.455553] x23: 0000000000000000 x22: 0000000000000000
[ 509.460848] x21: 0000000000000000 x20: 0000000000000000
[ 509.466147] x19: 00000000004038d8 x18: 0000000000000001
[ 509.471438] x17: 0000007f80bafe40 x16: 0000000000414350
[ 509.476733] x15: 0000007f80cab030 x14: 00007a672e726174
[ 509.482027] x13: 2e6574616470752d x12: 3031393378787061
[ 509.487323] x11: 0000001600000000 x10: 0074005300200033
[ 509.492617] x9 : 00320020006c0065 x8 : 0064006f00000042
[ 509.497911] x7 : 0000000145534d54 x6 : 000000000ccb80c0
[ 509.503207] x5 : 0000000000000003 x4 : 0000000000000000
[ 509.508502] x3 : 0000000000000000 x2 : 0000000000000002
[ 509.513796] x1 : 0000007f80b24042 x0 : 000000000ccb8080
[ 509.519090]
顺便说一句:同样的代码也适用于Xilinx Zynq-7000 (ARM32)系列。
在这里可以找到一个类似的问题,但与DMA buffer有关:Linux on arm64: sendto causes “Unhandled fault: alignment fault (0x96000021)” when sending data from mmapped coherent DMA buffer
有没有pgprot_noncached的替代品,它提供了非缓存访问,但不意味着任何对齐要求?
发布于 2020-01-23 18:52:53
我可能会来晚一点,但为了将来参考,这是我的答案:
在ARM64/armv8上,设备内存(由pgprot_noncached设置)只能通过8字节(64位)对齐进行访问。(armv8 trm)。
#define pgprot_noncached(prot) __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE) | PTE_PXN | PTE_UXN
要与其他处理器通信,您可以使用普通内存,只要它被设置为非缓存。与上述函数设置的设备内存的主要不同之处在于,它可能具有推测性访问和未在设备内存上设置的GRE (armv8 trm)。特别注意R(重新排序)由于处理器可能会对程序中完成的任何内存访问进行重新排序,因此可以在实际制作内存缓冲区副本之前设置标志。
TL;DR:使用pgprot_writecombine将您的内存设置为普通和非缓存。
#define pgprot_writecombine(prot) __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
或者,您可以简单地在实际复制的结构/内存上强制64位对齐(不知道memcpy是否强制8位副本或是否支持64位)。
https://stackoverflow.com/questions/48862405
复制相似问题