UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Visitor dwjbosman
Visitor
194 Views
Registered: ‎06-17-2018

mmap on zed board + yocto linux

I want to test inter cpu communication using shared memory between a Microblaze soft core and Zynq A9 ARM processors running Linux on a Zed board. First I want to do some basic tests using mmap.

In the device tree I have reserved some memory:

   reserved-memory {
      #address-cells = <1>;
      #size-cells = <1>;
      ranges;

      mb_shared_mem: buffer@0x10000000 {
         no-map;
         reg = <0x10000000 0x0e000000>;
      };
   };

   reserved-driver@0 {
      compatible = "xlnx,reserved-memory";
      memory-region = <&mb_shared_mem>;
   };
  1. The Zed board has 512MB ram. If I reserve the upper 256MB then Linux won't start. Why? It works when I decrease the amount to 0x0e000000. The address editor in Vivado doesn't show any reserved address from 1e00_0000 to 2000_0000

  2. Do I need to use 'no-map'? The kernel should not use the memory, but I want to be able to access it using mmap.

I built a simple test program for mmap. The program writes a file byte by byte to a memory region mapped using mmap:

int write_file( char *argv[]) {
    int fd, fd_in;

    off_t size;
    off_t file_index;

    char* fname = 0;
    char* addr = argv[3];

    fname = argv[2];


    fd_in = open(fname, O_RDONLY);
    if (fd_in < 1) {
        printf("Unable to open input file %s\n",fname );
    }

    void* load_address = (void*)strtoul(addr, NULL, 16);
    printf("Loading at address %p\n ",load_address);

    fd = open("/dev/mem", O_RDWR | O_SYNC);

    if (fd < 1) {
        printf("Unable to open mem device file\n");
        close(fd_in);
        return -1;
    }

    // determine size
    size = lseek(fd_in, 0L, SEEK_END);
    lseek(fd_in, 0L, SEEK_SET);

    printf("Copying %ld bytes\n", size);


    base_address = mmap(load_address, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_UNINITIALIZED | MAP_FIXED, fd, 0);
    if (base_address == MAP_FAILED) {
        printf("mmap failed! %s\n", strerror(errno));
        close(fd);
        close(fd_in);
        return -1;
    }


    for (file_index = 0; file_index < size; file_index++) {
        uint8_t file_byte;
        ssize_t result = read(fd_in, &file_byte,1);

        if (result<0) {
            printf("Error during fileread: %s", strerror(errno));
            break;
        }
        base_address[file_index] = file_byte;

        if (base_address[file_index] != file_byte) {
            printf("Write failed, offset %lx failed\n", file_index);
            break;
        }
        if ((file_index % 100) == 0) {
            printf(".");
        }
    }
    printf("\n");

    munmap(base_address, size);
    close(fd_in);
    close(fd);
    return 0;
}
  • 3. In most examples I found I see:

    mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, load_address);

    3.1 Why not specify the physical address as the first argument and 0 as the offset (last argument)?

    3.2 Why are the MAP_UNINITIALIZED | MAP_FIXED options almost never used in examples? Especially MAP_UNINITIALIZED seems required when reading the output from PL.

  • 4. The page size of the system is 4096 bytes. If I use the function to write a file of 2890 bytes the function returns without errors. With a file of 60000 bytes the kernel hangs/crashes.

  • 5. I also wrote a program to read memory using mmap. I tried the following:

write 2980 bytes of file_A to 0x1000_0000

write 2980 bytes of file_B to 0x1200_0000

read 2980 bytes of 0x1000_0000 > file_A_tst

read 2980 bytes of 0x1200_0000 > file_B_tst

  • 6. When checking the contents of the read files I see that 'file_A_tst' is equal to 'file_B_tst" and 'file_B'. So it seems that the written mapped memory is not actually flushed to the physical memory? I just get old data from the previous mmap. I need to use MAP_UNINITIALIZED because I don't wan't Linux to clear the physical memory.
0 Kudos