1

I would like to write an integer(just one value, it can be also other type) to a specific register (for example: 0x60006666) on a Linux machine using the ARM platform.

There are many examples using the mmap(2), but it is not clear how to write just one value to a specific address using the mmap(). Having a look at the mmap() manual, it does not specify what value to write to the specific register: http://man7.org/linux/man-pages/man2/mmap.2.html

Here is the function:

void *mmap(void *addr, size_t length, int prot, int flags,
              int fd, off_t offset);

It is clear that *addr is the address, but where do we insert the value is written to this address?

In my case I would like to write an int to a specific address, how would mmap look like?

#define _WRITE_ADDR       0x60006666 //address where to write 
unsigned int value_addr = 0x00000080 //value to be written to the address

I would like to write the above mentioned value to the specified address. It should be trivial, but not very clear since it has been some time since I worked with this type of questions, hopefully somebody has some hints. Thanks!

Similar question:
WRITE and READ registers in Linux on ARM

SW Dev
  • 23
  • 5
  • 1
    Unrelated to your problem, but symbols beginning with an underscore and followed by an upper-case letter (like for example `_WRITE_ADDR`) are reserved everywhere for the "implementation" (i.e. the compiler and the standard C library). You should not use such symbols in your own code. – Some programmer dude Dec 21 '18 at 12:55
  • 1
    As for your problem, the address you provide to `mmap` is still a *virtual* address (IIRC). And the `mmap` call itself isn't used to write to the memory, only to map a portion of virtual memory into your process memory map. You use the pointer that `mmap` *returns* to write the data you need to store. – Some programmer dude Dec 21 '18 at 12:58
  • Lastly (and also IIRC) you need to open the raw memory device (`/dev/mem`, which requires elevated privileges) and then you can give the address as the *offset* of the file when you map it. – Some programmer dude Dec 21 '18 at 12:59
  • "It should be trivial" -- not at all. If you want to write to a specific *physical* address under the management of a virtual-memory system such as Linux then your code needs to run inside the kernel. If you're triggering it from user space then you're looking at writing a device driver (albeit perhaps a very simple one). – John Bollinger Dec 21 '18 at 13:00
  • @Someprogrammerdude yes, I open the raw memory: `int fd = open("/dev/mem", O_RDWR|O_SYNC);` But where do I specify what value to write to the address? – SW Dev Dec 21 '18 at 13:10
  • Note a word write to physical address 0x6666 may/should give you an alignment fault...mmap() works great for getting through the os if you are allowed. note you normally want to allocate a larger aligned space, at least on x86 your odds are better, for arm not sure which size is better 16mbytes, 1mbyte or 4096 bytes allocation size just has to be at larger than what you want to access, they will want to use a whole mmu page anyway. – old_timer Dec 21 '18 at 15:01
  • yeah, this is just a duplicate of that prior question, what didnt work for you when you tried that? – old_timer Dec 21 '18 at 15:02

1 Answers1

2

It is rather simple. Example based on RPI

first you need to:

mem_fd = open("/dev/mem", O_RDWR | O_SYNC);

then allocate memory for the map. For example for one BCM RPi peritheral it will me 4K + 4K

periph_mem = malloc( 8*1024 - 1);

then make sure that it is 4k aligned and mmap it:

gpio_map = (unsigned char *)mmap((caddr_t)poriph_mem, BLOCK_SIZE,PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, mem_fd, PERIPH_BASE    );

where PERIPH_BASE is the base address of the peripheral (for example GPIO 0x20000000 (BCM peripherals base) + 0x200000)

then you can access them as normal pointers (but remember they have to volatile)

*(volatile uint32_t *)(periph_mem + OFFSET) = VALUE;
0___________
  • 60,014
  • 4
  • 34
  • 74