L1 Cache Eviction Corrupting DDR on A9

Hi All!

I am working with a Xilinx Zynq 7000 SoC which uses the Cortex A9 as a CPU.

I've observed a problem wherein a section of memory marked strongly-ordered and non-cacheable (0xc02) in the MMU table gets corrupted by what appears to be L1 evictions back to DDR.

Setup: Linux master on CPU0 with FreeRTOS on CPU1. During the boot process, the region from 512MB to 1GB is marked 0xc02 in the translation table and aliased back to the lower region (0 to 512MB). This has the effect of allowing accesses to the same physical memory with different region attributes. The Linux CPU owns the L2 cache and its controller, the L2 cache is disabled on CPU1.

Thus, a pointer offset by 0x20000000 from its original value returned by malloc should be considered uncacheable, and all memory accesses will go directly to memory. I am using a buffer of 1024 integers, which is allocated by malloc then offset to make all accesses uncacheable.

Issue: After performing a memcpy to the uncached buffer, the value matches the source exactly. However, after a short amount of time, the uncached buffer drifts from the source (which remains unchanged throughout). When the buffer is instead marked as cached, this corruption does not occur, which leads me to believe that stale data is being evicted from the L1 cache and overwriting the new clean data that was placed in DDR.

I have tried disabling, flushing, and invalidating the cache (both before and after the memcpy), but these did not work. The buffer is unaligned to the L1 cache size, which would cause corruption at the front and end entries in the buffer from accesses to the cached pointers before and after, but the corruption is spread randomly throughout the buffer in chunks of 8 entries (8*4 = 32, the L1 line size). Additionally, I've tried disabling the prefetch bits in the ACTLR. Looking at the the disassembly of memcpy though, it does not issue any PLD instructions to the destination, only to the source.

What else could be the cause of this, and what else could I try to fix the issue of not being able to write to an uncached region?

Thanks!!!

Parents
  • This has the effect of allowing accesses to the same physical memory with different region attributes

    No it does not "allow" it; mapping the same physical memory region with different page table attributes is explicitly and repeatedly documented as "you must not ever do this" in the ARM ARM.

    • Mapping the same physical address to multiple virtual addresses with identical access attributes is allowed.
    • Mapping the same physical address to multiple virtual address with different attributes is not.

    Horrible things will likely go wrong, even if your software never touches the "wrong" mapping. Many A-profile cores will speculatively prefetch "normal / cached" memory, so may access conflicting mappings even though one mapping is never explicitly accessed in the executing code, and that's not to mention the impact of aliased mappings on systems relying on hardware cache coherency (which is likely your problem here).

    This presentation from Mark Rutland is a good run through all of the pitfalls of modern memory systems and caches:

    Taming the Chaos of Modern Caches | Linux.com | The source for Linux information

    The Linux CPU owns the L2 cache and its controller, the L2 cache is disabled on CPU1.

    It's a single cache shared by both cores. It's either on or off - it can't be on for one, and off for the other.

    HTH,

    Pete

Reply
  • This has the effect of allowing accesses to the same physical memory with different region attributes

    No it does not "allow" it; mapping the same physical memory region with different page table attributes is explicitly and repeatedly documented as "you must not ever do this" in the ARM ARM.

    • Mapping the same physical address to multiple virtual addresses with identical access attributes is allowed.
    • Mapping the same physical address to multiple virtual address with different attributes is not.

    Horrible things will likely go wrong, even if your software never touches the "wrong" mapping. Many A-profile cores will speculatively prefetch "normal / cached" memory, so may access conflicting mappings even though one mapping is never explicitly accessed in the executing code, and that's not to mention the impact of aliased mappings on systems relying on hardware cache coherency (which is likely your problem here).

    This presentation from Mark Rutland is a good run through all of the pitfalls of modern memory systems and caches:

    Taming the Chaos of Modern Caches | Linux.com | The source for Linux information

    The Linux CPU owns the L2 cache and its controller, the L2 cache is disabled on CPU1.

    It's a single cache shared by both cores. It's either on or off - it can't be on for one, and off for the other.

    HTH,

    Pete

Children