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