bml_over_mtd: Take care of bad blocks on "boot" partition for Samsung Galaxy S Phones.

The Samsung Galaxy S bootloader apparently expects the kernel to be flashed to BML-managed flash - bad erase blocks will be mapped from a reservoir area.
CWM however just skips bad blocks, the usual procedure for mtd-accessed flash.
Consequently, the bootloader sees a corrupt zImage, and will usually crash when the kernel initializes.
This of course will only happen when the "boot" partition has bad blocks.

This patch was written by "eifert" and adds a tool called "bml_over_mtd" for flashing boot images which takes care of bad blocks and maps them to a reservoir area, like BML does.

Change-Id: If570717a19b879d47d70d937a0751cd85853eacd
This commit is contained in:
codeworkx 2011-04-25 11:16:41 -07:00
parent 6a97396572
commit 9c4c8e2c66
4 changed files with 830 additions and 9 deletions

View File

@ -16,8 +16,8 @@ LOCAL_SRC_FILES := \
verifier.c \
encryptedfs_provisioning.c \
mounts.c \
extendedcommands.c \
nandroid.c \
extendedcommands.c \
nandroid.c \
reboot.c \
edifyscripting.c \
setprop.c
@ -57,7 +57,12 @@ LOCAL_STATIC_LIBRARIES += libext4_utils libz
LOCAL_STATIC_LIBRARIES += libminzip libunz libmincrypt
LOCAL_STATIC_LIBRARIES += libedify libbusybox libclearsilverregex libmkyaffs2image libunyaffs liberase_image libdump_image libflash_image
LOCAL_STATIC_LIBRARIES += libflashutils libmtdutils libmmcutils libbmlutils
LOCAL_STATIC_LIBRARIES += libflashutils libmtdutils libmmcutils libbmlutils
ifeq ($(BOARD_USES_BML_OVER_MTD),true)
LOCAL_STATIC_LIBRARIES += libbml_over_mtd
endif
LOCAL_STATIC_LIBRARIES += libminui libpixelflinger_static libpng libcutils
LOCAL_STATIC_LIBRARIES += libstdc++ libc

View File

@ -57,7 +57,6 @@ LOCAL_MODULE_TAGS := eng
LOCAL_CFLAGS += -Dmain=erase_image_main
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := dump_image.c
LOCAL_MODULE := utility_dump_image

View File

@ -2,15 +2,34 @@ ifneq ($(TARGET_SIMULATOR),true)
ifeq ($(TARGET_ARCH),arm)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
mtdutils.c
LOCAL_SRC_FILES := mtdutils.c
LOCAL_MODULE := libmtdutils
include $(BUILD_STATIC_LIBRARY)
ifeq ($(BOARD_USES_BML_OVER_MTD),true)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := bml_over_mtd.c
LOCAL_C_INCLUDES += bootable/recovery/mtdutils
LOCAL_MODULE := libbml_over_mtd
LOCAL_MODULE_TAGS := eng
LOCAL_CFLAGS += -Dmain=bml_over_mtd_main
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := bml_over_mtd.c
LOCAL_MODULE := bml_over_mtd
LOCAL_MODULE_TAGS := eng
LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES
LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities
LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities
LOCAL_MODULE_STEM := bml_over_mtd
LOCAL_C_INCLUDES += bootable/recovery/mtdutils
LOCAL_STATIC_LIBRARIES := libmtdutils libcutils libc
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
endif
endif # TARGET_ARCH == arm
endif # !TARGET_SIMULATOR

798
mtdutils/bml_over_mtd.c Normal file
View File

