Merge "[recovery/qcom]: Add SSD based implementation for image upgrade" into gingerbread

This commit is contained in:
Linux Build Service Account 2011-06-30 12:16:51 -07:00 committed by QuIC Gerrit Code Review
commit d6db4505a1
4 changed files with 234 additions and 10 deletions

View File

@ -36,16 +36,23 @@ def AddBootloaderAssertion(info, input_zip):
info.script.AssertSomeBootloader(*bootloaders) info.script.AssertSomeBootloader(*bootloaders)
info.metadata["pre-bootloader"] = m.group(1) 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): def InstallRadio(radio_img, api_version, input_zip, fn, info):
common.ZipWriteStr(info.output_zip, "radio.img", radio_img) fn2 = fn[6:]
fn3 = "/sdcard/radio/" + fn2
common.ZipWriteStr(info.output_zip, fn2, radio_img)
if api_version >= 3: if api_version >= 3:
info.script.UnmountAll()
info.script.AppendExtra((''' info.script.AppendExtra(('''
assert(qcom.install_radio(package_extract_file("radio.img"))); assert(package_extract_file("%s", "%s"));
''' % locals()).lstrip()) ''' %(fn2,fn3) % locals()).lstrip())
elif info.input_version >= 2: elif info.input_version >= 2:
info.script.AppendExtra( info.script.AppendExtra(
@ -57,15 +64,18 @@ assert(qcom.install_radio(package_extract_file("radio.img")));
def FullOTA_InstallEnd(info): def FullOTA_InstallEnd(info):
try: if info.files == {}:
radio_img = info.input_zip.read("RADIO/radio.img")
except KeyError:
print "warning sha: no radio image in input target_files; not flashing radio" print "warning sha: no radio image in input target_files; not flashing radio"
return return
info.script.UnmountAll()
for f in info.files:
info.script.Print("Writing radio image...") 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): def IncrementalOTA_InstallEnd(info):

View File

@ -42,6 +42,44 @@ static void dump_data(const char *data, int len) {
} }
#endif #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) { int get_bootloader_message(struct bootloader_message *out) {
size_t write_size; size_t write_size;
const MtdPartition *part = mtd_find_partition_by_name(MISC_NAME); const MtdPartition *part = mtd_find_partition_by_name(MISC_NAME);

View File

@ -22,6 +22,7 @@
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <sys/reboot.h> #include <sys/reboot.h>
#include <sys/mount.h>
/* Bootloader / Recovery Flow /* Bootloader / Recovery Flow
* *
@ -57,6 +58,9 @@
#undef LOGE #undef LOGE
#define LOGE(...) fprintf(stderr, "E:" __VA_ARGS__) #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, int install_firmware_update(const char *update_type,
const char *update_data, const char *update_data,
size_t update_length, size_t update_length,
@ -94,6 +98,154 @@ int install_firmware_update(const char *update_type,
reboot(RB_AUTOBOOT); 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? // Can't reboot? WTF?
LOGE("Can't reboot\n"); LOGE("Can't reboot\n");
return -1; return -1;

View File

@ -56,8 +56,32 @@ Value* UpdateFn(const char* name, State* state, int argc, Expr* argv[]) {
return StringValue(strdup("")); 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() { void Register_librecovery_updater_qcom() {
fprintf(stderr, "installing QCOM updater extensions\n"); fprintf(stderr, "installing QCOM updater extensions\n");
RegisterFunction("qcom.install_radio", UpdateFn); RegisterFunction("qcom.install_radio", UpdateFn);
RegisterFunction("qcom.set_radio", SetRadioFn);
} }