1

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!

A.Z.
  • 33
  • 1
  • 4
  • On a note unrelated to your problem, do you really mean `4069` for `MAP_SIZE`? Not the usual power-of-two value of `4096`? Is it a typo in the actual code, or did you rewrite the code for the question? If the latter, then don't do that. ***Copy-paste*** the [Minimal, Complete, and Verifiable Example](http://stackoverflow.com/help/mcve) instead. That way you won't introduce unrelated errors, or perhaps even (by mistake and without realizing it) fix the problem. – Some programmer dude Dec 12 '17 at 09:00
  • No, that is the actual code of my file. When I just write 4096 I get a warning that int is the wrong data type. Does it matter in that case? Edit: I changed the value to (int) 4096 and now I don't get a warning anymore... I got the warning when I was still struggling with getting a pointer from mmap instead of an error code. – A.Z. Dec 12 '17 at 09:03
  • 1
    Then it would not build (`#include ...`), and the output you show doesn't match the code (the code says `MAP_SIZE` is `4069` but your output shows it as `4096`). So the code you show is not the actual code you build and run. Small things like that makes it harder for us to trust the rest of the code, so many who could help you won't do it. – Some programmer dude Dec 12 '17 at 09:06
  • I swear the only thing I changed was deleting the includes. I edited my post and included a screenshot. – A.Z. Dec 12 '17 at 09:16
  • "MAP_PRIVATE | MAP_ANON" ,replace this by "MAP_SHARED" ,then it can print the file. I change the argument to simulate an old program of mmap demo,but I am not sure what's the problem in your argument, I will check it later – peter__barnes Dec 12 '17 at 09:30
  • Note : `do{ ... } while(0);` --> `do{ ... } while(0)` [ otherwise the funky do-while wouldn't make any sense ] – joop Dec 12 '17 at 09:34
  • @peter_barnes Thanks for the reply! I had "MAP_SHARED" instead of "MAP_PRIVATE | MAP_ANON" before, but then mmap fails and I get the output "Error at line 39, file src/main.c (19) [No such device]" [at]joop You are right, thank you! – A.Z. Dec 12 '17 at 09:37
  • Why do you want to mmap the `resource` file? That just tells you information about the port I/O and memory I/O regions, and is a fairly small file. You need to mmap one of the `resourceN` files (where `N` is the PCI BAR (Base Address Register) number) in order to access the PCI memory region covered by PCI BAR N. – Ian Abbott Dec 12 '17 at 10:36

1 Answers1

0

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.
Fat-Zer
  • 337
  • 2
  • 12
  • Oh, I see. Someone in another post said that and I was happy for not getting an error anymore. Yes, I indeed got the error "No such device" when not using MAP_ANON. Is there a possibility to access pci devices and also write values to BAR 0? I hought mmap would solve my problem, but it seems as if I was wrong. – A.Z. Dec 12 '17 at 09:49
  • @A.Z. If you are trying to access BAR 0, you should be mmaping the `resource0` file, not the `resource` file. The `resource` file just provides information about the BARs. – Ian Abbott Dec 12 '17 at 10:40
  • @IanAbbott Oh I see. Didn't know that, thank you! Since resource0 is a binary file, I wanted to access resource in order to check if my mmap works correctly first and then see where I can find BAR0. Can I access the resource0 file with mmap? And if yes, how do I do it correctly? – A.Z. Dec 12 '17 at 11:05
  • @A.Z. Yes you can mmap it as MAP_SHARED. If the PCI BAR has the "prefechable" bit set, there may also be a "resource*N*_wc" file. The "wc" stands for "write combine". – Ian Abbott Dec 12 '17 at 13:15
  • Note, thet there is a tool doing pretty much the same: https://github.com/billfarrow/pcimem. Also it seems that the resourceX is unavailable as far as a kernel module uses the device. – Fat-Zer Dec 12 '17 at 13:28
  • @IanAbbott the prefechable bit seems not to be set as I can't find the "resourceX_wc" files. And if I only use MAP_SHARED I get the error "No such device". MAP_SHARED | MAP_ANON gives me a valid return value with mmap, but I have the same problem as above, all bits are 0 – A.Z. Dec 13 '17 at 13:02
  • @A.Z. Read the damn _man mmap_ . If you set MAP_ANON the pci_dev fd you pass just being **ignored** ;). Are you sure you are receiving ENODEV when mmaping **resource0**? It should be EINVAL... If so, make sure that the device is not being used by a kernel driver... – Fat-Zer Dec 13 '17 at 13:28
  • @Fat-Zer Oh my god, I am so dumb ^^ You are right, the PCI device was used by a kernel module. By unloading that kernel module I got access to the device and now everything works perfectly. Thank you very much for your help and your patience! :) – A.Z. Dec 14 '17 at 07:37