blob: 19faf629b9faa0b1f45f9ac597d7c2f48d1b60c2 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001/*
2 * Copyright (c) 2006 OpenedHand Ltd.
3 *
4 * This file is licensed under GNU GPL v2.
5 */
6#include <string.h>
7#include <unistd.h>
8#include <stdint.h>
9#include <stdio.h>
10#include <sys/types.h>
11#include <stdlib.h>
12
13#define TFR(_) _
14#define VERBOSE
15#define PBAR_LEN 40
16
17#define PARTITION_START 0x00700000
18
19static const int ecc_pos8[] = {
20 0x0, 0x1, 0x2,
21};
22
23static const int ecc_pos16[] = {
24 0x0, 0x1, 0x2, 0x3, 0x6, 0x7,
25};
26
27static const int ecc_pos64[] = {
28 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
29 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
30 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
31};
32
33static const int ecc_akita[] = {
34 0x05, 0x01, 0x02, 0x03, 0x06, 0x07, 0x15, 0x11,
35 0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23,
36 0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37,
37};
38
39struct jffs_marker_s {
40 int pos;
41 uint8_t value;
42};
43
44static const struct jffs_marker_s free_pos8[] = {
45 { 0x03, 0xff }, { 0x04, 0xff }, { 0x06, 0x85 }, { 0x07, 0x19 },
46 { -1 },
47};
48
49static const struct jffs_marker_s free_pos16[] = {
50 { 0x08, 0x85 }, { 0x09, 0x19 }, { 0x0a, 0x03 }, { 0x0b, 0x20 },
51 { 0x0c, 0x08 }, { 0x0d, 0x00 }, { 0x0e, 0x00 }, { 0x0f, 0x00 },
52 { -1 },
53};
54
55static const struct jffs_marker_s free_pos64[] = {
56 { 0x02, 0xff }, { 0x03, 0xff }, { 0x04, 0xff }, { 0x05, 0xff },
57 { 0x06, 0xff }, { 0x07, 0xff }, { 0x08, 0xff }, { 0x09, 0xff },
58 { 0x0a, 0xff }, { 0x0b, 0xff }, { 0x0c, 0xff }, { 0x0d, 0xff },
59 { 0x0e, 0xff }, { 0x0f, 0xff }, { 0x10, 0x85 }, { 0x11, 0x19 },
60 { 0x12, 0x03 }, { 0x13, 0x20 }, { 0x14, 0x08 }, { 0x15, 0x00 },
61 { 0x16, 0x00 }, { 0x17, 0x00 }, { 0x18, 0xff }, { 0x19, 0xff },
62 { 0x1a, 0xff }, { 0x1b, 0xff }, { 0x1c, 0xff }, { 0x1d, 0xff },
63 { 0x1e, 0xff }, { 0x1f, 0xff }, { 0x20, 0xff }, { 0x21, 0xff },
64 { 0x22, 0xff }, { 0x23, 0xff }, { 0x24, 0xff }, { 0x25, 0xff },
65 { 0x26, 0xff }, { 0x27, 0xff },
66 { -1 },
67};
68
69static const struct jffs_marker_s free_akita[] = {
70 { 0x08, 0x85 }, { 0x09, 0x19 }, { 0x0a, 0x03 }, { 0x0b, 0x20 },
71 { 0x0c, 0x08 }, { 0x0d, 0x00 }, { 0x0e, 0x00 }, { 0x0f, 0x00 },
72 { 0x10, 0xff },
73 { -1 },
74};
75
76#define LEN(array) (sizeof(array) / sizeof(*array))
77
78static const struct ecc_style_s {
79 int page_size;
80 int oob_size;
81 int eccbytes;
82 int eccsize;
83 const int *eccpos;
84 int romsize;
85 const struct jffs_marker_s *freepos;
86} spitz = {
87 0x200, 0x10, 0x100, LEN(ecc_pos16), ecc_pos16, 0x01000000, free_pos16
88}, akita = {
89 0x800, 0x40, 0x100, LEN(ecc_akita), ecc_akita, 0x08000000, free_akita
90}, borzoi = {
91 0x800, 0x40, 0x100, LEN(ecc_akita), ecc_akita, 0x08000000, free_akita
92}, terrier = {
93 0x800, 0x40, 0x100, LEN(ecc_akita), ecc_akita, 0x08000000, free_akita
94};
95
96struct ecc_state_s {
97 int count;
98 uint8_t cp;
99 uint8_t lp[2];
100 const struct ecc_style_s *style;
101};
102
103#ifndef flash2raw
104/*
105 * Pre-calculated 256-way 1 byte column parity. Table borrowed from Linux.
106 */
107static const uint8_t ecc_precalc_table[] = {
108 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
109 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
110 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
111 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
112 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
113 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
114 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
115 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
116 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
117 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
118 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
119 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
120 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
121 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
122 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
123 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
124 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
125 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
126 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
127 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
128 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
129 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
130 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
131 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
132 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
133 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
134 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
135 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
136 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
137 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
138 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
139 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
140};
141
142/* Update ECC parity count */
143static inline uint8_t ecc_digest(struct ecc_state_s *s, uint8_t sample) {
144 uint8_t idx = ecc_precalc_table[sample];
145
146 s->cp ^= idx & 0x3f;
147 if (idx & 0x40) {
148 s->lp[0] ^= ~(s->count & 0xff);
149 s->lp[1] ^= s->count & 0xff;
150 }
151 s->count ++;
152
153 return sample;
154}
155
156static void buffer_digest(struct ecc_state_s *ecc,
157 const uint8_t *buf, uint8_t *out) {
158 int i, lp_a[2];
159
160 ecc->lp[0] = 0x00;
161 ecc->lp[1] = 0x00;
162 ecc->cp = 0x00;
163 ecc->count = 0;
164 for (i = 0; i < ecc->style->eccbytes; i ++)
165 ecc_digest(ecc, buf[i]);
166
167# define BSHR(byte, from, to) ((ecc->lp[byte] >> (from - to)) & (1 << to))
168 lp_a[0] =
169 BSHR(0, 4, 0) | BSHR(0, 5, 2) |
170 BSHR(0, 6, 4) | BSHR(0, 7, 6) |
171 BSHR(1, 4, 1) | BSHR(1, 5, 3) |
172 BSHR(1, 6, 5) | BSHR(1, 7, 7);
173
174# define BSHL(byte, from, to) ((ecc->lp[byte] << (to - from)) & (1 << to))
175 lp_a[1] =
176 BSHL(0, 0, 0) | BSHL(0, 1, 2) |
177 BSHL(0, 2, 4) | BSHL(0, 3, 6) |
178 BSHL(1, 0, 1) | BSHL(1, 1, 3) |
179 BSHL(1, 2, 5) | BSHL(1, 3, 7);
180
181 out[0] = ~lp_a[1];
182 out[1] = ~lp_a[0];
183 out[2] = (~ecc->cp << 2) | 0x03;
184}
185
186static void jffs2_format(const struct ecc_state_s *ecc, uint8_t oob[]) {
187 const struct jffs_marker_s *byte;
188 for (byte = ecc->style->freepos; byte->pos >= 0; byte ++)
189 oob[byte->pos] = byte->value;
190}
191
192static void buffer_fill(const struct ecc_state_s *ecc, uint8_t buffer[],
193 int *len, int *partition, int count, uint8_t jffs_buffer[]) {
194 int ret;
195
196 switch (*partition) {
197 case 0:
198 if (count < PARTITION_START) {
199 memcpy(buffer, jffs_buffer + count,
200 ecc->style->eccbytes);
201 *len = ecc->style->eccbytes;
202 break;
203 }
204 *partition = 1;
205 case 1:
206 if (count - PARTITION_START < PARTITION_START) {
207 memcpy(buffer, jffs_buffer + count - PARTITION_START,
208 ecc->style->eccbytes);
209 *len = ecc->style->eccbytes;
210 break;
211 }
212
213 while (*len < ecc->style->eccbytes) {
214 ret = TFR(read(0, buffer + *len, 0x800 - *len));
215 if (ret <= 0)
216 break;
217 *len += ret;
218 }
219
220 if (*len == 0)
221 *partition = 2;
222 else if (*len < ecc->style->eccbytes) {
223 fprintf(stderr, "\nWarning: %i stray bytes\n", *len);
224 memset(buffer + *len, 0xff,
225 ecc->style->eccbytes - *len);
226 *len = ecc->style->eccbytes;
227 break;
228 } else
229 break;
230 case 2:
231 memset(buffer, 0xff, ecc->style->eccbytes);
232 *len = ecc->style->eccbytes;
233 break;
234 }
235}
236
237int main(int argc, char *argv[], char *envp[]) {
238 struct ecc_state_s ecc;
239 uint8_t buffer[0x1000], ecc_payload[0x40], regs[3], *jffs;
240 int ret, len, eccbyte, count, partition;
241
242 /* Check if we're called by "raw2flash.spitz" or similar */
243 len = strlen(argv[0]);
244 if (!strcasecmp(argv[0] + len - 5, "akita"))
245 ecc.style = &akita;
246 else if (!strcasecmp(argv[0] + len - 6, "borzoi"))
247 ecc.style = &borzoi;
248 else if (!strcasecmp(argv[0] + len - 7, "terrier"))
249 ecc.style = &terrier;
250 else
251 ecc.style = &spitz;
252
253# ifdef VERBOSE
254 fprintf(stderr, "[");
255# endif
256
257 /* Skip first 10 bytes */
258 TFR(read(0, buffer, 0x10));
259
260 len = 0;
261 jffs = (uint8_t *) malloc(PARTITION_START);
262 while (len < PARTITION_START) {
263 ret = TFR(read(0, jffs + len, PARTITION_START - len));
264 if (ret <= 0)
265 break;
266 len += ret;
267 }
268
269 /* Convert data from stdin */
270 partition = len = eccbyte = count = 0;
271 memset(ecc_payload, 0xff, ecc.style->oob_size);
272 jffs2_format(&ecc, ecc_payload);
273 while (count < ecc.style->romsize) {
274 buffer_fill(&ecc, buffer, &len, &partition, count, jffs);
275 buffer_digest(&ecc, buffer, regs);
276
277 ecc_payload[ecc.style->eccpos[eccbyte ++]] = regs[0];
278 ecc_payload[ecc.style->eccpos[eccbyte ++]] = regs[1];
279 ecc_payload[ecc.style->eccpos[eccbyte ++]] = regs[2];
280
281 TFR(write(1, buffer, ecc.style->eccbytes));
282 count += ecc.style->eccbytes;
283 len -= ecc.style->eccbytes;
284 memmove(buffer, buffer + ecc.style->eccbytes, len);
285
286 if (eccbyte >= ecc.style->eccsize) {
287 TFR(write(1, ecc_payload, ecc.style->oob_size));
288 eccbyte = 0;
289 memset(ecc_payload, 0xff, ecc.style->oob_size);
290 if (partition < 2)
291 jffs2_format(&ecc, ecc_payload);
292 }
293
294# ifdef VERBOSE
295 if (count * PBAR_LEN / ecc.style->romsize >
296 (count - ecc.style->eccbytes) *
297 PBAR_LEN / ecc.style->romsize)
298 fprintf(stderr, "#");
299# endif
300 }
301
302# ifdef VERBOSE
303 fprintf(stderr, "]\n");
304# endif
305 free(jffs);
306 return 0;
307}
308#else
309int main(int argc, char *argv[], char *envp[]) {
310 struct ecc_state_s ecc;
311 uint8_t buffer[0x1000];
312 int ret, len, count;
313
314 /* Check if we're called by "flash2raw.spitz" or similar */
315 len = strlen(argv[0]);
316 if (!strcasecmp(argv[0] + len - 5, "akita"))
317 ecc.style = &akita;
318 else if (!strcasecmp(argv[0] + len - 6, "borzoi"))
319 ecc.style = &borzoi;
320 else if (!strcasecmp(argv[0] + len - 7, "terrier"))
321 ecc.style = &terrier;
322 else
323 ecc.style = &spitz;
324
325# ifdef VERBOSE
326 fprintf(stderr, "[");
327# endif
328
329 /* Convert data from stdin */
330 count = 0;
331 while (count < ecc.style->romsize) {
332 len = 0;
333 while (len < ecc.style->page_size) {
334 ret = TFR(read(0, buffer + len,
335 ecc.style->page_size - len));
336 if (ret <= 0)
337 break;
338 len += ret;
339 }
340 if (len == 0)
341 break;
342 if (len < ecc.style->page_size) {
343 fprintf(stderr, "\nWarning: %i stray bytes\n", len);
344 }
345
346 TFR(write(1, buffer, ecc.style->page_size));
347
348 count += len;
349 len = 0;
350 while (len < ecc.style->oob_size) {
351 ret = TFR(read(0, buffer, ecc.style->oob_size - len));
352 if (ret <= 0)
353 break;
354 len += ret;
355 }
356
357# ifdef VERBOSE
358 if (count * PBAR_LEN / ecc.style->romsize >
359 (count - ecc.style->page_size) *
360 PBAR_LEN / ecc.style->romsize)
361 fprintf(stderr, "#");
362# endif
363 }
364
365# ifdef VERBOSE
366 fprintf(stderr, "]\n");
367# endif
368 return 0;
369}
370#endif