io.c (9728B)
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 fprintf(stderr, "Is CONFIG_DEVMEM activated?\n"); 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 munmap(real_io, real_len); 421 422 if (filename) 423 close(ffd); 424 close (mfd); 425 426 return 0; 427 } 428