From 077f748171840ffec70fb9f5cda65c2dcc711670 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Sun, 19 Jun 2011 21:53:14 -0700 Subject: [PATCH] [recovery/qcom]: Add SSD based implementation for image upgrade After recovery extracts the images to radio folder, for NAND targets, set cookie in FOTA and bootloader message. For eMMC targets, create cookie file in FAT partition. Change-Id: I79990b8f31e64186d8bcef68aa55fc1d8b2ca8b5 --- releasetools.py | 30 +++++--- updater/bootloader.c | 38 ++++++++++ updater/firmware.c | 152 +++++++++++++++++++++++++++++++++++++ updater/recovery_updater.c | 24 ++++++ 4 files changed, 234 insertions(+), 10 deletions(-) diff --git a/releasetools.py b/releasetools.py index 3f20f091..6337d38a 100644 --- a/releasetools.py +++ b/releasetools.py @@ -36,16 +36,23 @@ def AddBootloaderAssertion(info, input_zip): 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)) -def InstallRadio(radio_img, api_version, input_zip, info): - common.ZipWriteStr(info.output_zip, "radio.img", radio_img) +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) if api_version >= 3: - info.script.UnmountAll() info.script.AppendExtra((''' -assert(qcom.install_radio(package_extract_file("radio.img"))); -''' % locals()).lstrip()) +assert(package_extract_file("%s", "%s")); +''' %(fn2,fn3) % locals()).lstrip()) elif info.input_version >= 2: info.script.AppendExtra( @@ -57,15 +64,18 @@ assert(qcom.install_radio(package_extract_file("radio.img"))); def FullOTA_InstallEnd(info): - try: - radio_img = info.input_zip.read("RADIO/radio.img") - except KeyError: + if info.files == {}: print "warning sha: no radio image in input target_files; not flashing radio" return - info.script.Print("Writing radio image...") + info.script.UnmountAll() + for f in info.files: + info.script.Print("Writing radio image...") + radio_img = info.input_zip.read(f) + InstallRadio(radio_img, info.input_version, info.input_zip, f, info) - InstallRadio(radio_img, info.input_version, info.input_zip, info) + CheckRadiotarget(info, "/recovery") + return def IncrementalOTA_InstallEnd(info): diff --git a/updater/bootloader.c b/updater/bootloader.c index b969c234..30b88f52 100644 --- a/updater/bootloader.c +++ b/updater/bootloader.c @@ -42,6 +42,44 @@ static void dump_data(const char *data, int len) { } #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); diff --git a/updater/firmware.c b/updater/firmware.c index c9834a98..836b137d 100644 --- a/updater/firmware.c +++ b/updater/firmware.c @@ -22,6 +22,7 @@ #include #include #include +#include /* Bootloader / Recovery Flow * @@ -57,6 +58,9 @@ #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, @@ -94,6 +98,154 @@ int install_firmware_update(const char *update_type, 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; + } + strlcpy(boot.recovery, "recovery\n--radio_status\n", sizeof(boot.command)); + snprintf(boot.command, sizeof(boot.command), "update-%s", update_type); + 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/recovery_updater.c b/updater/recovery_updater.c index 01f215ce..10f667f6 100644 --- a/updater/recovery_updater.c +++ b/updater/recovery_updater.c @@ -56,8 +56,32 @@ Value* UpdateFn(const char* name, State* state, int argc, Expr* argv[]) { 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); }