• 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>3", TOYFLAG_USR|TOYFLAG_SBIN))
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 
xatolu(char * str,int bytes)20 unsigned long xatolu(char *str, int bytes)
21 {
22   char *end = str;
23   unsigned long lu;
24 
25   errno = 0;
26   lu = strtoul(str, &end, 0);
27   // Report out of range values as errors rather than truncating.
28   if (errno == ERANGE || lu > (~0UL)>>(sizeof(long)-bytes)*8)
29     error_exit("%s>%d bytes", str, bytes);
30   if (*end || errno) perror_exit("bad %s", str);
31 
32   return lu;
33 }
34 
devmem_main(void)35 void devmem_main(void)
36 {
37   int writing = toys.optc == 3, page_size = sysconf(_SC_PAGESIZE), bytes = 4,fd;
38   unsigned long data = 0, map_off, map_len,
39     addr = xatolu(*toys.optargs, sizeof(long));
40   char *sizes = sizeof(long)==8 ? "1248" : "124";
41   void *map, *p;
42 
43   // WIDTH?
44   if (toys.optc>1) {
45     int i;
46 
47     if ((i=stridx(sizes, *toys.optargs[1]))==-1 || toys.optargs[1][1])
48       error_exit("bad width: %s", toys.optargs[1]);
49     bytes = 1<<i;
50   }
51 
52   // DATA?
53   if (writing) data = xatolu(toys.optargs[2], bytes);
54 
55   // Map in just enough.
56   if (CFG_TOYBOX_FORK) {
57     fd = xopen("/dev/mem", (writing ? O_RDWR : O_RDONLY) | O_SYNC);
58 
59     map_off = addr & ~(page_size - 1ULL);
60     map_len = (addr+bytes-map_off);
61     map = xmmap(0, map_len, writing ? PROT_WRITE : PROT_READ, MAP_SHARED, fd,
62         map_off);
63     p = map + (addr & (page_size - 1));
64     close(fd);
65   } else p = (void *)addr;
66 
67   // Not using peek()/poke() because registers care about size of read/write
68   if (writing) {
69     if (bytes==1) *(char *)p = data;
70     else if (bytes==2) *(unsigned short *)p = data;
71     else if (bytes==4) *(unsigned int *)p = data;
72     else if (sizeof(long)==8 && bytes==8) *(unsigned long *)p = data;
73   } else {
74     if (bytes==1) data = *(char *)p;
75     else if (bytes==2) data = *(unsigned short *)p;
76     else if (bytes==4) data = *(unsigned int *)p;
77     else if (sizeof(long)==8 && bytes==8) data = *(unsigned long *)p;
78     printf((!strchr(*toys.optargs, 'x')) ? "%0*ld\n" : "0x%0*lx\n",
79       bytes*2, data);
80   }
81 
82   if (CFG_TOYBOX_FORK) munmap(map, map_len);
83 }
84