1 /* devmem.c - Access physical addresses
2  *
3  * Copyright 2019 The Android Open Source Project
4 
5 USE_DEVMEM(NEWTOY(devmem, "<1>3", TOYFLAG_USR|TOYFLAG_BIN))
6 
7 config DEVMEM
8   bool "devmem"
9   default y
10   help
11     usage: devmem ADDR [WIDTH [DATA]]
12 
13     Read/write physical address. WIDTH is 1, 2, 4, or 8 bytes (default 4).
14     Prefix ADDR with 0x for hexadecimal, output is in same base as address.
15 */
16 
17 #define FOR_devmem
18 #include "toys.h"
19 
devmem_main(void)20 void devmem_main(void)
21 {
22   int writing = toys.optc == 3, page_size = sysconf(_SC_PAGESIZE), bytes = 4,fd;
23   unsigned long long data = 0, map_off, map_len;
24   unsigned long addr = atolx(*toys.optargs);
25   void *map, *p;
26 
27   // WIDTH?
28   if (toys.optc>1) {
29     int i;
30 
31     if ((i=stridx("1248", *toys.optargs[1]))==-1 || toys.optargs[1][1])
32       error_exit("bad width: %s", toys.optargs[1]);
33     bytes = 1<<i;
34   }
35 
36   // DATA? Report out of range values as errors rather than truncating.
37   if (writing) data = atolx_range(toys.optargs[2], 0, (1ULL<<(8*bytes))-1);
38 
39   // Map in just enough.
40   if (CFG_TOYBOX_FORK) {
41     fd = xopen("/dev/mem", (writing ? O_RDWR : O_RDONLY) | O_SYNC);
42 
43     map_off = addr & ~(page_size - 1);
44     map_len = (addr+bytes-map_off);
45     map = xmmap(0, map_len, writing ? PROT_WRITE : PROT_READ, MAP_SHARED, fd,
46         map_off);
47     p = map + (addr & (page_size - 1));
48     close(fd);
49   } else p = (void *)addr;
50 
51   // Not using peek()/poke() because registers care about size of read/write
52   if (writing) {
53     if (bytes == 1) *(unsigned char *)p = data;
54     else if (bytes == 2) *(unsigned short *)p = data;
55     else if (bytes == 4) *(unsigned int *)p = data;
56     else if (bytes == 8) *(unsigned long long *)p = data;
57   } else {
58     if (bytes == 1) data = *(unsigned char *)p;
59     else if (bytes == 2) data = *(unsigned short *)p;
60     else if (bytes == 4) data = *(unsigned int *)p;
61     else if (bytes == 8) data = *(unsigned long long *)p;
62     printf((!strchr(*toys.optargs, 'x')) ? "%0*lld\n" : "0x%0*llx\n",
63       bytes*2, data);
64   }
65 
66   if (CFG_TOYBOX_FORK) munmap(map, map_len);
67 }
68