From 5f54e6c61e54d5fbcf7a61155b8f95092d648094 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Mon, 12 Dec 2016 00:03:01 +0100 Subject: [PATCH] io: add io-tool This add the io tool from the old package feed. Signed-off-by: Hauke Mehrtens --- utils/io/Makefile | 36 ++++ utils/io/src/io.c | 428 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 464 insertions(+) create mode 100644 utils/io/Makefile create mode 100644 utils/io/src/io.c diff --git a/utils/io/Makefile b/utils/io/Makefile new file mode 100644 index 0000000000..a861e7477e --- /dev/null +++ b/utils/io/Makefile @@ -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 + +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 index 0000000000..2572054049 --- /dev/null +++ b/utils/io/src/io.c @@ -0,0 +1,428 @@ +/* + * Simple app. to do memory accesses via /dev/mem. + * + * + * Copyright (c) Richard Hirst + * Copyright (c) Thomas Langer + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 ] [-f ] []\n\n" +" -v Verbose, asks for confirmation\n" +" -1|2|4 Sets memory access size in bytes (default byte)\n" +" -l 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 to write on memory read, or\n" +" to read on memory write\n" +" The memory address to access\n" +" 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 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 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 '%s'\n", argv[optind]); + exit(1); + } + if ((iosize == 1 && (req_value & 0xffffff00)) || + (iosize == 2 && (req_value & 0xffff0000))) { + fprintf(stderr, " 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 for access size\n"); + exit(1); + } + if ((iosize == 2 && (req_len & 1)) || + (iosize == 4 && (req_len & 3))) { + fprintf(stderr, "Badly aligned 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; +} +