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
This commit is contained in:
Sergey 'Jin' Bostandzhyan
2013-01-05 00:23:06 +01:00
parent d9a9616195
commit 80a90edd47
6 changed files with 140 additions and 0 deletions
+4
View File
@@ -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)
+5
View File
@@ -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
+12
View File
@@ -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",
+22
View File
@@ -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;
}
+60
View File
@@ -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 <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#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;
}
+37
View File
@@ -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 <sys/types.h> // 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__