e032b3768f34ba5dcb1b22df7ab50fda55181b10
[packages.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