qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "andrzej zaborowski" <balrog@zabor.org>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH] NAND image conversion utility for the Spitz machines.
Date: Fri, 16 Mar 2007 23:17:15 +0100	[thread overview]
Message-ID: <fb249edb0703161517u165dd8bbve12c7523d808d433@mail.gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 570 bytes --]

This is a small program that converts NAND Flash images from raw to
the format used by hw/nand.c. I don't know if it should be included in
qemu (it's handy for me to have it included). What it does:
 - takes on standard input flash rootfs partition images generated
from some OpenEmbedded-based build systems (i.e. Poky or OpenZaurus)
 - offsets the image to the rootfs partition's start,
 - inserts proper jffs2 markers in the Out-Of-Band areas in the flash
so that Linux doesn't protest. Also inserts empty block jffs2 markers
and ECC where necessary.

Cheers,
Andrew

[-- Attachment #2: 0017-NAND-Flash-image-conversion-utility-for-the-Spitz-machines.txt --]
[-- Type: text/plain, Size: 12269 bytes --]

From a6fb0b70ec61a3d37293a895f8d31262a12cbcb8 Mon Sep 17 00:00:00 2001
From: Andrzej Zaborowski <balrog@zabor.org>
Date: Fri, 16 Mar 2007 17:36:30 +0100
Subject: [PATCH] NAND Flash image conversion utility for the Spitz machines.

---
 Makefile    |   15 +++-
 raw2flash.c |  370 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 384 insertions(+), 1 deletions(-)

diff --git a/Makefile b/Makefile
index b6d7b1f..daac31a 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ BASE_CFLAGS += -mcpu=ultrasparc
 endif
 CPPFLAGS += -I. -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
 LIBS=
-TOOLS=qemu-img$(EXESUF)
+TOOLS=qemu-img$(EXESUF) raw2flash$(EXESUF) flash2raw$(EXESUF)
 ifdef CONFIG_STATIC
 BASE_LDFLAGS += -static
 endif
@@ -23,6 +23,7 @@ DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1
 else
 DOCS=
 endif
+MODELS=spitz akita borzoi terrier
 
 ifndef CONFIG_DARWIN
 ifndef CONFIG_WIN32
@@ -43,6 +44,13 @@ qemu-img$(EXESUF): qemu-img.c cutils.c block.c block-raw.c block-cow.c block-qco
 dyngen$(EXESUF): dyngen.c
 	$(HOST_CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -o $@ $^
 
+raw2flash$(EXESUF) flash2raw$(EXESUF): raw2flash.c
+	$(CC) -D$@ $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^
+	for m in $(MODELS); do \
+		[ -e $@.$$m$(EXESUF) ] || \
+		ln -s $@ $@.$$m$(EXESUF) ; \
+	done
+
 clean:
 # avoid old build problems by removing potentially incorrect old files
 	rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h 
@@ -89,6 +97,11 @@ endif
 	for d in $(TARGET_DIRS); do \
 	$(MAKE) -C $$d $@ || exit 1 ; \
         done
+	for m in $(MODELS); do \
+		for n in *.$$m; do \
+			$(INSTALL) $$n "$(DESTDIR)$(bindir)"; \
+		done; \
+	done
 
 # various test targets
 test speed test2: all
diff --git a/raw2flash.c b/raw2flash.c
new file mode 100644
index 0000000..19faf62
--- /dev/null
+++ b/raw2flash.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2006 OpenedHand Ltd.
+ *
+ * This file is licensed under GNU GPL v2.
+ */
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+#define TFR(_)		_
+#define VERBOSE
+#define PBAR_LEN	40
+
+#define PARTITION_START	0x00700000
+
+static const int ecc_pos8[] = {
+	0x0, 0x1, 0x2,
+};
+
+static const int ecc_pos16[] = {
+	0x0, 0x1, 0x2, 0x3, 0x6, 0x7,
+};
+
+static const int ecc_pos64[] = {
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+};
+
+static const int ecc_akita[] = {
+	0x05, 0x01, 0x02, 0x03, 0x06, 0x07, 0x15, 0x11,
+	0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23,
+	0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37,
+};
+
+struct jffs_marker_s {
+	int pos;
+	uint8_t value;
+};
+
+static const struct jffs_marker_s free_pos8[] = {
+	{ 0x03, 0xff }, { 0x04, 0xff }, { 0x06, 0x85 }, { 0x07, 0x19 },
+	{ -1 },
+};
+
+static const struct jffs_marker_s free_pos16[] = {
+	{ 0x08, 0x85 }, { 0x09, 0x19 }, { 0x0a, 0x03 }, { 0x0b, 0x20 },
+	{ 0x0c, 0x08 }, { 0x0d, 0x00 }, { 0x0e, 0x00 }, { 0x0f, 0x00 },
+	{ -1 },
+};
+
+static const struct jffs_marker_s free_pos64[] = {
+	{ 0x02, 0xff }, { 0x03, 0xff }, { 0x04, 0xff }, { 0x05, 0xff },
+	{ 0x06, 0xff }, { 0x07, 0xff }, { 0x08, 0xff }, { 0x09, 0xff },
+	{ 0x0a, 0xff }, { 0x0b, 0xff }, { 0x0c, 0xff }, { 0x0d, 0xff },
+	{ 0x0e, 0xff }, { 0x0f, 0xff }, { 0x10, 0x85 }, { 0x11, 0x19 },
+	{ 0x12, 0x03 }, { 0x13, 0x20 }, { 0x14, 0x08 }, { 0x15, 0x00 },
+	{ 0x16, 0x00 }, { 0x17, 0x00 }, { 0x18, 0xff }, { 0x19, 0xff },
+	{ 0x1a, 0xff }, { 0x1b, 0xff }, { 0x1c, 0xff }, { 0x1d, 0xff },
+	{ 0x1e, 0xff }, { 0x1f, 0xff }, { 0x20, 0xff }, { 0x21, 0xff },
+	{ 0x22, 0xff }, { 0x23, 0xff }, { 0x24, 0xff }, { 0x25, 0xff },
+	{ 0x26, 0xff }, { 0x27, 0xff },
+	{ -1 },
+};
+
+static const struct jffs_marker_s free_akita[] = {
+	{ 0x08, 0x85 }, { 0x09, 0x19 }, { 0x0a, 0x03 }, { 0x0b, 0x20 },
+	{ 0x0c, 0x08 }, { 0x0d, 0x00 }, { 0x0e, 0x00 }, { 0x0f, 0x00 },
+	{ 0x10, 0xff },
+	{ -1 },
+};
+
+#define LEN(array)	(sizeof(array) / sizeof(*array))
+
+static const struct ecc_style_s {
+	int page_size;
+	int oob_size;
+	int eccbytes;
+	int eccsize;
+	const int *eccpos;
+	int romsize;
+	const struct jffs_marker_s *freepos;
+} spitz = {
+	0x200, 0x10, 0x100, LEN(ecc_pos16), ecc_pos16, 0x01000000, free_pos16
+}, akita = {
+	0x800, 0x40, 0x100, LEN(ecc_akita), ecc_akita, 0x08000000, free_akita
+}, borzoi = {
+	0x800, 0x40, 0x100, LEN(ecc_akita), ecc_akita, 0x08000000, free_akita
+}, terrier = {
+	0x800, 0x40, 0x100, LEN(ecc_akita), ecc_akita, 0x08000000, free_akita
+};
+
+struct ecc_state_s {
+	int count;
+	uint8_t cp;
+	uint8_t lp[2];
+	const struct ecc_style_s *style;
+};
+
+#ifndef flash2raw
+/*
+ * Pre-calculated 256-way 1 byte column parity.  Table borrowed from Linux.
+ */
+static const uint8_t ecc_precalc_table[] = {
+	0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
+	0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+	0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
+	0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+	0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
+	0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+	0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
+	0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+	0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
+	0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+	0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
+	0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+	0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
+	0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+	0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
+	0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+	0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
+	0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+	0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
+	0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+	0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
+	0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+	0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
+	0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+	0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
+	0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+	0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
+	0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+	0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
+	0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+	0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
+	0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+};
+
+/* Update ECC parity count */
+static inline uint8_t ecc_digest(struct ecc_state_s *s, uint8_t sample) {
+	uint8_t idx = ecc_precalc_table[sample];
+
+	s->cp ^= idx & 0x3f;
+	if (idx & 0x40) {
+		s->lp[0] ^= ~(s->count & 0xff);
+		s->lp[1] ^= s->count & 0xff;
+	}
+	s->count ++;
+
+	return sample;
+}
+
+static void buffer_digest(struct ecc_state_s *ecc,
+		const uint8_t *buf, uint8_t *out) {
+	int i, lp_a[2];
+
+	ecc->lp[0] = 0x00;
+	ecc->lp[1] = 0x00;
+	ecc->cp = 0x00;
+	ecc->count = 0;
+	for (i = 0; i < ecc->style->eccbytes; i ++)
+		ecc_digest(ecc, buf[i]);
+
+# define BSHR(byte, from, to)	((ecc->lp[byte] >> (from - to)) & (1 << to))
+	lp_a[0] =
+		BSHR(0, 4, 0) | BSHR(0, 5, 2) |
+		BSHR(0, 6, 4) | BSHR(0, 7, 6) |
+		BSHR(1, 4, 1) | BSHR(1, 5, 3) |
+		BSHR(1, 6, 5) | BSHR(1, 7, 7);
+
+# define BSHL(byte, from, to)	((ecc->lp[byte] << (to - from)) & (1 << to))
+	lp_a[1] =
+		BSHL(0, 0, 0) | BSHL(0, 1, 2) |
+		BSHL(0, 2, 4) | BSHL(0, 3, 6) |
+		BSHL(1, 0, 1) | BSHL(1, 1, 3) |
+		BSHL(1, 2, 5) | BSHL(1, 3, 7);
+
+	out[0] = ~lp_a[1];
+	out[1] = ~lp_a[0];
+	out[2] = (~ecc->cp << 2) | 0x03;
+}
+
+static void jffs2_format(const struct ecc_state_s *ecc, uint8_t oob[]) {
+	const struct jffs_marker_s *byte;
+	for (byte = ecc->style->freepos; byte->pos >= 0; byte ++)
+		oob[byte->pos] = byte->value;
+}
+
+static void buffer_fill(const struct ecc_state_s *ecc, uint8_t buffer[],
+		int *len, int *partition, int count, uint8_t jffs_buffer[]) {
+	int ret;
+
+	switch (*partition) {
+	case 0:
+		if (count < PARTITION_START) {
+			memcpy(buffer, jffs_buffer + count,
+					ecc->style->eccbytes);
+			*len = ecc->style->eccbytes;
+			break;
+		}
+		*partition = 1;
+	case 1:
+		if (count - PARTITION_START < PARTITION_START) {
+			memcpy(buffer, jffs_buffer + count - PARTITION_START,
+					ecc->style->eccbytes);
+			*len = ecc->style->eccbytes;
+			break;
+		}
+
+		while (*len < ecc->style->eccbytes) {
+			ret = TFR(read(0, buffer + *len, 0x800 - *len));
+			if (ret <= 0)
+				break;
+			*len += ret;
+		}
+
+		if (*len == 0)
+			*partition = 2;
+		else if (*len < ecc->style->eccbytes) {
+			fprintf(stderr, "\nWarning: %i stray bytes\n", *len);
+			memset(buffer + *len, 0xff,
+					ecc->style->eccbytes - *len);
+			*len = ecc->style->eccbytes;
+			break;
+		} else
+			break;
+	case 2:
+		memset(buffer, 0xff, ecc->style->eccbytes);
+		*len = ecc->style->eccbytes;
+		break;
+	}
+}
+
+int main(int argc, char *argv[], char *envp[]) {
+	struct ecc_state_s ecc;
+	uint8_t buffer[0x1000], ecc_payload[0x40], regs[3], *jffs;
+	int ret, len, eccbyte, count, partition;
+
+	/* Check if we're called by "raw2flash.spitz" or similar */
+	len = strlen(argv[0]);
+	if (!strcasecmp(argv[0] + len - 5, "akita"))
+		ecc.style = &akita;
+	else if (!strcasecmp(argv[0] + len - 6, "borzoi"))
+		ecc.style = &borzoi;
+	else if (!strcasecmp(argv[0] + len - 7, "terrier"))
+		ecc.style = &terrier;
+	else
+		ecc.style = &spitz;
+
+# ifdef VERBOSE
+	fprintf(stderr, "[");
+# endif
+
+	/* Skip first 10 bytes */
+	TFR(read(0, buffer, 0x10));
+
+	len = 0;
+	jffs = (uint8_t *) malloc(PARTITION_START);
+	while (len < PARTITION_START) {
+		ret = TFR(read(0, jffs + len, PARTITION_START - len));
+		if (ret <= 0)
+			break;
+		len += ret;
+	}
+
+	/* Convert data from stdin */
+	partition = len = eccbyte = count = 0;
+	memset(ecc_payload, 0xff, ecc.style->oob_size);
+	jffs2_format(&ecc, ecc_payload);
+	while (count < ecc.style->romsize) {
+		buffer_fill(&ecc, buffer, &len, &partition, count, jffs);
+		buffer_digest(&ecc, buffer, regs);
+
+		ecc_payload[ecc.style->eccpos[eccbyte ++]] = regs[0];
+		ecc_payload[ecc.style->eccpos[eccbyte ++]] = regs[1];
+		ecc_payload[ecc.style->eccpos[eccbyte ++]] = regs[2];
+
+		TFR(write(1, buffer, ecc.style->eccbytes));
+		count += ecc.style->eccbytes;
+		len -= ecc.style->eccbytes;
+		memmove(buffer, buffer + ecc.style->eccbytes, len);
+
+		if (eccbyte >= ecc.style->eccsize) {
+			TFR(write(1, ecc_payload, ecc.style->oob_size));
+			eccbyte = 0;
+			memset(ecc_payload, 0xff, ecc.style->oob_size);
+			if (partition < 2)
+				jffs2_format(&ecc, ecc_payload);
+		}
+
+# ifdef VERBOSE
+		if (count * PBAR_LEN / ecc.style->romsize >
+				(count - ecc.style->eccbytes) *
+				PBAR_LEN / ecc.style->romsize)
+			fprintf(stderr, "#");
+# endif
+	}
+
+# ifdef VERBOSE
+	fprintf(stderr, "]\n");
+# endif
+	free(jffs);
+	return 0;
+}
+#else
+int main(int argc, char *argv[], char *envp[]) {
+	struct ecc_state_s ecc;
+	uint8_t buffer[0x1000];
+	int ret, len, count;
+
+	/* Check if we're called by "flash2raw.spitz" or similar */
+	len = strlen(argv[0]);
+	if (!strcasecmp(argv[0] + len - 5, "akita"))
+		ecc.style = &akita;
+	else if (!strcasecmp(argv[0] + len - 6, "borzoi"))
+		ecc.style = &borzoi;
+	else if (!strcasecmp(argv[0] + len - 7, "terrier"))
+		ecc.style = &terrier;
+	else
+		ecc.style = &spitz;
+
+# ifdef VERBOSE
+	fprintf(stderr, "[");
+# endif
+
+	/* Convert data from stdin */
+	count = 0;
+	while (count < ecc.style->romsize) {
+		len = 0;
+		while (len < ecc.style->page_size) {
+			ret = TFR(read(0, buffer + len,
+						ecc.style->page_size - len));
+			if (ret <= 0)
+				break;
+			len += ret;
+		}
+		if (len == 0)
+			break;
+		if (len < ecc.style->page_size) {
+			fprintf(stderr, "\nWarning: %i stray bytes\n", len);
+		}
+
+		TFR(write(1, buffer, ecc.style->page_size));
+
+		count += len;
+		len = 0;
+		while (len < ecc.style->oob_size) {
+			ret = TFR(read(0, buffer, ecc.style->oob_size - len));
+			if (ret <= 0)
+				break;
+			len += ret;
+		}
+
+# ifdef VERBOSE
+		if (count * PBAR_LEN / ecc.style->romsize >
+				(count - ecc.style->page_size) *
+				PBAR_LEN / ecc.style->romsize)
+			fprintf(stderr, "#");
+# endif
+	}
+
+# ifdef VERBOSE
+	fprintf(stderr, "]\n");
+# endif
+	return 0;
+}
+#endif
-- 
1.4.4.3


                 reply	other threads:[~2007-03-16 22:18 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=fb249edb0703161517u165dd8bbve12c7523d808d433@mail.gmail.com \
    --to=balrog@zabor.org \
    --cc=balrogg@gmail.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).