From e03df7326702365d88caf5cc4de72259e7f22f0f Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Thu, 30 Jun 2011 19:05:19 -0700 Subject: Support bootloader and radio OTAs for Prime. For bootloader figure out the correct xloader location in bootloader.img and write to /xloader. The sbl is always in the same place, and can be written to /sbl. For radio the radio.img just needs to be written to /radio. Change-Id: I7b3b82b5c093331287ada24ba8ebce31a79f74bf --- BoardConfig.mk | 3 + recovery.fstab | 5 +- recovery/Android.mk | 13 ++++ recovery/bootloader.c | 157 ++++++++++++++++++++++++++++++++++++++++++++ recovery/bootloader.h | 25 +++++++ recovery/recovery_updater.c | 62 +++++++++++++++++ releasetools.py | 76 +++++++++++++++++++++ 7 files changed, 339 insertions(+), 2 deletions(-) create mode 100644 recovery/bootloader.c create mode 100644 recovery/bootloader.h create mode 100644 recovery/recovery_updater.c create mode 100644 releasetools.py diff --git a/BoardConfig.mk b/BoardConfig.mk index ba350b1..8fed1a7 100644 --- a/BoardConfig.mk +++ b/BoardConfig.mk @@ -45,6 +45,9 @@ USE_OPENGL_RENDERER := true TARGET_RECOVERY_PIXEL_FORMAT := "BGRA_8888" TARGET_RECOVERY_UI_LIB := librecovery_ui_tuna + +# device-specific extensions to the updater binary +TARGET_RECOVERY_UPDATER_LIBS += librecovery_updater_tuna TARGET_RELEASETOOLS_EXTENSIONS := device/samsung/tuna TARGET_USERIMAGES_USE_EXT4 := true diff --git a/recovery.fstab b/recovery.fstab index b00e6a2..6e33ce7 100644 --- a/recovery.fstab +++ b/recovery.fstab @@ -7,5 +7,6 @@ /misc emmc /dev/block/platform/omap/omap_hsmmc.0/by-name/misc /boot emmc /dev/block/platform/omap/omap_hsmmc.0/by-name/boot /recovery emmc /dev/block/platform/omap/omap_hsmmc.0/by-name/recovery -/bootloader mtd bootloader -/radio mtd radio +/sbl emmc /dev/block/platform/omap/omap_hsmmc.0/by-name/sbl +/xloader emmc /dev/block/platform/omap/omap_hsmmc.0/by-name/xloader +/radio emmc /dev/block/platform/omap/omap_hsmmc.0/by-name/radio diff --git a/recovery/Android.mk b/recovery/Android.mk index 375424c..585db84 100644 --- a/recovery/Android.mk +++ b/recovery/Android.mk @@ -12,4 +12,17 @@ LOCAL_MODULE := librecovery_ui_tuna include $(BUILD_STATIC_LIBRARY) +include $(CLEAR_VARS) + +# Edify extension functions for doing bootloader updates on Tuna devices. + +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES += bootable/recovery +LOCAL_SRC_FILES := recovery_updater.c bootloader.c + +# should match TARGET_RECOVERY_UPDATER_LIBS set in BoardConfig.mk +LOCAL_MODULE := librecovery_updater_tuna + +include $(BUILD_STATIC_LIBRARY) + endif diff --git a/recovery/bootloader.c b/recovery/bootloader.c new file mode 100644 index 0000000..e178b7b --- /dev/null +++ b/recovery/bootloader.c @@ -0,0 +1,157 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include "bootloader.h" + +#define PARTITION_TABLE_SIZE 4096 // 4KB + +#define BOOT_PART_LEN 0x20000 // 128KB + +#define SMALL_BUFFER_SIZE 0x20 + +static const char* FAMILY_LOCATION = "/sys/board_properties/soc/family"; +static const char* TYPE_LOCATION = "/sys/board_properties/soc/type"; + +unsigned int read_whole_file(const char* fname, char* buffer, + int buffer_size) { + memset(buffer, 0, buffer_size); + + FILE* f = fopen(fname, "rb"); + if (f == NULL) { + fprintf(stderr, "Cannot open %s!\n", fname); + return 0; + } + + int read_byte_count = fread(buffer, 1, buffer_size, f); + fclose(f); + if (read_byte_count >= buffer_size) { + fprintf(stderr, "The data in %s is too large for the buffer", fname); + return 0; + } + + return 1; +} + +// Four different device/chip type xloaders are supported by a bootloader.img: +// 4460 EMU, 4460 HS, 4430 EMU, 4430 HS. +// The layout of the bootloader.img is: +// +// Partition table (4KB) +// 4460 EMU xloader (128KB) +// 4460 HS xloader (128KB) +// 4430 EMU xloader (128KB) +// 4430 HS xloader(128KB) +// sbl (the rest) +unsigned int get_xloader_offset() { + unsigned int offset = 0; + char* file_data = malloc(SMALL_BUFFER_SIZE); + if (file_data == NULL) { + return -1; + } + + if (!read_whole_file(FAMILY_LOCATION, file_data, SMALL_BUFFER_SIZE)) { + fprintf(stderr, "Cannot read the family\n"); + free(file_data); + return -1; + } + + if (strncmp(file_data, "OMAP4430", 8) == 0) { + offset += (BOOT_PART_LEN * 2); + } else if (strncmp(file_data, "OMAP4460", 8) != 0) { + fprintf(stderr, "Unknown family: %s\n", file_data); + free(file_data); + return -1; + } + + if (!read_whole_file(TYPE_LOCATION, file_data, SMALL_BUFFER_SIZE)) { + fprintf(stderr, "Cannot read the type\n"); + free(file_data); + return -1; + } + + if (strncmp(file_data, "HS", 2) == 0) { + offset += BOOT_PART_LEN; + } else if (strncmp(file_data, "EMU", 3) != 0) { + fprintf(stderr, "Unknown type: %s\n", file_data); + free(file_data); + return -1; + } + + return offset; +} + +int update_bootloader(const char* image_data, + size_t image_size, + const char* xloader_loc, + const char* sbl_loc) { + unsigned int xloader_offset=0; + unsigned int sbl_offset=0; + + int type_family_offset = get_xloader_offset(); + if (type_family_offset < 0) { + return -1; + } + + // The offsets into the relevant parts of the bootloader image + xloader_offset = PARTITION_TABLE_SIZE + type_family_offset; + sbl_offset = PARTITION_TABLE_SIZE + (BOOT_PART_LEN * 4); + + if (image_size < sbl_offset) { + fprintf(stderr, "image size %d is too small\n", image_size); + return -1; + } + + int written = 0; + int close_status = 0; + + FILE* xloader = fopen(xloader_loc, "r+b"); + if (xloader == NULL) { + fprintf(stderr, "Could not open %s\n", xloader_loc); + return -1; + } + + // index into the correct xloader offset + written = fwrite(image_data+xloader_offset, 1, BOOT_PART_LEN, xloader); + close_status = fclose(xloader); + if (written != BOOT_PART_LEN || close_status != 0) { + fprintf(stderr, "Failed writing to /xloader\n"); + return -1; + } + + unsigned int sbl_size = image_size - sbl_offset; + FILE* sbl = fopen(sbl_loc, "r+b"); + if (sbl == NULL) { + fprintf(stderr, "Could not open %s\n", sbl_loc); + return -1; + } + + written = fwrite(image_data+sbl_offset, 1, sbl_size, sbl); + close_status = fclose(sbl); + if (written != sbl_size || close_status != 0) { + fprintf(stderr, "Failed writing to /sbl\n"); + return -1; + } + + return 0; +} diff --git a/recovery/bootloader.h b/recovery/bootloader.h new file mode 100644 index 0000000..f7f7f26 --- /dev/null +++ b/recovery/bootloader.h @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#ifndef __BOOTLOADER_H__ +#define __BOOTLOADER_H__ + +int update_bootloader(const char* image_data, + size_t image_size, + const char* xloader_loc, + const char* sbl_loc); + +#endif diff --git a/recovery/recovery_updater.c b/recovery/recovery_updater.c new file mode 100644 index 0000000..02963f5 --- /dev/null +++ b/recovery/recovery_updater.c @@ -0,0 +1,62 @@ +/* + * 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 +#include +#include +#include +#include + +#include "edify/expr.h" +#include "bootloader.h" + +Value* WriteBootloaderFn(const char* name, State* state, int argc, Expr* argv[]) +{ + int result = -1; + Value* img; + Value* xloader_loc; + Value* sbl_loc; + + if (argc != 3) { + return ErrorAbort(state, "%s() expects 3 args, got %d", name, argc); + } + + if (ReadValueArgs(state, argv, 3, &img, &xloader_loc, &sbl_loc) < 0) { + return NULL; + } + + if(img->type != VAL_BLOB || + xloader_loc->type != VAL_STRING || + sbl_loc->type != VAL_STRING) { + FreeValue(img); + FreeValue(xloader_loc); + FreeValue(sbl_loc); + return ErrorAbort(state, "%s(): argument types are incorrect", name); + } + + result = update_bootloader(img->data, img->size, + xloader_loc->data, sbl_loc->data); + FreeValue(img); + FreeValue(xloader_loc); + FreeValue(sbl_loc); + return StringValue(strdup(result == 0 ? "t" : "")); +} + +void Register_librecovery_updater_tuna() { + fprintf(stderr, "installing samsung updater extensions\n"); + + RegisterFunction("samsung.write_bootloader", WriteBootloaderFn); +} diff --git a/releasetools.py b/releasetools.py new file mode 100644 index 0000000..1d0863c --- /dev/null +++ b/releasetools.py @@ -0,0 +1,76 @@ +# Copyright (C) 2009 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. + +"""Emit commands needed for Prime during OTA installation +(installing the bootloader and radio images).""" + +import common + +def FullOTA_InstallEnd(info): + try: + bootloader_img = info.input_zip.read("RADIO/bootloader.img") + except KeyError: + print "no bootloader.img in target_files; skipping install" + else: + WriteBootloader(info, bootloader_img) + + try: + radio_img = info.input_zip.read("RADIO/radio.img") + except KeyError: + print "no radio.img in target_files; skipping install" + else: + WriteRadio(info, radio_img) + +def IncrementalOTA_InstallEnd(info): + try: + target_bootloader_img = info.target_zip.read("RADIO/bootloader.img") + try: + source_bootloader_img = info.source_zip.read("RADIO/bootloader.img") + except KeyError: + source_bootloader_img = None + + if source_bootloader_img == target_bootloader_img: + print "bootloader unchanged; skipping" + else: + WriteBootloader(info, target_bootloader_img) + except KeyError: + print "no bootloader.img in target target_files; skipping install" + + try: + target_radio_img = info.target_zip.read("RADIO/radio.img") + try: + source_radio_img = info.source_zip.read("RADIO/radio.img") + except KeyError: + source_radio_img = None + + if source_radio_img == target_radio_img: + print "radio unchanged; skipping" + else: + WriteRadio(info, target_radio_img) + except KeyError: + print "no radio.img in target target_files; skipping install" + +def WriteBootloader(info, bootloader_img): + common.ZipWriteStr(info.output_zip, "bootloader.img", bootloader_img) + fstab = info.info_dict["fstab"] + + info.script.Print("Writing bootloader...") + info.script.AppendExtra('''samsung.write_bootloader( + package_extract_file("bootloader.img"), "%s", "%s");''' % \ + (fstab["/xloader"].device, fstab["/sbl"].device)) + +def WriteRadio(info, radio_img): + common.ZipWriteStr(info.output_zip, "radio.img", radio_img) + info.script.Print("Writing radio...") + info.script.WriteRawImage("/radio", "radio.img") -- cgit v1.1