diff --git a/Android.mk b/Android.mk index 1ae53b25b6e63e6b57495c7b409f05670d9ab279..ba3cab01977b0f508fac1de3066d217cbb10de10 100644 --- a/Android.mk +++ b/Android.mk @@ -47,3 +47,5 @@ $(DX): $(AAPT): mkdir -p $(@D) ln -sf $(FAKETOOLS_AAPT) $@ + +include $(LOCAL_PATH)/updater/Android.mk diff --git a/b2g_product.mk b/b2g_product.mk index dd76bca59336721cb33aa393a2b6c7820ce94d6a..bce99c260bc2c8753410bbe74cacde9b967b5e8d 100644 --- a/b2g_product.mk +++ b/b2g_product.mk @@ -28,6 +28,7 @@ include gonk-misc/b2g.mk TARGET_PROVIDES_INIT_RC := PRODUCT_PACKAGES := $(filter-out fakeperm rilproxy,$(PRODUCT_PACKAGES)) +PRODUCT_PACKAGES += librecovery_updater_qcom PRODUCT_PROPERTY_OVERRIDES += \ ro.moz.ril.emergency_by_default=true diff --git a/patch/ics_strawberry/bootable/bootloader/lk/ota_fotacookie_withECC.patch b/patch/ics_strawberry/bootable/bootloader/lk/ota_fotacookie_withECC.patch new file mode 100644 index 0000000000000000000000000000000000000000..1977c473a43be11d31b2cae2a78febc5a3feaa26 --- /dev/null +++ b/patch/ics_strawberry/bootable/bootloader/lk/ota_fotacookie_withECC.patch @@ -0,0 +1,34 @@ +From ddd6a1ad574c18e33804be4122ea08ab6717eae6 Mon Sep 17 00:00:00 2001 +From: Vasanthakumar Pandurangan <vasanth@codeaurora.org> +Date: Tue, 23 Oct 2012 12:16:53 +0530 +Subject: [PATCH] For Modem ota update in Nand devices, bootloader should + write a magic cookie in FOTA partition which it already does + but without ECC. This change is to do the same with ECC + +Change-Id: Iadaf6fd2c5197abc618aa249b88b2c4529257eee +Signed-off-by: Vasanthakumar Pandurangan <vasanth@codeaurora.org> +--- + platform/msm_shared/nand.c | 5 ----- + 1 files changed, 0 insertions(+), 5 deletions(-) + +diff --git a/platform/msm_shared/nand.c b/platform/msm_shared/nand.c +index 08b68dd..b59df28 100644 +--- a/platform/msm_shared/nand.c ++++ b/platform/msm_shared/nand.c +@@ -159,13 +159,8 @@ static struct flash_identification supported_flash[] = { + + static void set_nand_configuration(char type) + { +- if (type == TYPE_MODEM_PARTITION) { +- CFG0 = CFG0_M; +- CFG1 = CFG1_M; +- } else { + CFG0 = CFG0_A; + CFG1 = CFG1_A; +- } + } + + static void flash_nand_read_id(dmov_s * cmdlist, unsigned *ptrlist) +-- +1.7.8.3 + diff --git a/patch/ics_strawberry/bootable/recovery/handle_radio_update.patch b/patch/ics_strawberry/bootable/recovery/handle_radio_update.patch new file mode 100644 index 0000000000000000000000000000000000000000..a93ebf34d4777bb17c527ccb155a4d3d8495cc3c --- /dev/null +++ b/patch/ics_strawberry/bootable/recovery/handle_radio_update.patch @@ -0,0 +1,109 @@ +diff --git a/recovery.c b/recovery.c +index cddcbd6..e261af7 100644 +--- a/recovery.c ++++ b/recovery.c +@@ -1,6 +1,6 @@ + /* + * Copyright (C) 2007 The Android Open Source Project +- * ++ * Copyright (c) 2012, The Linux Foundation. All rights reserved. + * 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 +@@ -58,6 +58,7 @@ static const struct option OPTIONS[] = { + { "wipe_data", no_argument, NULL, 'w' }, + { "wipe_cache", no_argument, NULL, 'c' }, + { "show_text", no_argument, NULL, 't' }, ++ { "radio_status", no_argument, NULL, 'r' }, + { NULL, 0, NULL, 0 }, + }; + +@@ -67,6 +68,7 @@ static const char *LOG_FILE = "/cache/recovery/log"; + static const char *LAST_LOG_FILE = "/cache/recovery/last_log"; + static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install"; + static const char *CACHE_ROOT = "/cache"; ++static const char *RADIO_DIR = "/sdcard/radio"; + static const char *SDCARD_ROOT = "/sdcard"; + static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log"; + static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install"; +@@ -592,9 +594,12 @@ update_directory(const char* path, const char* unmount_when_done, + ui_print("\n-- Install %s ...\n", path); + set_sdcard_update_bootloader_message(); + char* copy = copy_sideloaded_package(new_path); +- if (unmount_when_done != NULL) { +- ensure_path_unmounted(unmount_when_done); ++ // create radio folder for QCOM radio image update ++ if((mkdir(RADIO_DIR,777) != 0) && (errno != EEXIST)) { // In this case EEXIST is not a valid error ++ result = INSTALL_ERROR; ++ break; + } ++ + if (copy) { + result = install_package(copy, wipe_cache, TEMPORARY_INSTALL_FILE); + free(copy); +@@ -1326,7 +1331,7 @@ main(int argc, char **argv) { + const char *send_intent = NULL; + const char *update_package = NULL; + int wipe_data = 0, wipe_cache = 0; +- ++ int radio_status_present = 0; + //check delta update first + handle_deltaupdate_status(); + +@@ -1339,6 +1344,7 @@ main(int argc, char **argv) { + case 'w': wipe_data = wipe_cache = 1; break; + case 'c': wipe_cache = 1; break; + case 't': ui_show_text(1); break; ++ case 'r': radio_status_present = 1; break; + case '?': + LOGE("Invalid command argument\n"); + continue; +@@ -1375,13 +1381,25 @@ main(int argc, char **argv) { + int status = INSTALL_SUCCESS; + + if (update_package != NULL) { +- status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE); +- if (status == INSTALL_SUCCESS && wipe_cache) { +- if (erase_volume("/cache")) { +- LOGE("Cache wipe (requested by package) failed."); ++ if(ensure_path_mounted(SDCARD_ROOT) != 0) { ++ ui_print("ensure_path_mounted failed.\n"); ++ status = INSTALL_ERROR; ++ } else if((mkdir(RADIO_DIR,777) != 0) && (errno != EEXIST)) { ++ //In this case EEXIST is not a valid error ++ ui_print("creating radio directory failed. errno = %d\n", errno); ++ status = INSTALL_ERROR; ++ } else { ++ finish_recovery(NULL); ++ status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE); ++ if (status == INSTALL_SUCCESS && wipe_cache) { ++ if (erase_volume("/cache")) { ++ LOGE("Cache wipe (requested by package) failed."); ++ status = INSTALL_ERROR; ++ } + } ++ if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n"); ++ ensure_path_unmounted(SDCARD_ROOT); + } +- if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n"); + } else if (wipe_data) { + if (device_wipe_data()) status = INSTALL_ERROR; + if (erase_volume("/data")) status = INSTALL_ERROR; +@@ -1390,6 +1408,9 @@ main(int argc, char **argv) { + } else if (wipe_cache) { + if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR; + if (status != INSTALL_SUCCESS) ui_print("Cache wipe failed.\n"); ++ } else if (radio_status_present) { ++ //irrespective of radio_status value, request for a reboot ++ goto recovery_end; + } else { + status = INSTALL_ERROR; // No command specified + } +@@ -1399,6 +1420,7 @@ main(int argc, char **argv) { + prompt_and_wait(); + } + ++recovery_end: + // Otherwise, get ready to boot the main system... + finish_recovery(send_intent); + ui_print("Rebooting...\n"); diff --git a/patch/ics_strawberry/build/include_radio_image.patch b/patch/ics_strawberry/build/include_radio_image.patch new file mode 100644 index 0000000000000000000000000000000000000000..b5ab986e8599442d7b6e09755ac7b99cf7188959 --- /dev/null +++ b/patch/ics_strawberry/build/include_radio_image.patch @@ -0,0 +1,47 @@ +diff --git a/core/Makefile b/core/Makefile +index 48275cf..eb20e75 100644 +--- a/core/Makefile ++++ b/core/Makefile +@@ -1273,6 +1273,7 @@ name := $(name)-target_files-$(FILE_NAME_TAG) + + intermediates := $(call intermediates-dir-for,PACKAGING,target_files) + BUILT_TARGET_FILES_PACKAGE := $(intermediates)/$(name).zip ++BUILT_TARGET_RADIO_PACKAGE := $(intermediates)/$(name)/RADIO + $(BUILT_TARGET_FILES_PACKAGE): intermediates := $(intermediates) + $(BUILT_TARGET_FILES_PACKAGE): \ + zip_root := $(intermediates)/$(name) +@@ -1440,6 +1441,7 @@ ifdef BOARD_KERNEL_2KPAGESIZE + endif + endif + $(hide) $(foreach t,$(INSTALLED_RADIOIMAGE_TARGET),\ ++ echo "INSTALLED_RADIOIMAGE_TARGET $(t)"; \ + mkdir -p $(zip_root)/RADIO; \ + $(ACP) $(t) $(zip_root)/RADIO/$(notdir $(t));) + @# Contents of the system image +@@ -1523,7 +1525,7 @@ INTERNAL_OTA_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip + + $(INTERNAL_OTA_PACKAGE_TARGET): KEY_CERT_PAIR := $(DEFAULT_KEY_CERT_PAIR) + +-$(INTERNAL_OTA_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(OTATOOLS) ++$(INTERNAL_OTA_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(OTATOOLS) $(INSTALLED_RADIOIMAGE_TARGET) + @echo "Package OTA: $@" + $(hide) ./build/tools/releasetools/ota_from_target_files -v \ + -p $(HOST_OUT) \ +@@ -1535,7 +1537,7 @@ INTERNAL_2KNAND_OTA_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name)_2knand.zip + + $(INTERNAL_2KNAND_OTA_PACKAGE_TARGET): KEY_CERT_PAIR := $(DEFAULT_KEY_CERT_PAIR) + +-$(INTERNAL_2KNAND_OTA_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(OTATOOLS) ++$(INTERNAL_2KNAND_OTA_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(OTATOOLS) $(INSTALLED_RADIOIMAGE_TARGET) + @echo "Package OTA: $@" + $(hide) ./build/tools/releasetools/ota_from_target_files -v \ + -p $(HOST_OUT) \ +@@ -1552,7 +1554,7 @@ endif + + $(INTERNAL_MMC_OTA_PACKAGE_TARGET): KEY_CERT_PAIR := $(DEFAULT_KEY_CERT_PAIR) + +-$(INTERNAL_MMC_OTA_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(OTATOOLS) ++$(INTERNAL_MMC_OTA_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(OTATOOLS) $(INSTALLED_RADIOIMAGE_TARGET) + @echo "Package OTA: $@" + $(hide) ./build/tools/releasetools/ota_from_target_files -v \ + -p $(HOST_OUT) \ diff --git a/patch/ics_strawberry/device/qcom/common/device_specific_fw_update.patch b/patch/ics_strawberry/device/qcom/common/device_specific_fw_update.patch new file mode 100644 index 0000000000000000000000000000000000000000..90dcab2fbb5cb67696ee0df4d402daee4491333b --- /dev/null +++ b/patch/ics_strawberry/device/qcom/common/device_specific_fw_update.patch @@ -0,0 +1,163 @@ +diff --git a/common.mk b/common.mk +index 2f3622f..8080d70 100755 +--- a/common.mk ++++ b/common.mk +@@ -360,6 +360,8 @@ TSLIB_EXTERNAL += ts + QRGND := qrngd + QRGND += qrngtest + ++#UPDATER ++UPDATER := librecovery_ui_qcom + #WPA + WPA := wpa_supplicant.conf + +diff --git a/releasetools.py b/releasetools.py +index 45d0953..f6210b1 100755 +--- a/releasetools.py ++++ b/releasetools.py +@@ -19,22 +18,6 @@ + import common + import re + +-def LoadFilesMap(zip, type): +- try: +- data = zip.read("RADIO/filesmap") +- except KeyError: +- print "Warning: could not find RADIO/filesmap in %s." % zip +- data = "" +- d = {} +- for line in data.split("\n"): +- line = line.strip() +- if not line or line.startswith("#"): continue +- pieces = line.split() +- if not (len(pieces) == 2): +- raise ValueError("malformed filesmap line: \"%s\"" % (line,)) +- d[pieces[0]] = pieces[1] +- return d +- + def GetRadioFiles(z): + out = {} + for info in z.infolist(): +@@ -44,51 +27,93 @@ def GetRadioFiles(z): + return out + + def FullOTA_Assertions(info): +- #TODO: Implement device specific asserstions. +- return ++ AddBootloaderAssertion(info, info.input_zip) ++ + + def IncrementalOTA_Assertions(info): +- #TODO: Implement device specific asserstions. +- return ++ AddBootloaderAssertion(info, info.target_zip) ++ ++ ++def AddBootloaderAssertion(info, input_zip): ++ android_info = input_zip.read("OTA/android-info.txt") ++ m = re.search(r"require\s+version-bootloader\s*=\s*(\S+)", android_info) ++ if m: ++ bootloaders = m.group(1).split("|") ++ if "*" not in bootloaders: ++ info.script.AssertSomeBootloader(*bootloaders) ++ info.metadata["pre-bootloader"] = m.group(1) ++ ++def CheckRadiotarget(info, mount_point): ++ fstab = info.script.info.get("fstab", None) ++ if fstab: ++ p = fstab[mount_point] ++ info.script.AppendExtra('assert(qcom.set_radio("%s"));' % ++ (p.fs_type)) ++ ++# map qcom partitions with filenames ++QCOM_MOUNT_MAP = { "NON-HLOS.bin": "modem", ++ "rpm.mbn": "rpm", ++ "sbl1.mbn": "sbl1", ++ "sbl2.mbn": "sbl2", ++ "sbl3.mbn": "sbl3", ++ "tz.mbn": "tz", ++ "emmc_appsboot.mbn": "aboot", ++ "radio.img": "radio"} ++ ++ ++def InstallRadio(radio_img, api_version, input_zip, fn, info): ++ fn2 = fn[6:] ++ fn3 = "/sdcard/radio/" + fn2 ++ common.ZipWriteStr(info.output_zip, fn2, radio_img) + +-def InstallRawImage(image_data, api_version, input_zip, fn, info, filesmap): +- #fn is in RADIO/* format. Extracting just file name. +- filename = fn[6:] + if api_version >= 3: +- if filename not in filesmap: ++ if (fn2.endswith("ENC") or fn2.endswith("enc")): ++ info.script.AppendExtra((''' ++assert(package_extract_file("%s", "%s")); ++''' %(fn2,fn3) % locals()).lstrip()) ++ else: ++ fstab = info.script.info.get("fstab", None) ++ if fn2 not in QCOM_MOUNT_MAP: ++ return ++ if QCOM_MOUNT_MAP[fn2] not in fstab: ++ return ++ info.script.WriteRawImage(QCOM_MOUNT_MAP[fn2], fn2); + return +- info.script.AppendExtra('package_extract_file("%s", "%s");' % (filename,filesmap[filename])) +- common.ZipWriteStr(info.output_zip, filename, image_data) +- return ++ elif info.input_version >= 2: ++ info.script.AppendExtra( ++ 'write_firmware_image("PACKAGE:radio.img", "radio");') + else: +- print "warning raido-update: no support for api_version less than 3." ++ info.script.AppendExtra( ++ ('assert(package_extract_file("radio.img", "/tmp/radio.img"),\n' ++ ' write_firmware_image("/tmp/radio.img", "radio"));\n')) ++ + +-def FULLOTA_InstallEnd_MMC(info): ++def FullOTA_InstallEnd(info): + files = GetRadioFiles(info.input_zip) + if files == {}: +- print "warning radio-update: no radio image in input target_files; not flashing radio" ++ print "warning sha: no radio image in input target_files; not flashing radio" + return ++ ++ enc_file = "false"; ++ + info.script.UnmountAll() + info.script.Print("Writing radio image...") +- #Load filesmap file +- filesmap = LoadFilesMap(info.input_zip, info.type) +- if filesmap == {}: +- print "warning radio-update: no or invalid filesmap file found. not flashing radio" +- return + for f in files: +- image_data = info.input_zip.read(f) +- InstallRawImage(image_data, info.input_version, info.input_zip, f, info, filesmap) +- return ++ if (f.endswith("ENC") or f.endswith("enc")): ++ continue ++ radio_img = info.input_zip.read(f) ++ InstallRadio(radio_img, info.input_version, info.input_zip, f, info) + +-def FULLOTA_InstallEnd_MTD(info): +- print "warning radio-update: no implementation for radio upgrade for NAND devices" ++ for f in files: ++ if (f.endswith("ENC") or f.endswith("enc")): ++ radio_img = info.input_zip.read(f) ++ InstallRadio(radio_img, info.input_version, info.input_zip, f, info) ++ enc_file = "true" ++ ++ if (enc_file == "true"): ++ CheckRadiotarget(info, "/recovery") + return + +-def FullOTA_InstallEnd(info): +- if info.type == 'MTD': +- FULLOTA_InstallEnd_MTD(info) +- if info.type == 'MMC': +- FULLOTA_InstallEnd_MMC(info) + + def IncrementalOTA_InstallEnd(info): + #TODO: Implement device specific asserstions. diff --git a/patch/ics_strawberry/device/qcom/msm7627a/enable_recovery_updater.patch b/patch/ics_strawberry/device/qcom/msm7627a/enable_recovery_updater.patch new file mode 100644 index 0000000000000000000000000000000000000000..38aa1e0419cd38a4e7a65d47272053a0b722ab69 --- /dev/null +++ b/patch/ics_strawberry/device/qcom/msm7627a/enable_recovery_updater.patch @@ -0,0 +1,21 @@ +diff --git a/BoardConfig.mk b/BoardConfig.mk +index e8b6695..2d0243d 100644 +--- a/BoardConfig.mk ++++ b/BoardConfig.mk +@@ -61,6 +61,7 @@ BOARD_HAVE_BLUETOOTH := true + BOARD_HAVE_QCOM_FM := true + TARGET_HAVE_TSLIB := true + ++ADD_RADIO_FILES := true + TARGET_NO_BOOTLOADER := false + TARGET_NO_KERNEL := false + TARGET_NO_RADIOIMAGE := true +@@ -109,7 +110,7 @@ BOARD_USERDATAIMAGE_PARTITION_SIZE := 314556416 + BOARD_PERSISTIMAGE_PARTITION_SIZE := 10485760 + BOARD_CACHEIMAGE_PARTITION_SIZE := 41943040 + BOARD_FLASH_BLOCK_SIZE := 131072 # (BOARD_KERNEL_PAGESIZE * 64) +-#TARGET_RECOVERY_UPDATER_LIBS += librecovery_updater_qcom ++TARGET_RECOVERY_UPDATER_LIBS += librecovery_updater_qcom + + BOARD_HAVE_MXT224_CFG := true + diff --git a/updater/Android.mk b/updater/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..824b0b287be2edd0c1c672297b3be67eca8db10d --- /dev/null +++ b/updater/Android.mk @@ -0,0 +1,19 @@ +ifneq ($(TARGET_SIMULATOR),true) +ifeq ($(TARGET_ARCH),arm) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +# librecovery_update_qcom is a set of edify extension functions for +# doing radio update on QCOM devices. + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := recovery_updater.c firmware.c bootloader.c +LOCAL_STATIC_LIBRARIES += libmtdutils +LOCAL_C_INCLUDES += bootable/recovery +LOCAL_MODULE := librecovery_updater_qcom +include $(BUILD_STATIC_LIBRARY) + +endif # TARGET_ARCH == arm +endif # !TARGET_SIMULATOR diff --git a/updater/MODULE_LICENSE_APACHE2 b/updater/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/updater/NOTICE b/updater/NOTICE new file mode 100644 index 0000000000000000000000000000000000000000..64aaa8dbd68e6917b35c02655ba2f8d763165368 --- /dev/null +++ b/updater/NOTICE @@ -0,0 +1,190 @@ + + 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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/updater/bootloader.c b/updater/bootloader.c new file mode 100644 index 0000000000000000000000000000000000000000..2c2aee9d8d7526b1dca3f8efea87610bf2abad5e --- /dev/null +++ b/updater/bootloader.c @@ -0,0 +1,311 @@ +/* Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * 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 "bootloader.h" +#include "common.h" +#include "mtdutils/mtdutils.h" +#include "roots.h" + +#include <errno.h> +#include <stdio.h> +#include <string.h> + +static const int MISC_PAGES = 3; // number of pages to save +static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page + +#undef LOGE +#define LOGE(...) fprintf(stderr, "E:" __VA_ARGS__) + +#ifdef LOG_VERBOSE +static void dump_data(const char *data, int len) { + int pos; + for (pos = 0; pos < len; ) { + printf("%05x: %02x", pos, data[pos]); + for (++pos; pos < len && (pos % 24) != 0; ++pos) { + printf(" %02x", data[pos]); + } + printf("\n"); + } +} +#endif + +int get_bootloader_message_emmc(struct bootloader_message *out, Volume *v) { + FILE* f = fopen(v->device, "rb"); + if (f == NULL) { + LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); + return -1; + } + struct bootloader_message temp; + int count = fread(&temp, sizeof(temp), 1, f); + if (count != 1) { + LOGE("Failed reading %s\n(%s)\n", v->device, strerror(errno)); + return -1; + } + if (fclose(f) != 0) { + LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno)); + return -1; + } + memcpy(out, &temp, sizeof(temp)); + return 0; +} + +int set_bootloader_message_emmc(const struct bootloader_message *in, Volume *v) { + FILE* f = fopen(v->device, "wb"); + if (f == NULL) { + LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); + return -1; + } + int count = fwrite(in, sizeof(*in), 1, f); + if (count != 1) { + LOGE("Failed writing %s\n(%s)\n", v->device, strerror(errno)); + return -1; + } + if (fclose(f) != 0) { + LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno)); + return -1; + } + return 0; +} + +int get_bootloader_message(struct bootloader_message *out) { + size_t write_size; + const MtdPartition *part = mtd_find_partition_by_name(MISC_NAME); + if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) { + LOGE("Can't find %s\n", MISC_NAME); + return -1; + } + + MtdReadContext *read = mtd_read_partition(part); + if (read == NULL) { + LOGE("Can't open %s\n(%s)\n", MISC_NAME, strerror(errno)); + return -1; + } + + const ssize_t size = write_size * MISC_PAGES; + char data[size]; + ssize_t r = mtd_read_data(read, data, size); + if (r != size) LOGE("Can't read %s\n(%s)\n", MISC_NAME, strerror(errno)); + mtd_read_close(read); + if (r != size) return -1; + +#ifdef LOG_VERBOSE + printf("\n--- get_bootloader_message ---\n"); + dump_data(data, size); + printf("\n"); +#endif + + memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out)); + return 0; +} + +int set_bootloader_message(const struct bootloader_message *in) { + size_t write_size; + const MtdPartition *part = mtd_find_partition_by_name(MISC_NAME); + if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) { + LOGE("Can't find %s\n", MISC_NAME); + return -1; + } + + MtdReadContext *read = mtd_read_partition(part); + if (read == NULL) { + LOGE("Can't open %s\n(%s)\n", MISC_NAME, strerror(errno)); + return -1; + } + + ssize_t size = write_size * MISC_PAGES; + char data[size]; + ssize_t r = mtd_read_data(read, data, size); + if (r != size) LOGE("Can't read %s\n(%s)\n", MISC_NAME, strerror(errno)); + mtd_read_close(read); + if (r != size) return -1; + + memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in)); + +#ifdef LOG_VERBOSE + printf("\n--- set_bootloader_message ---\n"); + dump_data(data, size); + printf("\n"); +#endif + + MtdWriteContext *write = mtd_write_partition(part); + if (write == NULL) { + LOGE("Can't open %s\n(%s)\n", MISC_NAME, strerror(errno)); + return -1; + } + if (mtd_write_data(write, data, size) != size) { + LOGE("Can't write %s\n(%s)\n", MISC_NAME, strerror(errno)); + mtd_write_close(write); + return -1; + } + if (mtd_write_close(write)) { + LOGE("Can't finish %s\n(%s)\n", MISC_NAME, strerror(errno)); + return -1; + } + + LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : ""); + return 0; +} + +/* Update Image + * + * - will be stored in the "cache" partition + * - bad blocks will be ignored, like boot.img and recovery.img + * - the first block will be the image header (described below) + * - the size is in BYTES, inclusive of the header + * - offsets are in BYTES from the start of the update header + */ + +struct update_header { + unsigned char MAGIC[UPDATE_MAGIC_SIZE]; + + unsigned version; + unsigned size; + + unsigned image_offset; + unsigned image_length; +}; + +int write_update_for_bootloader( + const char *update, int update_length, + const char *log_filename) { + const MtdPartition *part = mtd_find_partition_by_name(CACHE_NAME); + if (part == NULL) { + LOGE("Can't find %s\n", CACHE_NAME); + return -1; + } + + MtdWriteContext *write = mtd_write_partition(part); + if (write == NULL) { + LOGE("Can't open %s\n(%s)\n", CACHE_NAME, strerror(errno)); + return -1; + } + + /* Write an invalid (zero) header first, to disable any previous + * update and any other structured contents (like a filesystem), + * and as a placeholder for the amount of space required. + */ + + struct update_header header; + memset(&header, 0, sizeof(header)); + const ssize_t header_size = sizeof(header); + if (mtd_write_data(write, (char*) &header, header_size) != header_size) { + LOGE("Can't write header to %s\n(%s)\n", CACHE_NAME, strerror(errno)); + mtd_write_close(write); + return -1; + } + + /* Write each section individually block-aligned, so we can write + * each block independently without complicated buffering. + */ + + memcpy(&header.MAGIC, UPDATE_MAGIC, UPDATE_MAGIC_SIZE); + header.version = UPDATE_VERSION; + header.size = header_size; + + if (log_filename != NULL) { + // Write 1 byte into the following block, then fill to the end + // in order to reserve that block. We'll use the block to + // send a copy of the log through to the next invocation of + // recovery. We write the log as late as possible in order to + // capture any messages emitted by this function. + mtd_erase_blocks(write, 0); + if (mtd_write_data(write, (char*) &header, 1) != 1) { + LOGE("Can't write log block to %s\n(%s)\n", + CACHE_NAME, strerror(errno)); + mtd_write_close(write); + return -1; + } + } + + off_t image_start_pos = mtd_erase_blocks(write, 0); + header.image_length = update_length; + if ((int) header.image_offset == -1 || + mtd_write_data(write, update, update_length) != update_length) { + LOGE("Can't write update to %s\n(%s)\n", CACHE_NAME, strerror(errno)); + mtd_write_close(write); + return -1; + } + mtd_erase_blocks(write, 0); + /* Sending image offset as it is.Apps bootloader will take care of bad blocks */ + header.image_offset = 0x80000; + + /* Write the header last, after all the blocks it refers to, so that + * when the magic number is installed everything is valid. + */ + + if (mtd_write_close(write)) { + LOGE("Can't finish writing %s\n(%s)\n", CACHE_NAME, strerror(errno)); + return -1; + } + + write = mtd_write_partition(part); + if (write == NULL) { + LOGE("Can't reopen %s\n(%s)\n", CACHE_NAME, strerror(errno)); + return -1; + } + + if (mtd_write_data(write, (char*) &header, header_size) != header_size) { + LOGE("Can't rewrite header to %s\n(%s)\n", CACHE_NAME, strerror(errno)); + mtd_write_close(write); + return -1; + } + + if (log_filename != NULL) { + LOGE("writing log\n"); + size_t erase_size; + if (mtd_partition_info(part, NULL, &erase_size, NULL) != 0) { + LOGE("Error reading block size\n(%s)\n", strerror(errno)); + mtd_write_close(write); + return -1; + } + mtd_erase_blocks(write, 0); + + if (erase_size > 0) { + char* log = malloc(erase_size); + FILE* f = fopen(log_filename, "rb"); + // The fseek() may fail if it tries to go before the + // beginning of the log, but that's okay because we want + // to be positioned at the start anyway. + fseek(f, -(erase_size-sizeof(size_t)-LOG_MAGIC_SIZE), SEEK_END); + memcpy(log, LOG_MAGIC, LOG_MAGIC_SIZE); + size_t read = fread(log+sizeof(size_t)+LOG_MAGIC_SIZE, + 1, erase_size-sizeof(size_t)-LOG_MAGIC_SIZE, f); + LOGI("read %d bytes from log\n", (int)read); + *(size_t *)(log + LOG_MAGIC_SIZE) = read; + fclose(f); + if (mtd_write_data(write, log, erase_size) != erase_size) { + LOGE("failed to store log in cache partition\n(%s)\n", + strerror(errno)); + mtd_write_close(write); + } + free(log); + } + } + + if (mtd_erase_blocks(write, 0) != image_start_pos) { + LOGE("Misalignment rewriting %s\n(%s)\n", CACHE_NAME, strerror(errno)); + mtd_write_close(write); + return -1; + } + + LOGE("closing partition\n"); + if (mtd_write_close(write)) { + LOGE("Can't finish header of %s\n(%s)\n", CACHE_NAME, strerror(errno)); + return -1; + } + + return 0; +} diff --git a/updater/bootloader.h b/updater/bootloader.h new file mode 100644 index 0000000000000000000000000000000000000000..bc80a258eb08343e068d8b933423b225971b7104 --- /dev/null +++ b/updater/bootloader.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008 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 _RECOVERY_BOOTLOADER_H +#define _RECOVERY_BOOTLOADER_H + +/* Bootloader Message + * + * This structure describes the content of a block in flash + * that is used for recovery and the bootloader to talk to + * each other. + * + * The command field is updated by linux when it wants to + * reboot into recovery or to update radio or bootloader firmware. + * It is also updated by the bootloader when firmware update + * is complete (to boot into recovery for any final cleanup) + * + * The status field is written by the bootloader after the + * completion of an "update-radio" command. + * + * The recovery field is only written by linux and used + * for the system to send a message to recovery or the + * other way around. + */ +struct bootloader_message { + char command[32]; + char status[32]; + char recovery[1024]; +}; + +/* Read and write the bootloader command from the "misc" partition. + * These return zero on success. + */ +int get_bootloader_message(struct bootloader_message *out); +int set_bootloader_message(const struct bootloader_message *in); + +/* Write an update to the cache partition for update-radio. + * Note, this destroys any filesystem on the cache partition! + */ +int write_update_for_bootloader( + const char *update, int update_len, + const char *log_filename); + +/* Look for a log stored in the cache partition in the block after the + * firmware update header. If we can read such a log, copy it to + * stdout (ie, the current log). + */ +void recover_firmware_update_log(); + +#define CACHE_NAME "cache" +#define MISC_NAME "misc" + +#define UPDATE_MAGIC "MSM-RADIO-UPDATE" +#define UPDATE_MAGIC_SIZE 16 +#define UPDATE_VERSION 0x00010000 + +#define LOG_MAGIC "LOGmagic" +#define LOG_MAGIC_SIZE 8 + + + +#endif diff --git a/updater/firmware.c b/updater/firmware.c new file mode 100644 index 0000000000000000000000000000000000000000..9fc673ab0f27caf051055a8d952c6bc3f087ce2d --- /dev/null +++ b/updater/firmware.c @@ -0,0 +1,251 @@ +/* Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * 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 "bootloader.h" +#include "common.h" +#include "firmware.h" +#include "mtdutils/mtdutils.h" + +#include <errno.h> +#include <string.h> +#include <sys/reboot.h> +#include <sys/mount.h> + +/* Bootloader / Recovery Flow + * + * On every boot, the bootloader will read the bootloader_message + * from flash and check the command field. The bootloader should + * deal with the command field not having a 0 terminator correctly + * (so as to not crash if the block is invalid or corrupt). + * + * The bootloader will have to publish the partition that contains + * the bootloader_message to the linux kernel so it can update it. + * + * if command == "boot-recovery" -> boot recovery.img + * else if command == "update-radio" -> update radio image (below) + * else -> boot boot.img (normal boot) + * + * Radio Update Flow + * 1. the bootloader will attempt to load and validate the header + * 2. if the header is invalid, status="invalid-update", goto #8 + * 3. display the busy image on-screen + * 4. if the update image is invalid, status="invalid-radio-image", goto #8 + * 5. attempt to update the firmware (depending on the command) + * 6. if successful, status="okay", goto #8 + * 7. if failed, and the old image can still boot, status="failed-update" + * 8. write the bootloader_message, leaving the recovery field + * unchanged, updating status, and setting command to + * "boot-recovery" + * 9. reboot + * + * The bootloader will not modify or erase the cache partition. + * It is recovery's responsibility to clean up the mess afterwards. + */ + +#undef LOGE +#define LOGE(...) fprintf(stderr, "E:" __VA_ARGS__) + +static int num_volumes = 0; +static Volume* device_volumes = NULL; + +int install_firmware_update(const char *update_type, + const char *update_data, + size_t update_length, + const char *log_filename) { + if (update_data == NULL || update_length == 0) return 0; + + mtd_scan_partitions(); + + /* We destroy the cache partition to pass the update image to the + * bootloader, so all we can really do afterwards is wipe cache and reboot. + * Set up this instruction now, in case we're interrupted while writing. + */ + + struct bootloader_message boot; + memset(&boot, 0, sizeof(boot)); + strlcpy(boot.command, "boot-recovery", sizeof(boot.command)); + strlcpy(boot.recovery, "recovery\n--wipe_cache\n", sizeof(boot.command)); + if (set_bootloader_message(&boot)) return -1; + + if (write_update_for_bootloader( + update_data, update_length, + log_filename)) { + LOGE("Can't write %s image\n(%s)\n", update_type, strerror(errno)); + return -1; + } + + /* The update image is fully written, so now we can instruct the bootloader + * to install it. (After doing so, it will come back here, and we will + * wipe the cache and reboot into the system.) + */ + snprintf(boot.command, sizeof(boot.command), "update-%s", update_type); + if (set_bootloader_message(&boot)) { + return -1; + } + + reboot(RB_AUTOBOOT); + + LOGE("Can't reboot\n"); + return -1; +} + +static void load_volume_table() { + int alloc = 2; + device_volumes = malloc(alloc * sizeof(Volume)); + + // Insert an entry for /tmp, which is the ramdisk and is always mounted. + device_volumes[0].mount_point = "/tmp"; + device_volumes[0].fs_type = "ramdisk"; + device_volumes[0].device = NULL; + device_volumes[0].device2 = NULL; + num_volumes = 1; + + FILE* fstab; + fstab = fopen("/etc/recovery_mmc.fstab", "r"); + + if (fstab == NULL) { + LOGE("failed to open /etc/recovery.fstab (%s)\n", strerror(errno)); + return; + } + + char buffer[1024]; + int i; + while (fgets(buffer, sizeof(buffer)-1, fstab)) { + for (i = 0; buffer[i] && isspace(buffer[i]); ++i); + if (buffer[i] == '\0' || buffer[i] == '#') continue; + + char* original = strdup(buffer); + + char* mount_point = strtok(buffer+i, " \t\n"); + char* fs_type = strtok(NULL, " \t\n"); + char* device = strtok(NULL, " \t\n"); + // lines may optionally have a second device, to use if + // mounting the first one fails. + char* device2 = strtok(NULL, " \t\n"); + + if (mount_point && fs_type && device) { + while (num_volumes >= alloc) { + alloc *= 2; + device_volumes = realloc(device_volumes, alloc*sizeof(Volume)); + } + device_volumes[num_volumes].mount_point = strdup(mount_point); + device_volumes[num_volumes].fs_type = strdup(fs_type); + device_volumes[num_volumes].device = strdup(device); + device_volumes[num_volumes].device2 = + device2 ? strdup(device2) : NULL; + ++num_volumes; + } else { + LOGE("skipping malformed recovery.fstab line: %s\n", original); + } + free(original); + } + + fclose(fstab); +} + +static Volume* volume_for_path(const char* path) { + int i; + for (i = 0; i < num_volumes; ++i) { + Volume* v = device_volumes+i; + int len = strlen(v->mount_point); + if (strncmp(path, v->mount_point, len) == 0 && + (path[len] == '\0' || path[len] == '/')) { + return v; + } + } + return NULL; +} + +int start_firmware_update(char *update_type, char *part_type) +{ + int result; + struct bootloader_message boot; + + memset(&boot, 0, sizeof(boot)); + + if(!strcmp(part_type, "mtd")) + { + mtd_scan_partitions(); + + strlcpy(boot.recovery, "recovery\n--radio_status\n", sizeof(boot.command)); + snprintf(boot.command, sizeof(boot.command), "update-%s", update_type); + if (set_bootloader_message(&boot)) { + return -1; + } + } + else if(!strcmp(part_type, "emmc")) + { + Volume *v = NULL; + + load_volume_table(); + + v = volume_for_path("/sys_boot"); + if (strcmp(v->fs_type, "vfat")) + { + LOGE("Error in fs_type for sys_boot partition\n"); + return -1; + } + + mkdir("/sys_boot", 777); + + /* Try mounting device first */ + result = mount(v->device, v->mount_point, v->fs_type, + MS_NOATIME | MS_NODEV | MS_NODIRATIME, ""); + if(result) + { + /* Try mounting device2 next */ + result = mount(v->device2, v->mount_point, v->fs_type, + MS_NOATIME | MS_NODEV | MS_NODIRATIME, ""); + } + if(result == 0) + { + /* Creating cookie file for radio update */ + FILE *fp = fopen("/sys_boot/upcookie.txt", "w"); + fclose(fp); + + /* Unmount the sdcard now */ + if(umount(v->mount_point)) + { + LOGE("Error in unmounting %s\n",v->mount_point); + return -1; + } + else + LOGI("Created cookie file for eMMC radio update\n"); + } + else + { + LOGE("Error in mounting %s\n",v->mount_point); + return -1; + } + memset(&boot, 0, sizeof(boot)); + v = volume_for_path("/misc"); + if (set_bootloader_message_emmc(&boot, v)) { + return -1; + } + } + else + { + LOGE("Error in part_type %s\n",part_type); + return -1; + } + + sync(); + reboot(RB_AUTOBOOT); + + // Can't reboot? WTF? + LOGE("Can't reboot\n"); + return -1; +} diff --git a/updater/firmware.h b/updater/firmware.h new file mode 100644 index 0000000000000000000000000000000000000000..bb319bf6075eb1d7266e522b4ab99c6673ffd99c --- /dev/null +++ b/updater/firmware.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2008 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 _RECOVERY_FIRMWARE_H +#define _RECOVERY_FIRMWARE_H + +/* Reboot into the bootloader to install the given update. + * Returns 0 if no radio image was defined, nonzero on error, + * doesn't return at all on success... + */ +int install_firmware_update(const char *update_type, + const char *update_data, + size_t update_length, + const char *log_filename); + +#endif diff --git a/updater/recovery_updater.c b/updater/recovery_updater.c new file mode 100644 index 0000000000000000000000000000000000000000..f5804908acce40ec141c73580288cb672b287849 --- /dev/null +++ b/updater/recovery_updater.c @@ -0,0 +1,87 @@ +/* Copyright (C) 2009 The Android Open Source Project + * Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * 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 <stdio.h> +#include <errno.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> + +#include "edify/expr.h" +#include "firmware.h" + +Value* UpdateFn(const char* name, State* state, int argc, Expr* argv[]) { + if (argc != 1) { + return ErrorAbort(state, "%s() expects 6 args, got %d", name, argc); + } + + char* type = strrchr(name, '_'); + if (type == NULL || *(type+1) == '\0') { + return ErrorAbort(state, "%s() couldn't get type from function name", + name); + } + ++type; + + Value* image; + + if (ReadValueArgs(state, argv, 1, &image) <0) { + return NULL; + } + + if (image->type != VAL_BLOB) { + printf("image argument is not blob (is type %d)\n", image->type); + goto done; + } + + install_firmware_update(type, image->data, image->size, "/tmp/recovery.log"); + printf("%s: install_firmware_update returned!\n", name); + + done: + FreeValue(image); + // install_firmware_update should reboot. If it returns, it failed. + return StringValue(strdup("")); +} + +Value* SetRadioFn(const char* name, State* state, int argc, Expr* argv[]) { + char *part_type; + + if (argc != 1) { + return ErrorAbort(state, "%s() expects arg, got %d", name, argc); + } + + char* type = strrchr(name, '_'); + if (type == NULL || *(type+1) == '\0') { + return ErrorAbort(state, "%s() couldn't get type from function name", + name); + } + ++type; + + if (ReadArgs(state, argv, 1, &part_type) <0) { + return NULL; + } + + start_firmware_update(type,part_type); + + return StringValue(strdup("")); +} + +void Register_librecovery_updater_qcom() { + fprintf(stderr, "installing QCOM updater extensions\n"); + + RegisterFunction("qcom.install_radio", UpdateFn); + RegisterFunction("qcom.set_radio", SetRadioFn); +}