You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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可写入的固定物理地址内存,需按以下步骤操作:

  1. 分配对齐且锁定的内存:用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);
}
  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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 02:55:25