1 /*
2 * Simple app. to do memory accesses via /dev/mem.
3 *
4 * $Id: io.c,v 1.5 2000/08/21 09:01:57 richard Exp $
5 *
6 * Copyright (c) Richard Hirst <rhirst@linuxcare.com>
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <sys/mman.h>
14 #include <sys/types.h>
15 #include <stdint.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <errno.h>
19
20 #ifndef FALSE
21 #define FALSE 0
22 #define TRUE (!FALSE)
23 #endif
24
25 #ifdef MMAP64
26 #define mmap mmap64
27 #endif
28
29 static char *argv0;
30
31 static void
usage(void)32 usage (void)
33 {
34 fprintf(stderr,
35 "Raw memory i/o utility - $Revision: 1.5 $\n\n"
36 "%s -v -1|2|4 -r|w [-l <len>] [-f <file>] <addr> [<value>]\n\n"
37 " -v Verbose, asks for confirmation\n"
38 " -1|2|4 Sets memory access size in bytes (default byte)\n"
39 " -l <len> Length in bytes of area to access (defaults to\n"
40 " one access, or whole file length)\n"
41 " -r|w Read from or Write to memory (default read)\n"
42 " -f <file> File to write on memory read, or\n"
43 " to read on memory write\n"
44 " <addr> The memory address to access\n"
45 " <val> The value to write (implies -w)\n\n"
46 "Examples:\n"
47 " %s 0x1000 Reads one byte from 0x1000\n"
48 " %s 0x1000 0x12 Writes 0x12 to location 0x1000\n"
49 " %s -2 -l 8 0x1000 Reads 8 words from 0x1000\n"
50 " %s -r -f dmp -l 100 200 Reads 100 bytes from addr 200 to file\n"
51 " %s -w -f img 0x10000 Writes the whole of file to memory\n"
52 "\n"
53 "Note access size (-1|2|4) does not apply to file based accesses.\n\n",
54 argv0, argv0, argv0, argv0, argv0, argv0);
55 exit(1);
56 }
57
58
59 static void
memread_memory(unsigned long phys_addr,uint8_t * addr,int len,int iosize)60 memread_memory(unsigned long phys_addr, uint8_t *addr, int len, int iosize)
61 {
62 int i;
63
64 while (len) {
65 printf("%08lx: ", phys_addr);
66 i = 0;
67 while (i < 16 && len) {
68 switch(iosize) {
69 case 1:
70 printf(" %02x", *(uint8_t *)addr);
71 break;
72 case 2:
73 printf(" %04x", *(uint16_t *)addr);
74 break;
75 case 4:
76 printf(" %08x", *(uint32_t *)addr);
77 break;
78 }
79 i += iosize;
80 addr += iosize;
81 len -= iosize;
82 }
83 phys_addr += 16;
84 printf("\n");
85 }
86 }
87
88
89 static void
write_memory(uint8_t * addr,int len,int iosize,unsigned long value)90 write_memory(uint8_t *addr, int len, int iosize, unsigned long value)
91 {
92 switch(iosize) {
93 case 1:
94 while (len) {
95 *(uint8_t *)addr = value;
96 len -= iosize;
97 addr += iosize;
98 }
99 break;
100 case 2:
101 while (len) {
102 *(uint16_t *)addr = value;
103 len -= iosize;
104 addr += iosize;
105 }
106 break;
107 case 4:
108 while (len) {
109 *(uint32_t *)addr = value;
110 len -= iosize;
111 addr += iosize;
112 }
113 break;
114 }
115 }
116
117
118 int
main(int argc,char ** argv)119 main (int argc, char **argv)
120 {
121 int mfd, ffd = 0, req_len = 0, opt;
122 uint8_t *real_io;
123 unsigned long real_len, real_addr, req_addr, req_value = 0, offset;
124 char *endptr;
125 int memread = TRUE;
126 int iosize = 1;
127 char *filename = NULL;
128 int verbose = 0;
129
130 argv0 = argv[0];
131 opterr = 0;
132 if (argc == 1)
133 usage();
134
135 while ((opt = getopt(argc, argv, "hv124rwl:f:")) > 0) {
136 switch (opt) {
137 case 'h':
138 usage();
139 case 'v':
140 verbose = 1;
141 break;
142 case '1':
143 case '2':
144 case '4':
145 iosize = opt - '0';
146 break;
147 case 'r':
148 memread = TRUE;
149 break;
150 case 'w':
151 memread = FALSE;
152 break;
153 case 'l':
154 req_len = strtoul(optarg, &endptr, 0);
155 if (*endptr) {
156 fprintf(stderr, "Bad <size> value '%s'\n", optarg);
157 exit(1);
158 }
159 break;
160 case 'f':
161 filename = strdup(optarg);
162 break;
163 default:
164 fprintf(stderr, "Unknown option: %c\n", opt);
165 usage();
166 }
167 }
168
169 if (optind == argc) {
170 fprintf(stderr, "No address given\n");
171 exit(1);
172 }
173 req_addr = strtoul(argv[optind], &endptr, 0);
174 if (*endptr) {
175 fprintf(stderr, "Bad <addr> value '%s'\n", argv[optind]);
176 exit(1);
177 }
178 optind++;
179 if (!filename && optind < argc)
180 memread = FALSE;
181 if (filename && optind > argc) {
182 fprintf(stderr, "Filename AND value given\n");
183 exit(1);
184 }
185 if (!filename && !memread && optind == argc) {
186 fprintf(stderr, "No value given for WRITE\n");
187 exit(1);
188 }
189 if (!filename && !memread) {
190 req_value = strtoul(argv[optind], &endptr, 0);
191 if (*endptr) {
192 fprintf(stderr, "Bad <value> value '%s'\n", argv[optind]);
193 exit(1);
194 }
195 if ((iosize == 1 && (req_value & 0xffffff00)) ||
196 (iosize == 2 && (req_value & 0xffff0000))) {
197 fprintf(stderr, "<value> too large\n");
198 exit(1);
199 }
200 optind++;
201 }
202 if (filename && memread && !req_len) {
203 fprintf(stderr, "No size given for file memread\n");
204 exit(1);
205 }
206 if (optind < argc) {
207 fprintf(stderr, "Too many arguments '%s'...\n", argv[optind]);
208 exit(1);
209 }
210 if (filename && memread) {
211 ffd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
212 if (ffd < 0) {
213 fprintf(stderr, "Failed to open destination file '%s': %s\n", filename, strerror(errno));
214 exit(1);
215 }
216 }
217 if (filename && !memread) {
218 ffd = open(filename, O_RDONLY);
219 if (ffd < 0) {
220 fprintf(stderr, "Failed to open source file '%s': %s\n", filename, strerror(errno));
221 exit(1);
222 }
223 }
224
225 if (filename && !req_len) {
226 req_len = lseek(ffd, 0, SEEK_END);
227 if (req_len < 0) {
228 fprintf(stderr, "Failed to seek on '%s': %s\n",
229 filename, strerror(errno));
230 exit(1);
231 }
232 if (lseek(ffd, 0, SEEK_SET)) {
233 fprintf(stderr, "Failed to seek on '%s': %s\n",
234 filename, strerror(errno));
235 exit(1);
236 }
237 }
238 if (!req_len)
239 req_len = iosize;
240
241 if ((iosize == 2 && (req_addr & 1)) ||
242 (iosize == 4 && (req_addr & 3))) {
243 fprintf(stderr, "Badly aligned <addr> for access size\n");
244 exit(1);
245 }
246 if ((iosize == 2 && (req_len & 1)) ||
247 (iosize == 4 && (req_len & 3))) {
248 fprintf(stderr, "Badly aligned <size> for access size\n");
249 exit(1);
250 }
251
252 if (!verbose)
253 /* Nothing */;
254 else if (filename && memread)
255 printf("Request to memread 0x%x bytes from address 0x%08lx\n"
256 "\tto file %s, using %d byte accesses\n",
257 req_len, req_addr, filename, iosize);
258 else if (filename)
259 printf("Request to write 0x%x bytes to address 0x%08lx\n"
260 "\tfrom file %s, using %d byte accesses\n",
261 req_len, req_addr, filename, iosize);
262 else if (memread)
263 printf("Request to memread 0x%x bytes from address 0x%08lx\n"
264 "\tusing %d byte accesses\n",
265 req_len, req_addr, iosize);
266 else
267 printf("Request to write 0x%x bytes to address 0x%08lx\n"
268 "\tusing %d byte accesses of value 0x%0*lx\n",
269 req_len, req_addr, iosize, iosize*2, req_value);
270
271 real_addr = req_addr & ~4095;
272 if (real_addr == 0xfffff000) {
273 fprintf(stderr, "Sorry, cannot map the top 4K page\n");
274 exit(1);
275 }
276 offset = req_addr - real_addr;
277 real_len = req_len + offset;
278 real_len = (real_len + 4095) & ~ 4095;
279 if (real_addr + real_len < real_addr) {
280 fprintf(stderr, "Aligned addr+len exceeds top of address space\n");
281 exit(1);
282 }
283 if (verbose)
284 printf("Attempting to map 0x%lx bytes at address 0x%08lx\n",
285 real_len, real_addr);
286
287 mfd = open("/dev/mem", (memread ? O_RDONLY : O_RDWR) | O_SYNC);
288 if (mfd == -1) {
289 perror("open /dev/mem");
290 exit(1);
291 }
292 if (verbose)
293 printf("open(/dev/mem) ok\n");
294 real_io = mmap(NULL, real_len,
295 memread ? PROT_READ:PROT_WRITE,
296 MAP_SHARED, mfd, real_addr);
297 if (real_io == (void *)(-1)) {
298 fprintf(stderr, "mmap() failed: %s\n", strerror(errno));
299 exit(1);
300 }
301 if (verbose)
302 printf("mmap() ok\n");
303
304 if (verbose) {
305 int c;
306
307 printf("OK? ");
308 fflush(stdout);
309 c = getchar();
310 if (c != 'y' && c != 'Y') {
311 printf("Aborted\n");
312 exit(1);
313 }
314 }
315
316 if (filename && memread) {
317 int n = write(ffd, real_io + offset, req_len);
318
319 if (n < 0) {
320 fprintf(stderr, "File write failed: %s\n", strerror(errno));
321 exit(1);
322 }
323 else if (n != req_len) {
324 fprintf(stderr, "Only wrote %d of %d bytes to file\n",
325 n, req_len);
326 exit(1);
327 }
328 }
329 else if (filename) {
330 int n = read(ffd, real_io + offset, req_len);
331
332 if (n < 0) {
333 fprintf(stderr, "File read failed: %s\n", strerror(errno));
334 exit(1);
335 }
336 else if (n != req_len) {
337 fprintf(stderr, "Only read %d of %d bytes from file\n",
338 n, req_len);
339 exit(1);
340 }
341 }
342 else if (memread)
343 memread_memory(req_addr, real_io + offset, req_len, iosize);
344 else
345 write_memory(real_io + offset, req_len, iosize, req_value);
346
347 if (filename)
348 close(ffd);
349 close (mfd);
350
351 return 0;
352 }
353
354