partt partition table parser

Jörn Engel joern at wohnheim.fh-wedel.de
Tue Sep 25 16:04:26 EDT 2001


Hi!

There has been time for some cleanups, so the code might actually
work. Please have a look and see if this is usable.

Jörn

-- 
``Plan to throw one away; you will, anyhow.'' 
(Fred Brooks, ``The Mythical Man-Month'', Chapter 11)
-------------- next part --------------
diff -Naur mtd.orig/drivers/mtd/Config.in mtd/drivers/mtd/Config.in
--- mtd.orig/drivers/mtd/Config.in	Sun Aug 12 00:00:07 2001
+++ mtd/drivers/mtd/Config.in	Tue Sep 25 20:19:20 2001
@@ -15,6 +15,13 @@
    dep_tristate '  RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS
    dep_tristate '  Compaq bootldr partition table parsing' CONFIG_MTD_BOOTLDR_PARTS $CONFIG_MTD_PARTITIONS
    dep_tristate '  ARM Firmware Suite partition parsing' CONFIG_MTD_AFS_PARTS $CONFIG_MTD_PARTITIONS
+   dep_tristate '  Partt partition table parsing' CONFIG_MTD_PARTT_PARTS $CONFIG_MTD_PARTITIONS
+   if [ "$CONFIG_MTD_PARTT_PARTS" = "y" -o "$CONFIG_MTD_PARTT_PARTS" = "m" ]; then
+      bool      '    use indirect address to partition table' CONFIG_MTD_PARTT_INDIRECT
+      bool      '    seek partition table [pointer] from end' CONFIG_MTD_PARTT_SEEK_FROM_END
+      hex       '    address to partition table [pointer]' CONFIG_MTD_PARTT_ADDRESS 0
+   fi
+
 
 comment 'User Modules And Translation Layers'
    dep_tristate '  Direct char device access to MTD devices' CONFIG_MTD_CHAR $CONFIG_MTD
diff -Naur mtd.orig/drivers/mtd/Makefile mtd/drivers/mtd/Makefile
--- mtd.orig/drivers/mtd/Makefile	Thu Jun 14 00:00:07 2001
+++ mtd/drivers/mtd/Makefile	Tue Sep 25 20:17:50 2001
@@ -48,6 +48,7 @@
 obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
 obj-$(CONFIG_MTD_BOOTLDR_PARTS) += bootldr.o
 obj-$(CONFIG_MTD_AFS_PARTS)	+= afs.o
+obj-$(CONFIG_MTD_PARTT_PARTS)	+= partt.o
 
 # 'Users' - code which presents functionality to userspace.
 obj-$(CONFIG_MTD_CHAR)		+= mtdchar.o
diff -Naur mtd.orig/drivers/mtd/maps/physmap.c mtd/drivers/mtd/maps/physmap.c
--- mtd.orig/drivers/mtd/maps/physmap.c	Sun Jul 15 00:00:11 2001
+++ mtd/drivers/mtd/maps/physmap.c	Tue Sep 25 20:28:03 2001
@@ -81,8 +81,15 @@
 #define cleanup_physmap cleanup_module
 #endif
 
