summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2005-11-07 22:12:52 (GMT)
committerH. Peter Anvin <hpa@zytor.com>2005-11-07 22:12:52 (GMT)
commitdd620f4881e5cb3fc8b720dc3772f94df8999771 (patch)
tree465a779cdc5dfb3e93c1253e549717de419c8c3c
downloadmemhack-dd620f4881e5cb3fc8b720dc3772f94df8999771.zip
memhack-dd620f4881e5cb3fc8b720dc3772f94df8999771.tar.gz
memhack-dd620f4881e5cb3fc8b720dc3772f94df8999771.tar.bz2
memhack-dd620f4881e5cb3fc8b720dc3772f94df8999771.tar.xz
I/O and memory manipulation programs
-rw-r--r--Makefile45
-rw-r--r--getio.c318
-rw-r--r--getmem.c52
-rw-r--r--setio.c121
-rw-r--r--setmem.c151
-rw-r--r--version.h4
6 files changed, 691 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..6be1151
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,45 @@
+#ident "$Id$"
+## -----------------------------------------------------------------------
+##
+## Copyright 2005 H. Peter Anvin - All Rights Reserved
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+## Boston MA 02111-1307, USA; either version 2 of the License, or
+## (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+
+#
+# Makefile for memhack
+#
+
+CC = gcc -Wall
+CFLAGS = -g -O2 -fomit-frame-pointer -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64
+LDFLAGS =
+
+BIN = getmem setmem getio setio
+
+sbindir = /usr/sbin
+
+all: $(BIN)
+
+clean:
+ rm -f *.o $(BIN)
+
+distclean: clean
+ rm -f *~ \#*
+
+install: all
+ install -m 755 $(BIN) $(sbindir)
+
+.o:
+ $(CC) $(LDFLAGS) -o $@ $<
+
+.c.o:
+ $(CC) $(CFLAGS) -o $@ $<
+
+.c:
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
diff --git a/getio.c b/getio.c
new file mode 100644
index 0000000..7305c57
--- /dev/null
+++ b/getio.c
@@ -0,0 +1,318 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2005 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * getio.c
+ *
+ * Utility to read an I/O register
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/io.h>
+
+#include "version.h"
+
+struct option long_options[] = {
+ { "help", 0, 0, 'h' },
+ { "version", 0, 0, 'V' },
+ { "hexadecimal", 0, 0, 'x' },
+ { "capital-hexadecimal", 0, 0, 'X' },
+ { "decimal", 0, 0, 'i' },
+ { "signed-decimal", 0, 0, 'i' },
+ { "unsigned-decimal", 0, 0, 'u' },
+ { "octal", 0, 0, 'o' },
+ { "c-language", 0, 0, 'c' },
+ { "zero-fill", 0, 0, '0' },
+ { "zero-pad", 0, 0, '0' },
+ { "raw", 0, 0, 'r' },
+ { "bitfield", 1, 0, 'f' },
+ { "long", 0, 0, 'l' },
+ { "dword", 0, 0, 'd' },
+ { "short", 0, 0, 's' },
+ { "word", 0, 0, 'w' },
+ { "byte", 0, 0, 'b' },
+ { 0, 0, 0, 0 }
+};
+
+/* Number of decimal digits for a certain number of bits */
+/* (int) ceil(log(2^n)/log(10)) */
+int decdigits[] = {
+ 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5,
+ 5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10,
+ 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15,
+ 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19,
+ 20
+};
+
+#define mo_hex 0x01
+#define mo_dec 0x02
+#define mo_oct 0x03
+#define mo_raw 0x04
+#define mo_uns 0x05
+#define mo_chx 0x06
+#define mo_mask 0x0f
+#define mo_fill 0x40
+#define mo_c 0x80
+
+const char *program;
+
+void usage(void)
+{
+ fprintf(stderr,
+ "Usage: %s [options] regno\n"
+ " --help -h Print this help\n"
+ " --version -V Print current version\n"
+ " --hexadecimal -x Hexadecimal output (lower case)\n"
+ " --capital-hex -X Hexadecimal output (upper case)\n"
+ " --decimal -d Signed decimal output\n"
+ " --unsigned -u Unsigned decimal output\n"
+ " --octal -o Octal output\n"
+ " --c-language -c Format output as a C language constant\n"
+ " --zero-pad -0 Output leading zeroes\n"
+ " --raw -r Raw binary output\n"
+ " --processor # -p Select processor number (default 0)\n"
+ " --bitfield h:l -f Output bits [h:l] only\n"
+ " --long -l Read longword (dword)\n"
+ " --dword -d Read longword (dword)\n"
+ " --short -s Read shortword (word)\n"
+ " --word -w Read shortword (word)\n"
+ " --byte -b Read byte (default)\n"
+ , program);
+}
+
+int main(int argc, char *argv[])
+{
+ uint32_t reg;
+ uint64_t data;
+ int c;
+ int mode = mo_hex;
+ int cpu = 0;
+ unsigned int highbit = 63, lowbit = 0, bits;
+ unsigned long arg;
+ char *endarg;
+ char *pat;
+ int width;
+ int size = 1;
+
+ program = argv[0];
+
+ while ( (c = getopt_long(argc,argv,"hVxXioruc0p:f:ldswb",long_options,NULL)) != -1 ) {
+ switch ( c ) {
+ case 'h':
+ usage();
+ exit(0);
+ case 'V':
+ fprintf(stderr, "%s: version %s\n", program, VERSION_STRING);
+ exit(0);
+ case 'x':
+ mode = (mode & ~mo_mask) | mo_hex;
+ break;
+ case 'X':
+ mode = (mode & ~mo_mask) | mo_chx;
+ break;
+ case 'o':
+ mode = (mode & ~mo_mask) | mo_oct;
+ break;
+ case 'i':
+ mode = (mode & ~mo_mask) | mo_dec;
+ break;
+ case 'r':
+ mode = (mode & ~mo_mask) | mo_raw;
+ break;
+ case 'u':
+ mode = (mode & ~mo_mask) | mo_uns;
+ break;
+ case 'c':
+ mode |= mo_c;
+ break;
+ case '0':
+ mode |= mo_fill;
+ break;
+ case 'p':
+ arg = strtoul(optarg, &endarg, 0);
+ if ( *endarg || arg > 255 ) {
+ usage();
+ exit(127);
+ }
+ cpu = (int)arg;
+ break;
+ case 'f':
+ {
+ if ( sscanf(optarg, "%u:%u", &highbit, &lowbit) != 2 ||
+ highbit > 63 || lowbit > highbit ) {
+ usage();
+ exit(127);
+ }
+ }
+ break;
+ case 'l':
+ case 'd':
+ size = 4;
+ break;
+ case 's':
+ case 'w':
+ size = 2;
+ break;
+ case 'b':
+ size = 1;
+ break;
+ default:
+ usage();
+ exit(127);
+ }
+ }
+
+ if ( optind != argc-1 ) {
+ /* Should have exactly one argument */
+ usage();
+ exit(127);
+ }
+
+ reg = strtoul(argv[optind], NULL, 0);
+
+ iopl(3);
+
+ switch(size) {
+ case 1:
+ data = inb(reg);
+ break;
+ case 2:
+ data = inw(reg);
+ break;
+ case 4:
+ data = inl(reg);
+ break;
+ default:
+ abort();
+ }
+
+ iopl(0);
+
+ bits = highbit-lowbit+1;
+ if ( bits < 64 ) {
+ /* Show only part of register */
+ data >>= lowbit;
+ data &= (1ULL << bits)-1;
+ }
+
+ pat = NULL;
+
+ width = 1; /* Default */
+ switch(mode) {
+ case mo_hex:
+ pat = "%*llx\n";
+ break;
+ case mo_chx:
+ pat = "%*llX\n";
+ break;
+ case mo_dec:
+ case mo_dec|mo_c:
+ case mo_dec|mo_fill|mo_c:
+ /* Make sure we get sign correct */
+ if ( data & (1ULL << (bits-1)) ) {
+ data &= ~(1ULL << (bits-1));
+ data = -data;
+ }
+ pat = "%*lld\n";
+ break;
+ case mo_uns:
+ pat = "%*llu\n";
+ break;
+ case mo_oct:
+ pat = "%*llo\n";
+ break;
+ case mo_hex|mo_c:
+ pat = "0x%*llx\n";
+ break;
+ case mo_chx|mo_c:
+ pat = "0x%*llX\n";
+ break;
+ case mo_oct|mo_c:
+ pat = "0%*llo\n";
+ break;
+ case mo_uns|mo_c:
+ case mo_uns|mo_fill|mo_c:
+ pat = "%*lluU\n";
+ break;
+ case mo_hex|mo_fill:
+ pat = "%0*llx\n";
+ width = (bits+3)/4;
+ break;
+ case mo_chx|mo_fill:
+ pat = "%0*llX\n";
+ width = (bits+3)/4;
+ break;
+ case mo_dec|mo_fill:
+ /* Make sure we get sign correct */
+ if ( data & (1ULL << (bits-1)) ) {
+ data &= ~(1ULL << (bits-1));
+ data = -data;
+ }
+ pat = "%0*lld\n";
+ width = decdigits[bits-1]+1;
+ break;
+ case mo_uns|mo_fill:
+ pat = "%0*llu\n";
+ width = decdigits[bits];
+ break;
+ case mo_oct|mo_fill:
+ pat = "%0*llo\n";
+ width = (bits+2)/3;
+ break;
+ case mo_hex|mo_fill|mo_c:
+ pat = "0x%0*llx\n";
+ width = (bits+3)/4;
+ break;
+ case mo_chx|mo_fill|mo_c:
+ pat = "0x%0*llX\n";
+ width = (bits+3)/4;
+ break;
+ case mo_oct|mo_fill|mo_c:
+ pat = "0%0*llo\n";
+ width = (bits+2)/3;
+ break;
+ case mo_raw:
+ case mo_raw|mo_fill:
+ fwrite(&data,sizeof data,1,stdout);
+ break;
+ case mo_raw|mo_c:
+ case mo_raw|mo_fill|mo_c:
+ {
+ unsigned char *p = (unsigned char *)&data;
+ int i;
+ for ( i = 0 ; i < sizeof data ; i++ ) {
+ printf("%s0x%02x", i?",":"{", (unsigned int)(*p++));
+ }
+ printf("}\n");
+ }
+ break;
+ default:
+ fprintf(stderr, "%s: Impossible case, line %d\n", program, __LINE__);
+ exit(127);
+ }
+
+ if ( width < 1 )
+ width = 1;
+
+ if ( pat )
+ printf(pat, width, data);
+
+ exit(0);
+}
diff --git a/getmem.c b/getmem.c
new file mode 100644
index 0000000..f0bd755
--- /dev/null
+++ b/getmem.c
@@ -0,0 +1,52 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[])
+{
+ uintptr_t start, mapstart, len, maplen;
+ char *mem, *buffer;
+ int fd;
+
+ if ( argc != 3 ) {
+ fprintf(stderr, "Usage: %s start bytes\n", argv[0]);
+ exit(1);
+ }
+
+ fd = open("/dev/mem", O_RDONLY);
+ if ( fd < 0 ) {
+ perror("/dev/mem");
+ exit(1);
+ }
+
+ start = (uintptr_t)strtoumax(argv[1], NULL, 0);
+ len = (uintptr_t)strtoumax(argv[2], NULL, 0);
+
+ buffer = malloc(len);
+ if ( !buffer ) {
+ perror("malloc");
+ exit(1);
+ }
+
+ mapstart = start & ~0xffff;
+ maplen = (len + (start-mapstart) + 0xffff) & ~0xffff;
+
+ mem = mmap(NULL, maplen, PROT_READ, MAP_SHARED, fd, mapstart);
+ if ( mem == MAP_FAILED ) {
+ perror("mmap");
+ exit(1);
+ }
+
+ memcpy(buffer, mem+(start-mapstart), len);
+
+ fwrite(buffer, len, 1, stdout);
+
+ return 0;
+}
+
+
diff --git a/setio.c b/setio.c
new file mode 100644
index 0000000..c77d0ae
--- /dev/null
+++ b/setio.c
@@ -0,0 +1,121 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2005 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * setmem.c
+ *
+ * Utility to write to I/O memory
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/io.h>
+
+#include "version.h"
+
+struct option long_options[] = {
+ { "help", 0, 0, 'h' },
+ { "version", 0, 0, 'V' },
+ { "long", 0, 0, 'l' },
+ { "dword", 0, 0, 'd' },
+ { "short", 0, 0, 's' },
+ { "word", 0, 0, 'w' },
+ { "byte", 0, 0, 'b' },
+ { 0, 0, 0, 0 }
+};
+
+const char *program;
+
+void usage(void)
+{
+ fprintf(stderr, "Usage: %s [options] address value...\n"
+ " --help -h Print this help\n"
+ " --version -V Print current version\n"
+ " --long -l Write longword (dword)\n"
+ " --dword -d Write longword (dword)\n"
+ " --short -s Write shortword (word)\n"
+ " --word -w Write shortword (word)\n"
+ " --byte -b Write byte (default)\n"
+ , program);
+}
+
+int main(int argc, char *argv[])
+{
+ uintptr_t reg;
+ uint64_t data;
+ int c;
+ int size = 1;
+
+ program = argv[0];
+
+ while ( (c = getopt_long(argc,argv,"hVldswb",long_options,NULL)) != - 1 ) {
+ switch( c ) {
+ case 'h':
+ usage();
+ exit(0);
+ case 'V':
+ fprintf(stderr, "%s: version %s\n", program, VERSION_STRING);
+ exit(0);
+ case 'l':
+ case 'd':
+ size = 4;
+ break;
+ case 'w':
+ case 's':
+ size = 2;
+ break;
+ case 'b':
+ size = 1;
+ break;
+ default:
+ usage();
+ exit(127);
+ }
+ }
+
+ if ( optind > argc-2 ) {
+ /* Should have at least two arguments */
+ usage();
+ exit(127);
+ }
+
+ iopl(3);
+
+ reg = (uintptr_t)strtoumax(argv[optind++], NULL, 0);
+
+ while ( optind < argc ) {
+ data = (uint64_t)strtoumax(argv[optind++], NULL, 0);
+
+ switch ( size ) {
+ case 1:
+ outb(data, reg);
+ break;
+ case 2:
+ outw(data, reg);
+ break;
+ case 4:
+ outl(data, reg);
+ break;
+ default:
+ abort(); /* Should never happen */
+ }
+ }
+
+ exit(0);
+}
diff --git a/setmem.c b/setmem.c
new file mode 100644
index 0000000..d563655
--- /dev/null
+++ b/setmem.c
@@ -0,0 +1,151 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2005 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * setmem.c
+ *
+ * Utility to write to I/O memory
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include "version.h"
+
+struct option long_options[] = {
+ { "help", 0, 0, 'h' },
+ { "version", 0, 0, 'V' },
+ { "quad", 0, 0, 'q' },
+ { "long", 0, 0, 'l' },
+ { "dword", 0, 0, 'd' },
+ { "short", 0, 0, 's' },
+ { "word", 0, 0, 'w' },
+ { "byte", 0, 0, 'b' },
+ { 0, 0, 0, 0 }
+};
+
+const char *program;
+
+void usage(void)
+{
+ fprintf(stderr, "Usage: %s [options] address value...\n"
+ " --help -h Print this help\n"
+ " --version -V Print current version\n"
+ " --quad -q Write quadword (qword)\n"
+ " --long -l Write longword (dword)\n"
+ " --dword -d Write longword (dword)\n"
+ " --short -s Write shortword (word)\n"
+ " --word -w Write shortword (word)\n"
+ " --byte -b Write byte (default)\n"
+ , program);
+}
+
+int main(int argc, char *argv[])
+{
+ uintptr_t reg, page_mask, start, len;
+ uint64_t data;
+ int fd;
+ int c;
+ int size = 1;
+ void *map, *ptr;
+
+ program = argv[0];
+
+ while ( (c = getopt_long(argc,argv,"hVqldswb",long_options,NULL)) != - 1 ) {
+ switch( c ) {
+ case 'h':
+ usage();
+ exit(0);
+ case 'V':
+ fprintf(stderr, "%s: version %s\n", program, VERSION_STRING);
+ exit(0);
+ case 'q':
+ size = 8;
+ break;
+ case 'l':
+ case 'd':
+ size = 4;
+ break;
+ case 'w':
+ case 's':
+ size = 2;
+ break;
+ case 'b':
+ size = 1;
+ break;
+ default:
+ usage();
+ exit(127);
+ }
+ }
+
+ if ( optind > argc-2 ) {
+ /* Should have at least two arguments */
+ usage();
+ exit(127);
+ }
+
+ reg = (uintptr_t)strtoumax(argv[optind++], NULL, 0);
+
+ fd = open("/dev/mem", O_RDWR);
+ if ( fd < 0 ) {
+ perror("setmem:/dev/mem");
+ exit(1);
+ }
+
+ page_mask = ~((uintptr_t)getpagesize()-1);
+ start = reg & page_mask;
+ len = ((reg + size*(argc-optind)) & page_mask) - start;
+
+ map = mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, start);
+ if ( map == MAP_FAILED ) {
+ perror("setmem:mmap");
+ exit(1);
+ }
+
+ ptr = (char *)map + (reg & ~page_mask);
+
+ while ( optind < argc ) {
+ data = (uint64_t)strtoumax(argv[optind++], NULL, 0);
+
+ switch ( size ) {
+ case 1:
+ *(volatile uint8_t *)ptr = data;
+ break;
+ case 2:
+ *(volatile uint16_t *)ptr = data;
+ break;
+ case 4:
+ *(volatile uint32_t *)ptr = data;
+ break;
+ case 8:
+ *(volatile uint64_t *)ptr = data;
+ break;
+ default:
+ abort(); /* Should never happen */
+ }
+
+ ptr = (char *)ptr + size;
+ }
+
+ close(fd);
+
+ exit(0);
+}
diff --git a/version.h b/version.h
new file mode 100644
index 0000000..2764294
--- /dev/null
+++ b/version.h
@@ -0,0 +1,4 @@
+#ifndef VERSION_H
+#define VERSION_H
+#define VERSION_STRING "memhack-1.0"
+#endif