Reputation: 4567
I am trying accessing /dev/mem from user space. Using qemu-system-arm for this purpose.
UART0 is mapped: 0x101f1000 and UARTDR is placed at offset 0x0
$ devmem 0x101f1000 8 0x61
The above writes 'a' on the console.
When i try the achieve the same logic from C code, it fails
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd;
char ch = 'a';
fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd < 0) {
perror("open failed");
return -1;
}
if (lseek(fd, 0x101f1000, SEEK_SET) == -1) {
perror("lseek");
}
if (write(fd, &ch, sizeof(ch)) == -1) {
perror("write");
}
close(fd);
return 0;
}
It fails with error: write: Bad address
Upvotes: 0
Views: 2285
Reputation: 11483
Trying to access device registers by using the read and write syscalls on /dev/mem is not a good idea. /dev/mem implements those syscalls mostly for convenience in accessing RAM, and there is no guarantee about whether it will make accesses of the right width for the device if you try to do that on an area of the address space with a device there. For accessing devices you should instead use mmap() and then access the right addresses directly (which gives you more control about the width of the access and exactly which addresses are touched). For an example of this you can look at the source code for devmem itself: https://github.com/hackndev/tools/blob/master/devmem2.c -- at less than 100 lines of code it's very simple and you already know it works correctly for your use case.
Upvotes: 1
Reputation: 70971
[probably not your main problem but still]
lseek: Success write: Bad address
You only want to use errno
(or call perror()
) is the previous call failed (and is documented to set errno
on failure).
So this
lseek(fd, 0x101f1000, SEEK_SET);
perror("lseek");
should look like
if ((off_t) -1 == lseek(fd, 0x101f1000, SEEK_SET))
{
perror("lseek() failed");
}
Same for the call to write()
, BTW.
Upvotes: 0