Отображение физического устройства на указатель в пространстве пользователя

У нас есть встроенная система, в которой подключено устройство с отображенной памятью, а процессор ARM работает под управлением Linux. Устройство находится по адресу0x40400000 и занимает мегабайт (большая часть его не поддерживается реальной памятью, но адресное пространство в любом случае отображается на устройстве). Мы в настоящее времяне есть драйвер устройства для этого устройства.

В устройстве есть специальный регистр только для чтения (называемый CID) по адресу0x404f0704, Этот регистр содержит значениеCID = 0x404, Я пытаюсь прочитать этот регистр из программы, запущенной на ARM.

Поиск в сети, я узнал оmmap() функция, которая предположительно позволяет мне получить доступ к физическому адресу из пространства пользователя. Итак, пытаясь следовать паре примеров, которые я нашел, я написал следующий тест:


#include 
#include 
#include 
#include 
#include 

int main(void)
{
    void          *pdev = (void *) 0x40400000;
    size_t         ldev = (1024*1024);
    int           *pu;
    int  volatile *pcid;
    int  volatile  cid;

    pu = mmap(pdev, ldev, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
    if (pu == MAP_FAILED)
        errx(1, "mmap failure");

    pcid = (int *) (((void *) pu) + 0xf0704);

    printf("pu    = %08p\n", pu);
    printf("pcid  = %08p\n", pcid);

    cid = *pcid;
    printf("CID   = %x\n", cid);

    munmap(pu, ldev);

    return (EXIT_SUCCESS);
}

Компиляция с помощью кросс-компилятора ARM:

a-gcc -O0 -g3 -o mmap-test.elf mmap-test.c

Я могу'не получить ожидаемый результат. Что я вижу, так это:

pu   = 0x40400000
pcid = 0x404f0704
CID  = 0

вместо ожидаемого

CID  = 404

Что я здесь упускаю / делаю неправильно?

ОБНОВИТЬ:

Я нашел другую демонстрационную программу и, следуя ее коду, смог заставить свой код работать:


int main(void)
{
    off_t          dev_base = 0x40400000;
    size_t         ldev = (1024 * 1024);
    unsigned long  mask = (1024 * 1024)-1;
    int           *pu;
    void          *mapped_base;
    void          *mapped_dev_base;
    int  volatile *pcid;
    int  volatile  cid;
    int            memfd;

    memfd = open("/dev/mem", O_RDWR | O_SYNC);
    mapped_base = mmap(0, MAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, memfd, dev_base & ~MAP_MASK);
    if (mapped_base == MAP_FAILED)
        errx(1, "mmap failure");
    mapped_dev_base = mapped_base + (dev_base & MAP_MASK);
    pu = mapped_dev_base;

    pcid = (int *) (((void *) pu) + 0xf0704);

    printf("pu    = %08p\n", pu);
    printf("pcid  = %08p\n", pcid);

    cid = *pcid;
    printf("CID   = %x\n", cid);

    munmap(mapped_base, ldev);
    close(memfd);

    return (EXIT_SUCCESS);
}

Тем не менее, я не очень уверен, почему 1-я версия не работает. Насколько я понимаю, когда вы используетеMAP_ANONYMOUS вам не нужен дескриптор файла для сопоставления. Кроме того, я явно ошибаюсьадр аргумент (pepi в моей 1-й версии) быть физическим адресом. Если я сейчас, то это фактически виртуальный адрес.

Ответы на вопрос(1)

Ваш ответ на вопрос