Получение пустого вывода при чтении из файла с использованием mmap

У меня проблема с использованием mmap. Я пытаюсь сопоставить устройство pci с виртуальным адресом и прочитать его содержимое. В будущем я планирую также записывать в него значения.

Проблема в том, что я (по-видимому) успешно сопоставил устройство с пространством виртуальной памяти. Однако, когда я читаю содержимое этого виртуального адреса, все значения равны нулю, несмотря на то, что файл не пуст.

Вот мой код:

#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;
}

Вот содержимое первой строки из файла "/sys/bus/pci/devices/0000:04:00.0/resource", к которому я пытаюсь получить доступ:

0x00000000cd000000 0x00000000cd07ffff 0x0000000000040200

Однако вывод, который я получаю:

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

Я делаю что-то неправильно? Каждая помощь приветствуется!


person A.Z.    schedule 12.12.2017    source источник
comment
В примечании, не имеющем отношения к вашей проблеме, вы действительно имеете в виду 4069 вместо MAP_SIZE? Не обычное значение степени двойки 4096? Это опечатка в самом коде, или вы переписали код для вопроса? Если второе, то не делайте этого. Вместо скопируйте и вставьте минимальный, полный и проверяемый пример. Таким образом, вы не внесете несвязанных ошибок или, возможно, даже (по ошибке и не осознавая этого) устраните проблему.   -  person Some programmer dude    schedule 12.12.2017
comment
Нет, это фактический код моего файла. Когда я просто пишу 4096, я получаю предупреждение, что int является неправильным типом данных. Имеет ли это значение в таком случае? Изменить: я изменил значение на (int) 4096, и теперь я больше не получаю предупреждение... Я получил предупреждение, когда все еще пытался получить указатель из mmap вместо кода ошибки.   -  person A.Z.    schedule 12.12.2017
comment
Тогда он не будет собираться (#include ...), и вывод, который вы показываете, не соответствует коду (код говорит, что MAP_SIZE равен 4069, но ваш вывод показывает его как 4096). Таким образом, код, который вы показываете, не является фактическим кодом, который вы создаете и запускаете. Подобные мелочи мешают нам доверять остальному коду, поэтому многие, кто мог бы вам помочь, не будут этого делать.   -  person Some programmer dude    schedule 12.12.2017
comment
Клянусь, единственное, что я изменил, это удаление включений. Я отредактировал свой пост и добавил скриншот.   -  person A.Z.    schedule 12.12.2017
comment
КАРТА_ЧАСТНАЯ | MAP_ANON, замените его на MAP_SHARED, тогда он сможет распечатать файл. Я меняю аргумент, чтобы имитировать старую программу демонстрации mmap, но я не уверен, в чем проблема в вашем аргументе, я проверю это позже.   -  person peter__barnes    schedule 12.12.2017
comment
Примечание: do{ ... } while(0); --> do{ ... } while(0) [иначе причудливое do-while не имело бы никакого смысла]   -  person joop    schedule 12.12.2017
comment
@peter_barnes Спасибо за ответ! У меня была MAP_SHARED вместо MAP_PRIVATE | MAP_ANON раньше, но затем mmap терпит неудачу, и я получаю вывод Error в строке 39, файл src/main.c (19) [Нет такого устройства] [at]joop Вы правы, спасибо!   -  person A.Z.    schedule 12.12.2017
comment
Почему вы хотите отобразить файл resource? Это просто сообщает вам информацию об областях ввода-вывода порта и памяти ввода-вывода и представляет собой довольно небольшой файл. Вам необходимо сопоставить один из resourceN файлов (где N — номер PCI BAR (регистра базового адреса)) для доступа к области памяти PCI, охватываемой PCI BAR N.   -  person Ian Abbott    schedule 12.12.2017


Ответы (1)


На самом деле у вас 2 ошибки:

  1. Не используйте MAP_ANON при создании карты для реального файла в файловой системе, она предназначена для IPC и требует дополнительной памяти от ОС, например. в то время как malloc().
  2. Когда вы удалите этот флаг, mmap(), скорее всего, вернет ENODEV, потому что linux sysfs не поддерживает mmaping; Таким образом, вы должны использовать read() здесь.
person Fat-Zer    schedule 12.12.2017
comment
Ага, понятно. Кто-то в другом посте сказал это, и я был счастлив, что больше не получаю ошибку. Да, я действительно получил ошибку Нет такого устройства, когда не использую MAP_ANON. Есть ли возможность получить доступ к устройствам pci, а также записать значения в BAR 0? Я думал, что mmap решит мою проблему, но, похоже, я ошибался. - person A.Z.; 12.12.2017
comment
@А.З. Если вы пытаетесь получить доступ к BAR 0, вы должны отображать файл resource0, а не файл resource. Файл resource просто предоставляет информацию о BAR. - person Ian Abbott; 12.12.2017
comment
@IanAbbott О, понятно. Не знал этого, спасибо! Поскольку resource0 является двоичным файлом, я хотел получить доступ к ресурсу, чтобы сначала проверить, правильно ли работает мой mmap, а затем посмотреть, где я могу найти BAR0. Могу ли я получить доступ к файлу resource0 с помощью mmap? И если да, то как мне правильно это сделать? - person A.Z.; 12.12.2017
comment
@А.З. Да, вы можете отобразить его как MAP_SHARED. Если в шине PCI BAR установлен бит prefechable, также может существовать файл ресурсаN_wc. Туалет означает объединение записи. - person Ian Abbott; 12.12.2017
comment
Обратите внимание, что есть инструмент, делающий почти то же самое: github.com/billfarrow/pcimem. Также кажется, что resourceX недоступен, поскольку модуль ядра использует устройство. - person Fat-Zer; 12.12.2017
comment
@IanAbbott бит предварительной загрузки, похоже, не установлен, так как я не могу найти файлы resourceX_wc. И если я использую только MAP_SHARED, я получаю сообщение об ошибке Нет такого устройства. КАРТА_SHARED | MAP_ANON дает мне действительное возвращаемое значение с mmap, но у меня та же проблема, что и выше, все биты равны 0 - person A.Z.; 13.12.2017
comment
@А.З. Прочтите чертову man mmap . Если вы установите MAP_ANON для pci_dev fd, вы просто проигнорируете ;). Вы уверены, что получаете ENODEV при ммэппинге resource0? Должно быть EINVAL... Если это так, убедитесь, что устройство не используется драйвером ядра... - person Fat-Zer; 13.12.2017
comment
@ Fat-Zer Боже мой, я такой тупой ^^ Вы правы, устройство PCI использовалось модулем ядра. Выгрузив этот модуль ядра, я получил доступ к устройству, и теперь все работает отлично. Большое спасибо за вашу помощь и ваше терпение! :) - person A.Z.; 14.12.2017