From 80a90edd47d20141cfb7b18ededc9a3090fba58c Mon Sep 17 00:00:00 2001 From: Sergey 'Jin' Bostandzhyan Date: Fri, 4 Jan 2013 02:29:03 +0100 Subject: Work around MEMERASE ioctl for rk3066 compatibility Due to a kernel bug and no available sources we have to work around the MEMERASE ioctl - if used, it hangs and never returns. I straced the original recovery executable and could see that it is simply calling write() with a bunch of zeroes instead of using MEMERASE. Added a hack that does the same and now the resulting TWRP recovery image works. Change-Id: I1b1c1c9e870e350776346bdca5d442c7ef565aa0 --- Android.mk | 4 ++++ mtdutils/Android.mk | 5 +++++ mtdutils/bml_over_mtd.c | 12 ++++++++++ mtdutils/mtdutils.c | 22 ++++++++++++++++++ mtdutils/rk30hack.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ mtdutils/rk30hack.h | 37 ++++++++++++++++++++++++++++++ 6 files changed, 140 insertions(+) create mode 100644 mtdutils/rk30hack.c create mode 100644 mtdutils/rk30hack.h diff --git a/Android.mk b/Android.mk index 725436a0a..2f8c1942d 100644 --- a/Android.mk +++ b/Android.mk @@ -206,6 +206,10 @@ ifeq ($(TW_INCLUDE_JB_CRYPTO), true) LOCAL_C_INCLUDES += system/extras/ext4_utils external/openssl/include endif +ifeq ($(TARGET_BOARD_PLATFORM),rk30xx) +LOCAL_CFLAGS += -DRK3066 +endif + include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) diff --git a/mtdutils/Android.mk b/mtdutils/Android.mk index 12322b457..0c238e1d2 100644 --- a/mtdutils/Android.mk +++ b/mtdutils/Android.mk @@ -7,9 +7,14 @@ LOCAL_SRC_FILES := \ mtdutils.c \ mounts.c +ifeq ($(TARGET_BOARD_PLATFORM),rk30xx) +LOCAL_SRC_FILES += rk30hack.c +endif + LOCAL_MODULE := libmtdutils LOCAL_STATIC_LIBRARIES := libcutils libc LOCAL_FORCE_STATIC_EXECUTABLE := true + include $(BUILD_STATIC_LIBRARY) endif # !TARGET_SIMULATOR diff --git a/mtdutils/bml_over_mtd.c b/mtdutils/bml_over_mtd.c index c40179281..a68950e40 100644 --- a/mtdutils/bml_over_mtd.c +++ b/mtdutils/bml_over_mtd.c @@ -31,6 +31,10 @@ #include "mtdutils.h" +#ifdef RK3066 + #include "rk30hack.h" +#endif + typedef struct BmlOverMtdReadContext { const MtdPartition *partition; char *buffer; @@ -518,11 +522,19 @@ static ssize_t bml_over_mtd_write_block(int fd, ssize_t erase_size, char* data) erase_info.length = size; int retry; for (retry = 0; retry < 2; ++retry) { +#ifdef RK3066 + if (rk30_zero_out(fd, pos, size) < 0) { + fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n", + pos, strerror(errno)); + continue; + } +#else if (ioctl(fd, MEMERASE, &erase_info) < 0) { fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } +#endif if (lseek(fd, pos, SEEK_SET) != pos || write(fd, data, size) != size) { fprintf(stderr, "mtd: write error at 0x%08lx (%s)\n", diff --git a/mtdutils/mtdutils.c b/mtdutils/mtdutils.c index a76b8e992..032b04bac 100644 --- a/mtdutils/mtdutils.c +++ b/mtdutils/mtdutils.c @@ -28,6 +28,10 @@ #include "mtdutils.h" +#ifdef RK3066 + #include "rk30hack.h" +#endif + struct MtdReadContext { const MtdPartition *partition; char *buffer; @@ -423,11 +427,19 @@ static int write_block(MtdWriteContext *ctx, const char *data) erase_info.length = size; int retry; for (retry = 0; retry < 2; ++retry) { +#ifdef RK3066 + if (rk30_zero_out(fd, pos, size) < 0) { + fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n", + pos, strerror(errno)); + continue; + } +#else if (ioctl(fd, MEMERASE, &erase_info) < 0) { fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } +#endif if (lseek(fd, pos, SEEK_SET) != pos || write(fd, data, size) != size) { fprintf(stderr, "mtd: write error at 0x%08lx (%s)\n", @@ -457,7 +469,11 @@ static int write_block(MtdWriteContext *ctx, const char *data) // Try to erase it once more as we give up on this block add_bad_block_offset(ctx, pos); fprintf(stderr, "mtd: skipping write block at 0x%08lx\n", pos); +#ifdef RK3066 + rk30_zero_out(fd, pos, size); +#else ioctl(fd, MEMERASE, &erase_info); +#endif pos += partition->erase_size; } @@ -527,9 +543,15 @@ off_t mtd_erase_blocks(MtdWriteContext *ctx, int blocks) struct erase_info_user erase_info; erase_info.start = pos; erase_info.length = ctx->partition->erase_size; +#ifdef RK3066 + if (rk30_zero_out(ctx->fd, pos, ctx->partition->erase_size) < 0) { + fprintf(stderr, "mtd: erase failure at 0x%08lx\n", pos); + } +#else if (ioctl(ctx->fd, MEMERASE, &erase_info) < 0) { fprintf(stderr, "mtd: erase failure at 0x%08lx\n", pos); } +#endif pos += ctx->partition->erase_size; } diff --git a/mtdutils/rk30hack.c b/mtdutils/rk30hack.c new file mode 100644 index 000000000..e9351b52e --- /dev/null +++ b/mtdutils/rk30hack.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013, Sergey 'Jin' Bostandzhyan + * + * 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. + */ + +/* This is a hack for Rockchip rk30xx based devices. The problem is that + * the MEMERASE ioctl is failing (hangs and never returns) in their kernel. + * The sources are not fully available, so fixing it in the rk30xxnand_ko driver + * is not possible. + * + * I straced the stock recovery application and it seems to avoid this + * particular ioctl, instead it is simply writing zeroes using the write() call. + * + * This workaround does the same and will replace all MEMERASE occurances in + * the recovery code. + */ + +#include +#include +#include +#include +#include + +#include "rk30hack.h" + +int rk30_zero_out(int fd, off_t pos, ssize_t size) +{ + if (lseek(fd, pos, SEEK_SET) != pos) { + fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n", + pos, strerror(errno)); + return -1; + } + + unsigned char *zb = (unsigned char *)calloc(1, size); + if (zb == NULL) { + fprintf(stderr, "mtd: erase failure, could not allocate memory\n"); + return -1; + } + + if (write(fd, zb, size) != size) { + fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n", + pos, strerror(errno)); + free(zb); + return -1; + } + + free(zb); + return 0; +} diff --git a/mtdutils/rk30hack.h b/mtdutils/rk30hack.h new file mode 100644 index 000000000..d492793ff --- /dev/null +++ b/mtdutils/rk30hack.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013 Sergey 'Jin' Bostandzhyan + * + * 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. + */ + +/* This is a hack for Rockchip rk30xx based devices. The problem is that + * the MEMERASE ioctl is failing (hangs and never returns) in their kernel. + * The sources are not fully available, so fixing it in the rk30xxnand_ko driver + * is not possible. + * + * I straced the stock recovery application and it seems to avoid this + * particular ioctl, instead it is simply writing zeroes using the write() call. + * + * This workaround does the same and will replace all MEMERASE occurances in + * the recovery code. + */ + +#ifndef __RK30_HACK_H__ +#define __RK30_HACK_H__ + +#include // for size_t, etc. + +// write zeroes to fd at position pos +int zero_out(int fd, off_t pos, ssize_t length); + +#endif//__RK30_HACK_H__ -- cgit v1.2.3