예제 #1
0
파일: ui.c 프로젝트: manhthiep/htc-leo-cLK
static void ui_handle_command(void)
{
    char command[32];

    struct menu_item *chosen_item = ui_get_menu_selection();
    if (chosen_item == NULL) {
    	return;
    }
	strcpy(command, chosen_item->menu_cmd);

	if (!memcmp(command,"boot_recv", strlen(command)))
	{
		boot_into_sboot = 0;
        boot_into_recovery = 1;
        boot_linux_from_flash();
	}
	else if (!memcmp(command,"prnt_part", strlen(command)))
	{
		htcleo_ptable_dump(&flash_ptable);
	}
	else if (!memcmp(command,"prnt_clrs", strlen(command)))
	{
		fbcon_reset();
	}
	else if (!memcmp(command,"boot_sbot", strlen(command)))
	{
        boot_into_sboot = 1;
        boot_into_recovery = 0;
        boot_linux_from_flash();
	}
	else if (!memcmp(command,"boot_nand", strlen(command)))
	{
        boot_into_sboot = 0;
        boot_into_recovery = 0;
        boot_linux_from_flash();
	}
	else if (!memcmp(command,"acpu_ggwp", strlen(command)))
	{
        reboot_device(0);
	}
	else if (!memcmp(command,"acpu_bgwp", strlen(command)))
	{
		reboot_device(FASTBOOT_MODE);
	}
	else if (!memcmp(command,"acpu_pawn", strlen(command)))
	{
        shutdown();
	}
	else
	{
		dprintf(CRITICAL, "Unimplemented command...\n");
	}
}
예제 #2
0
파일: recovery.c 프로젝트: Ever-Never/lk
int recovery_init (void)
{
	struct recovery_message msg;
	struct update_header header;
	char partition_name[32];
	unsigned valid_command = 0;

	// get recovery message
	if(get_recovery_message(&msg))
		return -1;
	if (msg.command[0] != 0 && msg.command[0] != 255) {
		dprintf("Recovery command: %.*s\n", sizeof(msg.command), msg.command);
	}
	msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination

	if (!strcmp("boot-recovery",msg.command)) {
		valid_command = 1;
		strcpy(msg.command, "");	// to safe against multiple reboot into recovery
		strcpy(msg.status, "OKAY");
		set_recovery_message(&msg);	// send recovery message
		boot_into_recovery = 1;		// Boot in recovery mode
		return 0;
	}

// cedesmith: wince phone update radio and boot loader using spl
#ifndef WSPL_VADDR
	if (!strcmp("update-radio",msg.command)) {
		valid_command = 1;
		strcpy(partition_name, "FOTA");
	}

	//Todo: Add support for bootloader update too.
#endif

	if(!valid_command) {
		//We need not to do anything
		return 0; // Boot in normal mode
	}

	if (read_update_header_for_bootloader(&header)) {
		strcpy(msg.status, "invalid-update");
		goto SEND_RECOVERY_MSG;
	}

	if (update_firmware_image (&header, partition_name)) {
		strcpy(msg.status, "failed-update");
		goto SEND_RECOVERY_MSG;
	}
	strcpy(msg.status, "OKAY");

SEND_RECOVERY_MSG:
	strcpy(msg.command, "boot-recovery");
	set_recovery_message(&msg);	// send recovery message
	boot_into_recovery = 1;		// Boot in recovery mode
	reboot_device(0);
	return 0;
}
예제 #3
0
파일: moboot.c 프로젝트: adel71/moboot
void moboot_init(const struct app_descriptor *app)
{
	int rv, keys_pressed;
	unsigned act;
	char *entries[10];

	keys_pressed = 0;

	if (gpiokeys_poll(KEY_ALL)) {
		keys_pressed = 1;
		printf("\nPlease release key(s)...\n");
		while (1) {
			thread_sleep(20);
			if (!gpiokeys_poll(KEY_ALL)) {
				break;
			}
		}
	}

	fbcon_clear();
	fbcon_setpos(0,0);
	printf("welcome to moboot\n");

	entries[0] = "Recover";
	entries[1] = "Reboot";
	entries[2] = "Shutdown";

	act = moboot_menu(0, 2, entries, 0, 3, keys_pressed ? 0 : 9);

	fbcon_setpos(0, 2 + 3 + 2); /* y_start + num_entries + 2 */

	if (act == 0) {
		reboot_device(RESTART_REASON_RECOVER);
	} else if (act == 1) {
		reboot_device(RESTART_REASON_REBOOT);
	} else if (act == 2) {
		reboot_device(RESTART_REASON_SHUTDOWN);
	}

}
예제 #4
0
int emmc_recovery_init(void)
{
	int update_status = 0;
	struct recovery_message msg;
	struct update_header header;
	unsigned valid_command  = 0;
	

	// get recovery message
	if(emmc_get_recovery_msg(&msg))
		return -1;
	if (msg.command[0] != 0 && msg.command[0] != 255) {
		dprintf(INFO,"Recovery command:%s\n",msg.command);
	}
	msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination

	if (!strcmp("boot-recovery",msg.command)) {
		valid_command = 1;
		strcpy(msg.command, "");	// to safe against multiple reboot into recovery
		strcpy(msg.status, "OKAY");
		emmc_set_recovery_msg(&msg);	// send recovery message
		boot_into_recovery = 1;		// Boot in recovery mode
		return 0;
	}

	if (!strcmp("update-bootloader",msg.command))
	{
		read_update_header_for_emmc_bootloader(&header);

		if(update_firmware_emmc_image(&header , "bootloader") == -1)
			return -1;
		
	}
	else
		return 0;	// do nothing
	
	strcpy(msg.command, "boot-recovery");	// clearing recovery command
	emmc_set_recovery_msg(&msg);	// send recovery message
	boot_into_recovery = 1;		// Boot in recovery mode
	reboot_device(0);
	return 0;
}
void flash_recovery_to_boot(int no_flash, int no_reboot) {
	char twrp_device_path[255], recovery_path[255], boot_path[255],
		exec[255], md5recovery[255], md5boot[255],
		recoveryimg[255], bootimg[255], tempimg[255];
	int ret_val = 0;
	FILE *fp;
	char* token;

	// Create folders
	if (verbose)
		printf("Making '/sdcard/TWRP'\n");
	mkdir("/sdcard/TWRP", 0777);
	if (verbose)
		printf("Making folder '/sdcard/TWRP/htcdumlock'\n");
	mkdir("/sdcard/TWRP/htcdumlock", 0777);
	strcpy(twrp_device_path, "/sdcard/TWRP/htcdumlock/");
	strcat(twrp_device_path, device_id);
	if (verbose)
		printf("Making folder '%s'\n", twrp_device_path);
	mkdir(twrp_device_path, 0777);
	// Make folder for recovery
	strcpy(recovery_path, twrp_device_path);
	strcat(recovery_path, "/recovery");
	if (verbose)
		printf("Making folder '%s'\n", recovery_path);
	mkdir(recovery_path, 0777);
	strcat(recovery_path, "/");
	// Make folder for boot
	strcpy(boot_path, twrp_device_path);
	strcat(boot_path, "/boot");
	if (verbose)
		printf("Making folder '%s'\n", boot_path);
	mkdir(boot_path, 0777);
	strcat(boot_path, "/");

	// Set up file locations
	strcpy(recoveryimg, recovery_path);
	strcat(recoveryimg, "recovery.img");
	strcpy(bootimg, boot_path);
	strcat(bootimg, "boot.img");
	strcpy(tempimg, twrp_device_path);
	strcat(tempimg, "/temp.img");

	// Dump recovery
	strcpy(exec, "dump_image recovery ");
	strcat(exec, recoveryimg);
	if (verbose)
		printf("Running command: '%s'\n", exec);
	ret_val = system(exec);
	if (ret_val != 0) {
		printf("Unable to dump recovery.\nFailed\n");
		return;
	}

	// Dump boot (kernel)
	strcpy(exec, "dump_image boot ");
	strcat(exec, tempimg);
	if (verbose)
		printf("Running command: '%s'\n", exec);
	ret_val = system(exec);
	if (ret_val != 0) {
		printf("Unable to dump recovery.\nFailed\n");
		return;
	}

	// Compare the ramdisks of the images from boot and recovery to make sure they are different
	// If they are the same, then recovery is already flashed to boot and we don't want to wipe
	// out our existing backup of boot
	if (compare_ramdisks(tempimg, recoveryimg) != 0) {
		if (verbose)
			printf("Boot and recovery do not match so recovery is not flashed to boot yet...\n");
		strcpy(exec, "mv ");
		strcat(exec, tempimg);
		strcat(exec, " ");
		strcat(exec, bootimg);
		if (verbose)
			printf("Moving temporary boot.img: '%s'\n", exec);
		ret_val = system(exec);
		if (ret_val != 0) {
			printf("Unable to move temporary boot image.\nFailed\n");
			return;
		}
	} else {
		if (!java)
			printf("Ramdisk recovery and boot matches! Recovery is already flashed to boot!\n");
		if (!no_reboot)
			reboot_device();
		return;
	}

	// Flash recovery to boot
	strcpy(exec, "flash_image boot ");
	strcat(exec, recoveryimg);
	if (no_flash) {
		if (verbose)
			printf("NOT flashing recovery to boot due to argument 'noflash', command is '%s'\n", exec);
	} else {
		if (verbose)
			printf("Running command: '%s'\n", exec);
		ret_val = system(exec);
		if (ret_val != 0) {
			printf("Unable to flash recovery to boot.\nFailed\n");
			return;
		}
	}

	if (!no_reboot && !ret_val)
		reboot_device();
}
예제 #6
0
파일: recovery.c 프로젝트: jaehyek/lk
int recovery_init (void)
{
	struct recovery_message msg;
	char partition_name[32];
	unsigned valid_command = 0;
	int update_status = 0;

	// get recovery message
	if (get_recovery_message(&msg))
		return -1;
	msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination
	if (msg.command[0] != 0 && msg.command[0] != 255) {
		dprintf(INFO,"Recovery command: %d %s\n",
			sizeof(msg.command), msg.command);
	}

	if (!strcmp("boot-recovery",msg.command))
	{
		if(!strcmp("RADIO",msg.status))
		{
			/* We're now here due to radio update, so check for update status */
			int ret = get_boot_info_apps(UPDATE_STATUS, (unsigned int *) &update_status);

			if(!ret && (update_status & 0x01))
			{
				dprintf(INFO,"radio update success\n");
				strlcpy(msg.status, "OKAY", sizeof(msg.status));
			}
			else
			{
				dprintf(INFO,"radio update failed\n");
				strlcpy(msg.status, "failed-update", sizeof(msg.status));
			}
			strlcpy(msg.command, "", sizeof(msg.command));	// clearing recovery command
			set_recovery_message(&msg);	// send recovery message
			boot_into_recovery = 1;		// Boot in recovery mode
			return 0;
		}

		valid_command = 1;
		strlcpy(msg.command, "", sizeof(msg.command));	// to safe against multiple reboot into recovery
		strlcpy(msg.status, "OKAY", sizeof(msg.status));
		set_recovery_message(&msg);	// send recovery message
		boot_into_recovery = 1;		// Boot in recovery mode
		return 0;
	}

	if (!strcmp("update-radio",msg.command)) {
		dprintf(INFO,"start radio update\n");
		valid_command = 1;
		strlcpy(partition_name, "FOTA", sizeof(partition_name));
	}

	//Todo: Add support for bootloader update too.

	if(!valid_command) {
		//We need not to do anything
		return 0; // Boot in normal mode
	}

#ifdef OLD_FOTA_UPGRADE
	if (read_update_header_for_bootloader(&header)) {
		strlcpy(msg.status, "invalid-update", sizeof(msg.status));
		goto SEND_RECOVERY_MSG;
	}

	if (update_firmware_image (&header, partition_name)) {
		strlcpy(msg.status, "failed-update", sizeof(msg.status));
		goto SEND_RECOVERY_MSG;
	}
#else
	if (set_ssd_radio_update(partition_name)) {
		/* If writing to FOTA partition fails */
		strlcpy(msg.command, "", sizeof(msg.command));
		strlcpy(msg.status, "failed-update", sizeof(msg.status));
		goto SEND_RECOVERY_MSG;
	}
	else {
		/* Setting this to check the radio update status */
		strlcpy(msg.command, "boot-recovery", sizeof(msg.command));
		strlcpy(msg.status, "RADIO", sizeof(msg.status));
		goto SEND_RECOVERY_MSG;
	}
#endif
	strlcpy(msg.status, "OKAY", sizeof(msg.status));

SEND_RECOVERY_MSG:
	set_recovery_message(&msg);	// send recovery message
	boot_into_recovery = 1;		// Boot in recovery mode
	reboot_device(0);
	return 0;
}
예제 #7
0
void moboot_init(const struct app_descriptor *app)
{
	int rv, keys_pressed;
	unsigned act;
	menu_entry_t *real_entries[32];

	char *ptr;
	int rc;
	char path[256];
	char *newpath;
	char *newtitle;
	char *newname;

	unsigned xoff, yoff;

	unsigned ramdisk_mounted, ramdisk_start, ramdisk_size;

	unsigned i, j;

	unsigned default_menu_entry = 0;
	unsigned next_menu_entry = 0;

	char default_image[256];
	char next_image[256];

	unsigned default_timeout;
	unsigned counted_images;
	unsigned use_next;
	ssize_t splash_sz;
	void *splash_ptr = NULL;
	ssize_t background_sz;
	void *background_ptr;
	ssize_t tile_sz;
	void *tile_ptr;
	char splash_path[256];

	unsigned boot_flags;

	ssize_t rdmsgsz;
	char *rdmsg;

	keys_pressed = 0;

	display_surface = NULL;

	entries = real_entries;

	gfx_trans = 0;

	gfxconsole_clear();
	gfxconsole_setpos(0,0);

	ramdisk_mounted = 0;
	atags_get_ramdisk(&ramdisk_start, &ramdisk_size);
	if (ramdisk_size && ramdisk_start) {
		ramdisk_init((void*)ramdisk_start, ramdisk_size);
		if (fs_mount("/ramdisk", "/dev/ramdisk")) {
			printf("Ramdisk start=%08x size=%08x\n", ramdisk_start, ramdisk_size);
			printf("Unable to mount /ramdisk\n");
			printf("Press SELECT to continue\n");
			gpiokeys_wait_select();
		} else {
			ramdisk_mounted = 1;
		}
	}


    if (fs_mount("/boot", "/dev/mmcblk0p13")) {
		printf("\nUnable to mount /boot, exiting.\n");
		while (1) {
			thread_sleep(20);
		}
	}

	default_timeout = 5;
	if ((rv = fs_load_file("/boot/moboot.timeout", &default_image, 256)) > 0) {
		default_image[rv] = 0;
		if (default_image[rv - 1] == '\n') default_image[rv - 1] = 0;
		default_timeout = atoui(default_image);
	}
	default_image[0] = 0;
	rv = fs_load_file("/boot/moboot.default", &default_image, 256);
	if (rv > 0) {
		default_image[rv] = 0;
		if (default_image[rv - 1] == '\n') default_image[rv - 1] = 0;
	}
	use_next = 0;
	next_image[0] = 0;
	rv = fs_load_file("/boot/moboot.next", &next_image, 256);
	if (rv > 0) {
		next_image[rv] = 0;
		if (next_image[rv - 1] == '\n') next_image[rv - 1] = 0;
	}

	tile_sz = fs_load_file_mem("/boot/moboot.background.tga", &tile_ptr);

	background_surface = NULL;
	tile_surface = NULL;

	if (tile_sz > 0) {
		tile_surface = tga_decode(tile_ptr, tile_sz,
									GFX_FORMAT_RGB_x888);
		struct display_info disp_info;
		if (!display_surface) {
			display_get_info(&disp_info);
			display_surface = gfx_create_surface_from_display(&disp_info);
		}
		background_surface = gfx_create_surface(NULL,
								display_surface->width,
								display_surface->height,
								display_surface->stride,
								display_surface->format);
		for (i = 0; i < display_surface->width; i += tile_surface->width) {
			for (j = 0; j < display_surface->height;
							j += tile_surface->height) {
				gfx_surface_blend(background_surface,
									tile_surface,
									i, j);
			}
		}
	}


	num_menu_entries = 0;

	i = 0;
	counted_images = 0;
	while ((rc = fs_dirent("/boot", i, &ptr)) > 0) {
		sprintf(path, "/boot/%s", ptr);
		if (strncmp("uImage.", ptr, 7) == 0) {
			if (strncmp("uImage.moboot", ptr, 13) != 0) {
				newtitle = malloc(strlen(ptr) - 7 + 5 + 1);
				sprintf(newtitle, "boot %s", ptr + 7);
				newpath = malloc(strlen(ptr) + 6 + 1);
				sprintf(newpath, "/boot/%s", ptr);
				newname = malloc(strlen(ptr) - 7 + 1);
				sprintf(newname, "%s", ptr + 7);
				if (strcmp(default_image, ptr + 7) == 0) {
					default_menu_entry = num_menu_entries;
				}
				if (strcmp(next_image, ptr + 7) == 0) {
					next_menu_entry = num_menu_entries;
					use_next = 1;
				}
				set_menu_entry(newtitle, BOOT_FS, newpath, newname);
				counted_images++;
			}
		}
		free(ptr);
		i++;
	}
	if (rc < 0) {
		dprintf(SPEW, "/boot dirList ERROR rc = %d\n", rc);
	}
	i = 0;
	while ((rc = fs_dirent("/ramdisk/boot", i, &ptr)) > 0) {
		sprintf(path, "/ramdisk/boot/%s", ptr);
		if (strncmp("uImage.", ptr, 7) == 0) {
			if (strncmp("uImage.moboot", ptr, 13) != 0) {
				newtitle = malloc(strlen(ptr) - 7 + 5 + 1);
				sprintf(newtitle, "boot %s", ptr + 7);
				newpath = malloc(strlen(ptr) + 14 + 1);
				sprintf(newpath, "/ramdisk/boot/%s", ptr);
				newname = malloc(strlen(ptr) - 7 + 1);
				sprintf(newname, "%s", ptr + 7);
				if (strcmp(default_image, ptr + 7) == 0) {
					default_menu_entry = num_menu_entries;
				}
				if (strcmp(next_image, ptr + 7) == 0) {
					next_menu_entry = num_menu_entries;
					use_next = 1;
				}
				set_menu_entry(newtitle, BOOT_FS, newpath, newname);
				counted_images++;
			}
		}
		free(ptr);
		i++;
	}
	if (rc < 0) {
		dprintf(SPEW, "/ramdisk/boot dirList ERROR rc = %d\n", rc);
	}
	
	if (counted_images == 0) {
		set_menu_entry("boot", BOOT_FS, "/boot/uImage-2.6.35-palm-tenderloin", "default");
	}


	if (gpiokeys_poll(KEY_ALL)) {
		keys_pressed = 1;
		printf("\nPlease release key(s)...");
		while (1) {
			thread_sleep(20);
			if (!gpiokeys_poll(KEY_ALL)) {
				break;
			}
		}
	}

	gfx_trans = 0;
	if (tile_surface) {
		gfx_trans = 1;
	}


	set_menu_entry("boot webOS Recovery", BOOT_RECOVER, "", "recover");
	set_menu_entry("reboot", BOOT_REBOOT, "", "reboot");
	// set_menu_entry("DFU", BOOT_DFU, "", "");
	set_menu_entry("shutdown", BOOT_SHUTDOWN, "", "shutdown");

	xoff = (gfxconsole_getwidth() - 16 ) / 2;
	if (num_menu_entries < 10) {
		yoff = (gfxconsole_getheight() - 12) / 2;
	} else {
		yoff = (gfxconsole_getheight() - (num_menu_entries + 4)) / 2;
	}

#if 0
	tgasz = fs_load_file_mem("/boot/moboot.tga", &tgaptr);

	tga_surface = NULL;

	if (tgasz > 0) {
		tga_surface = tga_decode(tgaptr, tgasz, GFX_FORMAT_RGB_x888);
		struct display_info disp_info;
		if (!display_surface) {
			display_get_info(&disp_info);
			display_surface = gfx_create_surface_from_display(&disp_info);
		}
	}
#endif

	while (1) {
		gfxconsole_clear();

		show_background();

		if (background_surface) {
			gfxconsole_setbackground(background_surface);
		}

		gfxconsole_settrans(gfx_trans);

		gfxconsole_setpos(xoff,yoff);
		if (gfx_trans) {
			gfxconsole_set_colors(0xffffffff, 0x00000000);
			printf("moboot %s", MOBOOT_VERSION);
			gfxconsole_setpos(xoff,yoff);
			gfxconsole_set_colors(0x00000000, 0x00000000);
		} else {
			gfxconsole_set_colors(0x00000000, 0xffffffff);
			printf("moboot %s", MOBOOT_VERSION);
			gfxconsole_set_colors(0x00000000, 0x000000ff);
		}

		if (!use_next || keys_pressed) {
			act = moboot_menu(xoff, yoff + 2, entries, default_menu_entry, num_menu_entries, keys_pressed ? 0 : default_timeout);
		} else {
			act = next_menu_entry;
			use_next = 0;
		}

		keys_pressed = 1;

		gfxconsole_setpos(xoff, yoff + 2 + num_menu_entries + 2);

		boot_flags = BOOTLINUX_NOFLAGS;

		switch (entries[act]->type) {
			case BOOT_RECOVER:
				reboot_device(RESTART_REASON_RECOVER);
				break;
			case BOOT_REBOOT:
				reboot_device(RESTART_REASON_REBOOT);
				break;
			case BOOT_DFU:
				reboot_device(RESTART_REASON_DFU);
				break;
			case BOOT_SHUTDOWN:
				reboot_device(RESTART_REASON_SHUTDOWN);
				break;
			case BOOT_FS:
				gfxconsole_clear();
				gfxconsole_settrans(gfx_trans);
				show_background();
				gfxconsole_setpos(0,0);

				if (gfx_trans) {
					gfxconsole_set_colors(0x00000000, 0x00000000);
				} else {
					gfxconsole_set_colors(0x00000000, 0x000000ff);
				}

				printf("Selected: '%s'\n\n", entries[act]->title);
				printf("Loading '%s'... ", entries[act]->arg);
				if ((rv = fs_load_file(entries[act]->arg,
							(void *)SCRATCH_ADDR, 
							SCRATCH_SIZE * 1024 * 1024)) < 0) {
					printf("FAILED\n");
				} else {
					printf("OK\n");

					/* check for verbose boot */
					sprintf(splash_path, "/boot/moboot.verbose.%s", 
								entries[act]->name);

					splash_sz = fs_load_file_mem(splash_path, &splash_ptr);

					if (splash_sz > 0) {
						if (strncmp(splash_ptr, "yes", 3) == 0) {
							boot_flags |= BOOTLINUX_VERBOSE;
						}
					}

					/* check for sercon boot */
					sprintf(splash_path, "/boot/moboot.sercon.%s", 
								entries[act]->name);

					splash_sz = fs_load_file_mem(splash_path, &splash_ptr);

					if (splash_sz > 0) {
						if (strncmp(splash_ptr, "yes", 3) == 0) {
							boot_flags |= BOOTLINUX_SERCON;
						}
					}

					if (splash_ptr) free(splash_ptr);

					/* check for splash image */
					sprintf(splash_path, "/boot/moboot.splash.%s.tga", 
								entries[act]->name);

					splash_sz = fs_load_file_mem(splash_path, &splash_ptr);

					splash_surface = NULL;

					if (splash_sz > 0) {
						splash_surface = tga_decode(splash_ptr, splash_sz,
													GFX_FORMAT_RGB_x888);
						struct display_info disp_info;
						if (!display_surface) {
							display_get_info(&disp_info);
							display_surface = gfx_create_surface_from_display(
													&disp_info);
						}
					}

					/* do it to it! */
					bootlinux_uimage_mem((void *)SCRATCH_ADDR, rv, boot_splash,
							boot_flags);
				}

				gfxconsole_set_colors(0x00000000, 0x00ff0000);
				printf("\n\nBOOT FAILED!\n\nPress SELECT to continue\n");
				gfxconsole_set_colors(0x00000000, 0x000000ff);
				gpiokeys_wait_select();
				break;
		}
	}
}
예제 #8
0
static void menu_reboot(void) {
	reboot_device(DLOAD);
	dprintf(CRITICAL,"Failed to reboot\n");
}
예제 #9
0
int update_firmware_image (struct update_header *header, char *name)
{
	struct ptentry *ptn;
	struct ptable *ptable;
	unsigned offset = 0;
	unsigned pagesize = flash_page_size();
	unsigned pagemask = pagesize -1;
	unsigned n = 0;

	ptable = flash_get_ptable();
	if (ptable == NULL) {
		dprintf(CRITICAL, "ERROR: Partition table not found\n");
		return -1;
	}

	ptn = ptable_find(ptable, "cache");
	if (ptn == NULL) {
		dprintf(CRITICAL, "ERROR: No cache partition found\n");
		return -1;
	}

	offset += header->image_offset;
	n = (header->image_length + pagemask) & (~pagemask);

	if (flash_read(ptn, offset, SCRATCH_ADDR, n)) {
		dprintf(CRITICAL, "ERROR: Cannot read radio image\n");
		return -1;
	}

	if (!strcmp(name, "radio")) {
		ptn = ptable_find(ptable, name);
		if (ptn == NULL) {
			dprintf(CRITICAL, "ERROR: No %s partition found\n", name);
			return -1;
		}

		if (flash_write(ptn, 0, SCRATCH_ADDR, n)) {
			dprintf(CRITICAL, "ERROR: flash write fail!\n");
			return -1;
		}
	} else if (!strcmp(name, "bootloader")) {
#ifdef PLATFORM_TCC
		struct ptentry ptn = {
			.name = "bootloader",
		};

		flash_write(&ptn, 0, SCRATCH_ADDR, n);
#endif
	}


	dprintf(INFO, "Partition writen successfully!");
	return 0;
}

