• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* devmem.c - Access physical addresses
2  *
3  * Copyright 2019 The Android Open Source Project
4 
5 USE_DEVMEM(NEWTOY(devmem, "<1(no-sync)(no-mmap)f:", TOYFLAG_USR|TOYFLAG_SBIN))
6 
7 config DEVMEM
8   bool "devmem"
9   default y
10   help
11     usage: devmem [-f FILE] ADDR [WIDTH [DATA...]]
12 
13     Read/write physical addresses. 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     -f FILE		File to operate on (default /dev/mem)
17     --no-sync	Don't open the file with O_SYNC (for cached access)
18     --no-mmap	Don't mmap the file
19 */
20 
21 #define FOR_devmem
22 #include "toys.h"
23 
GLOBALS(char * f;)24 GLOBALS(
25   char *f;
26 )
27 
28 unsigned long xatolu(char *str, int bytes)
29 {
30   char *end = str;
31   unsigned long lu;
32 
33   errno = 0;
34   lu = strtoul(str, &end, 0);
35   // Report out of range values as errors rather than truncating.
36   if (errno == ERANGE || lu > (~0UL)>>(sizeof(long)-bytes)*8)
37     error_exit("%s>%d bytes", str, bytes);
38   if (*end || errno) perror_exit("bad %s", str);
39 
40   return lu;
41 }
42 
devmem_main(void)43 void devmem_main(void)
44 {
45   int ii, writing = toys.optc > 2, bytes = 4, fd;
46   unsigned long data = 0, map_len QUIET,
47     addr = xatolu(*toys.optargs, sizeof(long));
48   void *map QUIET, *p QUIET;
49   char *pdata;
50 
51   // WIDTH?
52   if (toys.optc>1) {
53     char *sizes = sizeof(long)==8 ? "1248" : "124";
54 
55     if ((ii = stridx(sizes, *toys.optargs[1]))==-1 || toys.optargs[1][1])
56       error_exit("bad width: %s", toys.optargs[1]);
57     bytes = 1<<ii;
58   }
59   pdata = ((char *)&data)+IS_BIG_ENDIAN*(sizeof(long)-bytes);
60 
61   // Map in just enough.
62   if (CFG_TOYBOX_FORK) {
63     fd = xopen(TT.f ? : "/dev/mem", O_RDWR*writing+O_SYNC*!FLAG(no_sync));
64     if (FLAG(no_mmap)) xlseek(fd, addr, SEEK_SET);
65     else {
66       unsigned long long page_size = sysconf(_SC_PAGESIZE)-1, map_off;
67 
68       map_off = addr & ~page_size;
69       map_len = addr + (writing ? (toys.optc - 2) * bytes : bytes) - map_off;
70       map = xmmap(0, map_len, writing ? PROT_WRITE : PROT_READ, MAP_SHARED, fd,
71           map_off);
72       p = map+(addr&page_size);
73       close(fd);
74     }
75   } else p = (void *)addr;
76 
77   // Not using peek()/poke() because registers care about size of read/write.
78   if (writing) for (ii = 2; ii<toys.optc; ii++) {
79     data = xatolu(toys.optargs[ii], bytes);
80     if (FLAG(no_mmap)) xwrite(fd, pdata, bytes);
81     else {
82       if (bytes==1) *(char *)p = data;
83       else if (bytes==2) *(unsigned short *)p = data;
84       else if (bytes==4) *(unsigned *)p = data;
85       else if (sizeof(long)==8 && bytes==8) *(unsigned long *)p = data;
86       p += bytes;
87     }
88   } else {
89     if (FLAG(no_mmap)) xread(fd, pdata, bytes);
90     else {
91       if (bytes==1) data = *(char *)p;
92       else if (bytes==2) data = *(unsigned short *)p;
93       else if (bytes==4) data = *(unsigned *)p;
94       else if (sizeof(long)==8 && bytes==8) data = *(unsigned long *)p;
95     }
96     printf(strchr(*toys.optargs, 'x') ? "0x%0*lx\n" : "%0*ld\n", bytes*2, data);
97   }
98 
99   if (CFG_TOYBOX_FORK) {
100     if (FLAG(no_mmap)) close(fd);
101     else munmap(map, map_len);
102   }
103 }
104