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:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__
|
||||
Reference in New Issue
Block a user