changeset 224:2900fe603f8a

beginning of MPFFS->TIFFS naming convention change
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Sun, 12 Jan 2014 07:59:00 +0000
parents 0848c7f419fd
children c04aa85559ed
files doc/TIFFS ffstools/tiffs-rd/README ffstools/tiffs-rd/pathname.h ffstools/tiffs-rd/struct.h ffstools/tiffs-rd/types.h target-utils/Makefile target-utils/libmpffs/Makefile target-utils/libmpffs/basicfind.c target-utils/libmpffs/cmd_find.c target-utils/libmpffs/findfile.c target-utils/libmpffs/globals.c target-utils/libmpffs/globals.h target-utils/libmpffs/init.c target-utils/libmpffs/macros.h target-utils/libmpffs/rdinmem.c target-utils/libmpffs/struct.h target-utils/libtiffs/Makefile target-utils/libtiffs/basicfind.c target-utils/libtiffs/cmd_find.c target-utils/libtiffs/findfile.c target-utils/libtiffs/globals.c target-utils/libtiffs/globals.h target-utils/libtiffs/init.c target-utils/libtiffs/macros.h target-utils/libtiffs/rdinmem.c target-utils/libtiffs/struct.h target-utils/pirexplore/Makefile
diffstat 27 files changed, 512 insertions(+), 374 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/TIFFS	Sun Jan 12 07:59:00 2014 +0000
@@ -0,0 +1,50 @@
+All TI GSM firmwares known to this author (FreeCalypso developer Space Falcon)
+implement some kind of flash file system, or FFS.  Several different FFS code
+implementations, and correspondingly several different on-flash data formats,
+have been used throughout the history of TI's involvement in the wireless
+terminal business.  The FFS incarnation of primary interest to the FreeCalypso
+project is the one invented by Mads Meisner-Jensen at TI in the early 2000s
+(at least according to the comments in the sources available to us), and it is
+relevant to us in the following ways:
+
+* When targeting the GSM modem in Openmoko's GTA01/02 smartphones, we need to
+  work with the original FFS from the factory (call it MokoFFS), the same FFS
+  as used by the mokoN firmwares: this FFS contains the IMEI and the RF
+  calibration values from the factory, which we most certainly don't want to go
+  without.
+
+* The Leonardo firmware semi-src which we are using as the reference for
+  building our own full source, multi-target GSM fw contains a turnkey-working
+  implementation of this very FFS, using the on-flash format in question and
+  providing run-time APIs expected by the rest of the GSM fw suite.  Following
+  the principle of ``if it ain't broke, don't fix it'', we can use this FFS not
+  only on the gtamodem target, but also on other targets, including those where
+  we would be starting from a blank state and thus have the freedom to use
+  whatever FFS we like.
+
+* The original proprietary fw on the Pirelli DP-L10 phone also happens to use
+  an FFS in the same format.  Pirelli's FFS does *not* contain the IMEI or any
+  of the RF calibration values though, and trying to reuse it directly for our
+  own FC GSM fw seems to be more trouble than benefit - so we'll probably have
+  our fw start with a blank TIFFS instead - but there is still insight to be
+  gained from in-vitro examination of captured Pirelli FFS images.
+
+Naming
+======
+
+I have previously referred to the FFS format in question as Mokopir-FFS or
+MPFFS, from "Moko" and "Pirelli".  I was originally hesitant to call it TIFFS,
+as lacking the source code, I had no way of knowing whether the FFS format and
+implementation were of TI's own invention, or something that TI licensed as a
+black box from one of their many proprietary software partners.  (I was unable
+to identify it as any well-known, industry-standard FFS format, but absence of
+evidence is not evidence of absence.)  But now that we have TI's original source
+code which implements this FFS (first the MV100-0.1.rar source, then the full
+Leonardo one), complete with comments and a HISTORY file, we know that our FFS
+was invented and implemented by someone named Mads Meisner-Jensen at TI - I'm
+guessing in the SSA group in Nice, France.
+
+I am now making a naming transition from MPFFS to TIFFS: there is really no
+link between this FFS format and the Openmoko+Pirelli duo, other than the
+happenstance of me having first encountered this FFS on these two GSM device
+brands, and the name TIFFS is more neutrally-descriptive.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ffstools/tiffs-rd/README	Sun Jan 12 07:59:00 2014 +0000
@@ -0,0 +1,33 @@
+The utility being developed in this source directory will allow one to examine
+("in vitro") flash file system (FFS) images read out of TI GSM devices - or
+more precisely, out of GSM devices using a TI chipset and running TI's GSM
+firmware versions from the late Calypso era.  The FFS version in question is
+implemented in our own FreeCalypso GSM fw, also happens to be used by the
+original proprietary firmware on the Pirelli DP-L10, and on some devices like
+Openmoko GTA0x the use of this FFS format is required in order to make use of
+the factory IMEI and RF calibration data.
+
+This new tiffs utility is intended to replace the earlier mpffs-* utilities
+released in the summer of SE52 (A.D. 2013), and will also incorporate the
+additional examination functionality that was developed as part of the
+"pirollback" utilities.
+
+Naming
+======
+
+I have previously referred to the FFS format in question as Mokopir-FFS or
+MPFFS, from "Moko" and "Pirelli".  I was originally hesitant to call it TIFFS,
+as lacking the source code, I had no way of knowing whether the FFS format and
+implementation were of TI's own invention, or something that TI licensed as a
+black box from one of their many proprietary software partners.  (I was unable
+to identify it as any well-known, industry-standard FFS format, but absence of
+evidence is not evidence of absence.)  But now that we have TI's original source
+code which implements this FFS (first the MV100-0.1.rar source, then the full
+Leonardo one), complete with comments and a HISTORY file, we know that our FFS
+was invented and implemented by someone named Mads Meisner-Jensen at TI - I'm
+guessing in the SSA group in Nice, France.
+
+I am now making a naming transition from MPFFS to TIFFS: there is really no
+link between this FFS format and the Openmoko+Pirelli duo, other than the
+happenstance of me having first encountered this FFS on these two GSM device
+brands, and the name TIFFS is more neutrally-descriptive.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ffstools/tiffs-rd/pathname.h	Sun Jan 12 07:59:00 2014 +0000
@@ -0,0 +1,3 @@
+#define	MAX_FN_COMPONENT	20
+#define	MAX_DIR_NEST		6
+#define	PATHNAME_BUF_SIZE	((MAX_FN_COMPONENT+1) * MAX_DIR_NEST + 2)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ffstools/tiffs-rd/struct.h	Sun Jan 12 07:59:00 2014 +0000
@@ -0,0 +1,40 @@
+/* actual TIFFS on-media structure */
+struct inode_flash {
+	u16	len;
+	u8	reserved1;
+	u8	type;
+	u16	descend;
+	u16	sibling;
+	u32	dataptr;
+	u16	sequence;
+	u16	updates;
+};
+
+struct journal_entry {
+	u8	status;
+	u8	objtype;
+	u16	this_ino;
+	u16	link_ptr;
+	u16	replacee;
+	u32	location;
+	u16	size;
+	u16	repli;	/* ??? */
+};
+
+/* our own struct for convenience */
+struct inode_info {
+	struct	inode_flash *flash;
+	int	parent;
+	int	type;
+	u8	*dataptr;
+	u32	offset;
+	u32	rawloc;
+	u16	len;
+	int	descend;
+	int	sibling;
+	u8	*byte_after_name;
+	/* info added from parsing the journal */
+	struct	journal_entry *jflash;
+	int	j_unlink_ptr;
+	int	j_oldver;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ffstools/tiffs-rd/types.h	Sun Jan 12 07:59:00 2014 +0000
@@ -0,0 +1,12 @@
+/*
+ * I like using u8/u16/u32, but they don't seem to be defined anywhere.
+ * So I solve the whole portability problem by defining them myself.
+ */
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+typedef signed char s8;
+typedef signed short s16;
+typedef signed int s32;
--- a/target-utils/Makefile	Tue Jan 07 05:58:11 2014 +0000
+++ b/target-utils/Makefile	Sun Jan 12 07:59:00 2014 +0000
@@ -1,5 +1,5 @@
 PROGS=	helloapp loadagent pirexplore
-LIBS=	libcommon libload libmpffs libprintf
+LIBS=	libcommon libload libprintf libtiffs
 SUBDIR=	${PROGS} ${LIBS}
 
 default:	loadagent
@@ -7,7 +7,7 @@
 
 helloapp:	libcommon libprintf
 loadagent:	libcommon libload libprintf
-pirexplore:	libcommon libload libmpffs libprintf
+pirexplore:	libcommon libload libprintf libtiffs
 
 ${SUBDIR}: FRC
 	cd $@; ${MAKE} ${MFLAGS}
--- a/target-utils/libmpffs/Makefile	Tue Jan 07 05:58:11 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-CC=	arm-elf-gcc
-CFLAGS=	-Os -fno-builtin
-CPPFLAGS=-I../include
-AR=	arm-elf-ar
-RANLIB=	arm-elf-ranlib
-
-OBJS=	basicfind.o cmd_find.o findfile.o globals.o init.o rdinmem.o
-
-all:	libmpffs.a
-
-libmpffs.a:	${OBJS}
-	${AR} cru $@ ${OBJS}
-	${RANLIB} $@
-
-clean:
-	rm -f *.[oa] *errs
--- a/target-utils/libmpffs/basicfind.c	Tue Jan 07 05:58:11 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-#include <sys/types.h>
-#include "types.h"
-#include "struct.h"
-#include "globals.h"
-#include "macros.h"
-
-extern char *index();
-
-static
-find_named_child(start, seekname)
-	char *seekname;
-{
-	int ino;
-	struct inode *irec;
-
-	for (ino = start; ino != 0xFFFF; ino = irec->sibling) {
-		irec = mpffs_active_index + ino;
-		if (!irec->type)
-			continue;
-		if (!strcmp(inode_to_dataptr(irec), seekname))
-			return(ino);
-	}
-	return(0);
-}
-
-mpffs_pathname_to_inode(pathname)
-	char *pathname;
-{
-	int ino, stat;
-	struct inode *irec;
-	char *cur, *next;
-
-	stat = mpffs_init();
-	if (stat < 0)
-		return(stat);
-	cur = pathname;
-	if (*cur == '/')
-		cur++;
-	for (ino = mpffs_root_ino; cur; cur = next) {
-		if (!*cur)
-			break;
-		next = index(cur, '/');
-		if (next == cur) {
-		    printf("malformed pathname: multiple adjacent slashes\n");
-			return(-1);
-		}
-		if (next)
-			*next++ = '\0';
-		irec = mpffs_active_index + ino;
-		if (irec->type != OBJTYPE_DIR) {
-			printf("Error: non-terminal non-directory\n");
-			if (next)
-				next[-1] = '/';
-			return(-1);
-		}
-		ino = find_named_child(irec->descend, cur);
-		if (next)
-			next[-1] = '/';
-		if (!ino) {
-			printf("Error: pathname component not found\n");
-			return(-1);
-		}
-	}
-	return(ino);
-}
--- a/target-utils/libmpffs/cmd_find.c	Tue Jan 07 05:58:11 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#include <sys/types.h>
-#include "types.h"
-
-void
-cmd_find(argbulk)
-	char *argbulk;
-{
-	char *argv[2];
-	int stat, cont;
-	u8 *start;
-	size_t size;
-
-	if (parse_args(argbulk, 1, 1, argv, 0) < 0)
-		return;
-	stat = mpffs_find_file(argv[0], &start, &size, &cont);
-	if (stat < 0)
-		return;
-	printf("chunk @%08X size %x\n", (u32)start, (u32)size);
-	while (cont) {
-		stat = mpffs_get_segment(cont, &start, &size, &cont);
-		if (stat < 0)
-			return;
-		printf("chunk @%08X size %x\n", (u32)start, (u32)size);
-	}
-}
--- a/target-utils/libmpffs/findfile.c	Tue Jan 07 05:58:11 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-#include <sys/types.h>
-#include "types.h"
-#include "struct.h"
-#include "globals.h"
-#include "macros.h"
-
-static u8 *
-find_endofchunk(ino)
-{
-	struct inode *irec = mpffs_active_index + ino;
-	u8 *p;
-	int i;
-
-	p = inode_to_dataptr(irec) + irec->len;
-	for (i = 0; i < 16; i++) {
-		p--;
-		if (!*p)
-			return(p);
-		if (*p != 0xFF)
-			break;
-	}
-	printf("Error: inode #%x has no valid termination\n", ino);
-	return(p);	/* XXX */
-}
-
-mpffs_find_file(pathname, startret, sizeret, continue_ret)
-	char *pathname;
-	u8 **startret;
-	size_t *sizeret;
-	int *continue_ret;
-{
-	int ino, cont;
-	struct inode *irec;
-	u8 *start, *end;
-	int size;
-
-	ino = mpffs_pathname_to_inode(pathname);
-	if (ino <= 0)
-		return(-1);
-	irec = mpffs_active_index + ino;
-	if (irec->type != OBJTYPE_FILE) {
-		printf("Error: %s is not a regular file\n", pathname);
-		return(-1);
-	}
-	start = inode_to_dataptr(irec);
-	start += strlen(start) + 1;
-	end = find_endofchunk(ino);
-	size = end - start;
-	if (size < 0)
-		size = 0;
-	cont = irec->descend;
-	if (cont == 0xFFFF)
-		cont = 0;
-	if (startret)
-		*startret = start;
-	if (sizeret)
-		*sizeret = size;
-	if (continue_ret)
-		*continue_ret = cont;
-	return(0);
-}
-
-mpffs_get_segment(ino, startret, sizeret, continue_ret)
-	int ino;
-	u8 **startret;
-	size_t *sizeret;
-	int *continue_ret;
-{
-	int cont;
-	struct inode *irec;
-	u8 *start, *end;
-	int size;
-
-	for (;;) {
-		irec = mpffs_active_index + ino;
-		if (irec->type)
-			break;
-		if (irec->sibling == 0xFFFF) {
-		    printf("Error: segment inode #%d: deleted and no sibling\n",
-				ino);
-			return(-1);
-		}
-		ino = irec->sibling;
-	}
-	if (irec->type != OBJTYPE_SEGMENT) {
-		printf("Error: inode #%x is not a segment\n", ino);
-		return(-1);
-	}
-	start = inode_to_dataptr(irec);
-	end = find_endofchunk(ino);
-	size = end - start;
-	if (size <= 0) {
-		printf("Error: segment inode #%x: bad length\n", ino);
-		return(-1);
-	}
-	cont = irec->descend;
-	if (cont == 0xFFFF)
-		cont = 0;
-	if (startret)
-		*startret = start;
-	if (sizeret)
-		*sizeret = size;
-	if (continue_ret)
-		*continue_ret = cont;
-	return(0);
-}
--- a/target-utils/libmpffs/globals.c	Tue Jan 07 05:58:11 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-/* global variables for the MPFFS reader code */
-
-#include "types.h"
-#include "struct.h"
-
-struct inode *mpffs_active_index;
-int mpffs_root_ino;
-int mpffs_init_done;
--- a/target-utils/libmpffs/globals.h	Tue Jan 07 05:58:11 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-/* global variables for the MPFFS reader code - extern declarations */
-
-extern struct inode *mpffs_active_index;
-extern int mpffs_root_ino;
-extern int mpffs_init_done;
-
-extern const u32 mpffs_base_addr;
-extern const u32 mpffs_sector_size;
-extern const int mpffs_nsectors;
--- a/target-utils/libmpffs/init.c	Tue Jan 07 05:58:11 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-#include "types.h"
-#include "struct.h"
-#include "globals.h"
-#include "macros.h"
-
-static const u8 ffs_sector_signature[6] = {'F', 'f', 's', '#', 0x10, 0x02};
-static const u8 blank_flash_line[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-					0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-					0xFF, 0xFF, 0xFF, 0xFF};
-
-static
-find_indexblk()
-{
-	u32 sector_addr;
-	u8 *sector_ptr;
-	int i;
-
-	printf("Looking for MPFFS active index block\n");
-	sector_addr = mpffs_base_addr;
-	for (i = 0; i < mpffs_nsectors; i++) {
-		sector_ptr = (u8 *) sector_addr;
-		if (!bcmp(sector_ptr, ffs_sector_signature, 6) &&
-		    sector_ptr[8] == 0xAB) {
-			printf("Found at %08X\n", sector_addr);
-			mpffs_active_index = (struct inode *) sector_ptr;
-			return(0);
-		}
-		sector_addr += mpffs_sector_size;
-	}
-	printf("Error: Not found in any of the %d candidate sectors\n",
-		mpffs_nsectors);
-	return(-1);
-}
-
-static
-find_rootino()
-{
-	int ino;
-	struct inode *irec;
-
-	printf("Looking for the root inode\n");
-	for (ino = 1; ; ino++) {
-		if (ino >= mpffs_sector_size >> 4) {
-		    printf("Error: Hit end of sector, no root inode found\n");
-			return(-1);
-		}
-		irec = mpffs_active_index + ino;
-		if (!bcmp((u8 *) irec, blank_flash_line, 16)) {
-			printf("Error: Hit blank flash, no root inode found\n");
-			return(-1);
-		}
-		if (irec->type == OBJTYPE_DIR && *inode_to_dataptr(irec) == '/')
-			break;
-	}
-	printf("Found at inode #%x\n", ino);
-	mpffs_root_ino = ino;
-	return(0);
-}
-
-mpffs_init()
-{
-	int stat;
-
-	if (mpffs_init_done)
-		return(0);
-	stat = find_indexblk();
-	if (stat < 0)
-		return(stat);
-	stat = find_rootino();
-	if (stat < 0)
-		return(stat);
-	mpffs_init_done = 1;
-	return(0);
-}
--- a/target-utils/libmpffs/macros.h	Tue Jan 07 05:58:11 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-#define	inode_to_dataptr(i)	((u8 *)mpffs_base_addr + ((i)->dataptr << 4))
--- a/target-utils/libmpffs/rdinmem.c	Tue Jan 07 05:58:11 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-#include <sys/types.h>
-#include "types.h"
-#include "struct.h"
-#include "globals.h"
-#include "macros.h"
-
-mpffs_read_into_ram(pathname, buf, maxlen, lenrtn)
-	char *pathname;
-	u8 *buf;
-	size_t maxlen, *lenrtn;
-{
-	int stat, cont;
-	u8 *chunk_start;
-	size_t chunk_size, real_len, roomleft;
-
-	stat = mpffs_find_file(pathname, &chunk_start, &chunk_size, &cont);
-	if (stat < 0)
-		return(stat);
-	if (chunk_size > maxlen) {
-toobig:		printf("Error: %s is bigger than the read buffer\n", pathname);
-		return(-1);
-	}
-	real_len = chunk_size;
-	bcopy(chunk_start, buf, chunk_size);
-	buf += chunk_size;
-	roomleft = maxlen - chunk_size;
-	while (cont) {
-		stat = mpffs_get_segment(cont, &chunk_start, &chunk_size,
-					 &cont);
-		if (stat < 0)
-			return(stat);
-		if (chunk_size > roomleft)
-			goto toobig;
-		real_len += chunk_size;
-		bcopy(chunk_start, buf, chunk_size);
-		buf += chunk_size;
-		roomleft -= chunk_size;
-	}
-	if (lenrtn)
-		*lenrtn = real_len;
-	return(0);
-}
--- a/target-utils/libmpffs/struct.h	Tue Jan 07 05:58:11 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-struct inode {
-	u16	len;
-	u8	reserved1;
-	u8	type;
-	u16	descend;
-	u16	sibling;
-	u32	dataptr;
-	u16	sequence;
-	u16	updates;
-};
-
-#define	OBJTYPE_FILE	0xF1
-#define	OBJTYPE_DIR	0xF2
-#define	OBJTYPE_SEGMENT	0xF4
-
-struct journal {
-	u8	status;
-	u8	objtype;
-	u16	this_ino;
-	u16	link_ptr;
-	u16	replacee;
-	u32	location;
-	u16	size;
-	u16	repli;	/* ??? */
-};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/target-utils/libtiffs/Makefile	Sun Jan 12 07:59:00 2014 +0000
@@ -0,0 +1,16 @@
+CC=	arm-elf-gcc
+CFLAGS=	-Os -fno-builtin
+CPPFLAGS=-I../include
+AR=	arm-elf-ar
+RANLIB=	arm-elf-ranlib
+
+OBJS=	basicfind.o cmd_find.o findfile.o globals.o init.o rdinmem.o
+
+all:	libtiffs.a
+
+libtiffs.a:	${OBJS}
+	${AR} cru $@ ${OBJS}
+	${RANLIB} $@
+
+clean:
+	rm -f *.[oa] *errs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/target-utils/libtiffs/basicfind.c	Sun Jan 12 07:59:00 2014 +0000
@@ -0,0 +1,65 @@
+#include <sys/types.h>
+#include "types.h"
+#include "struct.h"
+#include "globals.h"
+#include "macros.h"
+
+extern char *index();
+
+static
+find_named_child(start, seekname)
+	char *seekname;
+{
+	int ino;
+	struct inode *irec;
+
+	for (ino = start; ino != 0xFFFF; ino = irec->sibling) {
+		irec = mpffs_active_index + ino;
+		if (!irec->type)
+			continue;
+		if (!strcmp(inode_to_dataptr(irec), seekname))
+			return(ino);
+	}
+	return(0);
+}
+
+mpffs_pathname_to_inode(pathname)
+	char *pathname;
+{
+	int ino, stat;
+	struct inode *irec;
+	char *cur, *next;
+
+	stat = mpffs_init();
+	if (stat < 0)
+		return(stat);
+	cur = pathname;
+	if (*cur == '/')
+		cur++;
+	for (ino = mpffs_root_ino; cur; cur = next) {
+		if (!*cur)
+			break;
+		next = index(cur, '/');
+		if (next == cur) {
+		    printf("malformed pathname: multiple adjacent slashes\n");
+			return(-1);
+		}
+		if (next)
+			*next++ = '\0';
+		irec = mpffs_active_index + ino;
+		if (irec->type != OBJTYPE_DIR) {
+			printf("Error: non-terminal non-directory\n");
+			if (next)
+				next[-1] = '/';
+			return(-1);
+		}
+		ino = find_named_child(irec->descend, cur);
+		if (next)
+			next[-1] = '/';
+		if (!ino) {
+			printf("Error: pathname component not found\n");
+			return(-1);
+		}
+	}
+	return(ino);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/target-utils/libtiffs/cmd_find.c	Sun Jan 12 07:59:00 2014 +0000
@@ -0,0 +1,25 @@
+#include <sys/types.h>
+#include "types.h"
+
+void
+cmd_find(argbulk)
+	char *argbulk;
+{
+	char *argv[2];
+	int stat, cont;
+	u8 *start;
+	size_t size;
+
+	if (parse_args(argbulk, 1, 1, argv, 0) < 0)
+		return;
+	stat = mpffs_find_file(argv[0], &start, &size, &cont);
+	if (stat < 0)
+		return;
+	printf("chunk @%08X size %x\n", (u32)start, (u32)size);
+	while (cont) {
+		stat = mpffs_get_segment(cont, &start, &size, &cont);
+		if (stat < 0)
+			return;
+		printf("chunk @%08X size %x\n", (u32)start, (u32)size);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/target-utils/libtiffs/findfile.c	Sun Jan 12 07:59:00 2014 +0000
@@ -0,0 +1,106 @@
+#include <sys/types.h>
+#include "types.h"
+#include "struct.h"
+#include "globals.h"
+#include "macros.h"
+
+static u8 *
+find_endofchunk(ino)
+{
+	struct inode *irec = mpffs_active_index + ino;
+	u8 *p;
+	int i;
+
+	p = inode_to_dataptr(irec) + irec->len;
+	for (i = 0; i < 16; i++) {
+		p--;
+		if (!*p)
+			return(p);
+		if (*p != 0xFF)
+			break;
+	}
+	printf("Error: inode #%x has no valid termination\n", ino);
+	return(p);	/* XXX */
+}
+
+mpffs_find_file(pathname, startret, sizeret, continue_ret)
+	char *pathname;
+	u8 **startret;
+	size_t *sizeret;
+	int *continue_ret;
+{
+	int ino, cont;
+	struct inode *irec;
+	u8 *start, *end;
+	int size;
+
+	ino = mpffs_pathname_to_inode(pathname);
+	if (ino <= 0)
+		return(-1);
+	irec = mpffs_active_index + ino;
+	if (irec->type != OBJTYPE_FILE) {
+		printf("Error: %s is not a regular file\n", pathname);
+		return(-1);
+	}
+	start = inode_to_dataptr(irec);
+	start += strlen(start) + 1;
+	end = find_endofchunk(ino);
+	size = end - start;
+	if (size < 0)
+		size = 0;
+	cont = irec->descend;
+	if (cont == 0xFFFF)
+		cont = 0;
+	if (startret)
+		*startret = start;
+	if (sizeret)
+		*sizeret = size;
+	if (continue_ret)
+		*continue_ret = cont;
+	return(0);
+}
+
+mpffs_get_segment(ino, startret, sizeret, continue_ret)
+	int ino;
+	u8 **startret;
+	size_t *sizeret;
+	int *continue_ret;
+{
+	int cont;
+	struct inode *irec;
+	u8 *start, *end;
+	int size;
+
+	for (;;) {
+		irec = mpffs_active_index + ino;
+		if (irec->type)
+			break;
+		if (irec->sibling == 0xFFFF) {
+		    printf("Error: segment inode #%d: deleted and no sibling\n",
+				ino);
+			return(-1);
+		}
+		ino = irec->sibling;
+	}
+	if (irec->type != OBJTYPE_SEGMENT) {
+		printf("Error: inode #%x is not a segment\n", ino);
+		return(-1);
+	}
+	start = inode_to_dataptr(irec);
+	end = find_endofchunk(ino);
+	size = end - start;
+	if (size <= 0) {
+		printf("Error: segment inode #%x: bad length\n", ino);
+		return(-1);
+	}
+	cont = irec->descend;
+	if (cont == 0xFFFF)
+		cont = 0;
+	if (startret)
+		*startret = start;
+	if (sizeret)
+		*sizeret = size;
+	if (continue_ret)
+		*continue_ret = cont;
+	return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/target-utils/libtiffs/globals.c	Sun Jan 12 07:59:00 2014 +0000
@@ -0,0 +1,8 @@
+/* global variables for the MPFFS reader code */
+
+#include "types.h"
+#include "struct.h"
+
+struct inode *mpffs_active_index;
+int mpffs_root_ino;
+int mpffs_init_done;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/target-utils/libtiffs/globals.h	Sun Jan 12 07:59:00 2014 +0000
@@ -0,0 +1,9 @@
+/* global variables for the MPFFS reader code - extern declarations */
+
+extern struct inode *mpffs_active_index;
+extern int mpffs_root_ino;
+extern int mpffs_init_done;
+
+extern const u32 mpffs_base_addr;
+extern const u32 mpffs_sector_size;
+extern const int mpffs_nsectors;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/target-utils/libtiffs/init.c	Sun Jan 12 07:59:00 2014 +0000
@@ -0,0 +1,74 @@
+#include "types.h"
+#include "struct.h"
+#include "globals.h"
+#include "macros.h"
+
+static const u8 ffs_sector_signature[6] = {'F', 'f', 's', '#', 0x10, 0x02};
+static const u8 blank_flash_line[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+					0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+					0xFF, 0xFF, 0xFF, 0xFF};
+
+static
+find_indexblk()
+{
+	u32 sector_addr;
+	u8 *sector_ptr;
+	int i;
+
+	printf("Looking for MPFFS active index block\n");
+	sector_addr = mpffs_base_addr;
+	for (i = 0; i < mpffs_nsectors; i++) {
+		sector_ptr = (u8 *) sector_addr;
+		if (!bcmp(sector_ptr, ffs_sector_signature, 6) &&
+		    sector_ptr[8] == 0xAB) {
+			printf("Found at %08X\n", sector_addr);
+			mpffs_active_index = (struct inode *) sector_ptr;
+			return(0);
+		}
+		sector_addr += mpffs_sector_size;
+	}
+	printf("Error: Not found in any of the %d candidate sectors\n",
+		mpffs_nsectors);
+	return(-1);
+}
+
+static
+find_rootino()
+{
+	int ino;
+	struct inode *irec;
+
+	printf("Looking for the root inode\n");
+	for (ino = 1; ; ino++) {
+		if (ino >= mpffs_sector_size >> 4) {
+		    printf("Error: Hit end of sector, no root inode found\n");
+			return(-1);
+		}
+		irec = mpffs_active_index + ino;
+		if (!bcmp((u8 *) irec, blank_flash_line, 16)) {
+			printf("Error: Hit blank flash, no root inode found\n");
+			return(-1);
+		}
+		if (irec->type == OBJTYPE_DIR && *inode_to_dataptr(irec) == '/')
+			break;
+	}
+	printf("Found at inode #%x\n", ino);
+	mpffs_root_ino = ino;
+	return(0);
+}
+
+mpffs_init()
+{
+	int stat;
+
+	if (mpffs_init_done)
+		return(0);
+	stat = find_indexblk();
+	if (stat < 0)
+		return(stat);
+	stat = find_rootino();
+	if (stat < 0)
+		return(stat);
+	mpffs_init_done = 1;
+	return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/target-utils/libtiffs/macros.h	Sun Jan 12 07:59:00 2014 +0000
@@ -0,0 +1,1 @@
+#define	inode_to_dataptr(i)	((u8 *)mpffs_base_addr + ((i)->dataptr << 4))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/target-utils/libtiffs/rdinmem.c	Sun Jan 12 07:59:00 2014 +0000
@@ -0,0 +1,42 @@
+#include <sys/types.h>
+#include "types.h"
+#include "struct.h"
+#include "globals.h"
+#include "macros.h"
+
+mpffs_read_into_ram(pathname, buf, maxlen, lenrtn)
+	char *pathname;
+	u8 *buf;
+	size_t maxlen, *lenrtn;
+{
+	int stat, cont;
+	u8 *chunk_start;
+	size_t chunk_size, real_len, roomleft;
+
+	stat = mpffs_find_file(pathname, &chunk_start, &chunk_size, &cont);
+	if (stat < 0)
+		return(stat);
+	if (chunk_size > maxlen) {
+toobig:		printf("Error: %s is bigger than the read buffer\n", pathname);
+		return(-1);
+	}
+	real_len = chunk_size;
+	bcopy(chunk_start, buf, chunk_size);
+	buf += chunk_size;
+	roomleft = maxlen - chunk_size;
+	while (cont) {
+		stat = mpffs_get_segment(cont, &chunk_start, &chunk_size,
+					 &cont);
+		if (stat < 0)
+			return(stat);
+		if (chunk_size > roomleft)
+			goto toobig;
+		real_len += chunk_size;
+		bcopy(chunk_start, buf, chunk_size);
+		buf += chunk_size;
+		roomleft -= chunk_size;
+	}
+	if (lenrtn)
+		*lenrtn = real_len;
+	return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/target-utils/libtiffs/struct.h	Sun Jan 12 07:59:00 2014 +0000
@@ -0,0 +1,25 @@
+struct inode {
+	u16	len;
+	u8	reserved1;
+	u8	type;
+	u16	descend;
+	u16	sibling;
+	u32	dataptr;
+	u16	sequence;
+	u16	updates;
+};
+
+#define	OBJTYPE_FILE	0xF1
+#define	OBJTYPE_DIR	0xF2
+#define	OBJTYPE_SEGMENT	0xF4
+
+struct journal {
+	u8	status;
+	u8	objtype;
+	u16	this_ino;
+	u16	link_ptr;
+	u16	replacee;
+	u32	location;
+	u16	size;
+	u16	repli;	/* ??? */
+};
--- a/target-utils/pirexplore/Makefile	Tue Jan 07 05:58:11 2014 +0000
+++ b/target-utils/pirexplore/Makefile	Sun Jan 12 07:59:00 2014 +0000
@@ -6,7 +6,7 @@
 
 PROG=	pirexplore
 OBJS=	crt0.o cmdtab.o ffsparam.o flashid.o lcd.o main.o mygetchar.o rtc.o
-LIBS=	../libcommon/libcommon.a ../libload/libload.a ../libmpffs/libmpffs.a \
+LIBS=	../libcommon/libcommon.a ../libload/libload.a ../libtiffs/libtiffs.a \
 	../libprintf/libprintf.a
 LDS=	../env/iram.lds