@ -0,0 +1,798 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include "cutils/log.h"
#include <mtd/mtd-user.h>
#include "mtdutils.h"
typedef struct BmlOverMtdReadContext {
const MtdPartition *partition;
char *buffer;
size_t consumed;
int fd;
} BmlOverMtdReadContext;
typedef struct BmlOverMtdWriteContext {
const MtdPartition *partition;
char *buffer;
size_t stored;
int fd;
off_t* bad_block_offsets;
int bad_block_alloc;
int bad_block_count;
} BmlOverMtdWriteContext;
static BmlOverMtdReadContext *bml_over_mtd_read_partition(const MtdPartition *partition)
{
BmlOverMtdReadContext *ctx = (BmlOverMtdReadContext*) malloc(sizeof(BmlOverMtdReadContext));
if (ctx == NULL) return NULL;
ctx->buffer = malloc(partition->erase_size);
if (ctx->buffer == NULL) {
free(ctx);
return NULL;
}
char mtddevname[32];
sprintf(mtddevname, "/dev/mtd/mtd%d", partition->device_index);
ctx->fd = open(mtddevname, O_RDONLY);
if (ctx->fd < 0) {
free(ctx);
free(ctx->buffer);
return NULL;
}
ctx->partition = partition;
ctx->consumed = partition->erase_size;
return ctx;
}
static void bml_over_mtd_read_close(BmlOverMtdReadContext *ctx)
{
close(ctx->fd);
free(ctx->buffer);
free(ctx);
}
static BmlOverMtdWriteContext *bml_over_mtd_write_partition(const MtdPartition *partition)
{
BmlOverMtdWriteContext *ctx = (BmlOverMtdWriteContext*) malloc(sizeof(BmlOverMtdWriteContext));
if (ctx == NULL) return NULL;
ctx->bad_block_offsets = NULL;
ctx->bad_block_alloc = 0;
ctx->bad_block_count = 0;
ctx->buffer = malloc(partition->erase_size);
if (ctx->buffer == NULL) {
free(ctx);
return NULL;
}
char mtddevname[32];
sprintf(mtddevname, "/dev/mtd/mtd%d", partition->device_index);
ctx->fd = open(mtddevname, O_RDWR);
if (ctx->fd < 0) {
free(ctx->buffer);
free(ctx);
return NULL;
}
ctx->partition = partition;
ctx->stored = 0;
return ctx;
}
static int bml_over_mtd_write_close(BmlOverMtdWriteContext *ctx)
{
int r = 0;
if (close(ctx->fd)) r = -1;
free(ctx->bad_block_offsets);
free(ctx->buffer);
free(ctx);
return r;
}
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "bml_over_mtd"
#define BLOCK_SIZE 2048
#define SPARE_SIZE (BLOCK_SIZE >> 5)
#define EXIT_CODE_BAD_BLOCKS 15
static int die(const char *msg, ...) {
int err = errno;
va_list args;
va_start(args, msg);
char buf[1024];
vsnprintf(buf, sizeof(buf), msg, args);
va_end(args);
if (err != 0) {
strlcat(buf, ": ", sizeof(buf));
strlcat(buf, strerror(err), sizeof(buf));
}
fprintf(stderr, "%s\n", buf);
return 1;
}
static unsigned short* CreateEmptyBlockMapping(const MtdPartition* pSrcPart)
{
size_t srcTotal, srcErase, srcWrite;
if (mtd_partition_info(pSrcPart, &srcTotal, &srcErase, &srcWrite) != 0)
{
fprintf(stderr, "Failed to access partition.\n");
return NULL;
}
int numSrcBlocks = srcTotal/srcErase;
unsigned short* pMapping = malloc(numSrcBlocks * sizeof(unsigned short));
if (pMapping == NULL)
{
fprintf(stderr, "Failed to allocate block mapping memory.\n");
return NULL;
}
memset(pMapping, 0xFF, numSrcBlocks * sizeof(unsigned short));
return pMapping;
}
static const unsigned short* CreateBlockMapping(const MtdPartition* pSrcPart, int srcPartStartBlock,
const MtdPartition *pReservoirPart, int reservoirPartStartBlock)
{
size_t srcTotal, srcErase, srcWrite;
if (mtd_partition_info(pSrcPart, &srcTotal, &srcErase, &srcWrite) != 0)
{
fprintf(stderr, "Failed to access partition.\n");
return NULL;
}
int numSrcBlocks = srcTotal/srcErase;
unsigned short* pMapping = malloc(numSrcBlocks * sizeof(unsigned short));
if (pMapping == NULL)
{
fprintf(stderr, "Failed to allocate block mapping memory.\n");
return NULL;
}
memset(pMapping, 0xFF, numSrcBlocks * sizeof(unsigned short));
size_t total, erase, write;
if (mtd_partition_info(pReservoirPart, &total, &erase, &write) != 0)
{
fprintf(stderr, "Failed to access reservoir partition.\n");
free(pMapping);
return NULL;
}
if (erase != srcErase || write != srcWrite)
{
fprintf(stderr, "Source partition and reservoir partition differ in size properties.\n");
free(pMapping);
return NULL;
}
printf("Partition info: Total %d, Erase %d, write %d\n", total, erase, write);
BmlOverMtdReadContext *readctx = bml_over_mtd_read_partition(pReservoirPart);
if (readctx == NULL)
{
fprintf(stderr, "Failed to open reservoir partition for reading.\n");
free(pMapping);
return NULL;
}
if (total < erase || total > INT_MAX)
{
fprintf(stderr, "Unsuitable reservoir partition properties.\n");
free(pMapping);
bml_over_mtd_read_close(readctx);
return NULL;
}
int foundMappingTable = 0;
int currOffset = total; //Offset *behind* the last byte
while (currOffset > 0)
{
currOffset -= erase;
loff_t pos = lseek64(readctx->fd, currOffset, SEEK_SET);
int mgbb = ioctl(readctx->fd, MEMGETBADBLOCK, &pos);
if (mgbb != 0)
{
printf("Bad block %d in reservoir area, skipping.\n", currOffset/erase);
continue;
}
ssize_t readBytes = read(readctx->fd, readctx->buffer, erase);
if (readBytes != (ssize_t)erase)
{
fprintf(stderr, "Failed to read good block in reservoir area (%s).\n",
strerror(errno));
free(pMapping);
bml_over_mtd_read_close(readctx);
return NULL;
}
if (readBytes >= 0x2000)
{
char* buf = readctx->buffer;
if (buf[0]=='U' && buf[1]=='P' && buf[2]=='C' && buf[3]=='H')
{
printf ("Found mapping block mark at 0x%x (block %d).\n", currOffset, currOffset/erase);
unsigned short* mappings = (unsigned short*) &buf[0x1000];
if (mappings[0]==0 && mappings[1]==0xffff)
{
printf("Found start of mapping table.\n");
foundMappingTable = 1;
//Skip first entry (dummy)
unsigned short* mappingEntry = mappings + 2;
while (mappingEntry - mappings < 100
&& mappingEntry[0] != 0xffff)
{
unsigned short rawSrcBlk = mappingEntry[0];
unsigned short rawDstBlk = mappingEntry[1];
printf("Found raw block mapping %d -> %d\n", rawSrcBlk,
rawDstBlk);
unsigned int srcAbsoluteStartAddress = srcPartStartBlock * erase;
unsigned int resAbsoluteStartAddress = reservoirPartStartBlock * erase;
int reservoirLastBlock = reservoirPartStartBlock + numSrcBlocks - 1;
if (rawDstBlk < reservoirPartStartBlock
|| rawDstBlk*erase >= resAbsoluteStartAddress+currOffset)
{
fprintf(stderr, "Mapped block not within reasonable reservoir area.\n");
foundMappingTable = 0;
break;
}
int srcLastBlock = srcPartStartBlock + numSrcBlocks - 1;
if (rawSrcBlk >= srcPartStartBlock && rawSrcBlk <= srcLastBlock)
{
unsigned short relSrcBlk = rawSrcBlk - srcPartStartBlock;
unsigned short relDstBlk = rawDstBlk - reservoirPartStartBlock;
printf("Partition relative block mapping %d -> %d\n",relSrcBlk, relDstBlk);
printf("Absolute mapped start addresses 0x%x -> 0x%x\n",
srcAbsoluteStartAddress+relSrcBlk*erase,
resAbsoluteStartAddress+relDstBlk*erase);
printf("Partition relative mapped start addresses 0x%x -> 0x%x\n",
relSrcBlk*erase, relDstBlk*erase);
//Set mapping entry. For duplicate entries, later entries replace former ones.
//*Assumption*: Bad blocks in reservoir area will not be mapped themselves in
//the mapping table. User partition blocks will not be mapped to bad blocks
//(only) in the reservoir area. This has to be confirmed on a wider range of
//devices.
pMapping[relSrcBlk] = relDstBlk;
}
mappingEntry+=2;
}
break; //We found the mapping table, no need to search further
}
}
}
}
bml_over_mtd_read_close(readctx);
if (foundMappingTable == 0)
{
fprintf(stderr, "Cannot find mapping table in reservoir partition.\n");
free(pMapping);
return NULL;
}
//Consistency and validity check
int mappingValid = 1;
readctx = bml_over_mtd_read_partition(pSrcPart);
if (readctx == NULL)
{
fprintf(stderr, "Cannot open source partition for reading.\n");
free(pMapping);
return NULL;
}
int currBlock = 0;
for (;currBlock < numSrcBlocks; ++currBlock)
{
loff_t pos = lseek64(readctx->fd, currBlock*erase, SEEK_SET);
int mgbb = ioctl(readctx->fd, MEMGETBADBLOCK, &pos);
if (mgbb == 0)
{
if (pMapping[currBlock]!=0xffff)
{
fprintf(stderr, "Consistency error: Good block has mapping entry %d -> %d\n", currBlock, pMapping[currBlock]);
mappingValid = 0;
}
} else
{
//Bad block!
if (pMapping[currBlock]==0xffff)
{
fprintf(stderr, "Consistency error: Bad block has no mapping entry \n");
mappingValid = 0;
} else
{
BmlOverMtdReadContext* reservoirReadCtx = bml_over_mtd_read_partition(pReservoirPart);
if (reservoirReadCtx == 0)
{
fprintf(stderr, "Reservoir partition cannot be opened for reading in consistency check.\n");
mappingValid = 0;
} else
{
pos = lseek64(reservoirReadCtx->fd, pMapping[currBlock]*erase, SEEK_SET);
mgbb = ioctl(reservoirReadCtx->fd, MEMGETBADBLOCK, &pos);
if (mgbb == 0)
{
printf("Bad block has properly mapped reservoir block %d -> %d\n",currBlock, pMapping[currBlock]);
}
else
{
fprintf(stderr, "Consistency error: Mapped block is bad, too. (%d -> %d)\n",currBlock, pMapping[currBlock]);
mappingValid = 0;
}
}
bml_over_mtd_read_close(reservoirReadCtx);
}
}
}
bml_over_mtd_read_close(readctx);
if (!mappingValid)
{
free(pMapping);
return NULL;
}
return pMapping;
}
static void ReleaseBlockMapping(const unsigned short* blockMapping)
{
free((void*)blockMapping);
}
static int dump_bml_partition(const MtdPartition* pSrcPart, const MtdPartition* pReservoirPart,
const unsigned short* blockMapping, const char* filename)
{
int fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
if (fd < 0)
{
fprintf(stderr, "error opening %s", filename);
return -1;
}
BmlOverMtdReadContext* pSrcRead = bml_over_mtd_read_partition(pSrcPart);
if (pSrcRead == NULL)
{
close(fd);
fprintf(stderr, "dump_bml_partition: Error opening src part for reading.\n");
return -1;
}
BmlOverMtdReadContext* pResRead = bml_over_mtd_read_partition(pReservoirPart);
if (pResRead == NULL)
{
close(fd);
bml_over_mtd_read_close(pSrcRead);
fprintf(stderr, "dump_bml_partition: Error opening reservoir part for reading.\n");
return -1;
}
int numBlocks = pSrcPart->size / pSrcPart->erase_size;
int currblock = 0;
for (;currblock < numBlocks; ++currblock)
{
int srcFd = -1;
if (blockMapping[currblock] == 0xffff)
{
//Good block, use src partition
srcFd = pSrcRead->fd;
if (lseek64(pSrcRead->fd, currblock*pSrcPart->erase_size, SEEK_SET)==-1)
{
close(fd);
bml_over_mtd_read_close(pSrcRead);
bml_over_mtd_read_close(pResRead);
fprintf(stderr, "dump_bml_partition: lseek in src partition failed\n");
return -1;
}
} else
{
//Bad block, use mapped block in reservoir partition
srcFd = pResRead->fd;
if (lseek64(pResRead->fd, blockMapping[currblock]*pSrcPart->erase_size, SEEK_SET)==-1)
{
close(fd);
bml_over_mtd_read_close(pSrcRead);
bml_over_mtd_read_close(pResRead);
fprintf(stderr, "dump_bml_partition: lseek in reservoir partition failed\n");
return -1;
}
}
size_t blockBytesRead = 0;
while (blockBytesRead < pSrcPart->erase_size)
{
ssize_t len = read(srcFd, pSrcRead->buffer + blockBytesRead,
pSrcPart->erase_size - blockBytesRead);
if (len <= 0)
{
close(fd);
bml_over_mtd_read_close(pSrcRead);
bml_over_mtd_read_close(pResRead);
fprintf(stderr, "dump_bml_partition: reading partition failed\n");
return -1;
}
blockBytesRead += len;
}
size_t blockBytesWritten = 0;
while (blockBytesWritten < pSrcPart->erase_size)
{
ssize_t len = write(fd, pSrcRead->buffer + blockBytesWritten,
pSrcPart->erase_size - blockBytesWritten);
if (len <= 0)
{
close(fd);
bml_over_mtd_read_close(pSrcRead);
bml_over_mtd_read_close(pResRead);
fprintf(stderr, "dump_bml_partition: writing partition dump file failed\n");
return -1;
}
blockBytesWritten += len;
}
}
bml_over_mtd_read_close(pSrcRead);
bml_over_mtd_read_close(pResRead);
if (close(fd)) {
unlink(filename);
printf("error closing %s", filename);
return -1;
}
return 0;
}
static ssize_t bml_over_mtd_write_block(int fd, ssize_t erase_size, char* data)
{
off_t pos = lseek(fd, 0, SEEK_CUR);
if (pos == (off_t) -1) return -1;
ssize_t size = erase_size;
loff_t bpos = pos;
int ret = ioctl(fd, MEMGETBADBLOCK, &bpos);
if (ret != 0 && !(ret == -1 && errno == EOPNOTSUPP)) {
fprintf(stderr,
"Mapping failure: Trying to write bad block at 0x%08lx (ret %d errno %d)\n",
pos, ret, errno);
return -1;
}
struct erase_info_user erase_info;
erase_info.start = pos;
erase_info.length = size;
int retry;
for (retry = 0; retry < 2; ++retry) {
if (ioctl(fd, MEMERASE, &erase_info) < 0) {
fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n",
pos, strerror(errno));
continue;
}
if (lseek(fd, pos, SEEK_SET) != pos ||
write(fd, data, size) != size) {
fprintf(stderr, "mtd: write error at 0x%08lx (%s)\n",
pos, strerror(errno));
}
char verify[size];
if (lseek(fd, pos, SEEK_SET) != pos ||
read(fd, verify, size) != size) {
fprintf(stderr, "mtd: re-read error at 0x%08lx (%s)\n",
pos, strerror(errno));
continue;
}
if (memcmp(data, verify, size) != 0) {
fprintf(stderr, "mtd: verification error at 0x%08lx (%s)\n",
pos, strerror(errno));
continue;
}
if (retry > 0) {
fprintf(stderr, "mtd: wrote block after %d retries\n", retry);
}
fprintf(stderr, "mtd: successfully wrote block at %llx\n", pos);
return size; // Success!
}
fprintf(stderr, "mtd: Block at %llx could not be properly written.\n", pos);
// Ran out of space on the device
errno = ENOSPC;
return -1;
}
static int flash_bml_partition(const MtdPartition* pSrcPart, const MtdPartition* pReservoirPart,
const unsigned short* blockMapping, const char* filename)
{
int fd = open(filename, O_RDONLY);
if (fd < 0)
{
fprintf(stderr, "error opening %s", filename);
return -1;
}
BmlOverMtdWriteContext* pSrcWrite = bml_over_mtd_write_partition(pSrcPart);
if (pSrcWrite == NULL)
{
close(fd);
fprintf(stderr, "flash_bml_partition: Error opening src part for writing.\n");
return -1;
}
#ifdef DUMMY_WRITING
close(pSrcWrite->fd);
pSrcWrite->fd = open("/sdcard/srcPartWriteDummy.bin", O_WRONLY|O_CREAT|O_TRUNC, 0666);
#endif
BmlOverMtdWriteContext* pResWrite = bml_over_mtd_write_partition(pReservoirPart);
if (pResWrite == NULL)
{
close(fd);
bml_over_mtd_write_close(pSrcWrite);
fprintf(stderr, "flash_bml_partition: Error opening reservoir part for writing.\n");
return -1;
}
#ifdef DUMMY_WRITING
close(pResWrite->fd);
pResWrite->fd = open("/sdcard/resPartWriteDummy.bin", O_WRONLY|O_CREAT|O_TRUNC, 0666);
#endif
struct stat fileStat;
if (fstat(fd, &fileStat) != 0)
{
close(fd);
bml_over_mtd_write_close(pSrcWrite);
bml_over_mtd_write_close(pResWrite);
fprintf(stderr, "flash_bml_partition: Failed to stat source file.\n");
return -1;
}
if (fileStat.st_size > pSrcPart->size)
{
close(fd);
bml_over_mtd_write_close(pSrcWrite);
bml_over_mtd_write_close(pResWrite);
fprintf(stderr, "flash_bml_partition: Source file too large for target partition.\n");
return -1;
}
int numBlocks = (fileStat.st_size + pSrcPart->erase_size - 1) / pSrcPart->erase_size;
int currblock;
for (currblock = 0 ;currblock < numBlocks; ++currblock)
{
memset(pSrcWrite->buffer, 0xFF, pSrcPart->erase_size);
size_t blockBytesRead = 0;
while (blockBytesRead < pSrcPart->erase_size)
{
ssize_t len = read(fd, pSrcWrite->buffer + blockBytesRead,
pSrcPart->erase_size - blockBytesRead);
if (len < 0)
{
close(fd);
bml_over_mtd_write_close(pSrcWrite);
bml_over_mtd_write_close(pResWrite);
fprintf(stderr, "flash_bml_partition: read source file failed\n");
return -1;
}
if (len == 0)
{
//End of file
break;
}
blockBytesRead += len;
}
int srcFd = -1;
if (blockMapping[currblock] == 0xffff)
{
//Good block, use src partition
srcFd = pSrcWrite->fd;
if (lseek64(pSrcWrite->fd, currblock*pSrcPart->erase_size, SEEK_SET)==-1)
{
close(fd);
bml_over_mtd_write_close(pSrcWrite);
bml_over_mtd_write_close(pResWrite);
fprintf(stderr, "flash_bml_partition: lseek in src partition failed\n");
return -1;
}
} else
{
//Bad block, use mapped block in reservoir partition
srcFd = pResWrite->fd;
if (lseek64(pResWrite->fd, blockMapping[currblock]*pSrcPart->erase_size, SEEK_SET)==-1)
{
close(fd);
bml_over_mtd_write_close(pSrcWrite);
bml_over_mtd_write_close(pResWrite);
fprintf(stderr, "flash_bml_partition: lseek in reservoir partition failed\n");
return -1;
}
}
size_t blockBytesWritten = 0;
while (blockBytesWritten < pSrcPart->erase_size)
{
#ifdef DUMMY_WRITING
ssize_t len = write(srcFd, pSrcWrite->buffer + blockBytesWritten,
pSrcPart->erase_size - blockBytesWritten);
#else
ssize_t len = bml_over_mtd_write_block(srcFd, pSrcPart->erase_size, pSrcWrite->buffer);
#endif
if (len <= 0)
{
close(fd);
bml_over_mtd_write_close(pSrcWrite);
bml_over_mtd_write_close(pResWrite);
fprintf(stderr, "flash_bml_partition: writing to partition failed\n");
return -1;
}
blockBytesWritten += len;
}
}
bml_over_mtd_write_close(pSrcWrite);
bml_over_mtd_write_close(pResWrite);
if (close(fd)) {
printf("error closing %s", filename);
return -1;
}
return 0;
}
static int scan_partition(const MtdPartition* pPart)
{
BmlOverMtdReadContext* readCtx = bml_over_mtd_read_partition(pPart);
if (readCtx == NULL)
{
fprintf(stderr, "Failed to open partition for reading.\n");
return -1;
}
int numBadBlocks = 0;
size_t numBlocks = pPart->size / pPart->erase_size;
size_t currBlock;
for (currBlock = 0; currBlock < numBlocks; ++currBlock)
{
loff_t pos = currBlock * pPart->erase_size;
int mgbb = ioctl(readCtx->fd, MEMGETBADBLOCK, &pos);
if (mgbb != 0)
{
printf("Bad block %d at 0x%x.\n", currBlock, (unsigned int)pos);
numBadBlocks++;
}
}
bml_over_mtd_read_close(readCtx);
if (numBadBlocks == 0)
{
printf("No bad blocks.\n");
return 0;
}
return -1 ;
}
int main(int argc, char **argv)
{
if (argc != 7 && (argc != 3 || (argc == 3 && strcmp(argv[1],"scan"))!=0)
&& (argc != 6 || (argc == 6 && strcmp(argv[1],"scan"))!=0))
return die("Usage: %s dump|flash <partition> <partition_start_block> <reservoirpartition> <reservoir_start_block> <file>\n"
"E.g. %s dump boot 72 reservoir 2004 file.bin\n"
"Usage: %s scan <partition> [<partition_start_block> <reservoirpartition> <reservoir_start_block>]\n"
,argv[0], argv[0], argv[0]);
int num_partitions = mtd_scan_partitions();
const MtdPartition *pSrcPart = mtd_find_partition_by_name(argv[2]);
if (pSrcPart == NULL)
return die("Cannot find partition %s", argv[2]);
int scanResult = scan_partition(pSrcPart);
if (argc == 3 && strcmp(argv[1],"scan")==0)
{
return (scanResult == 0 ? 0 : EXIT_CODE_BAD_BLOCKS);
}
int retVal = 0;
const MtdPartition* pReservoirPart = mtd_find_partition_by_name(argv[4]);
if (pReservoirPart == NULL)
return die("Cannot find partition %s", argv[4]);
int srcPartStartBlock = atoi(argv[3]);
int reservoirPartStartBlock = atoi(argv[5]);
const unsigned short* pMapping = CreateBlockMapping(pSrcPart, srcPartStartBlock,
pReservoirPart, reservoirPartStartBlock);
if (pMapping == NULL && scanResult == 0)
{
printf("Generating empty block mapping table for error-free partition.\n");
pMapping = CreateEmptyBlockMapping(pSrcPart);
}
if (argc == 6 && strcmp(argv[1],"scan")==0)
{
retVal = (scanResult == 0 ? 0 : EXIT_CODE_BAD_BLOCKS);
}
if (pMapping == NULL)
return die("Failed to create block mapping table");
if (strcmp(argv[1],"dump")==0)
{
retVal = dump_bml_partition(pSrcPart, pReservoirPart, pMapping, argv[6]);
if (retVal == 0)
printf("Successfully dumped partition to %s\n", argv[6]);
}
if (strcmp(argv[1],"flash")==0)
{
retVal = flash_bml_partition(pSrcPart, pReservoirPart, pMapping, argv[6]);
if (retVal == 0)
printf("Successfully wrote %s to partition\n", argv[6]);
}
ReleaseBlockMapping(pMapping);
return retVal;
}