diff --git a/tools/.gitignore b/tools/.gitignore
index e458413..e89174f 100644
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -1 +1,2 @@
 gen_reloc_table
+sloffs
diff --git a/tools/Makefile b/tools/Makefile
index 06cdaa7..a035960 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -12,7 +12,9 @@
 
 include ../make.rules
 
-all: gen_reloc_table
+TARGETS = gen_reloc_table sloffs
+
+all: $(TARGETS)
 
 %.o: %.c
 		$(HOSTCC) -W $(HOSTCFLAGS) -c $^
@@ -20,11 +22,13 @@ all: gen_reloc_table
 gen_reloc_table: gen_reloc_table.o
 		$(HOSTCC) $(HOSTCFLAGS) -o $@ $^
 
+sloffs: sloffs.o
+		$(HOSTCC) $(HOSTCFLAGS) -o $@ $^
+
 clean_here:
-	rm -f *.o gen_reloc_table
+	rm -f *.o $(TARGETS)
 
-clean:	clean_here
+clean: clean_here
 
 
-distclean:	clean_here
-
+distclean: clean_here
diff --git a/tools/sloffs.c b/tools/sloffs.c
new file mode 100644
index 0000000..4b9ba5e
--- /dev/null
+++ b/tools/sloffs.c
@@ -0,0 +1,289 @@
+/******************************************************************************
+ * Copyright (c) 2008, 2009 Adrian Reber
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     Adrian Reber - initial implementation
+ *****************************************************************************/
+
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <byteswap.h>
+#include <getopt.h>
+
+#include <calculatecrc.h>
+
+#define VERSION 1
+
+#ifdef _BIG_ENDIAN
+#define cpu_to_be64(x)  (x)
+#define be64_to_cpu(x)  (x)
+#define be16_to_cpu(x)  (x)
+#define be32_to_cpu(x)  (x)
+#else
+#define cpu_to_be64(x)  bswap_64(x)
+#define be64_to_cpu(x)  bswap_64(x)
+#define be16_to_cpu(x)  bswap_16(x)
+#define be32_to_cpu(x)  bswap_32(x)
+#endif
+
+
+/* no board dependencies wanted here, let's hardcode SLOF's
+ * magic strings here */
+
+#define FLASHFS_MAGIC "magic123"
+#define FLASHFS_PLATFORM_MAGIC "JS2XBlade"
+#define FLASHFS_PLATFORM_REVISION "1"
+
+/* there seems to be no structure defined anywhere in the code
+ * which resembles the actual sloffs/romfs file header;
+ * so defining it here for now */
+
+struct sloffs {
+	uint64_t next;
+	uint64_t len;
+	uint64_t flags;
+	uint64_t data;
+	char *name;
+};
+
+static struct sloffs *
+next_file(struct sloffs *sloffs)
+{
+	return (struct sloffs *)((unsigned char *)sloffs +
+				 be64_to_cpu(sloffs->next));
+}
+
+static struct sloffs *
+find_file(const void *data, const char *name)
+{
+	struct sloffs *sloffs = (struct sloffs *)data;
+
+	for (;;) {
+		if (!strcmp((char *)&sloffs->name, name))
+			return sloffs;
+
+		if (be64_to_cpu(sloffs->next) == 0)
+			break;
+		sloffs = next_file(sloffs);
+	}
+	return NULL;
+}
+
+static void
+sloffs_dump(const void *data)
+{
+	struct stH *header;
+	struct sloffs *sloffs;
+	int i;
+	uint64_t crc;
+	uint64_t *datetmp;
+
+	/* find the "header" file with all the information about
+	 * the flash image */
+	sloffs = find_file(data, "header");
+	if (!sloffs) {
+		printf("sloffs file \"header\" not found. aborting...\n");
+		return;
+	}
+
+	header = (struct stH *)((unsigned char *)sloffs +
+				be64_to_cpu(sloffs->data));
+
+	if (memcmp(FLASHFS_MAGIC, header->magic, strlen(FLASHFS_MAGIC))) {
+		printf("sloffs magic not found. "
+		       "probably not a valid SLOF flash image. aborting...\n");
+		return;
+	}
+	printf("  Magic       : %s\n", header->magic);
+	printf("  Platform    : %s\n", header->platform_name);
+	printf("  Version     : %s\n", header->version);
+	/* there is a bug in the date position;
+	 * it should be at header->date, but it is at (header->date + 2) */
+	printf("  Build Date  : ");
+	datetmp = (void *)header->date;
+	if (be64_to_cpu(*datetmp)) {
+	    printf("%04x", be16_to_cpu(*(uint16_t *)(header->date + 2)));
+	    printf("-%02x", *(uint8_t *)(header->date + 4));
+	    printf("-%02x", *(uint8_t *)(header->date + 5));
+	    printf(" %02x:", *(uint8_t *)(header->date + 6));
+	    printf("%02x", *(uint8_t *)(header->date + 7));
+	} else {
+	    printf("N/A");
+	}
+	printf("\n");
+	printf("  Modify Date : ");
+	datetmp = (void *)header->mdate;
+	if (be64_to_cpu(*datetmp)) {
+	    printf("%04x", be16_to_cpu(*(uint16_t *)(header->mdate + 2)));
+	    printf("-%02x", *(uint8_t *)(header->mdate + 4));
+	    printf("-%02x", *(uint8_t *)(header->mdate + 5));
+	    printf(" %02x:", *(uint8_t *)(header->mdate + 6));
+	    printf("%02x", *(uint8_t *)(header->mdate + 7));
+	} else {
+	    printf("N/A");
+	}
+	printf("\n");
+	printf("  Image Length: %ld", be64_to_cpu(header->flashlen));
+	printf(" (0x%lx) bytes\n", be64_to_cpu(header->flashlen));
+	printf("  Revision    : %s\n", header->platform_revision);
+	crc = be64_to_cpu(header->ui64CRC);
+	printf("  Header CRC  : 0x%016lx\n", crc);
+	crc = be64_to_cpu(header->flashlen);
+	crc = *(uint64_t *)(unsigned char *)(data + crc - 8);
+	crc = be64_to_cpu(crc);
+	printf("  Image CRC   : 0x%016lx\n", crc);
+
+	/* count number of files */
+	sloffs = (struct sloffs *)data;
+	i = 0;
+	for (;;) {
+		i++;
+		if (be64_to_cpu(sloffs->next) == 0)
+			break;
+		sloffs = next_file(sloffs);
+	}
+	printf("  Files       : %d\n", i);
+}
+
+static void
+sloffs_list(const void *data)
+{
+	struct sloffs *sloffs = (struct sloffs *)data;
+	const char *name_header = "File Name";
+	unsigned int i;
+	unsigned int max;
+	unsigned int line;
+
+	/* find largest name */
+	max = strlen(name_header);;
+	for (;;) {
+		if (max < strlen((char *)&sloffs->name))
+			max = strlen((char *)&sloffs->name);
+
+		if (be64_to_cpu(sloffs->next) == 0)
+			break;
+		sloffs = next_file(sloffs);
+	}
+
+	/* have at least two spaces between name and size column */
+	max += 2;
+
+	/* header for listing */
+	line = printf("   Offset      ");
+	line += printf("%s", name_header);
+	for (i = 0; i < max - strlen(name_header); i++)
+		line += printf(" ");
+	line += printf("Size                ");
+	line += printf("Flags\n");
+	printf("   ");
+	for (i = 0; i <= line; i++)
+		printf("=");
+	printf("\n");
+
+	sloffs = (struct sloffs *)data;
+	for (;;) {
+		printf("   0x%08lx", (void *)sloffs - (void *)data);
+		printf("  %s", (char *)&sloffs->name);
+		for (i = 0; i < max - strlen((char *)&sloffs->name); i++)
+			printf(" ");
+
+		printf("%07ld ", be64_to_cpu(sloffs->len));
+		printf("(0x%06lx)", be64_to_cpu(sloffs->len));
+		printf("  0x%08lx\n", be64_to_cpu(sloffs->flags));
+
+		if (be64_to_cpu(sloffs->next) == 0)
+			break;
+		sloffs = next_file(sloffs);
+	}
+}
+
+static void
+usage(void)
+{
+	printf("sloffs lists or changes a SLOF flash image\n\n");
+	printf("Usage:\n");
+	printf("  sloffs [OPTION]... [FILE]\n\n");
+	printf("Options:\n");
+	printf("  -h, --help             show this help, then exit\n");
+	printf("  -l, --list             list all files in the flash image\n");
+	printf("  -v, --version          print the version, then exit\n");
+	printf("  -d, --dump             dump the information from the header\n");
+	printf("\n");
+	exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+	int fd;
+	void *file;
+	struct stat stat;
+	const struct option loption[] = {
+		{ "help", 0, NULL, 'h' },
+		{ "list", 0, NULL, 'l' },
+		{ "version", 0, NULL, 'v' },
+		{ "dump", 0, NULL, 'd' },
+		{ 0, 0, 0, 0 }
+	};
+	const char *soption = "dhlv";
+	int c;
+	char mode = 0;
+
+	for (;;) {
+		c = getopt_long(argc, argv, soption, loption, NULL);
+		if (c == -1)
+			break;
+		switch (c) {
+		case 'l':
+			mode = 'l';
+			break;
+		case 'v':
+			printf("sloffs (version %d)\n", VERSION);
+			exit(0);
+		case 'd':
+			mode = 'd';
+			break;
+		case 'h':
+		default:
+			usage();
+		}
+	}
+
+	if (optind >= argc)
+		usage();
+
+	fd = open(argv[optind], O_RDONLY);
+
+	if (fd == -1) {
+		perror(argv[optind]);
+		exit(1);
+	}
+
+	fstat(fd, &stat);
+	file = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
+
+	switch (mode) {
+	case 'l':
+		sloffs_list(file);
+		break;
+	case 'd':
+		sloffs_dump(file);
+		break;
+	}
+
+	munmap(file, stat.st_size);
+	close(fd);
+	return 0;
+}
