We have an embedded system in which a device with a memory display is connected, and the ARM processor is running Linux. The device is located at 0x40400000 and occupies megabytes (most of it is not supported by real memory, but the address space is mapped to the device in any case). We currently do not have a device driver for this device.
The device has a special read-only register (called CID) at 0x404f0704 . This register contains the value CID = 0x404 . I am trying to read this register from a program running on ARM.
Web Search I learned about the mmap() function, which supposedly allows me to access a physical address from user space. So, trying to find a couple of examples that I found, I wrote the following 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); }
#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); }
Compiling with the ARM cross-compiler:
a-gcc -O0 -g3 -o mmap-test.elf mmap-test.c
I can not get the expected result. I see that:
pu = 0x40400000 pcid = 0x404f0704 CID = 0
instead of the expected
CID = 404
What am I missing / doing wrong here?
UPDATE:
I found another demo program and executed its code. I managed to run my code:
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); }
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); }
However, I'm not quite sure why the first version does not work. I realized that after using MAP_ANONYMOUS you do not need a file descriptor for matching. Also, I obviously mistakenly accept the addr argument ( pepi in my first version) as a physical address. If I am now, then this is actually a virtual address.