Merge "[recovery/qcom]: Add SSD based implementation for image upgrade" into gingerbread
This commit is contained in:
commit
d6db4505a1
|
@ -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):
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue