diff options
Diffstat (limited to 'meta/recipes-devtools/qemu/qemu-helper/raw2flash.c')
-rw-r--r-- | meta/recipes-devtools/qemu/qemu-helper/raw2flash.c | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/meta/recipes-devtools/qemu/qemu-helper/raw2flash.c b/meta/recipes-devtools/qemu/qemu-helper/raw2flash.c new file mode 100644 index 00000000000..19faf629b9f --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu-helper/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 |