我們有一個嵌入式系統,其中連接了內存映射設備,ARM CPU運行Linux。該設備位於地址0x40400000
並佔用兆字節(大部分內容不由實際內存支持,但地址空間無論如何映射到設備)。我們目前有不需要有這個設備的設備驅動程序。將物理設備映射到用戶空間中的指針
該設備在地址0x404f0704
有一個特殊的只讀寄存器(稱爲CID)。該寄存器包含值CID = 0x404
。我正嘗試從運行在ARM上的程序讀取此寄存器。
搜索網絡我學到了mmap()
函數,該函數可以讓我從用戶空間訪問物理地址。因此,試圖跟隨一對夫婦的例子,我發現,我寫了下面的測試:
#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);
}
與ARM交叉編譯器編譯:
a-gcc -O0 -g3 -o mmap-test.elf mmap-test.c
我不能得到預期的結果。我看到的是:
pu = 0x40400000
pcid = 0x404f0704
CID = 0
,而不是預期
CID = 404
我缺少/做錯了什麼?
UPDATE:
我發現了另外一個演示程序和下面的代碼,我能得到我的代碼工作:
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);
}
不過,我不太知道爲什麼第一次版本不起作用。我的理解是,一旦你使用MAP_ANONYMOUS
你不需要一個文件句柄的映射。另外,我明顯錯誤地將addr參數(我的第一個版本中的pepi
)作爲物理地址。如果我現在是這樣,那麼這實際上是虛擬地址。