blob: a68950e40d04af0a2ed33ca72d6293964c155ed8 [file] [log] [blame]
Dees_Troy51a0e822012-09-05 15:24:24 -04001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <errno.h>
18#include <fcntl.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <unistd.h>
23#include <sys/ioctl.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <limits.h>
27
28#include "cutils/log.h"
29
30#include <mtd/mtd-user.h>
31
32#include "mtdutils.h"
33
Sergey 'Jin' Bostandzhyan80a90ed2013-01-04 02:29:03 +010034#ifdef RK3066
35 #include "rk30hack.h"
36#endif
37
Dees_Troy51a0e822012-09-05 15:24:24 -040038typedef struct BmlOverMtdReadContext {
39 const MtdPartition *partition;
40 char *buffer;
41 size_t consumed;
42 int fd;
43} BmlOverMtdReadContext;
44
45typedef struct BmlOverMtdWriteContext {
46 const MtdPartition *partition;
47 char *buffer;
48 size_t stored;
49 int fd;
50
51 off_t* bad_block_offsets;
52 int bad_block_alloc;
53 int bad_block_count;
54} BmlOverMtdWriteContext;
55
56
57static BmlOverMtdReadContext *bml_over_mtd_read_partition(const MtdPartition *partition)
58{
59 BmlOverMtdReadContext *ctx = (BmlOverMtdReadContext*) malloc(sizeof(BmlOverMtdReadContext));
60 if (ctx == NULL) return NULL;
61
62 ctx->buffer = malloc(partition->erase_size);
63 if (ctx->buffer == NULL) {
64 free(ctx);
65 return NULL;
66 }
67
68 char mtddevname[32];
69 sprintf(mtddevname, "/dev/mtd/mtd%d", partition->device_index);
70 ctx->fd = open(mtddevname, O_RDONLY);
71 if (ctx->fd < 0) {
72 free(ctx);
73 free(ctx->buffer);
74 return NULL;
75 }
76
77 ctx->partition = partition;
78 ctx->consumed = partition->erase_size;
79 return ctx;
80}
81
82static void bml_over_mtd_read_close(BmlOverMtdReadContext *ctx)
83{
84 close(ctx->fd);
85 free(ctx->buffer);
86 free(ctx);
87}
88
89static BmlOverMtdWriteContext *bml_over_mtd_write_partition(const MtdPartition *partition)
90{
91 BmlOverMtdWriteContext *ctx = (BmlOverMtdWriteContext*) malloc(sizeof(BmlOverMtdWriteContext));
92 if (ctx == NULL) return NULL;
93
94 ctx->bad_block_offsets = NULL;
95 ctx->bad_block_alloc = 0;
96 ctx->bad_block_count = 0;
97
98 ctx->buffer = malloc(partition->erase_size);
99 if (ctx->buffer == NULL) {
100 free(ctx);
101 return NULL;
102 }
103
104 char mtddevname[32];
105 sprintf(mtddevname, "/dev/mtd/mtd%d", partition->device_index);
106 ctx->fd = open(mtddevname, O_RDWR);
107 if (ctx->fd < 0) {
108 free(ctx->buffer);
109 free(ctx);
110 return NULL;
111 }
112
113 ctx->partition = partition;
114 ctx->stored = 0;
115 return ctx;
116}
117
118static int bml_over_mtd_write_close(BmlOverMtdWriteContext *ctx)
119{
120 int r = 0;
121 if (close(ctx->fd)) r = -1;
122 free(ctx->bad_block_offsets);
123 free(ctx->buffer);
124 free(ctx);
125 return r;
126}
127
128
129#ifdef LOG_TAG
130#undef LOG_TAG
131#endif
132
133#define LOG_TAG "bml_over_mtd"
134
135#define BLOCK_SIZE 2048
136#define SPARE_SIZE (BLOCK_SIZE >> 5)
137
138#define EXIT_CODE_BAD_BLOCKS 15
139
140static int die(const char *msg, ...) {
141 int err = errno;
142 va_list args;
143 va_start(args, msg);
144 char buf[1024];
145 vsnprintf(buf, sizeof(buf), msg, args);
146 va_end(args);
147
148 if (err != 0) {
149 strlcat(buf, ": ", sizeof(buf));
150 strlcat(buf, strerror(err), sizeof(buf));
151 }
152
153 fprintf(stderr, "%s\n", buf);
154 return 1;
155}
156
157static unsigned short* CreateEmptyBlockMapping(const MtdPartition* pSrcPart)
158{
159 size_t srcTotal, srcErase, srcWrite;
160 if (mtd_partition_info(pSrcPart, &srcTotal, &srcErase, &srcWrite) != 0)
161 {
162 fprintf(stderr, "Failed to access partition.\n");
163 return NULL;
164 }
165
166 int numSrcBlocks = srcTotal/srcErase;
167
168 unsigned short* pMapping = malloc(numSrcBlocks * sizeof(unsigned short));
169 if (pMapping == NULL)
170 {
171 fprintf(stderr, "Failed to allocate block mapping memory.\n");
172 return NULL;
173 }
174 memset(pMapping, 0xFF, numSrcBlocks * sizeof(unsigned short));
175 return pMapping;
176}
177
178static const unsigned short* CreateBlockMapping(const MtdPartition* pSrcPart, int srcPartStartBlock,
179 const MtdPartition *pReservoirPart, int reservoirPartStartBlock)
180{
181 size_t srcTotal, srcErase, srcWrite;
182 if (mtd_partition_info(pSrcPart, &srcTotal, &srcErase, &srcWrite) != 0)
183 {
184 fprintf(stderr, "Failed to access partition.\n");
185 return NULL;
186 }
187
188 int numSrcBlocks = srcTotal/srcErase;
189
190 unsigned short* pMapping = malloc(numSrcBlocks * sizeof(unsigned short));
191 if (pMapping == NULL)
192 {
193 fprintf(stderr, "Failed to allocate block mapping memory.\n");
194 return NULL;
195 }
196 memset(pMapping, 0xFF, numSrcBlocks * sizeof(unsigned short));
197
198 size_t total, erase, write;
199 if (mtd_partition_info(pReservoirPart, &total, &erase, &write) != 0)
200 {
201 fprintf(stderr, "Failed to access reservoir partition.\n");
202 free(pMapping);
203 return NULL;
204 }
205
206 if (erase != srcErase || write != srcWrite)
207 {
208 fprintf(stderr, "Source partition and reservoir partition differ in size properties.\n");
209 free(pMapping);
210 return NULL;
211 }
212
213 printf("Partition info: Total %d, Erase %d, write %d\n", total, erase, write);
214
215 BmlOverMtdReadContext *readctx = bml_over_mtd_read_partition(pReservoirPart);
216 if (readctx == NULL)
217 {
218 fprintf(stderr, "Failed to open reservoir partition for reading.\n");
219 free(pMapping);
220 return NULL;
221 }
222
223 if (total < erase || total > INT_MAX)
224 {
225 fprintf(stderr, "Unsuitable reservoir partition properties.\n");
226 free(pMapping);
227 bml_over_mtd_read_close(readctx);
228 return NULL;
229 }
230
231 int foundMappingTable = 0;
232
233 int currOffset = total; //Offset *behind* the last byte
234 while (currOffset > 0)
235 {
236 currOffset -= erase;
237 loff_t pos = lseek64(readctx->fd, currOffset, SEEK_SET);
238 int mgbb = ioctl(readctx->fd, MEMGETBADBLOCK, &pos);
239 if (mgbb != 0)
240 {
241 printf("Bad block %d in reservoir area, skipping.\n", currOffset/erase);
242 continue;
243 }
244 ssize_t readBytes = read(readctx->fd, readctx->buffer, erase);
245 if (readBytes != (ssize_t)erase)
246 {
247 fprintf(stderr, "Failed to read good block in reservoir area (%s).\n",
248 strerror(errno));
249 free(pMapping);
250 bml_over_mtd_read_close(readctx);
251 return NULL;
252 }
253 if (readBytes >= 0x2000)
254 {
255 char* buf = readctx->buffer;
256 if (buf[0]=='U' && buf[1]=='P' && buf[2]=='C' && buf[3]=='H')
257 {
258 printf ("Found mapping block mark at 0x%x (block %d).\n", currOffset, currOffset/erase);
259
260 unsigned short* mappings = (unsigned short*) &buf[0x1000];
261 if (mappings[0]==0 && mappings[1]==0xffff)
262 {
263 printf("Found start of mapping table.\n");
264 foundMappingTable = 1;
265 //Skip first entry (dummy)
266 unsigned short* mappingEntry = mappings + 2;
267 while (mappingEntry - mappings < 100
268 && mappingEntry[0] != 0xffff)
269 {
270 unsigned short rawSrcBlk = mappingEntry[0];
271 unsigned short rawDstBlk = mappingEntry[1];
272
273 printf("Found raw block mapping %d -> %d\n", rawSrcBlk,
274 rawDstBlk);
275
276 unsigned int srcAbsoluteStartAddress = srcPartStartBlock * erase;
277 unsigned int resAbsoluteStartAddress = reservoirPartStartBlock * erase;
278
279 int reservoirLastBlock = reservoirPartStartBlock + numSrcBlocks - 1;
280 if (rawDstBlk < reservoirPartStartBlock
281 || rawDstBlk*erase >= resAbsoluteStartAddress+currOffset)
282 {
283 fprintf(stderr, "Mapped block not within reasonable reservoir area.\n");
284 foundMappingTable = 0;
285 break;
286 }
287
288 int srcLastBlock = srcPartStartBlock + numSrcBlocks - 1;
289 if (rawSrcBlk >= srcPartStartBlock && rawSrcBlk <= srcLastBlock)
290 {
291
292 unsigned short relSrcBlk = rawSrcBlk - srcPartStartBlock;
293 unsigned short relDstBlk = rawDstBlk - reservoirPartStartBlock;
294 printf("Partition relative block mapping %d -> %d\n",relSrcBlk, relDstBlk);
295
296 printf("Absolute mapped start addresses 0x%x -> 0x%x\n",
297 srcAbsoluteStartAddress+relSrcBlk*erase,
298 resAbsoluteStartAddress+relDstBlk*erase);
299 printf("Partition relative mapped start addresses 0x%x -> 0x%x\n",
300 relSrcBlk*erase, relDstBlk*erase);
301
302 //Set mapping entry. For duplicate entries, later entries replace former ones.
303 //*Assumption*: Bad blocks in reservoir area will not be mapped themselves in
304 //the mapping table. User partition blocks will not be mapped to bad blocks
305 //(only) in the reservoir area. This has to be confirmed on a wider range of
306 //devices.
307 pMapping[relSrcBlk] = relDstBlk;
308
309 }
310 mappingEntry+=2;
311 }
312 break; //We found the mapping table, no need to search further
313 }
314
315
316 }
317 }
318
319 }
320 bml_over_mtd_read_close(readctx);
321
322 if (foundMappingTable == 0)
323 {
324 fprintf(stderr, "Cannot find mapping table in reservoir partition.\n");
325 free(pMapping);
326 return NULL;
327 }
328
329 //Consistency and validity check
330 int mappingValid = 1;
331 readctx = bml_over_mtd_read_partition(pSrcPart);
332 if (readctx == NULL)
333 {
334 fprintf(stderr, "Cannot open source partition for reading.\n");
335 free(pMapping);
336 return NULL;
337 }
338 int currBlock = 0;
339 for (;currBlock < numSrcBlocks; ++currBlock)
340 {
341 loff_t pos = lseek64(readctx->fd, currBlock*erase, SEEK_SET);
342 int mgbb = ioctl(readctx->fd, MEMGETBADBLOCK, &pos);
343 if (mgbb == 0)
344 {
345 if (pMapping[currBlock]!=0xffff)
346 {
347 fprintf(stderr, "Consistency error: Good block has mapping entry %d -> %d\n", currBlock, pMapping[currBlock]);
348 mappingValid = 0;
349 }
350 } else
351 {
352 //Bad block!
353 if (pMapping[currBlock]==0xffff)
354 {
355 fprintf(stderr, "Consistency error: Bad block has no mapping entry \n");
356 mappingValid = 0;
357 } else
358 {
359 BmlOverMtdReadContext* reservoirReadCtx = bml_over_mtd_read_partition(pReservoirPart);
360 if (reservoirReadCtx == 0)
361 {
362 fprintf(stderr, "Reservoir partition cannot be opened for reading in consistency check.\n");
363 mappingValid = 0;
364 } else
365 {
366 pos = lseek64(reservoirReadCtx->fd, pMapping[currBlock]*erase, SEEK_SET);
367 mgbb = ioctl(reservoirReadCtx->fd, MEMGETBADBLOCK, &pos);
368 if (mgbb == 0)
369 {
370 printf("Bad block has properly mapped reservoir block %d -> %d\n",currBlock, pMapping[currBlock]);
371 }
372 else
373 {
374 fprintf(stderr, "Consistency error: Mapped block is bad, too. (%d -> %d)\n",currBlock, pMapping[currBlock]);
375 mappingValid = 0;
376 }
377
378 }
379 bml_over_mtd_read_close(reservoirReadCtx);
380 }
381
382 }
383
384 }
385 bml_over_mtd_read_close(readctx);
386
387
388 if (!mappingValid)
389 {
390 free(pMapping);
391 return NULL;
392 }
393
394 return pMapping;
395}
396
397static void ReleaseBlockMapping(const unsigned short* blockMapping)
398{
399 free((void*)blockMapping);
400}
401
402static int dump_bml_partition(const MtdPartition* pSrcPart, const MtdPartition* pReservoirPart,
403 const unsigned short* blockMapping, const char* filename)
404{
405 int fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
406 if (fd < 0)
407 {
408 fprintf(stderr, "error opening %s", filename);
409 return -1;
410 }
411 BmlOverMtdReadContext* pSrcRead = bml_over_mtd_read_partition(pSrcPart);
412 if (pSrcRead == NULL)
413 {
414 close(fd);
415 fprintf(stderr, "dump_bml_partition: Error opening src part for reading.\n");
416 return -1;
417 }
418
419 BmlOverMtdReadContext* pResRead = bml_over_mtd_read_partition(pReservoirPart);
420 if (pResRead == NULL)
421 {
422 close(fd);
423 bml_over_mtd_read_close(pSrcRead);
424 fprintf(stderr, "dump_bml_partition: Error opening reservoir part for reading.\n");
425 return -1;
426 }
427
428
429 int numBlocks = pSrcPart->size / pSrcPart->erase_size;
430 int currblock = 0;
431 for (;currblock < numBlocks; ++currblock)
432 {
433 int srcFd = -1;
434 if (blockMapping[currblock] == 0xffff)
435 {
436 //Good block, use src partition
437 srcFd = pSrcRead->fd;
438 if (lseek64(pSrcRead->fd, currblock*pSrcPart->erase_size, SEEK_SET)==-1)
439 {
440 close(fd);
441 bml_over_mtd_read_close(pSrcRead);
442 bml_over_mtd_read_close(pResRead);
443 fprintf(stderr, "dump_bml_partition: lseek in src partition failed\n");
444 return -1;
445 }
446 } else
447 {
448 //Bad block, use mapped block in reservoir partition
449 srcFd = pResRead->fd;
450 if (lseek64(pResRead->fd, blockMapping[currblock]*pSrcPart->erase_size, SEEK_SET)==-1)
451 {
452 close(fd);
453 bml_over_mtd_read_close(pSrcRead);
454 bml_over_mtd_read_close(pResRead);
455 fprintf(stderr, "dump_bml_partition: lseek in reservoir partition failed\n");
456 return -1;
457 }
458 }
459 size_t blockBytesRead = 0;
460 while (blockBytesRead < pSrcPart->erase_size)
461 {
462 ssize_t len = read(srcFd, pSrcRead->buffer + blockBytesRead,
463 pSrcPart->erase_size - blockBytesRead);
464 if (len <= 0)
465 {
466 close(fd);
467 bml_over_mtd_read_close(pSrcRead);
468 bml_over_mtd_read_close(pResRead);
469 fprintf(stderr, "dump_bml_partition: reading partition failed\n");
470 return -1;
471 }
472 blockBytesRead += len;
473 }
474
475 size_t blockBytesWritten = 0;
476 while (blockBytesWritten < pSrcPart->erase_size)
477 {
478 ssize_t len = write(fd, pSrcRead->buffer + blockBytesWritten,
479 pSrcPart->erase_size - blockBytesWritten);
480 if (len <= 0)
481 {
482 close(fd);
483 bml_over_mtd_read_close(pSrcRead);
484 bml_over_mtd_read_close(pResRead);
485 fprintf(stderr, "dump_bml_partition: writing partition dump file failed\n");
486 return -1;
487 }
488 blockBytesWritten += len;
489 }
490
491 }
492
493 bml_over_mtd_read_close(pSrcRead);
494 bml_over_mtd_read_close(pResRead);
495
496 if (close(fd)) {
497 unlink(filename);
498 printf("error closing %s", filename);
499 return -1;
500 }
501
502 return 0;
503}
504
505static ssize_t bml_over_mtd_write_block(int fd, ssize_t erase_size, char* data)
506{
507 off_t pos = lseek(fd, 0, SEEK_CUR);
508 if (pos == (off_t) -1) return -1;
509
510 ssize_t size = erase_size;
511 loff_t bpos = pos;
512 int ret = ioctl(fd, MEMGETBADBLOCK, &bpos);
513 if (ret != 0 && !(ret == -1 && errno == EOPNOTSUPP)) {
514 fprintf(stderr,
515 "Mapping failure: Trying to write bad block at 0x%08lx (ret %d errno %d)\n",
516 pos, ret, errno);
517 return -1;
518 }
519
520 struct erase_info_user erase_info;
521 erase_info.start = pos;
522 erase_info.length = size;
523 int retry;
524 for (retry = 0; retry < 2; ++retry) {
Sergey 'Jin' Bostandzhyan80a90ed2013-01-04 02:29:03 +0100525#ifdef RK3066
526 if (rk30_zero_out(fd, pos, size) < 0) {
527 fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n",
528 pos, strerror(errno));
529 continue;
530 }
531#else
Dees_Troy51a0e822012-09-05 15:24:24 -0400532 if (ioctl(fd, MEMERASE, &erase_info) < 0) {
533 fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n",
534 pos, strerror(errno));
535 continue;
536 }
Sergey 'Jin' Bostandzhyan80a90ed2013-01-04 02:29:03 +0100537#endif
Dees_Troy51a0e822012-09-05 15:24:24 -0400538 if (lseek(fd, pos, SEEK_SET) != pos ||
539 write(fd, data, size) != size) {
540 fprintf(stderr, "mtd: write error at 0x%08lx (%s)\n",
541 pos, strerror(errno));
542 }
543
544 char verify[size];
545 if (lseek(fd, pos, SEEK_SET) != pos ||
546 read(fd, verify, size) != size) {
547 fprintf(stderr, "mtd: re-read error at 0x%08lx (%s)\n",
548 pos, strerror(errno));
549 continue;
550 }
551 if (memcmp(data, verify, size) != 0) {
552 fprintf(stderr, "mtd: verification error at 0x%08lx (%s)\n",
553 pos, strerror(errno));
554 continue;
555 }
556
557 if (retry > 0) {
558 fprintf(stderr, "mtd: wrote block after %d retries\n", retry);
559 }
560 fprintf(stderr, "mtd: successfully wrote block at %llx\n", pos);
561 return size; // Success!
562 }
563
564
565 fprintf(stderr, "mtd: Block at %llx could not be properly written.\n", pos);
566 // Ran out of space on the device
567 errno = ENOSPC;
568 return -1;
569}
570
571static int flash_bml_partition(const MtdPartition* pSrcPart, const MtdPartition* pReservoirPart,
572 const unsigned short* blockMapping, const char* filename)
573{
574 int fd = open(filename, O_RDONLY);
575 if (fd < 0)
576 {
577 fprintf(stderr, "error opening %s", filename);
578 return -1;
579 }
580 BmlOverMtdWriteContext* pSrcWrite = bml_over_mtd_write_partition(pSrcPart);
581 if (pSrcWrite == NULL)
582 {
583 close(fd);
584 fprintf(stderr, "flash_bml_partition: Error opening src part for writing.\n");
585 return -1;
586 }
587
588#ifdef DUMMY_WRITING
589 close(pSrcWrite->fd);
590 pSrcWrite->fd = open("/sdcard/srcPartWriteDummy.bin", O_WRONLY|O_CREAT|O_TRUNC, 0666);
591#endif
592
593 BmlOverMtdWriteContext* pResWrite = bml_over_mtd_write_partition(pReservoirPart);
594 if (pResWrite == NULL)
595 {
596 close(fd);
597 bml_over_mtd_write_close(pSrcWrite);
598 fprintf(stderr, "flash_bml_partition: Error opening reservoir part for writing.\n");
599 return -1;
600 }
601#ifdef DUMMY_WRITING
602 close(pResWrite->fd);
603 pResWrite->fd = open("/sdcard/resPartWriteDummy.bin", O_WRONLY|O_CREAT|O_TRUNC, 0666);
604#endif
605
606 struct stat fileStat;
607 if (fstat(fd, &fileStat) != 0)
608 {
609 close(fd);
610 bml_over_mtd_write_close(pSrcWrite);
611 bml_over_mtd_write_close(pResWrite);
612 fprintf(stderr, "flash_bml_partition: Failed to stat source file.\n");
613 return -1;
614
615 }
616 if (fileStat.st_size > pSrcPart->size)
617 {
618 close(fd);
619 bml_over_mtd_write_close(pSrcWrite);
620 bml_over_mtd_write_close(pResWrite);
621 fprintf(stderr, "flash_bml_partition: Source file too large for target partition.\n");
622 return -1;
623 }
624
625 int numBlocks = (fileStat.st_size + pSrcPart->erase_size - 1) / pSrcPart->erase_size;
626 int currblock;
627 for (currblock = 0 ;currblock < numBlocks; ++currblock)
628 {
629 memset(pSrcWrite->buffer, 0xFF, pSrcPart->erase_size);
630 size_t blockBytesRead = 0;
631 while (blockBytesRead < pSrcPart->erase_size)
632 {
633 ssize_t len = read(fd, pSrcWrite->buffer + blockBytesRead,
634 pSrcPart->erase_size - blockBytesRead);
635 if (len < 0)
636 {
637 close(fd);
638 bml_over_mtd_write_close(pSrcWrite);
639 bml_over_mtd_write_close(pResWrite);
640 fprintf(stderr, "flash_bml_partition: read source file failed\n");
641 return -1;
642 }
643 if (len == 0)
644 {
645 //End of file
646 break;
647 }
648
649 blockBytesRead += len;
650 }
651
652
653
654 int srcFd = -1;
655 if (blockMapping[currblock] == 0xffff)
656 {
657 //Good block, use src partition
658 srcFd = pSrcWrite->fd;
659 if (lseek64(pSrcWrite->fd, currblock*pSrcPart->erase_size, SEEK_SET)==-1)
660 {
661 close(fd);
662 bml_over_mtd_write_close(pSrcWrite);
663 bml_over_mtd_write_close(pResWrite);
664 fprintf(stderr, "flash_bml_partition: lseek in src partition failed\n");
665 return -1;
666 }
667 } else
668 {
669 //Bad block, use mapped block in reservoir partition
670 srcFd = pResWrite->fd;
671 if (lseek64(pResWrite->fd, blockMapping[currblock]*pSrcPart->erase_size, SEEK_SET)==-1)
672 {
673 close(fd);
674 bml_over_mtd_write_close(pSrcWrite);
675 bml_over_mtd_write_close(pResWrite);
676 fprintf(stderr, "flash_bml_partition: lseek in reservoir partition failed\n");
677 return -1;
678 }
679 }
680 size_t blockBytesWritten = 0;
681 while (blockBytesWritten < pSrcPart->erase_size)
682 {
683#ifdef DUMMY_WRITING
684 ssize_t len = write(srcFd, pSrcWrite->buffer + blockBytesWritten,
685 pSrcPart->erase_size - blockBytesWritten);
686#else
687 ssize_t len = bml_over_mtd_write_block(srcFd, pSrcPart->erase_size, pSrcWrite->buffer);
688#endif
689 if (len <= 0)
690 {
691 close(fd);
692 bml_over_mtd_write_close(pSrcWrite);
693 bml_over_mtd_write_close(pResWrite);
694 fprintf(stderr, "flash_bml_partition: writing to partition failed\n");
695 return -1;
696 }
697 blockBytesWritten += len;
698 }
699
700
701 }
702
703 bml_over_mtd_write_close(pSrcWrite);
704 bml_over_mtd_write_close(pResWrite);
705
706 if (close(fd)) {
707 printf("error closing %s", filename);
708 return -1;
709 }
710
711 return 0;
712}
713
714static int scan_partition(const MtdPartition* pPart)
715{
716 BmlOverMtdReadContext* readCtx = bml_over_mtd_read_partition(pPart);
717 if (readCtx == NULL)
718 {
719 fprintf(stderr, "Failed to open partition for reading.\n");
720 return -1;
721 }
722
723 int numBadBlocks = 0;
724 size_t numBlocks = pPart->size / pPart->erase_size;
725 size_t currBlock;
726 for (currBlock = 0; currBlock < numBlocks; ++currBlock)
727 {
728
729 loff_t pos = currBlock * pPart->erase_size;
730 int mgbb = ioctl(readCtx->fd, MEMGETBADBLOCK, &pos);
731 if (mgbb != 0)
732 {
733 printf("Bad block %d at 0x%x.\n", currBlock, (unsigned int)pos);
734 numBadBlocks++;
735 }
736 }
737
738 bml_over_mtd_read_close(readCtx);
739 if (numBadBlocks == 0)
740 {
741 printf("No bad blocks.\n");
742 return 0;
743 }
744 return -1 ;
745}
746
747int main(int argc, char **argv)
748{
749 if (argc != 7 && (argc != 3 || (argc == 3 && strcmp(argv[1],"scan"))!=0)
750 && (argc != 6 || (argc == 6 && strcmp(argv[1],"scan"))!=0))
751 return die("Usage: %s dump|flash <partition> <partition_start_block> <reservoirpartition> <reservoir_start_block> <file>\n"
752 "E.g. %s dump boot 72 reservoir 2004 file.bin\n"
753 "Usage: %s scan <partition> [<partition_start_block> <reservoirpartition> <reservoir_start_block>]\n"
754 ,argv[0], argv[0], argv[0]);
755 int num_partitions = mtd_scan_partitions();
756 const MtdPartition *pSrcPart = mtd_find_partition_by_name(argv[2]);
757 if (pSrcPart == NULL)
758 return die("Cannot find partition %s", argv[2]);
759
760 int scanResult = scan_partition(pSrcPart);
761
762 if (argc == 3 && strcmp(argv[1],"scan")==0)
763 {
764 return (scanResult == 0 ? 0 : EXIT_CODE_BAD_BLOCKS);
765 }
766
767 int retVal = 0;
768 const MtdPartition* pReservoirPart = mtd_find_partition_by_name(argv[4]);
769 if (pReservoirPart == NULL)
770 return die("Cannot find partition %s", argv[4]);
771
772 int srcPartStartBlock = atoi(argv[3]);
773 int reservoirPartStartBlock = atoi(argv[5]);
774 const unsigned short* pMapping = CreateBlockMapping(pSrcPart, srcPartStartBlock,
775 pReservoirPart, reservoirPartStartBlock);
776
777 if (pMapping == NULL && scanResult == 0)
778 {
779 printf("Generating empty block mapping table for error-free partition.\n");
780 pMapping = CreateEmptyBlockMapping(pSrcPart);
781 }
782
783 if (argc == 6 && strcmp(argv[1],"scan")==0)
784 {
785 retVal = (scanResult == 0 ? 0 : EXIT_CODE_BAD_BLOCKS);
786 }
787
788 if (pMapping == NULL)
789 return die("Failed to create block mapping table");
790
791 if (strcmp(argv[1],"dump")==0)
792 {
793 retVal = dump_bml_partition(pSrcPart, pReservoirPart, pMapping, argv[6]);
794 if (retVal == 0)
795 printf("Successfully dumped partition to %s\n", argv[6]);
796 }
797
798 if (strcmp(argv[1],"flash")==0)
799 {
800 retVal = flash_bml_partition(pSrcPart, pReservoirPart, pMapping, argv[6]);
801 if (retVal == 0)
802 printf("Successfully wrote %s to partition\n", argv[6]);
803
804 }
805
806
807 ReleaseBlockMapping(pMapping);
808 return retVal;
809}
810