Abbiamo un sistema incorporato in cui è connesso un dispositivo mappato in memoria e una CPU ARM esegue Linux. Il dispositivo si trova all'indirizzo 0x40400000
e occupa un megabyte (la maggior parte non è supportato da una memoria effettiva, ma lo spazio degli indirizzi viene comunque mappato sul dispositivo). Al momento, non dispone di un driver di dispositivo per questo dispositivo.Mappatura di un dispositivo fisico a un puntatore nello spazio utente
Nel dispositivo è presente uno speciale registro di sola lettura (denominato CID) all'indirizzo 0x404f0704
. Questo registro contiene il valore CID = 0x404
. Sto cercando di leggere questo registro da un programma in esecuzione su ARM.
Ricerca in rete Ho imparato a conoscere la funzione mmap()
che presumibilmente mi consente di accedere a un indirizzo fisico da userspace. Così, cercando di seguire un paio di esempi che ho trovato, ho scritto il seguente 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);
}
Compilare con ARM cross-compilatore:
a-gcc -O0 -g3 -o mmap-test.elf mmap-test.c
non riesco a ottenere il risultato atteso. Quello che vedo è che:
pu = 0x40400000
pcid = 0x404f0704
CID = 0
invece dei previsti
CID = 404
Che cosa mi manca/facendo male qui?
UPDATE:
ho trovato un altro programma demo e seguendo il suo codice sono stato in grado di ottenere il mio codice di lavoro:
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);
}
Eppure, io non sono così sicuro perché il 1 ° la versione non ha funzionato. La mia comprensione è stata che una volta che si utilizza MAP_ANONYMOUS
non è necessario un handle di file per la mappatura. Inoltre, ho ovviamente scambiato l'argomento addr (pepi
nella mia prima versione) come indirizzo fisico. Se sono in questo momento, questo è in realtà l'indirizzo virtuale.