Zynq PetaLinux system PL needs to write to PS RAM - how do I provide PL with the correct physical address?

195 Views Asked by At

I have a Zynq system where logic in the PL generates a large block of data that needs to be written into PS RAM. In my naive thinking, I would use new or malloc() to get a pointer to allocated memory, then translate that pointer virtual address to a physical address.

Several things are wrong with this. One is that the memory may not exist until written to by my application. Another is the physical address might change. Probably other reasons too.

The PL wants to write to the same place all the time and expects for the memory to exist, obviously!

Here is what I've tried (C++):

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);
}

uint8_t * physAddr = nullptr;
physAddr = reinterpret_cast<uint8_t *>(mmap(reinterpret_cast<void*>(memBlockPtr),
                length_in_bytes, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, -1, 0));
if (physAddr == MAP_FAILED)
{
    perror("mmap");
    exit(1);
}

This fails with mmap: Bad file descriptor.

I don't have much experience with mmap(), but our application does use it to create a mapping from a memory space in the PL into the application memory space, which is kind of the opposite of what I need now. Also, I'm wondering if there are any cache-related issues, like once the PL writes to the buffer, does a read from the PS see the data immediately?

One more thing - I ran the code above on my Ubuntu PC workstation, not PetaLinux. Not quite ready for that yet. I don't know if I'm getting this error because it's not on the actual platform.

1

There are 1 best solutions below

0
On

I did solve this problem, but it was only after I realized I was thinking about this completely wrong. First off, the proposed code above was developed with one of those LLM AIs, which was clearly hallucinating. The correct way to do this can be summarized as:

  1. Define some reserved memory in your Petalinux device tree file. This will let you specify the physical or "bus address" of the base of the memory block and its length. For my case, with the PL writing to PS RAM, this was the address specified in the DMA memory controllers of the PL (using Vivado) and becomes part of the bitstream. Rebuild Petalinux with the updated device tree.
  2. Do the exact same thing with mmap() that you would do if you wanted to access some memory address that exists in the PL. There are multiple links out there that talk about how to do this. This will give you a way to read or write through the physical address.

This is the short story. There are many omitted steps, but this is the general idea.

There were a few good resources I found along the way:

Device Tree: hardware description for everybody !

https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842482/Device+Tree+Tips

Good luck!