1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include "libbb.h"
26
27int devmem_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
28int devmem_main(int argc UNUSED_PARAM, char **argv)
29{
30 void *map_base, *virt_addr;
31 uint64_t read_result;
32 off_t target;
33 unsigned page_size, mapped_size, offset_in_page;
34 int fd;
35 unsigned width = 8 * sizeof(int);
36
37
38
39
40
41
42
43
44
45 if (!argv[1])
46 bb_show_usage();
47 errno = 0;
48 target = bb_strtoull(argv[1], NULL, 0);
49
50
51 if (argv[2]) {
52 if (isdigit(argv[2][0]) || argv[2][1])
53 width = xatou(argv[2]);
54 else {
55 static const char bhwl[] ALIGN1 = "bhwl";
56 static const uint8_t sizes[] ALIGN1 = {
57 8 * sizeof(char),
58 8 * sizeof(short),
59 8 * sizeof(int),
60 8 * sizeof(long),
61 0
62 };
63 width = strchrnul(bhwl, (argv[2][0] | 0x20)) - bhwl;
64 width = sizes[width];
65 }
66 } else {
67
68 argv--;
69 }
70 if (errno)
71 bb_show_usage();
72
73 fd = xopen("/dev/mem", argv[3] ? (O_RDWR | O_SYNC) : (O_RDONLY | O_SYNC));
74 mapped_size = page_size = bb_getpagesize();
75 offset_in_page = (unsigned)target & (page_size - 1);
76 if (offset_in_page + width > page_size) {
77
78
79 mapped_size *= 2;
80 }
81 map_base = mmap(NULL,
82 mapped_size,
83 argv[3] ? (PROT_READ | PROT_WRITE) : PROT_READ,
84 MAP_SHARED,
85 fd,
86 target & ~(off_t)(page_size - 1));
87 if (map_base == MAP_FAILED)
88 bb_simple_perror_msg_and_die("mmap");
89
90
91
92 virt_addr = (char*)map_base + offset_in_page;
93
94 if (!argv[3]) {
95#ifdef __SIZEOF_INT128__
96 if (width == 128) {
97 unsigned __int128 rd =
98 *(volatile unsigned __int128 *)virt_addr;
99 printf("0x%016llX%016llX\n",
100 (unsigned long long)(uint64_t)(rd >> 64),
101 (unsigned long long)(uint64_t)rd
102 );
103 } else
104#endif
105 {
106 switch (width) {
107 case 8:
108 read_result = *(volatile uint8_t*)virt_addr;
109 break;
110 case 16:
111 read_result = *(volatile uint16_t*)virt_addr;
112 break;
113 case 32:
114 read_result = *(volatile uint32_t*)virt_addr;
115 break;
116 case 64:
117 read_result = *(volatile uint64_t*)virt_addr;
118 break;
119 default:
120 bb_simple_error_msg_and_die("bad width");
121 }
122
123
124
125
126 printf("0x%0*llX\n", (width >> 2), (unsigned long long)read_result);
127 }
128 } else {
129
130#ifdef __SIZEOF_INT128__
131 unsigned __int128 writeval = strtoumax(argv[3], NULL, 0);
132#else
133 uint64_t writeval = bb_strtoull(argv[3], NULL, 0);
134#endif
135 switch (width) {
136 case 8:
137 *(volatile uint8_t*)virt_addr = writeval;
138
139 break;
140 case 16:
141 *(volatile uint16_t*)virt_addr = writeval;
142
143 break;
144 case 32:
145 *(volatile uint32_t*)virt_addr = writeval;
146
147 break;
148 case 64:
149 *(volatile uint64_t*)virt_addr = writeval;
150
151 break;
152#ifdef __SIZEOF_INT128__
153 case 128:
154 *(volatile unsigned __int128 *)virt_addr = writeval;
155
156 break;
157#endif
158 default:
159 bb_simple_error_msg_and_die("bad width");
160 }
161
162
163
164 }
165
166 if (ENABLE_FEATURE_CLEAN_UP) {
167 if (munmap(map_base, mapped_size) == -1)
168 bb_simple_perror_msg_and_die("munmap");
169 close(fd);
170 }
171
172 return EXIT_SUCCESS;
173}
174