Using mmap on Zynq 7000

0

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.

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

  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;
}
  1. In most examples I found I see:

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

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

  1. 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.

  2. 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

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.

linux
linux-kernel
device-tree
zynq
asked on Stack Overflow Feb 25, 2019 by dwjbosman

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0