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