--- /dev/null
+/*
+ * Simple app. to do memory accesses via /dev/mem.
+ *
+ * $Id: io.c,v 1.5 2000/08/21 09:01:57 richard Exp $
+ *
+ * Copyright (c) Richard Hirst <rhirst@linuxcare.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE (!FALSE)
+#endif
+
+static char *argv0;
+
+static void
+usage (void)
+{
+ fprintf(stderr,
+"Raw memory i/o utility - $Revision: 1.5 $\n\n"
+"%s -v -1|2|4 -r|w [-l <len>] [-f <file>] <addr> [<value>]\n\n"
+" -v Verbose, asks for confirmation\n"
+" -1|2|4 Sets memory access size in bytes (default byte)\n"
+" -l <len> Length in bytes of area to access (defaults to\n"
+" one access, or whole file length)\n"
+" -r|w Read from or Write to memory (default read)\n"
+" -f <file> File to write on memory read, or\n"
+" to read on memory write\n"
+" <addr> The memory address to access\n"
+" <val> The value to write (implies -w)\n\n"
+"Examples:\n"
+" %s 0x1000 Reads one byte from 0x1000\n"
+" %s 0x1000 0x12 Writes 0x12 to location 0x1000\n"
+" %s -2 -l 8 0x1000 Reads 8 words from 0x1000\n"
+" %s -r -f dmp -l 100 200 Reads 100 bytes from addr 200 to file\n"
+" %s -w -f img 0x10000 Writes the whole of file to memory\n"
+"\n"
+"Note access size (-1|2|4) does not apply to file based accesses.\n\n",
+ argv0, argv0, argv0, argv0, argv0, argv0);
+ exit(1);
+}
+
+
+static void
+memread_memory(unsigned long phys_addr, void *addr, int len, int iosize)
+{
+ int i;
+
+ while (len) {
+ printf("%08lx: ", phys_addr);
+ i = 0;
+ while (i < 16 && len) {
+ switch(iosize) {
+ case 1:
+ printf(" %02x", *(unsigned char *)addr);
+ break;
+ case 2:
+ printf(" %04x", *(unsigned short *)addr);
+ break;
+ case 4:
+ printf(" %08lx", *(unsigned long *)addr);
+ break;
+ }
+ i += iosize;
+ addr += iosize;
+ len -= iosize;
+ }
+ phys_addr += 16;
+ printf("\n");
+ }
+}
+
+
+static void
+write_memory(unsigned long phys_addr, void *addr, int len, int iosize, unsigned long value)
+{
+ switch(iosize) {
+ case 1:
+ while (len) {
+ *(unsigned char *)addr = value;
+ len -= iosize;
+ addr += iosize;
+ }
+ break;
+ case 2:
+ while (len) {
+ *(unsigned short *)addr = value;
+ len -= iosize;
+ addr += iosize;
+ }
+ break;
+ case 4:
+ while (len) {
+ *(unsigned long *)addr = value;
+ len -= iosize;
+ addr += iosize;
+ }
+ break;
+ }
+}
+
+
+int
+main (int argc, char **argv)
+{
+ int mfd, ffd = 0, req_len = 0, opt;
+ void *real_io;
+ unsigned long real_len, real_addr, req_addr, req_value = 0, offset;
+ char *endptr;
+ int memread = TRUE;
+ int iosize = 1;
+ char *filename = NULL;
+ int verbose = 0;
+
+ argv0 = argv[0];
+ opterr = 0;
+ if (argc == 1)
+ usage();
+
+ while ((opt = getopt(argc, argv, "hv124rwl:f:")) > 0) {
+ switch (opt) {
+ case 'h':
+ usage();
+ case 'v':
+ verbose = 1;
+ break;
+ case '1':
+ case '2':
+ case '4':
+ iosize = opt - '0';
+ break;
+ case 'r':
+ memread = TRUE;
+ break;
+ case 'w':
+ memread = FALSE;
+ break;
+ case 'l':
+ req_len = strtoul(optarg, &endptr, 0);
+ if (*endptr) {
+ fprintf(stderr, "Bad <size> value '%s'\n", optarg);
+ exit(1);
+ }
+ break;
+ case 'f':
+ filename = strdup(optarg);
+ break;
+ default:
+ fprintf(stderr, "Unknown option: %c\n", opt);
+ usage();
+ }
+ }
+
+ if (optind == argc) {
+ fprintf(stderr, "No address given\n");
+ exit(1);
+ }
+ req_addr = strtoul(argv[optind], &endptr, 0);
+ if (*endptr) {
+ fprintf(stderr, "Bad <addr> value '%s'\n", argv[optind]);
+ exit(1);
+ }
+ optind++;
+ if (!filename && optind < argc)
+ memread = FALSE;
+ if (filename && optind > argc) {
+ fprintf(stderr, "Filename AND value given\n");
+ exit(1);
+ }
+ if (!filename && !memread && optind == argc) {
+ fprintf(stderr, "No value given for WRITE\n");
+ exit(1);
+ }
+ if (!filename && !memread) {
+ req_value = strtoul(argv[optind], &endptr, 0);
+ if (*endptr) {
+ fprintf(stderr, "Bad <value> value '%s'\n", argv[optind]);
+ exit(1);
+ }
+ if ((iosize == 1 && (req_value & 0xffffff00)) ||
+ (iosize == 2 && (req_value & 0xffff0000))) {
+ fprintf(stderr, "<value> too large\n");
+ exit(1);
+ }
+ optind++;
+ }
+ if (filename && memread && !req_len) {
+ fprintf(stderr, "No size given for file memread\n");
+ exit(1);
+ }
+ if (optind < argc) {
+ fprintf(stderr, "Too many arguments '%s'...\n", argv[optind]);
+ exit(1);
+ }
+ if (filename && memread) {
+ ffd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if (ffd < 0) {
+ fprintf(stderr, "Failed to open destination file '%s': %s\n", filename, strerror(errno));
+ exit(1);
+ }
+ }
+ if (filename && !memread) {
+ ffd = open(filename, O_RDONLY);
+ if (ffd < 0) {
+ fprintf(stderr, "Failed to open source file '%s': %s\n", filename, strerror(errno));
+ exit(1);
+ }
+ }
+
+ if (filename && !req_len) {
+ req_len = lseek(ffd, 0, SEEK_END);
+ if (req_len < 0) {
+ fprintf(stderr, "Failed to seek on '%s': %s\n",
+ filename, strerror(errno));
+ exit(1);
+ }
+ if (lseek(ffd, 0, SEEK_SET)) {
+ fprintf(stderr, "Failed to seek on '%s': %s\n",
+ filename, strerror(errno));
+ exit(1);
+ }
+ }
+ if (!req_len)
+ req_len = iosize;
+
+ if ((iosize == 2 && (req_addr & 1)) ||
+ (iosize == 4 && (req_addr & 3))) {
+ fprintf(stderr, "Badly aligned <addr> for access size\n");
+ exit(1);
+ }
+ if ((iosize == 2 && (req_len & 1)) ||
+ (iosize == 4 && (req_len & 3))) {
+ fprintf(stderr, "Badly aligned <size> for access size\n");
+ exit(1);
+ }
+
+ if (!verbose)
+ /* Nothing */;
+ else if (filename && memread)
+ printf("Request to memread 0x%x bytes from address 0x%08lx\n"
+ "\tto file %s, using %d byte accesses\n",
+ req_len, req_addr, filename, iosize);
+ else if (filename)
+ printf("Request to write 0x%x bytes to address 0x%08lx\n"
+ "\tfrom file %s, using %d byte accesses\n",
+ req_len, req_addr, filename, iosize);
+ else if (memread)
+ printf("Request to memread 0x%x bytes from address 0x%08lx\n"
+ "\tusing %d byte accesses\n",
+ req_len, req_addr, iosize);
+ else
+ printf("Request to write 0x%x bytes to address 0x%08lx\n"
+ "\tusing %d byte accesses of value 0x%0*lx\n",
+ req_len, req_addr, iosize, iosize*2, req_value);
+
+ real_addr = req_addr & ~4095;
+ if (real_addr == 0xfffff000) {
+ fprintf(stderr, "Sorry, cannot map the top 4K page\n");
+ exit(1);
+ }
+ offset = req_addr - real_addr;
+ real_len = req_len + offset;
+ real_len = (real_len + 4095) & ~ 4095;
+ if (real_addr + real_len < real_addr) {
+ fprintf(stderr, "Aligned addr+len exceeds top of address space\n");
+ exit(1);
+ }
+ if (verbose)
+ printf("Attempting to map 0x%lx bytes at address 0x%08lx\n",
+ real_len, real_addr);
+
+ mfd = open("/dev/mem", memread ? O_RDONLY : O_RDWR);
+ if (mfd == -1) {
+ perror("open /dev/mem");
+ exit(1);
+ }
+ if (verbose)
+ printf("open(/dev/mem) ok\n");
+ real_io = mmap(NULL, real_len,
+ memread ? PROT_READ:PROT_WRITE,
+ MAP_SHARED, mfd, real_addr);
+ if (real_io == (void *)(-1)) {
+ fprintf(stderr, "mmap() failed: %s\n", strerror(errno));
+ exit(1);
+ }
+ if (verbose)
+ printf("mmap() ok\n");
+
+ if (verbose) {
+ int c;
+
+ printf("OK? ");
+ fflush(stdout);
+ c = getchar();
+ if (c != 'y' && c != 'Y') {
+ printf("Aborted\n");
+ exit(1);
+ }
+ }
+
+ if (filename && memread) {
+ int n = write(ffd, real_io + offset, req_len);
+
+ if (n < 0) {
+ fprintf(stderr, "File write failed: %s\n", strerror(errno));
+ exit(1);
+ }
+ else if (n != req_len) {
+ fprintf(stderr, "Only wrote %d of %d bytes to file\n",
+ n, req_len);
+ exit(1);
+ }
+ }
+ else if (filename) {
+ int n = read(ffd, real_io + offset, req_len);
+
+ if (n < 0) {
+ fprintf(stderr, "File read failed: %s\n", strerror(errno));
+ exit(1);
+ }
+ else if (n != req_len) {
+ fprintf(stderr, "Only read %d of %d bytes from file\n",
+ n, req_len);
+ exit(1);
+ }
+ }
+ else if (memread)
+ memread_memory(req_addr, real_io + offset, req_len, iosize);
+ else
+ write_memory(req_addr, real_io + offset, req_len, iosize, req_value);
+
+ if (filename)
+ close(ffd);
+ close (mfd);
+
+ return 0;
+}
+