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 via /dev/mem.
14
15 WIDTH is 1, 2, 4, or 8 bytes (default 4).
16 */
17
18 #define FOR_devmem
19 #include "toys.h"
20
devmem_main(void)21 void devmem_main(void)
22 {
23 int writing = toys.optc == 3, page_size = getpagesize(), bytes = 4, fd;
24 unsigned long long addr = atolx(toys.optargs[0]), data = 0, map_off, map_len;
25 void *map, *p;
26
27 // WIDTH?
28 if (toys.optc>1) {
29 int i;
30
31 if (strlen(toys.optargs[1])!=1 || (i=stridx("1248", *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 fd = xopen("/dev/mem", (writing ? O_RDWR : O_RDONLY) | O_SYNC);
41 map_off = addr & ~(page_size - 1);
42 map_len = (addr+bytes-map_off);
43 map = xmmap(NULL, map_len, writing ? PROT_WRITE : PROT_READ, MAP_SHARED, fd,
44 map_off);
45 p = map + (addr & (page_size - 1));
46 close(fd);
47
48 // Not using peek()/poke() because registers care about size of read/write
49 if (writing) {
50 if (bytes == 1) *(char *)p = data;
51 else if (bytes == 2) *(short *)p = data;
52 else if (bytes == 4) *(int *)p = data;
53 else if (bytes == 8) *(long long *)p = data;
54 } else {
55 if (bytes == 1) data = *(char *)p;
56 else if (bytes == 2) data = *(short *)p;
57 else if (bytes == 4) data = *(int *)p;
58 else if (bytes == 8) data = *(long long *)p;
59 printf("%#0*llx\n", bytes*2, data);
60 }
61
62 munmap(map, map_len);
63 }
64