![在 zynq 上访问非对齐内存时出现总线错误](https://linux22.com/image/156483/%E5%9C%A8%20zynq%20%E4%B8%8A%E8%AE%BF%E9%97%AE%E9%9D%9E%E5%AF%B9%E9%BD%90%E5%86%85%E5%AD%98%E6%97%B6%E5%87%BA%E7%8E%B0%E6%80%BB%E7%BA%BF%E9%94%99%E8%AF%AF.png)
编辑:我应该把它放在一个更好的 stackexchange 网站上吗?
我正在尝试使用连接到 zynq 超大规模芯片的 FPGA 端的 DDR4,特别是在 Xilinx 的开发板 zcu102 上。我正在使用 Vivado 的 MIG 生成控制器并连接到主处理器的 HPM0 AXI 端口。内存长度为0x2000_0000,映射到物理地址0x4_0000_0000。
我遇到的问题是访问未对齐的内存时。我认为这是由于设备树中缺少细节而导致 MMU 中的一些配置错误。
我知道的一件事是,这个手臂(A53)应该能够在必要时将未对齐的访问转变为对内存的多次访问。我收到总线错误告诉我 MMU 在某种程度上配置错误,但我不确定如何配置。
设备树太长,放在这里,所以我将我认为最重要的部分直接放在这里,其余的作为帕斯特宾。
amba_pl@0 {
#address-cells = <0x2>;
#size-cells = <0x2>;
compatible = "simple-bus";
ranges;
ddr4@400000000 {
compatible = "xlnx,ddr4-2.2";
reg = <0x4 0x0 0x0 0x20000000>;
alignment = <0x10>;
};
PERIPHERAL@ff380000 {
compatible = "xlnx,PERIPHERAL-1.0";
reg = <0x0 0xff380000 0x0 0x80000>;
};
PERIPHERAL@ff990000 {
compatible = "xlnx,PERIPHERAL-1.0";
reg = <0x0 0xff990000 0x0 0x10000>;
};
};
aliases {
ethernet0 = "/amba/ethernet@ff0e0000";
i2c0 = "/amba/i2c@ff020000";
i2c1 = "/amba/i2c@ff030000";
serial0 = "/amba/serial@ff000000";
serial1 = "/amba/serial@ff010000";
spi0 = "/amba/spi@ff0f0000";
};
memory {
#address-cells = <0x2>;
#size-cells = <0x2>;
device_type = "memory";
alignment = <0x10>;
reg = <0x4 0x0 0x0 0x20000000>;
};
我尝试在 /memory 和 /amba_pl 上的 ddr 控制器上设置对齐方式,但似乎没有什么区别。事实上,它似乎忽略了 /memory 部分,因为它仍然从主系统内存而不是 fpga 上的内存启动。
我可以使用 mmap 和 devmem 访问内存,如下所示:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdint.h>
#include <math.h>
#define ARRAY_TYPE uint16_t
int main(int argc, char *argv[]) {
if (argc != 2){
printf("Wrong arg count\n");
return -1;
}
volatile ARRAY_TYPE * ps = malloc(sizeof(ARRAY_TYPE)*10);
if (NULL==ps){
printf("Failed to malloc for ps\n");
return -1;
}
int fd = open("/dev/mem", O_RDWR | O_SYNC );
volatile ARRAY_TYPE *pl = mmap((void*)0x400000000, 0x20000000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x400000000);
if (pl == MAP_FAILED) {
perror("Can't map memory for pl");
printf("FAIL\n");
return -1;
}
//force them out of alignment by argv[1] bytes.
volatile ARRAY_TYPE *ps_unaligned = (volatile ARRAY_TYPE *)(((uint8_t *)ps) + atoi(argv[1]));
volatile ARRAY_TYPE *pl_unaligned = (volatile ARRAY_TYPE *)(((uint8_t *)pl) + atoi(argv[1]));
printf("trying ps with offset %d\n", atoi(argv[1]));
ps_unaligned[0] = 1;
printf("trying pl with offset %d\n", atoi(argv[1]));
pl_unaligned[0] = 1;
munmap(pl, 0x20000000);
free(ps);
close(fd);
return 0;
}
每当我尝试访问与主系统内存不对齐的内存时,它都可以正常工作。然而,当我访问悬挂在未对齐的 FPGA 上的内存时,会出现总线错误。
root@zynq: ~
17:22:08 $ ./memtest 0
trying ps with offset 0
trying pl with offset 0
root@zynq: ~
17:22:12 $ ./memtest 1
trying ps with offset 1
trying pl with offset 1
Bus error
root@zynq: ~
17:22:13 $ ./memtest 2
trying ps with offset 2
trying pl with offset 2
root@zynq: ~
17:22:14 $ ./memtest 3
trying ps with offset 3
trying pl with offset 3
Bus error
我还通过在 gdb 会话期间查看 /proc/$pid/smaps 来查看内存区域的虚拟内存映射:这是包含使用 devmem/mmap 分配的系统内存的部分:
400000000-420000000 rw-s 400000000 00:06 1054 /dev/mem
Size: 524288 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 0 kB
Pss: 0 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 0 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
VmFlags: rd wr sh mr mw me ms pf io de dd
以下是从 FPGA 映射的内存部分:
5555567000-5555588000 rw-p 00000000 00:00 0 [heap]
Size: 132 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
VmFlags: rd wr mr mw me ac
我不确定标志中的任何差异是否可以解释发生的情况,但我将它们包括在内,以防更精通内存映射的人知道一些事情。