/* Bootloader / Recovery Flow
 *
 * On every boot, the bootloader will read the recovery_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 recovery_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 recovery_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.
 */

int recovery_init (void)
{
	struct recovery_message msg;
	struct update_header header;
	char partition_name[32];
	unsigned valid_command = 0;
	
	// get recovery message
	if(get_recovery_message(&msg))
		return -1;
	if (msg.command[0] != 0 && msg.command[0] != 255) {
		dprintf(INFO, "Recovery command: %s\n", msg.command);
	}
	msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination

	if (!strcmp("boot-recovery",msg.command)) {
		valid_command = 1;
		strcpy(msg.command, "");	// to safe against multiple reboot into recovery
		strcpy(msg.status, "OKAY");
		set_recovery_message(&msg);	// send recovery message
		boot_into_recovery = 1;		// Boot in recovery mode
		return 0;
	}

	if (!strcmp("update-radio",msg.command)) {
		valid_command = 1;
		strcpy(partition_name, "AMSS");
	} else if (!strcmp("update-bootloader", msg.command)) {
		valid_command = 1;
		strcpy(partition_name, "bootloader");
	}

	if(!valid_command) {
		//We need not to do anything
		return 0; // Boot in normal mode
	}

	if (read_update_header_for_bootloader(&header)) {
		strcpy(msg.status, "invalid-update");
		goto SEND_RECOVERY_MSG;
	}

	if (update_firmware_image (&header, partition_name)) {
		strcpy(msg.status, "failed-update");
		goto SEND_RECOVERY_MSG;
	}
	strcpy(msg.status, "OKAY");

SEND_RECOVERY_MSG:
	strcpy(msg.command, "boot-recovery");
	set_recovery_message(&msg);	// send recovery message
	boot_into_recovery = 1;		// Boot in recovery mode
	reboot_device(0);
	return 0;
}

#elif defined(TNFTL_V8_INCLUDE)
static int set_recovery_msg_v8(struct recovery_message *out)
{
	char *ptn_name = "misc";
	unsigned long long ptn = 0;
	unsigned int size = ROUND_TO_PAGE(sizeof(*out),511);
	unsigned char data[size];
	
	ptn = flash_ptn_offset(ptn_name);

	if(ptn == 0) {
		dprintf(CRITICAL,"partition %s doesn't exist\n",ptn_name);
		return -1;
	}
	
	memcpy(data, out, sizeof(*out));

	if (flash_write_tnftl_v8(ptn_name, ptn , size, (unsigned int*)data))
	{
		dprintf(CRITICAL,"write failure %s %d\n",ptn_name, sizeof(*out));
		return -1;
	}
	return 0;
}