Wir verfügen über ein eingebettetes System, in das ein Speichergerät eingebunden ist, und auf einer ARM-CPU wird Linux ausgeführt. Das Gerät befindet sich unter der Adresse 0x40400000
und belegt ein Megabyte (das meiste davon ist nicht durch einen tatsächlichen Speicher belegt, aber der Adressraum ist dem Gerät trotzdem zugeordnet). Wir haben derzeit nicht haben einen Gerätetreiber für dieses Gerät.Zuordnung eines physischen Geräts zu einem Zeiger im Benutzerbereich
Im Gerät gibt es ein spezielles Nur-Lese-Register (CID) unter der Adresse 0x404f0704
. Dieses Register enthält den Wert CID = 0x404
. Ich versuche, dieses Register von einem Programm zu lesen, das auf dem ARM läuft.
Suche im Internet habe ich über die mmap()
Funktion, die angeblich ich auf eine physische Adresse aus dem Benutzerbereich zugreifen erfahren. Also, versuchte ein paar Beispiele zu folgen, ich fand, schrieb ich den folgenden Test:
#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 den ARM-Cross-Compiler:
a-gcc -O0 -g3 -o mmap-test.elf mmap-test.c
Ich kann nicht das erwartete Ergebnis. Was ich sehe, ist, dass:
pu = 0x40400000
pcid = 0x404f0704
CID = 0
statt der
erwartetCID = 404
Was bin ich fehlt/falsch hier?
UPDATE:
ich ein weiteres Demo-Programm gefunden und seinen Code folgende 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);
}
Aber ich bin nicht so sicher, warum die erste Version hat nicht funktioniert. Mein Verständnis war, dass, sobald Sie MAP_ANONYMOUS
verwenden, Sie kein Dateihandle für das Mapping benötigen. Außerdem verwechselte ich offensichtlich das Adr Argument (pepi
in meiner 1. Version), um die physikalische Adresse zu sein. Wenn ich gerade bin, dann ist das eigentlich die virtuelle Adresse.