md.jamal
md.jamal

Reputation: 4567

write on /dev/mem fails with bad address

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

Answers (2)

Peter Maydell
Peter Maydell

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

alk
alk

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

Related Questions