Add io, thanks Thomas Langer !
[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 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 <sys/stat.h>
16 #include <fcntl.h>
17 #include <errno.h>
18
19 #ifndef FALSE
20 #define FALSE 0
21 #define TRUE (!FALSE)
22 #endif
23
24 static char *argv0;
25
26 static void
27 usage (void)
28 {
29 fprintf(stderr,
30 "Raw memory i/o utility - $Revision: 1.5 $\n\n"
31 "%s -v -1|2|4 -r|w [-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 Read from or Write to memory (default read)\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 int
114 main (int argc, char **argv)
115 {
116 int mfd, ffd = 0, req_len = 0, opt;
117 void *real_io;
118 unsigned long real_len, real_addr, req_addr, req_value = 0, offset;
119 char *endptr;
120 int memread = TRUE;
121 int iosize = 1;
122 char *filename = NULL;
123 int verbose = 0;
124
125 argv0 = argv[0];
126 opterr = 0;
127 if (argc == 1)
128 usage();
129
130 while ((opt = getopt(argc, argv, "hv124rwl:f:")) > 0) {
131 switch (opt) {
132 case 'h':
133 usage();
134 case 'v':
135 verbose = 1;
136 break;
137 case '1':
138 case '2':
139 case '4':
140 iosize = opt - '0';
141 break;
142 case 'r':
143 memread = TRUE;
144 break;
145 case 'w':
146 memread = FALSE;
147 break;
148 case 'l':
149 req_len = strtoul(optarg, &endptr, 0);
150 if (*endptr) {
151 fprintf(stderr, "Bad <size> value '%s'\n", optarg);
152 exit(1);
153 }
154 break;
155 case 'f':
156 filename = strdup(optarg);
157 break;
158 default:
159 fprintf(stderr, "Unknown option: %c\n", opt);
160 usage();
161 }
162 }
163
164 if (optind == argc) {
165 fprintf(stderr, "No address given\n");
166 exit(1);
167 }
168 req_addr = strtoul(argv[optind], &endptr, 0);
169 if (*endptr) {
170 fprintf(stderr, "Bad <addr> value '%s'\n", argv[optind]);
171 exit(1);
172 }
173 optind++;
174 if (!filename && optind < argc)
175 memread = FALSE;
176 if (filename && optind > argc) {
177 fprintf(stderr, "Filename AND value given\n");
178 exit(1);
179 }
180 if (!filename && !memread && optind == argc) {
181 fprintf(stderr, "No value given for WRITE\n");
182 exit(1);
183 }
184 if (!filename && !memread) {
185 req_value = strtoul(argv[optind], &endptr, 0);
186 if (*endptr) {
187 fprintf(stderr, "Bad <value> value '%s'\n", argv[optind]);
188 exit(1);
189 }
190 if ((iosize == 1 && (req_value & 0xffffff00)) ||
191 (iosize == 2 && (req_value & 0xffff0000))) {
192 fprintf(stderr, "<value> too large\n");
193 exit(1);
194 }
195 optind++;
196 }
197 if (filename && memread && !req_len) {
198 fprintf(stderr, "No size given for file memread\n");
199 exit(1);
200 }
201 if (optind < argc) {
202 fprintf(stderr, "Too many arguments '%s'...\n", argv[optind]);
203 exit(1);
204 }
205 if (filename && memread) {
206 ffd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
207 if (ffd < 0) {
208 fprintf(stderr, "Failed to open destination file '%s': %s\n", filename, strerror(errno));
209 exit(1);
210 }
211 }
212 if (filename && !memread) {
213 ffd = open(filename, O_RDONLY);
214 if (ffd < 0) {
215 fprintf(stderr, "Failed to open source file '%s': %s\n", filename, strerror(errno));
216 exit(1);
217 }
218 }
219
220 if (filename && !req_len) {
221 req_len = lseek(ffd, 0, SEEK_END);
222 if (req_len < 0) {
223 fprintf(stderr, "Failed to seek on '%s': %s\n",
224 filename, strerror(errno));
225 exit(1);
226 }
227 if (lseek(ffd, 0, SEEK_SET)) {
228 fprintf(stderr, "Failed to seek on '%s': %s\n",
229 filename, strerror(errno));
230 exit(1);
231 }
232 }
233 if (!req_len)
234 req_len = iosize;
235
236 if ((iosize == 2 && (req_addr & 1)) ||
237 (iosize == 4 && (req_addr & 3))) {
238 fprintf(stderr, "Badly aligned <addr> for access size\n");
239 exit(1);
240 }
241 if ((iosize == 2 && (req_len & 1)) ||
242 (iosize == 4 && (req_len & 3))) {
243 fprintf(stderr, "Badly aligned <size> for access size\n");
244 exit(1);
245 }
246
247 if (!verbose)
248 /* Nothing */;
249 else if (filename && memread)
250 printf("Request to memread 0x%x bytes from address 0x%08lx\n"
251 "\tto file %s, using %d byte accesses\n",
252 req_len, req_addr, filename, iosize);
253 else if (filename)
254 printf("Request to write 0x%x bytes to address 0x%08lx\n"
255 "\tfrom file %s, using %d byte accesses\n",
256 req_len, req_addr, filename, iosize);
257 else if (memread)
258 printf("Request to memread 0x%x bytes from address 0x%08lx\n"
259 "\tusing %d byte accesses\n",
260 req_len, req_addr, iosize);
261 else
262 printf("Request to write 0x%x bytes to address 0x%08lx\n"
263 "\tusing %d byte accesses of value 0x%0*lx\n",
264 req_len, req_addr, iosize, iosize*2, req_value);
265
266 real_addr = req_addr & ~4095;
267 if (real_addr == 0xfffff000) {
268 fprintf(stderr, "Sorry, cannot map the top 4K page\n");
269 exit(1);
270 }
271 offset = req_addr - real_addr;
272 real_len = req_len + offset;
273 real_len = (real_len + 4095) & ~ 4095;
274 if (real_addr + real_len < real_addr) {
275 fprintf(stderr, "Aligned addr+len exceeds top of address space\n");
276 exit(1);
277 }
278 if (verbose)
279 printf("Attempting to map 0x%lx bytes at address 0x%08lx\n",
280 real_len, real_addr);
281
282 mfd = open("/dev/mem", memread ? O_RDONLY : O_RDWR);
283 if (mfd == -1) {
284 perror("open /dev/mem");
285 exit(1);
286 }
287 if (verbose)
288 printf("open(/dev/mem) ok\n");
289 real_io = mmap(NULL, real_len,
290 memread ? PROT_READ:PROT_WRITE,
291 MAP_SHARED, mfd, real_addr);
292 if (real_io == (void *)(-1)) {
293 fprintf(stderr, "mmap() failed: %s\n", strerror(errno));
294 exit(1);
295 }
296 if (verbose)
297 printf("mmap() ok\n");
298
299 if (verbose) {
300 int c;
301
302 printf("OK? ");
303 fflush(stdout);
304 c = getchar();
305 if (c != 'y' && c != 'Y') {
306 printf("Aborted\n");
307 exit(1);
308 }
309 }
310
311 if (filename && memread) {
312 int n = write(ffd, real_io + offset, req_len);
313
314 if (n < 0) {
315 fprintf(stderr, "File write failed: %s\n", strerror(errno));
316 exit(1);
317 }
318 else if (n != req_len) {
319 fprintf(stderr, "Only wrote %d of %d bytes to file\n",
320 n, req_len);
321 exit(1);
322 }
323 }
324 else if (filename) {
325 int n = read(ffd, real_io + offset, req_len);
326
327 if (n < 0) {
328 fprintf(stderr, "File read failed: %s\n", strerror(errno));
329 exit(1);
330 }
331 else if (n != req_len) {
332 fprintf(stderr, "Only read %d of %d bytes from file\n",
333 n, req_len);
334 exit(1);
335 }
336 }
337 else if (memread)
338 memread_memory(req_addr, real_io + offset, req_len, iosize);
339 else
340 write_memory(req_addr, real_io + offset, req_len, iosize, req_value);
341
342 if (filename)
343 close(ffd);
344 close (mfd);
345
346 return 0;
347 }
348