/* * Copyright (c) 2006 OpenedHand Ltd. * * This file is licensed under GNU GPL v2. */ #include #include #include #include #include #include #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