[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
This commit is contained in:
Subbaraman Narayanamurthy 2011-06-19 21:53:14 -07:00
parent bcc4923f00
commit 077f748171
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.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):

View File

@ -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);

View File

@ -22,6 +22,7 @@
#include <errno.h>
#include <string.h>
#include <sys/reboot.h>
#include <sys/mount.h>
/* 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;

View File

@ -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);
}