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