Search code examples
clinuxmmappcivirtual-address-space

Getting empty output when reading from file using "mmap"


I have a problem considering the usage of mmap. I am trying to map a pci device to a virtual address and read its content. In the future I am planning to write values to it as well.

The problem is that I (seemingly) successfully mapped the device to virtual memory space. However when I read the content of that virtual address all values are zero, despite the file not being empty.

Here is my code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "../include/types.h"
#include "../include/pci.h"

#define PRINT_ERROR \
    do { \
        fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
        __LINE__, __FILE__, errno, strerror(errno)); exit(1);\
     } while(0)

#define MAP_SIZE 4069
#define MAP_MASK (MAP_SIZE - 1)

int main(int argc, char *argv[])
{
    int pci_dev;
    int *mmap_base;
    int *content;
    char file[] = {"/sys/bus/pci/devices/0000:04:00.0/resource"};
    int i;

    printf("File to be read from: %s\n", file);

    pci_dev = open(file, O_RDONLY);
    if (pci_dev < 0)
    {
        PRINT_ERROR;
    }

    mmap_base = mmap(NULL, MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_ANON, pci_dev, 0);
    if (mmap_base == (void *)-1 || mmap_base == NULL)
    {
        PRINT_ERROR;
    }
    printf("Mapped on address %p of size %d Byte\n", mmap_base, (int)MAP_SIZE);
    content = (int *)mmap_base;

    for(i = 0; i < 1024; i++)
    {
        printf("%x", content[i]);
    }


    return 0;
}

Here's the content of the first line from the file "/sys/bus/pci/devices/0000:04:00.0/resource" that I am trying to access:

0x00000000cd000000 0x00000000cd07ffff 0x0000000000040200

However the output I get is:

File to be read from: /sys/bus/pci/devices/0000:04:00.0/resource
Mapped on address 0xb7705000 of size 4096 Byte
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...

Am I doing something wrong? Every help is appreciated!


Solution

  • Actually you've got 2 mistakes:

    1. Don't use MAP_ANON when you create a map for a real file on the file system, it's meant for IPC and requiring extra memory from OS e.g. while malloc().
    2. When you remove the flag, the mmap() will likely return ENODEV, because linux sysfs doesn't support mmaping; So you have to use read()'s here.