+#if defined(CONFIG_MTD_PARTT_PARTS)
+static struct mtd_partition *parts;
+#endif
+
 int __init init_physmap(void)
 {
+#if defined(CONFIG_MTD_PARTT_PARTS)
+	int nrparts = 0;
+#endif
        	printk(KERN_NOTICE "physmap flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
 	physmap_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
 
@@ -91,15 +98,19 @@
 		return -EIO;
 	}
 	mymtd = do_map_probe("cfi_probe", &physmap_map);
-	if (mymtd) {
-		mymtd->module = THIS_MODULE;
-
-		add_mtd_device(mymtd);
-		return 0;
+	if (!mymtd) {
+		iounmap((void *)physmap_map.map_priv_1);
+		return -ENXIO;
 	}
-
-	iounmap((void *)physmap_map.map_priv_1);
-	return -ENXIO;
+	mymtd->module = THIS_MODULE;
+	add_mtd_device(mymtd);
+#if defined(CONFIG_MTD_PARTT_PARTS)
+	nrparts = parse_partt_partitions(mymtd, &parts);
+	if (nrparts <= 0)
+		return nrparts; /* FIXME: Is there more cleanup to do? */
+	add_mtd_partitions(mymtd, parts, nrparts);
+#endif
+	return 0;
 }
 
 static void __exit cleanup_physmap(void)
diff -Naur mtd.orig/drivers/mtd/partt.c mtd/drivers/mtd/partt.c
--- mtd.orig/drivers/mtd/partt.c	Thu Jan  1 01:00:00 1970
+++ mtd/drivers/mtd/partt.c	Tue Sep 25 20:22:03 2001
@@ -0,0 +1,117 @@
+/*
+ * partt Partition Table Parser
+ *
+ * very minimal and flexible parser
+ *
+ * Copyright (C) 2001 Joern Engel
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/string.h>
+#include <linux/mtd/partt.h>
+
+/*
+ * Atomic wrapper for (struct mtdinfo)->read, so it always returns len bytes
+ * or fails completely 
+ */
+inline int wrapped_read(struct mtd_info *mtd, loff_t from, size_t len, u_char *buf)
+{
+	int ret;
+	size_t retlen, offset;
+	for (retlen=offset=0; offset < len; offset += retlen) {
+		ret = mtd->read (mtd, from, len, &retlen, buf+offset);
+		if (ret<0)
+			return ret;
+		if (retlen==0)
+			return -EIO;
+	}
+	return ret;
+}
+
+#ifdef CONFIG_MTD_PARTT_SEEK_FROM_END
+#	define ADDR (master->size - (CONFIG_MTD_PARTT_ADDRESS))
+#else
+#	define ADDR (CONFIG_MTD_PARTT_ADDRESS)
+#endif
+
+/*
+ * Partition table format:
+ * - <=16 Entries on a table
+ * - Null-terminated - the last entry's name starts with 0x00
+ * - Extendable - the terminating entry might include a pointer to the next
+ *     partition table, even though this feature is not used yet
+ * - Small flash footprint - includes only informations that the kernel uses
+ *
+ * TODO: 
+ * Handle multiple partition tables
+ * Change code to handle flash sizes >4GiB
+ */
+int parse_partt_partitions(struct mtd_info *master, struct mtd_partition **pparts)
+{
+	int ret;
+	u32 flash_table;
+	partt_table *mem_table;
+	struct mtd_partition *parts;
+	int nrparts = 0;
+	char *names;
+	int namelen = 0;
+	int i;
+
+	/* get position of partition table */ 
+#ifdef CONFIG_MTD_PARTT_INDIRECT
+	ret = wrapped_read (master, ADDR, sizeof(flash_table), (u_char*)&flash_table);
+	if (ret<0)
+		return ret;
+	if (flash_table >= (master->size - TABLE_SIZE))
+		return -EFAULT;
+#else
+	flash_table = ADDR;
+#endif
+	/* copy partition table to ram */
+	mem_table = kmalloc (sizeof(partt_table), GFP_KERNEL);
+	if (!mem_table)
+		return -ENOMEM;
+	ret = wrapped_read (master, flash_table, TABLE_SIZE, (u_char*)mem_table);
+	if (ret<0)
+		goto out;
+	if (mem_table[0][TABLE_NO_ENTRIES-1].mask_flags != PARTT_MAGIC)
+		goto out;
+
+	/* calculate number of partitions and memory need */
+	for (; mem_table[0][nrparts].name[0] && nrparts<TABLE_NO_ENTRIES; nrparts++) {
+		if (mem_table[0][nrparts].name[NAME_MAX_LEN])
+			goto out;
+		/* FIXME: Do some more sanity checks */
+		namelen += strlen (mem_table[0][nrparts].name) + 1;
+	}
+	if (!nrparts) {
+		ret = 0;
+		goto out;
+	}
+
+	/* copy data to linux partition table */
+	parts = kmalloc (nrparts*sizeof(*parts) + namelen, GFP_KERNEL);
+	if (!parts) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	names = (char*)&parts[nrparts];
+	for (i=0; i<nrparts; i++) {
+		parts[i].size = mem_table[0][i].size;
+		parts[i].offset = mem_table[0][i].offset;
+		parts[i].mask_flags = mem_table[0][i].mask_flags;
+		parts[i].name = names;
+		strcpy (names, mem_table[0][i].name);
+		names += strlen(names)+1;
+	}
+	*pparts = parts;
+	ret = nrparts;
+out:
+	kfree (mem_table);
+	return ret;
+}
diff -Naur mtd.orig/include/linux/mtd/partt.h mtd/include/linux/mtd/partt.h
--- mtd.orig/include/linux/mtd/partt.h	Thu Jan  1 01:00:00 1970
+++ mtd/include/linux/mtd/partt.h	Tue Sep 25 20:15:02 2001
@@ -0,0 +1,28 @@
+#ifndef _LINUX_MTD_PARTT_H
+#define _LINUX_MTD_PARTT_H
+
+#include <linux/types.h>
+
+#define PARTT_MAGIC 0x0054544a /* "\0TTJ" */
+
+#define TABLE_ENTRY_SIZE (32)
+#define TABLE_NO_ENTRIES (16)
+#define TABLE_SIZE ((TABLE_NO_ENTRIES)*(TABLE_ENTRY_SIZE))
+#define NAME_MAX_LEN ((TABLE_ENTRY_SIZE) - 3*sizeof(__u32))
+
+#ifndef PARTT_NODEBUG
+#	ifdef __KERNEL__
+#		define DOUT(fmt, args...) printk(KERN_CRIT "partt: " fmt, ## args)
+#	endif
+#endif
+
+struct partt_entry {
+	char name[NAME_MAX_LEN]; /* name is also padding */
+	__u32 size;
+	__u32 offset;
+	__u32 mask_flags; 
+};
+
+typedef struct partt_entry partt_table[TABLE_NO_ENTRIES];
+
+#endif
diff -Naur mtd.orig/util/Makefile mtd/util/Makefile
--- mtd.orig/util/Makefile	Thu Sep  6 00:00:07 2001
+++ mtd/util/Makefile	Tue Sep 25 20:15:37 2001
@@ -7,7 +7,7 @@
 
 TARGETS = ftl_format erase eraseall nftldump nanddump doc_loadbios \
 nftl_format mkfs.jffs ftl_check nandtest nandwrite mkfs.jffs2 lock unlock \
-einfo mtd_debug fcp jffs2reader
+einfo mtd_debug fcp jffs2reader mkpartt
 
 SYMLINKS = crc32.h crc32.c compr_rtime.c compr_rubin.c compr.c pushpull.c pushpull.h histo_mips.h compr_rubin.h
 
diff -Naur mtd.orig/util/Makefile.am mtd/util/Makefile.am
--- mtd.orig/util/Makefile.am	Tue Jun 26 10:26:53 2001
+++ mtd/util/Makefile.am	Tue Sep 25 20:15:48 2001
@@ -2,7 +2,7 @@
 
 sbin_PROGRAMS = ftl_format erase eraseall nftldump nanddump doc_loadbios \
                nftl_format mkfs.jffs ftl_check nandtest nandwrite mkfs.jffs2 \
-	       lock unlock einfo mtd_debug fcp
+	       lock unlock einfo mtd_debug fcp mkpartt
 
 CFLAGS = -O2 -Wall
 INCLUDES = -I at CONFIG_KERNELDIR@/include -I at CONFIG_KERNELDIR@/fs/jffs2
diff -Naur mtd.orig/util/mkfs.jffs2.c mtd/util/mkfs.jffs2.c
--- mtd.orig/util/mkfs.jffs2.c	Mon Sep 10 00:00:15 2001
+++ mtd/util/mkfs.jffs2.c	Tue Sep 25 20:12:28 2001
@@ -22,7 +22,7 @@
 
 //#define DMALLOC
 //#define debug_msg	error_msg
-#define debug_msg(...)	{ }
+#define debug_msg(args...)	{ }
 
 
 #define _GNU_SOURCE
diff -Naur mtd.orig/util/mkpartt.c mtd/util/mkpartt.c
--- mtd.orig/util/mkpartt.c	Thu Jan  1 01:00:00 1970
+++ mtd/util/mkpartt.c	Tue Sep 25 20:15:58 2001
@@ -0,0 +1,122 @@
+/*
+ * TODO: 
+ * Always write partition table in big endian format
+ * Allow for multiple partition tables
+ */
+#include <stdio.h>
+#include <unistd.h>
+#define _GNU_SOURCE
+#include <getopt.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "/usr/src/linux/include/linux/mtd/ibmpartt.h"
+
+#define MAX_BUF (4096)
+
+static int cross_endian = 0;
+
+void print_help ()
+{
+	printf ("\n"
+			"mkpartt\n"
+			"creates partt style flash partition tables\n"
+			"\n"
+			"Options:\n"
+			" -h --help          print this help\n"
+			" -c --cross-endian  write partition table in big enian on little endian machines or vice versa\n"
+			"\n"
+			);
+}
+
+void x_order_32 (__u32 *old32)
+{
+	__u32 new32;
+	__u8 *new8 = (__u8*)&new32;
+	__u8 *old8 = (__u8*)old32;
+	new8[0] = old8[3];
+	new8[1] = old8[2];
+	new8[2] = old8[1];
+	new8[3] = old8[0];
+	*old32 = new32;
+}
+
+int cross_endianize (partt_table *table)
+{
+	int i;
+	for (i=0; i<TABLE_NO_ENTRIES; i++) {
+		x_order_32 (&(table[0][i].size));
+		x_order_32 (&(table[0][i].offset));
+		x_order_32 (&(table[0][i].mask_flags));
+	}
+	return 0;
+}
+
+int parse_table (FILE *infile, FILE *outfile)
+{
+	partt_table table;
+	int entry;
+	char *buf;
+	int ret = 0;
+
+	__bzero ((char*)&table, sizeof(table));
+
+	buf = malloc (MAX_BUF); /* FIXME */
+	entry = 0;
+	while (fgets (buf, MAX_BUF, infile) && entry<TABLE_NO_ENTRIES-1) {
+		int columns;
+		if (buf[0] == '#')
+			continue;
+		columns = sscanf (buf, " %20s %x %x %x", /* FIXME: Replace 20 with NAME_MAX_LEN */
+			       	table[entry].name,
+			       	&(table[entry].size),
+			       	&(table[entry].offset),
+			       	&(table[entry].mask_flags));
+		if (columns < 3) {
+			ret = -EIO;
+			goto out;
+		}
+		if (columns == 3) /* mask_flags may be left empty */
+			table[entry].mask_flags = 0;
+		entry++;
+	}
+	__bzero (&(table[entry]), TABLE_ENTRY_SIZE);
+	table[TABLE_NO_ENTRIES-1].mask_flags = PARTT_MAGIC;
+
+	if (cross_endian)
+		cross_endianize (&table);
+
+	if (!fwrite (&table, TABLE_SIZE, 1, outfile))
+		ret = -EIO;
+out:
+	free (buf);
+	return ret;
+}
+
+int main (int argc, char** argv)
+{
+	while (1) {
+		int c, option_index;
+		char short_options[] = "ch";
+		static struct option long_options [] = {
+			{"cross-endian", 0, 0, 'c'},
+			{"help", 0, 0, 'h'},
+			{0, 0, 0, 0} /* FIXME: Parse some useful parameters */
+		};
+                c = getopt_long(argc, argv, short_options, long_options, &option_index);
+		if (c==-1)
+			break;
+		switch (c) {
+			case 'c':
+				cross_endian = 1;
+				break;
+			case 'h':
+				print_help ();
+				return 0;
+			default: 
+				printf ("Option not implemented, contact developer\n");
+		}
+	}
+	return parse_table (stdin, stdout);
+}


More information about the linux-mtd mailing list