Zuordnen eines physischen Geräts zu einem Zeiger im Benutzerbereich

Wir haben ein eingebettetes System, in dem ein Speichergerät angeschlossen ist und eine ARM-CPU Linux ausführt. Das Gerät befindet sich unter der Adresse0x40400000 und belegt ein Megabyte (das meiste davon wird nicht durch einen tatsächlichen Speicher gesichert, aber der Adressraum wird trotzdem dem Gerät zugeordnet). Wir sind derzeitnicht Habe einen Gerätetreiber für dieses Gerät.

Im Gerät befindet sich unter der Adresse ein spezielles Nur-Lese-Register (CID)0x404f0704. Dieses Register enthält den WertCID = 0x404. Ich versuche, dieses Register von einem Programm zu lesen, das auf dem ARM läuft.

Ich habe im Internet nach dem gesuchtmmap() Funktion, die mir angeblich den Zugriff auf eine physikalische Adresse aus dem Benutzerbereich ermöglicht. Um ein paar Beispielen zu folgen, die ich gefunden habe, habe ich den folgenden Test geschrieben:


#include <sys/mman.h>
#include <fcntl.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>

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

Kompilieren mit dem ARM-Cross-Compiler:

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

Ich kann das erwartete Ergebnis nicht erzielen. Was ich sehe, ist das:

pu   = 0x40400000
pcid = 0x404f0704
CID  = 0

statt der erwarteten

CID  = 404

Was vermisse ich / mache ich hier falsch?

AKTUALISIEREN:

Ich habe ein anderes Demo-Programm gefunden und anhand seines Codes konnte ich meinen Code zum Laufen bringen:


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

Trotzdem bin ich mir nicht so sicher, warum die 1. Version nicht funktioniert hat. Mein Verständnis war, dass Sie einmal verwendenMAP_ANONYMOUS Sie benötigen kein Dateihandle für das Mapping. Auch habe ich mich offensichtlich geirrtAdr Streit (pepi in meiner 1. Version) die physikalische Adresse sein. Wenn ich gerade bin, dann ist dies eigentlich die virtuelle Adresse.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage