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