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.