Zynq PetaLinux系统PL写入PS RAM的物理地址配置方法咨询
Zynq PL写入PS RAM的正确实现及问题解答
一、mmap报错原因及解决
你的代码出现mmap: Bad file descriptor错误有两个核心原因:
- 非法文件描述符:
mmap第5个参数传入-1是错误的,除非搭配MAP_ANONYMOUS标志做匿名映射,但你的场景不需要这种方式。 - 运行环境错误:这套代码只能在Zynq的PetaLinux环境下运行,Ubuntu工作站没有Zynq的硬件内存映射空间,完全不适用。
正确的内存分配与物理地址获取步骤(PetaLinux环境)
要实现PL可写入的固定物理地址内存,需按以下步骤操作:
- 分配对齐且锁定的内存:用
posix_memalign分配页对齐内存,再用mlock锁定内存,防止被系统换出,保证物理地址固定:
#include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <fcntl.h> #include <stdio.h> #include <stdint.h> size_t length_in_bytes = 4096 * 8; uint8_t *memBlockPtr; const size_t page_boundary = 4096; // 分配页对齐内存 int retval = posix_memalign(reinterpret_cast<void**>(&memBlockPtr), page_boundary, length_in_bytes); if (retval != 0) { perror("posix_memalign"); exit(1); } // 锁定内存,防止被换出 if (mlock(memBlockPtr, length_in_bytes) != 0) { perror("mlock"); free(memBlockPtr); exit(1); }
- 获取虚拟地址对应的物理地址:用户空间无法直接调用内核的
virt_to_phys,可通过读取/proc/self/pagemap文件解析:
#include <stdint.h> #include <fcntl.h> uint64_t get_phys_addr(void *virt_addr) { int fd = open("/proc/self/pagemap", O_RDONLY); if (fd == -1) { perror("open pagemap"); return 0; } uint64_t page_size = sysconf(_SC_PAGE_SIZE); uint64_t virt_page = reinterpret_cast<uint64_t>(virt_addr) / page_size; off_t offset = virt_page * sizeof(uint64_t); uint64_t pagemap_entry; if (pread(fd, &pagemap_entry, sizeof(pagemap_entry), offset) != sizeof(pagemap_entry)) { perror("pread pagemap"); close(fd); return 0; } close(fd); // 检查页面是否存在 if (!(pagemap_entry & (1ULL << 63))) { fprintf(stderr, "Page not present\n"); return 0; } // 提取物理页号,计算物理地址 uint64_t phys_page = pagemap_entry & ((1ULL << 55) - 1); return phys_page * page_size + (reinterpret_cast<uint64_t>(virt_addr) % page_size); } // 使用示例 uint64_t phys_addr = get_phys_addr(memBlockPtr); if (phys_addr == 0) { fprintf(stderr, "Failed to get physical address\n"); munlock(memBlockPtr, length_in_bytes); free(memBlockPtr); exit(1); }
二、缓存一致性问题解答
PL写入缓冲区后,PS能否立即读取到数据取决于内存的缓存配置:
- 如果内存配置为可缓存(Cached):PS的CPU缓存中可能存在旧数据,需要执行缓存无效操作(如
dcivac指令)才能读取到PL写入的最新数据。 - 如果内存配置为非缓存(Non-cached):PL写入后PS可以立即读取到最新数据,但访问速度会比缓存区慢。
在Zynq中,通常会将PL交互的内存配置为共享非缓存(Shareable Non-cached),既保证一致性,又避免缓存带来的同步问题。你可以在设备树中配置对应的内存区域属性,或者在用户空间通过mprotect结合MAP_UNCACHED标志(部分平台支持)来设置。
三、额外注意事项
- 必须在PetaLinux环境下测试:Ubuntu工作站没有Zynq的硬件架构和内存映射机制,代码无法正常工作。
- 物理地址需告知PL:将获取到的
phys_addr通过寄存器或其他方式配置给PL,让PL写入该固定物理地址。 - 内存释放:程序退出前需调用
munlock解锁内存,再调用free释放分配的内存。
内容的提问来源于stack exchange,提问作者crw4096
相关产品推荐
相关产品推荐

