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"); } }
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; }
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); } }
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(); }
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; }
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; } } }
static void menu_reboot(void) { reboot_device(DLOAD); dprintf(CRITICAL,"Failed to reboot\n"); }
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; }