io: add io-tool 3648/head
authorHauke Mehrtens <hauke@hauke-m.de>
Sun, 11 Dec 2016 23:03:01 +0000 (00:03 +0100)
committerHauke Mehrtens <hauke@hauke-m.de>
Sat, 17 Dec 2016 14:20:05 +0000 (15:20 +0100)
This add the io tool from the old package feed.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
utils/io/Makefile [new file with mode: 0644]
utils/io/src/io.c [new file with mode: 0644]

diff --git a/utils/io/Makefile b/utils/io/Makefile
new file mode 100644 (file)
index 0000000..a861e74
--- /dev/null
@@ -0,0 +1,36 @@
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=io
+PKG_RELEASE:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+PKG_MAINTAINER:=Hauke Mehrtens <hauke@hauke-m.de>
+
+define Package/io
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=Raw memory i/o utility
+  URL:=http://www.sleepie.demon.co.uk/linuxvme/io.c
+endef
+
+define Package/io/description
+       This tool can be used to access physical memory addresses from userspace.
+       It can be useful to access hardware for which no device driver exists!
+endef
+
+define Build/Compile
+       $(TARGET_CC) $(TARGET_CFLAGS) -Wall $(PKG_BUILD_DIR)/io.c -o $(PKG_BUILD_DIR)/$(PKG_NAME)
+endef
+
+define Package/io/install
+       $(INSTALL_DIR) $(1)/usr/bin
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/io $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,io))
diff --git a/utils/io/src/io.c b/utils/io/src/io.c
new file mode 100644 (file)
index 0000000..2572054
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * Simple app. to do memory accesses via /dev/mem.
+ *
+ *
+ * Copyright (c) Richard Hirst <rhirst@linuxcare.com>
+ * Copyright (c) Thomas Langer <thomas.langer@infineon.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>
+
+#define MEM_READ  0
+#define MEM_WRITE 1
+#define MEM_AND   2
+#define MEM_OR    3
+
+static void
+usage (char *argv0)
+{
+       fprintf(stderr,
+"Raw memory i/o utility - $Revision: 2.0 $\n\n"
+"%s -v -1|2|4 -r|w|a|o [-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|a|o   Read from or Write to memory (default read)\n"
+"               optional write with modify (and/or)\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;
+       }
+}
+
+
+static void
+and_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;
+       }
+}
+
+
+static void
+or_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 memfunc = MEM_READ;
+       int iosize = 1;
+       char *filename = NULL;
+       int verbose = 0;
+
+       opterr = 0;
+       if (argc == 1)
+               usage(argv[0]);
+
+       while ((opt = getopt(argc, argv, "hv124rwaol:f:")) > 0) {
+               switch (opt) {
+               case 'h':
+                       usage(argv[0]);
+               case 'v':
+                       verbose = 1;
+                       break;
+               case '1':
+               case '2':
+               case '4':
+                       iosize = opt - '0';
+                       break;
+               case 'r':
+                       memfunc = MEM_READ;
+                       break;
+               case 'a':
+                       memfunc = MEM_AND;
+                       break;
+               case 'o':
+                       memfunc = MEM_OR;
+                       break;
+               case 'w':
+                       memfunc = MEM_WRITE;
+                       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(argv[0]);
+               }
+       }
+
+       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 && (memfunc == MEM_READ) && optind < argc) {
+               memfunc = MEM_WRITE;
+       }
+       if (filename && optind > argc) {
+               fprintf(stderr, "Filename AND value given\n");
+               exit(1);
+       }
+       if (!filename && (memfunc != MEM_READ) && optind == argc) {
+               fprintf(stderr, "No value given for WRITE\n");
+               exit(1);
+       }
+       if (!filename && (memfunc != MEM_READ)) {
+               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 && (memfunc == MEM_READ) && !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 && (memfunc == MEM_READ)) {
+               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 && (memfunc != MEM_READ)) {
+               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 && (memfunc == MEM_READ))
+               printf("Request to read 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 (memfunc == MEM_READ)
+               printf("Request to read 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", (memfunc == MEM_READ) ? O_RDONLY : O_RDWR);
+       if (mfd == -1) {
+               perror("open /dev/mem");
+               fprintf(stderr, "Is CONFIG_DEVMEM activated?\n");
+               exit(1);
+       }
+       if (verbose)
+               printf("open(/dev/mem) ok\n");
+       real_io = mmap(NULL, real_len,
+                       (memfunc == MEM_READ) ? PROT_READ: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 && (memfunc == MEM_READ)) {
+               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 {
+               switch (memfunc)
+               {
+               case MEM_READ:
+                       memread_memory(req_addr, real_io + offset, req_len, iosize);
+                       break;
+               case MEM_WRITE:
+                       write_memory(req_addr, real_io + offset, req_len, iosize, req_value);
+                       break;
+               case MEM_AND:
+                       and_write_memory(req_addr, real_io + offset, req_len, iosize, req_value);
+                       break;
+               case MEM_OR:
+                       or_write_memory(req_addr, real_io + offset, req_len, iosize, req_value);
+                       break;
+               }
+       }
+
+       munmap(real_io, real_len);
+
+       if (filename)
+               close(ffd);
+       close (mfd);
+
+       return 0;
+}
+